diff --git a/browser/components/sessionstore/content/aboutSessionRestore.xhtml b/browser/components/sessionstore/content/aboutSessionRestore.xhtml
index 8e033e292fa..6b22250d77d 100644
--- a/browser/components/sessionstore/content/aboutSessionRestore.xhtml
+++ b/browser/components/sessionstore/content/aboutSessionRestore.xhtml
@@ -71,8 +71,8 @@
#ifdef XP_UNIX
-
-
#endif
diff --git a/browser/devtools/debugger/debugger-controller.js b/browser/devtools/debugger/debugger-controller.js
index 059152a5e8c..eda2e1e5e3b 100644
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -123,6 +123,7 @@ let DebuggerController = {
this._remoteConnectionTimeout = window.setTimeout(function() {
// If we couldn't connect to any server yet, try again...
if (!DebuggerController.activeThread) {
+ DebuggerController._onRemoteConnectionTimeout();
DebuggerController._connect();
}
}, Prefs.remoteTimeout);
@@ -130,6 +131,14 @@ let DebuggerController = {
return true;
},
+ /**
+ * Called when a remote connection timeout occurs.
+ */
+ _onRemoteConnectionTimeout: function DC__onRemoteConnectionTimeout() {
+ Cu.reportError("Couldn't connect to " +
+ Prefs.remoteHost + ":" + Prefs.remotePort);
+ },
+
/**
* Initializes a debugger client and connects it to the debugger server,
* wiring event handlers as necessary.
@@ -917,7 +926,7 @@ SourceScripts.prototype = {
}
// Use JS mode for files with .js and .jsm extensions.
- if (/\.jsm?$/.test(this._trimUrlQuery(aUrl))) {
+ if (/\.jsm?$/.test(this.trimUrlQuery(aUrl))) {
DebuggerView.editor.setMode(SourceEditor.MODES.JAVASCRIPT);
} else {
DebuggerView.editor.setMode(SourceEditor.MODES.HTML);
@@ -925,50 +934,121 @@ SourceScripts.prototype = {
},
/**
- * Trims the id selector or query part of a url string, if necessary.
+ * Trims the query part or reference identifier of a url string, if necessary.
*
* @param string aUrl
* The script url.
* @return string
+ * The url with the trimmed query.
*/
- _trimUrlQuery: function SS__trimUrlQuery(aUrl) {
- let q = aUrl.indexOf('#');
- if (q === -1) q = aUrl.indexOf('?');
- if (q === -1) q = aUrl.indexOf('&');
+ trimUrlQuery: function SS_trimUrlQuery(aUrl) {
+ let length = aUrl.length;
+ let q1 = aUrl.indexOf('?');
+ let q2 = aUrl.indexOf('&');
+ let q3 = aUrl.indexOf('#');
+ let q = Math.min(q1 !== -1 ? q1 : length,
+ q2 !== -1 ? q2 : length,
+ q3 !== -1 ? q3 : length);
- if (q > -1) {
- return aUrl.slice(0, q);
- }
- return aUrl;
+ return aUrl.slice(0, q);
},
/**
- * Gets the prePath for a script URL.
+ * Trims as much as possible from a URL, while keeping the result unique
+ * in the Debugger View scripts container.
*
- * @param string aUrl
- * The script url.
+ * @param string | nsIURL aUrl
+ * The script URL.
+ * @param string aLabel [optional]
+ * The resulting label at each step.
+ * @param number aSeq [optional]
+ * The current iteration step.
* @return string
- * The script prePath if the url is valid, null otherwise.
+ * The resulting label at the final step.
*/
- _getScriptPrePath: function SS__getScriptDomain(aUrl) {
- try {
- return Services.io.newURI(aUrl, null, null).prePath + "/";
- } catch (e) {
+ _trimURL: function SS__trimURL(aUrl, aLabel, aSeq) {
+ if (!(aUrl instanceof Ci.nsIURL)) {
+ try {
+ // Use an nsIURL to parse all the url path parts.
+ aUrl = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
+ } catch (e) {
+ // This doesn't look like a url, or nsIURL can't handle it.
+ return aUrl;
+ }
}
- return null;
+ if (!aSeq) {
+ let name = aUrl.fileName;
+ if (name) {
+ // This is a regular file url, get only the file name (contains the
+ // base name and extension if available).
+
+ // If this url contains an invalid query, unfortunately nsIURL thinks
+ // it's part of the file extension. It must be removed.
+ aLabel = aUrl.fileName.replace(/\&.*/, "");
+ } else {
+ // This is not a file url, hence there is no base name, nor extension.
+ // Proceed using other available information.
+ aLabel = "";
+ }
+ aSeq = 1;
+ }
+
+ // If we have a label and it doesn't start with a query...
+ if (aLabel && aLabel.indexOf("?") !== 0) {
+
+ if (DebuggerView.Scripts.containsIgnoringQuery(aUrl.spec)) {
+ // A page may contain multiple requests to the same url but with different
+ // queries. It would be redundant to show each one.
+ return aLabel;
+ }
+ if (!DebuggerView.Scripts.containsLabel(aLabel)) {
+ // We found the shortest unique label for the url.
+ return aLabel;
+ }
+ }
+
+ // Append the url query.
+ if (aSeq === 1) {
+ let query = aUrl.query;
+ if (query) {
+ return this._trimURL(aUrl, aLabel + "?" + query, aSeq + 1);
+ }
+ aSeq++;
+ }
+ // Append the url reference.
+ if (aSeq === 2) {
+ let ref = aUrl.ref;
+ if (ref) {
+ return this._trimURL(aUrl, aLabel + "#" + aUrl.ref, aSeq + 1);
+ }
+ aSeq++;
+ }
+ // Prepend the url directory.
+ if (aSeq === 3) {
+ let dir = aUrl.directory;
+ if (dir) {
+ return this._trimURL(aUrl, dir.replace(/^\//, "") + aLabel, aSeq + 1);
+ }
+ aSeq++;
+ }
+ // Prepend the hostname and port number.
+ if (aSeq === 4) {
+ let host = aUrl.hostPort;
+ if (host) {
+ return this._trimURL(aUrl, host + "/" + aLabel, aSeq + 1);
+ }
+ aSeq++;
+ }
+ // Use the whole url spec but ignoring the reference.
+ if (aSeq === 5) {
+ return this._trimURL(aUrl, aUrl.specIgnoringRef, aSeq + 1);
+ }
+ // Give up.
+ return aUrl.spec;
},
/**
* Gets a unique, simplified label from a script url.
- * ex: a). ici://some.address.com/random/subrandom/
- * b). ni://another.address.org/random/subrandom/page.html
- * c). san://interesting.address.gro/random/script.js
- * d). si://interesting.address.moc/random/another/script.js
- * =>
- * a). subrandom/
- * b). page.html
- * c). script.js
- * d). another/script.js
*
* @param string aUrl
* The script url.
@@ -979,30 +1059,7 @@ SourceScripts.prototype = {
* The simplified label.
*/
_getScriptLabel: function SS__getScriptLabel(aUrl, aHref) {
- let url = this._trimUrlQuery(aUrl);
-
- if (this._labelsCache[url]) {
- return this._labelsCache[url];
- }
-
- let content = window.parent.content;
- let domain = content ? content.location.href : this._getScriptPrePath(aUrl);
-
- let href = aHref || domain;
- let pathElements = url.split("/");
- let label = pathElements.pop() || (pathElements.pop() + "/");
-
- // If the label as a leaf name is already present in the scripts list.
- if (DebuggerView.Scripts.containsLabel(label)) {
- label = url.replace(href.substring(0, href.lastIndexOf("/") + 1), "");
-
- // If the path/to/script is exactly the same, we're in different domains.
- if (DebuggerView.Scripts.containsLabel(label)) {
- label = url;
- }
- }
-
- return this._labelsCache[url] = label;
+ return this._labelsCache[aUrl] || (this._labelsCache[aUrl] = this._trimURL(aUrl));
},
/**
diff --git a/browser/devtools/debugger/debugger-view.js b/browser/devtools/debugger/debugger-view.js
index d26a62a3c35..2e19cb90280 100644
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -157,6 +157,31 @@ ScriptsView.prototype = {
this._onScriptsSearch({});
},
+ /**
+ * Checks whether the script with the specified URL is among the scripts
+ * known to the debugger (ignoring the query & reference).
+ *
+ * @param string aUrl
+ * The script URL.
+ * @return boolean
+ */
+ containsIgnoringQuery: function DVS_containsIgnoringQuery(aUrl) {
+ let sourceScripts = DebuggerController.SourceScripts;
+ aUrl = sourceScripts.trimUrlQuery(aUrl);
+
+ if (this._tmpScripts.some(function(element) {
+ return sourceScripts.trimUrlQuery(element.script.url) == aUrl;
+ })) {
+ return true;
+ }
+ if (this.scriptLocations.some(function(url) {
+ return sourceScripts.trimUrlQuery(url) == aUrl;
+ })) {
+ return true;
+ }
+ return false;
+ },
+
/**
* Checks whether the script with the specified URL is among the scripts
* known to the debugger and shown in the list.
@@ -346,7 +371,7 @@ ScriptsView.prototype = {
aLabel, aScript, aIndex, aSelectIfEmptyFlag)
{
// Make sure we don't duplicate anything.
- if (aLabel == "null" || this.containsLabel(aLabel)) {
+ if (aLabel == "null" || this.containsLabel(aLabel) || this.contains(aScript.url)) {
return;
}
diff --git a/browser/devtools/debugger/test/browser_dbg_createRemote.js b/browser/devtools/debugger/test/browser_dbg_createRemote.js
index 261cccbc775..13cca8fd786 100644
--- a/browser/devtools/debugger/test/browser_dbg_createRemote.js
+++ b/browser/devtools/debugger/test/browser_dbg_createRemote.js
@@ -7,6 +7,7 @@
var gWindow = null;
var gTab = null;
+var gRemotePort = null;
var gAutoConnect = null;
const TEST_URL = EXAMPLE_URL + "browser_dbg_iframes.html";
@@ -17,6 +18,11 @@ function test() {
gWindow = aWindow;
let gDebugger = gWindow.contentWindow;
+ info("Current remote port: " +
+ Services.prefs.getIntPref("devtools.debugger.remote-port"));
+ info("Current autoconnect flag: " +
+ Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect"));
+
is(gDebugger.document.getElementById("close").getAttribute("hidden"), "true",
"The close button should be hidden in a remote debugger.");
@@ -60,21 +66,46 @@ function test() {
}
DebuggerServer.closeListener();
+ gRemotePort = Services.prefs.getIntPref("devtools.debugger.remote-port");
gAutoConnect = Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect");
- Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", true);
// Open the listener at some point in the future to test automatic reconnect.
- window.setTimeout(function() {
- DebuggerServer.openListener(
- Services.prefs.getIntPref("devtools.debugger.remote-port"));
- }, Math.random() * 1000);
+ openListener(gRemotePort + 1);
});
}
+let attempts = 0;
+
+function openListener(port) {
+ Services.prefs.setIntPref("devtools.debugger.remote-port", port);
+ Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", true);
+
+ info("Attempting to open a new listener on port " + port);
+ try {
+ info("Closing listener...");
+ DebuggerServer.closeListener();
+ info("Opening listener...");
+ DebuggerServer.openListener(port);
+ } catch (e) {
+ info(e);
+ info("Exception caught when opening listener on port " + port);
+ info("Retrying with port " + (++port));
+
+ if (++attempts < 100) {
+ DebuggerServer.closeListener();
+ openListener(port);
+ } else {
+ ok(false, "Timed out while opening a listener.");
+ }
+ }
+}
+
registerCleanupFunction(function() {
+ Services.prefs.setIntPref("devtools.debugger.remote-port", gRemotePort);
Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", gAutoConnect);
removeTab(gTab);
gWindow = null;
gTab = null;
+ gRemotePort = null;
gAutoConnect = null;
});
diff --git a/browser/devtools/debugger/test/browser_dbg_propertyview-01.js b/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
index 45568def6bf..13385a73942 100644
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
@@ -37,21 +37,32 @@ function testScriptLabelShortening() {
vs.empty();
vs._scripts.removeEventListener("select", vs._onScriptsChange, false);
- is(ss._trimUrlQuery("a/b/c.d?test=1&random=4"), "a/b/c.d",
+ is(ss.trimUrlQuery("a/b/c.d?test=1&random=4#reference"), "a/b/c.d",
"Trimming the url query isn't done properly.");
let urls = [
- { href: "ichi://some.address.com/random/", leaf: "subrandom/" },
- { href: "ni://another.address.org/random/subrandom/", leaf: "page.html" },
- { href: "san://interesting.address.gro/random/", leaf: "script.js" },
- { href: "shi://interesting.address.moc/random/", leaf: "script.js" },
- { href: "shi://interesting.address.moc/random/", leaf: "x/script.js" },
- { href: "shi://interesting.address.moc/random/", leaf: "x/y/script.js?a=1" },
- { href: "shi://interesting.address.moc/random/x/", leaf: "y/script.js?a=1&b=2", dupe: true },
- { href: "shi://interesting.address.moc/random/x/y/", leaf: "script.js?a=1&b=2&c=3", dupe: true },
- { href: "go://random/", leaf: "script_t1.js&a=1&b=2&c=3" },
- { href: "roku://random/", leaf: "script_t2.js#id" },
- { href: "nana://random/", leaf: "script_t3.js#id?a=1&b=2" }
+ { href: "http://some.address.com/random/", leaf: "subrandom/" },
+ { href: "http://some.address.com/random/", leaf: "suprandom/?a=1" },
+ { href: "http://some.address.com/random/", leaf: "?a=1" },
+ { href: "https://another.address.org/random/subrandom/", leaf: "page.html" },
+
+ { href: "ftp://interesting.address.org/random/", leaf: "script.js" },
+ { href: "ftp://interesting.address.com/random/", leaf: "script.js" },
+ { href: "ftp://interesting.address.com/random/", leaf: "x/script.js" },
+ { href: "ftp://interesting.address.com/random/", leaf: "x/y/script.js?a=1" },
+ { href: "ftp://interesting.address.com/random/x/", leaf: "y/script.js?a=1&b=2", dupe: true },
+ { href: "ftp://interesting.address.com/random/x/y/", leaf: "script.js?a=1&b=2&c=3", dupe: true },
+ { href: "ftp://interesting.address.com/random/", leaf: "x/y/script.js?a=2", dupe: true },
+ { href: "ftp://interesting.address.com/random/x/", leaf: "y/script.js?a=2&b=3", dupe: true },
+ { href: "ftp://interesting.address.com/random/x/y/", leaf: "script.js?a=2&b=3&c=4", dupe: true },
+
+ { href: "file://random/", leaf: "script_t1.js&a=1&b=2&c=3" },
+ { href: "file://random/", leaf: "script_t2_1.js#id" },
+ { href: "file://random/", leaf: "script_t2_2.js?a" },
+ { href: "file://random/", leaf: "script_t2_3.js&b" },
+ { href: "resource://random/", leaf: "script_t3_1.js#id?a=1&b=2" },
+ { href: "resource://random/", leaf: "script_t3_2.js?a=1&b=2#id" },
+ { href: "resource://random/", leaf: "script_t3_3.js&a=1&b=2#id" }
];
urls.forEach(function(url) {
@@ -62,31 +73,55 @@ function testScriptLabelShortening() {
});
executeSoon(function() {
+ info("Script labels:");
+ info(vs.scriptLabels.toSource());
+
+ info("Script locations:");
+ info(vs.scriptLocations.toSource());
+
urls.forEach(function(url) {
let loc = url.href + url.leaf;
- ok(url.dupe || vs.contains(loc), "Script url is incorrect: " + loc);
+ if (url.dupe) {
+ ok(!vs.contains(loc), "Shouldn't contain script: " + loc);
+ } else {
+ ok(vs.contains(loc), "Should contain script: " + loc);
+ }
});
- ok(gDebugger.DebuggerView.Scripts.containsLabel("subrandom/"),
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("random/subrandom/"),
"Script (0) label is incorrect.");
- ok(gDebugger.DebuggerView.Scripts.containsLabel("page.html"),
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("random/suprandom/?a=1"),
"Script (1) label is incorrect.");
- ok(gDebugger.DebuggerView.Scripts.containsLabel("script.js"),
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("random/?a=1"),
"Script (2) label is incorrect.");
- ok(gDebugger.DebuggerView.Scripts.containsLabel("shi://interesting.address.moc/random/script.js"),
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("page.html"),
"Script (3) label is incorrect.");
- ok(gDebugger.DebuggerView.Scripts.containsLabel("x/script.js"),
- "Script (4) label is incorrect.");
- ok(gDebugger.DebuggerView.Scripts.containsLabel("x/y/script.js"),
- "Script (5) label is incorrect.");
- ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t1.js"),
- "Script (6) label is incorrect.");
- ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t2.js"),
- "Script (7) label is incorrect.");
- ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t3.js"),
- "Script (8) label is incorrect.");
- is(vs._scripts.itemCount, 9,
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("script.js"),
+ "Script (4) label is incorrect.");
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("random/script.js"),
+ "Script (5) label is incorrect.");
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("random/x/script.js"),
+ "Script (6) label is incorrect.");
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("script.js?a=1"),
+ "Script (7) label is incorrect.");
+
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t1.js"),
+ "Script (8) label is incorrect.");
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t2_1.js"),
+ "Script (9) label is incorrect.");
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t2_2.js"),
+ "Script (10) label is incorrect.");
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t2_3.js"),
+ "Script (11) label is incorrect.");
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t3_1.js"),
+ "Script (12) label is incorrect.");
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t3_2.js"),
+ "Script (13) label is incorrect.");
+ ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t3_3.js"),
+ "Script (14) label is incorrect.");
+
+ is(vs._scripts.itemCount, urls.filter(function(url) !url.dupe).length,
"Didn't get the correct number of scripts in the list.");
closeDebuggerAndFinish();
diff --git a/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd b/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd
index f3af606685d..50993be90c2 100644
--- a/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd
@@ -14,8 +14,8 @@
-
-
+
+
diff --git a/browser/themes/gnomestripe/devtools/debugger.css b/browser/themes/gnomestripe/devtools/debugger.css
index 158cf3f6ad9..5bd1a93fd43 100644
--- a/browser/themes/gnomestripe/devtools/debugger.css
+++ b/browser/themes/gnomestripe/devtools/debugger.css
@@ -16,13 +16,16 @@
padding: 0;
}
+#scripts {
+ max-width: 350px;
+}
+
/**
* Lists and headers
*/
.list-item {
padding: 2px;
- font: -moz-list;
}
.list-item.selected {
@@ -48,6 +51,7 @@
}
.dbg-stackframe-name {
+ -moz-padding-end: 4px;
font-weight: 600;
}
@@ -65,7 +69,6 @@
.details {
-moz-margin-start: 10px;
- font: -moz-list;
}
/**
@@ -75,7 +78,6 @@
.scope > .title {
text-shadow: 0 1px #222;
color: #fff;
- font: -moz-list;
}
.scope > .title > .arrow {
diff --git a/browser/themes/pinstripe/devtools/debugger.css b/browser/themes/pinstripe/devtools/debugger.css
index 0ecd1ed0ca2..67d2e1bf001 100644
--- a/browser/themes/pinstripe/devtools/debugger.css
+++ b/browser/themes/pinstripe/devtools/debugger.css
@@ -18,13 +18,16 @@
padding: 0;
}
+#scripts {
+ max-width: 350px;
+}
+
/**
* Lists and headers
*/
.list-item {
padding: 2px;
- font: -moz-list;
}
.list-item.selected {
@@ -50,6 +53,7 @@
}
.dbg-stackframe-name {
+ -moz-padding-end: 4px;
font-weight: 600;
}
@@ -67,7 +71,6 @@
.details {
-moz-margin-start: 10px;
- font: -moz-list;
}
/**
@@ -77,7 +80,6 @@
.scope > .title {
text-shadow: 0 1px #222;
color: #fff;
- font: -moz-list;
}
.scope > .title > .arrow {
diff --git a/browser/themes/winstripe/devtools/debugger.css b/browser/themes/winstripe/devtools/debugger.css
index f127274ddde..171c42e926b 100644
--- a/browser/themes/winstripe/devtools/debugger.css
+++ b/browser/themes/winstripe/devtools/debugger.css
@@ -16,13 +16,16 @@
padding: 0;
}
+#scripts {
+ max-width: 350px;
+}
+
/**
* Lists and headers
*/
.list-item {
padding: 2px;
- font: -moz-list;
}
.list-item.selected {
@@ -48,6 +51,7 @@
}
.dbg-stackframe-name {
+ -moz-padding-end: 4px;
font-weight: 600;
}
@@ -65,7 +69,6 @@
.details {
-moz-margin-start: 10px;
- font: -moz-list;
}
/**
@@ -75,7 +78,6 @@
.scope > .title {
text-shadow: 0 1px #222;
color: #fff;
- font: -moz-list;
}
.scope > .title > .arrow {
diff --git a/content/events/public/nsEventStates.h b/content/events/public/nsEventStates.h
index c996b3f5168..e251d134eaf 100644
--- a/content/events/public/nsEventStates.h
+++ b/content/events/public/nsEventStates.h
@@ -236,6 +236,12 @@ private:
#define NS_EVENT_STATE_FULL_SCREEN_ANCESTOR NS_DEFINE_EVENT_STATE_MACRO(35)
// Handler for click to play plugin
#define NS_EVENT_STATE_TYPE_CLICK_TO_PLAY NS_DEFINE_EVENT_STATE_MACRO(36)
+// Content is in the optimum region.
+#define NS_EVENT_STATE_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(37)
+// Content is in the suboptimal region.
+#define NS_EVENT_STATE_SUB_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(38)
+// Content is in the sub-suboptimal region.
+#define NS_EVENT_STATE_SUB_SUB_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(39)
/**
* NOTE: do not go over 63 without updating nsEventStates::InternalType!
diff --git a/content/html/content/public/nsIFormControl.h b/content/html/content/public/nsIFormControl.h
index 73aa67f958e..65120007913 100644
--- a/content/html/content/public/nsIFormControl.h
+++ b/content/html/content/public/nsIFormControl.h
@@ -26,6 +26,7 @@ enum FormControlsTypes {
NS_FORM_SELECT,
NS_FORM_TEXTAREA,
NS_FORM_OBJECT,
+ NS_FORM_METER,
eFormControlsWithoutSubTypesMax,
// After this, all types will have sub-types which introduce new enum lists.
// eFormControlsWithoutSubTypesMax let us know if the previous types values
@@ -243,13 +244,12 @@ bool
nsIFormControl::IsLabelableControl() const
{
// TODO: keygen should be in that list, see bug 101019.
- // TODO: meter should be added, see bug 555985.
// TODO: NS_FORM_INPUT_HIDDEN should be removed, see bug 597650.
PRUint32 type = GetType();
return type & NS_FORM_INPUT_ELEMENT ||
type & NS_FORM_BUTTON_ELEMENT ||
// type == NS_FORM_KEYGEN ||
- // type == NS_FORM_METER ||
+ type == NS_FORM_METER ||
type == NS_FORM_OUTPUT ||
type == NS_FORM_SELECT ||
type == NS_FORM_TEXTAREA;
diff --git a/content/html/content/src/Makefile.in b/content/html/content/src/Makefile.in
index a384b843e44..8807ae727e6 100644
--- a/content/html/content/src/Makefile.in
+++ b/content/html/content/src/Makefile.in
@@ -58,6 +58,7 @@ CPPSRCS = \
nsHTMLMenuElement.cpp \
nsHTMLMenuItemElement.cpp \
nsHTMLMetaElement.cpp \
+ nsHTMLMeterElement.cpp \
nsHTMLModElement.cpp \
nsHTMLObjectElement.cpp \
nsHTMLOListElement.cpp \
diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp
index a208d26483d..6040f38d4da 100644
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -3466,7 +3466,8 @@ nsGenericHTMLFormElement::CanBeDisabled() const
return
type != NS_FORM_LABEL &&
type != NS_FORM_OBJECT &&
- type != NS_FORM_OUTPUT;
+ type != NS_FORM_OUTPUT &&
+ type != NS_FORM_METER;
}
bool
diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h
index 18ce572f368..31aaf45eeb4 100644
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -1544,6 +1544,7 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(Map)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Menu)
NS_DECLARE_NS_NEW_HTML_ELEMENT(MenuItem)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Meta)
+NS_DECLARE_NS_NEW_HTML_ELEMENT(Meter)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Object)
NS_DECLARE_NS_NEW_HTML_ELEMENT(OptGroup)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Option)
diff --git a/content/html/content/src/nsHTMLFieldSetElement.cpp b/content/html/content/src/nsHTMLFieldSetElement.cpp
index 9e3e94449ba..64950a1686f 100644
--- a/content/html/content/src/nsHTMLFieldSetElement.cpp
+++ b/content/html/content/src/nsHTMLFieldSetElement.cpp
@@ -128,7 +128,8 @@ nsHTMLFieldSetElement::MatchListedElements(nsIContent* aContent, PRInt32 aNamesp
nsIAtom* aAtom, void* aData)
{
nsCOMPtr formControl = do_QueryInterface(aContent);
- return formControl && formControl->GetType() != NS_FORM_LABEL;
+ return formControl && formControl->GetType() != NS_FORM_LABEL &&
+ formControl->GetType() != NS_FORM_METER;
}
NS_IMETHODIMP
diff --git a/content/html/content/src/nsHTMLFormElement.cpp b/content/html/content/src/nsHTMLFormElement.cpp
index 54ee721c373..b87804ec8a2 100644
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -191,6 +191,7 @@ ShouldBeInElements(nsIFormControl* aFormControl)
//
// NS_FORM_INPUT_IMAGE
// NS_FORM_LABEL
+ // NS_FORM_METER
return false;
}
diff --git a/content/html/content/src/nsHTMLMeterElement.cpp b/content/html/content/src/nsHTMLMeterElement.cpp
new file mode 100644
index 00000000000..0ddd8e579de
--- /dev/null
+++ b/content/html/content/src/nsHTMLMeterElement.cpp
@@ -0,0 +1,480 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri (original author)
+ * Vincent Lamotte
+ * Laurent Dulary
+ * Yoan Teboul
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIDOMHTMLMeterElement.h"
+#include "nsGenericHTMLElement.h"
+#include "nsAttrValue.h"
+#include "nsEventStateManager.h"
+#include "nsAlgorithm.h"
+
+
+class nsHTMLMeterElement : public nsGenericHTMLFormElement,
+ public nsIDOMHTMLMeterElement
+{
+public:
+ nsHTMLMeterElement(already_AddRefed aNodeInfo);
+ virtual ~nsHTMLMeterElement();
+
+ /* nsISupports */
+ NS_DECL_ISUPPORTS_INHERITED
+
+ /* nsIDOMNode */
+ NS_FORWARD_NSIDOMNODE(nsGenericHTMLFormElement::)
+
+ /* nsIDOMElement */
+ NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLFormElement::)
+
+ /* nsIDOMHTMLElement */
+ NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLFormElement::)
+
+ /* nsIDOMHTMLMeterElement */
+ NS_DECL_NSIDOMHTMLMETERELEMENT
+
+ /* nsIFormControl */
+ NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_METER; }
+ NS_IMETHOD Reset();
+ NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
+
+ virtual nsEventStates IntrinsicState() const;
+
+ nsresult Clone(nsINodeInfo* aNodeInfo, nsINode** aResult) const;
+
+ bool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
+ const nsAString& aValue, nsAttrValue& aResult);
+
+ virtual nsXPCClassInfo* GetClassInfo();
+
+ virtual nsIDOMNode* AsDOMNode() { return this; }
+
+private:
+
+ static const double kDefaultValue;
+ static const double kDefaultMin;
+ static const double kDefaultMax;
+
+ /**
+ * Returns the optimum state of the element.
+ * NS_EVENT_STATE_OPTIMUM if the actual value is in the optimum region.
+ * NS_EVENT_STATE_SUB_OPTIMUM if the actual value is in the sub-optimal region.
+ * NS_EVENT_STATE_SUB_SUB_OPTIMUM if the actual value is in the sub-sub-optimal region.
+ *
+ * @return the optimum state of the element.
+ */
+ nsEventStates GetOptimumState() const;
+
+ /* @return the minimum value */
+ double GetMin() const;
+
+ /* @return the maximum value */
+ double GetMax() const;
+
+ /* @return the actual value */
+ double GetValue() const;
+
+ /* @return the low value */
+ double GetLow() const;
+
+ /* @return the high value */
+ double GetHigh() const;
+
+ /* @return the optimum value */
+ double GetOptimum() const;
+};
+
+const double nsHTMLMeterElement::kDefaultValue = 0.0;
+const double nsHTMLMeterElement::kDefaultMin = 0.0;
+const double nsHTMLMeterElement::kDefaultMax = 1.0;
+
+NS_IMPL_NS_NEW_HTML_ELEMENT(Meter)
+
+
+nsHTMLMeterElement::nsHTMLMeterElement(already_AddRefed aNodeInfo)
+ : nsGenericHTMLFormElement(aNodeInfo)
+{
+}
+
+nsHTMLMeterElement::~nsHTMLMeterElement()
+{
+}
+
+NS_IMPL_ADDREF_INHERITED(nsHTMLMeterElement, nsGenericElement)
+NS_IMPL_RELEASE_INHERITED(nsHTMLMeterElement, nsGenericElement)
+
+DOMCI_NODE_DATA(HTMLMeterElement, nsHTMLMeterElement)
+
+NS_INTERFACE_TABLE_HEAD(nsHTMLMeterElement)
+ NS_HTML_CONTENT_INTERFACE_TABLE1(nsHTMLMeterElement,
+ nsIDOMHTMLMeterElement)
+ NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLMeterElement,
+ nsGenericHTMLFormElement)
+NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLMeterElement)
+
+NS_IMPL_ELEMENT_CLONE(nsHTMLMeterElement)
+
+
+NS_IMETHODIMP
+nsHTMLMeterElement::Reset()
+{
+ /* The meter element is not resettable. */
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
+{
+ /* The meter element is not submittable. */
+ return NS_OK;
+}
+
+nsEventStates
+nsHTMLMeterElement::IntrinsicState() const
+{
+ nsEventStates state = nsGenericHTMLFormElement::IntrinsicState();
+
+ state |= GetOptimumState();
+
+ return state;
+}
+
+bool
+nsHTMLMeterElement::ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
+ const nsAString& aValue, nsAttrValue& aResult)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aAttribute == nsGkAtoms::value || aAttribute == nsGkAtoms::max ||
+ aAttribute == nsGkAtoms::min || aAttribute == nsGkAtoms::low ||
+ aAttribute == nsGkAtoms::high || aAttribute == nsGkAtoms::optimum) {
+ return aResult.ParseDoubleValue(aValue);
+ }
+ }
+
+ return nsGenericHTMLFormElement::ParseAttribute(aNamespaceID, aAttribute,
+ aValue, aResult);
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::GetForm(nsIDOMHTMLFormElement** aForm)
+{
+ return nsGenericHTMLFormElement::GetForm(aForm);
+}
+
+/*
+ * Value getters :
+ * const getters used by XPCOM methods and by IntrinsicState
+ */
+
+double
+nsHTMLMeterElement::GetMin() const
+{
+ /**
+ * If the attribute min is defined, the minimum is this value.
+ * Otherwise, the minimum is the default value.
+ */
+ const nsAttrValue* attrMin = mAttrsAndChildren.GetAttr(nsGkAtoms::min);
+ if (attrMin && attrMin->Type() == nsAttrValue::eDoubleValue) {
+ return attrMin->GetDoubleValue();
+ }
+ return kDefaultMin;
+}
+
+double
+nsHTMLMeterElement::GetMax() const
+{
+ /**
+ * If the attribute max is defined, the maximum is this value.
+ * Otherwise, the maximum is the default value.
+ * If the maximum value is less than the minimum value,
+ * the maximum value is the same as the minimum value.
+ */
+ double max;
+
+ const nsAttrValue* attrMax = mAttrsAndChildren.GetAttr(nsGkAtoms::max);
+ if (attrMax && attrMax->Type() == nsAttrValue::eDoubleValue) {
+ max = attrMax->GetDoubleValue();
+ } else {
+ max = kDefaultMax;
+ }
+
+ return NS_MAX(max, GetMin());
+}
+
+double
+nsHTMLMeterElement::GetValue() const
+{
+ /**
+ * If the attribute value is defined, the actual value is this value.
+ * Otherwise, the actual value is the default value.
+ * If the actual value is less than the minimum value,
+ * the actual value is the same as the minimum value.
+ * If the actual value is greater than the maximum value,
+ * the actual value is the same as the maximum value.
+ */
+ double value;
+
+ const nsAttrValue* attrValue = mAttrsAndChildren.GetAttr(nsGkAtoms::value);
+ if (attrValue && attrValue->Type() == nsAttrValue::eDoubleValue) {
+ value = attrValue->GetDoubleValue();
+ } else {
+ value = kDefaultValue;
+ }
+
+ double min = GetMin();
+
+ if (value <= min) {
+ return min;
+ }
+
+ return NS_MIN(value, GetMax());
+}
+
+double
+nsHTMLMeterElement::GetLow() const
+{
+ /**
+ * If the low value is defined, the low value is this value.
+ * Otherwise, the low value is the minimum value.
+ * If the low value is less than the minimum value,
+ * the low value is the same as the minimum value.
+ * If the low value is greater than the maximum value,
+ * the low value is the same as the maximum value.
+ */
+
+ double min = GetMin();
+
+ const nsAttrValue* attrLow = mAttrsAndChildren.GetAttr(nsGkAtoms::low);
+ if (!attrLow || attrLow->Type() != nsAttrValue::eDoubleValue) {
+ return min;
+ }
+
+ double low = attrLow->GetDoubleValue();
+
+ if (low <= min) {
+ return min;
+ }
+
+ return NS_MIN(low, GetMax());
+}
+
+double
+nsHTMLMeterElement::GetHigh() const
+{
+ /**
+ * If the high value is defined, the high value is this value.
+ * Otherwise, the high value is the maximum value.
+ * If the high value is less than the low value,
+ * the high value is the same as the low value.
+ * If the high value is greater than the maximum value,
+ * the high value is the same as the maximum value.
+ */
+
+ double max = GetMax();
+
+ const nsAttrValue* attrHigh = mAttrsAndChildren.GetAttr(nsGkAtoms::high);
+ if (!attrHigh || attrHigh->Type() != nsAttrValue::eDoubleValue) {
+ return max;
+ }
+
+ double high = attrHigh->GetDoubleValue();
+
+ if (high >= max) {
+ return max;
+ }
+
+ return NS_MAX(high, GetLow());
+}
+
+double
+nsHTMLMeterElement::GetOptimum() const
+{
+ /**
+ * If the optimum value is defined, the optimum value is this value.
+ * Otherwise, the optimum value is the midpoint between
+ * the minimum value and the maximum value :
+ * min + (max - min)/2 = (min + max)/2
+ * If the optimum value is less than the minimum value,
+ * the optimum value is the same as the minimum value.
+ * If the optimum value is greater than the maximum value,
+ * the optimum value is the same as the maximum value.
+ */
+
+ double max = GetMax();
+
+ double min = GetMin();
+
+ const nsAttrValue* attrOptimum =
+ mAttrsAndChildren.GetAttr(nsGkAtoms::optimum);
+ if (!attrOptimum || attrOptimum->Type() != nsAttrValue::eDoubleValue) {
+ return (min + max) / 2.0;
+ }
+
+ double optimum = attrOptimum->GetDoubleValue();
+
+ if (optimum <= min) {
+ return min;
+ }
+
+ return NS_MIN(optimum, max);
+}
+
+/*
+ * XPCOM methods
+ */
+
+NS_IMETHODIMP
+nsHTMLMeterElement::GetMin(double* aValue)
+{
+ *aValue = GetMin();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::SetMin(double aValue)
+{
+ return SetDoubleAttr(nsGkAtoms::min, aValue);
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::GetMax(double* aValue)
+{
+ *aValue = GetMax();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::SetMax(double aValue)
+{
+ return SetDoubleAttr(nsGkAtoms::max, aValue);
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::GetValue(double* aValue)
+{
+ *aValue = GetValue();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::SetValue(double aValue)
+{
+ return SetDoubleAttr(nsGkAtoms::value, aValue);
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::GetLow(double* aValue)
+{
+ *aValue = GetLow();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::SetLow(double aValue)
+{
+ return SetDoubleAttr(nsGkAtoms::low, aValue);
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::GetHigh(double* aValue)
+{
+ *aValue = GetHigh();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::SetHigh(double aValue)
+{
+ return SetDoubleAttr(nsGkAtoms::high, aValue);
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::GetOptimum(double* aValue)
+{
+ *aValue = GetOptimum();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLMeterElement::SetOptimum(double aValue)
+{
+ return SetDoubleAttr(nsGkAtoms::optimum, aValue);
+}
+
+nsEventStates
+nsHTMLMeterElement::GetOptimumState() const
+{
+ /*
+ * If the optimum value is in [minimum, low[,
+ * return if the value is in optimal, suboptimal or sub-suboptimal region
+ *
+ * If the optimum value is in [low, high],
+ * return if the value is in optimal or suboptimal region
+ *
+ * If the optimum value is in ]high, maximum],
+ * return if the value is in optimal, suboptimal or sub-suboptimal region
+ */
+ double value = GetValue();
+ double low = GetLow();
+ double high = GetHigh();
+ double optimum = GetOptimum();
+
+ if (optimum < low) {
+ if (value < low) {
+ return NS_EVENT_STATE_OPTIMUM;
+ }
+ if (value <= high) {
+ return NS_EVENT_STATE_SUB_OPTIMUM;
+ }
+ return NS_EVENT_STATE_SUB_SUB_OPTIMUM;
+ }
+ if (optimum > high) {
+ if (value > high) {
+ return NS_EVENT_STATE_OPTIMUM;
+ }
+ if (value >= low) {
+ return NS_EVENT_STATE_SUB_OPTIMUM;
+ }
+ return NS_EVENT_STATE_SUB_SUB_OPTIMUM;
+ }
+ // optimum in [low, high]
+ if (value >= low && value <= high) {
+ return NS_EVENT_STATE_OPTIMUM;
+ }
+ return NS_EVENT_STATE_SUB_OPTIMUM;
+}
+
diff --git a/content/html/content/test/Makefile.in b/content/html/content/test/Makefile.in
index 0b622ce2fc3..ba2a62a1b23 100644
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -264,6 +264,8 @@ _TEST_FILES = \
test_bug742030.html \
test_bug742549.html \
test_bug745685.html \
+ test_bug657938.html \
+ test_bug660238.html \
test_input_file_picker.html \
$(NULL)
diff --git a/content/html/content/test/forms/test_form_attribute-1.html b/content/html/content/test/forms/test_form_attribute-1.html
index d04d5cc7084..a62d87b176d 100644
--- a/content/html/content/test/forms/test_form_attribute-1.html
+++ b/content/html/content/test/forms/test_form_attribute-1.html
@@ -400,12 +400,11 @@ var forms = [
var elementNames = [
'button', 'fieldset', 'input', 'label', 'object', 'output', 'select',
- 'textarea',
+ 'textarea', 'meter'
];
var todoElements = [
['keygen', 'Keygen'],
- ['meter', 'Meter'],
];
for each(var e in todoElements) {
diff --git a/content/html/content/test/test_bug389797.html b/content/html/content/test/test_bug389797.html
index a5f60656524..37389d461bb 100644
--- a/content/html/content/test/test_bug389797.html
+++ b/content/html/content/test/test_bug389797.html
@@ -178,6 +178,7 @@ HTML_TAG("mark", "");
HTML_TAG("marquee", "Div");
HTML_TAG("menu", "Menu");
HTML_TAG("meta", "Meta");
+HTML_TAG("meter", "Meter");
HTML_TAG("multicol", "Span");
HTML_TAG("nav", "")
HTML_TAG("nobr", "");
diff --git a/content/html/content/test/test_bug657938.html b/content/html/content/test/test_bug657938.html
new file mode 100644
index 00000000000..c3f6ccc7ef0
--- /dev/null
+++ b/content/html/content/test/test_bug657938.html
@@ -0,0 +1,393 @@
+
+
+
+
+ Test for Bug 657938
+
+
+
+
+
+Mozilla Bug 657938
+
+
+
+
+
+
+
+
+
+
diff --git a/content/html/content/test/test_bug660238.html b/content/html/content/test/test_bug660238.html
new file mode 100644
index 00000000000..e1bf74698a1
--- /dev/null
+++ b/content/html/content/test/test_bug660238.html
@@ -0,0 +1,170 @@
+
+
+
+
+ Test for Bug 660238
+
+
+
+
+
+Mozilla Bug 660238
+
+
+
+
+
+
diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp
index a65b82125f4..56fcfc54fca 100644
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -248,6 +248,7 @@
#include "nsIDOMHTMLMenuElement.h"
#include "nsIDOMHTMLMenuItemElement.h"
#include "nsIDOMHTMLMetaElement.h"
+#include "nsIDOMHTMLMeterElement.h"
#include "nsIDOMHTMLModElement.h"
#include "nsIDOMHTMLOListElement.h"
#include "nsIDOMHTMLObjectElement.h"
@@ -905,6 +906,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLMetaElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
+ NS_DEFINE_CLASSINFO_DATA(HTMLMeterElement, nsElementSH,
+ ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLModElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLOListElement, nsElementSH,
@@ -2918,6 +2921,11 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
+ DOM_CLASSINFO_MAP_BEGIN(HTMLMeterElement, nsIDOMHTMLMeterElement)
+ DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLMeterElement)
+ DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
+ DOM_CLASSINFO_MAP_END
+
DOM_CLASSINFO_MAP_BEGIN(HTMLModElement, nsIDOMHTMLModElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLModElement)
DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
diff --git a/dom/base/nsDOMClassInfoClasses.h b/dom/base/nsDOMClassInfoClasses.h
index ad155afaaa9..caff1ed5ce9 100644
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -95,6 +95,7 @@ DOMCI_CLASS(HTMLMapElement)
DOMCI_CLASS(HTMLMenuElement)
DOMCI_CLASS(HTMLMenuItemElement)
DOMCI_CLASS(HTMLMetaElement)
+DOMCI_CLASS(HTMLMeterElement)
DOMCI_CLASS(HTMLModElement)
DOMCI_CLASS(HTMLOListElement)
DOMCI_CLASS(HTMLObjectElement)
diff --git a/dom/interfaces/html/Makefile.in b/dom/interfaces/html/Makefile.in
index 098fa2ed141..e2c6eefbd8c 100644
--- a/dom/interfaces/html/Makefile.in
+++ b/dom/interfaces/html/Makefile.in
@@ -51,6 +51,7 @@ SDK_XPIDLSRCS = \
nsIDOMHTMLMenuElement.idl \
nsIDOMHTMLMenuItemElement.idl \
nsIDOMHTMLMetaElement.idl \
+ nsIDOMHTMLMeterElement.idl \
nsIDOMHTMLModElement.idl \
nsIDOMHTMLOListElement.idl \
nsIDOMHTMLObjectElement.idl \
diff --git a/dom/interfaces/html/nsIDOMHTMLMeterElement.idl b/dom/interfaces/html/nsIDOMHTMLMeterElement.idl
new file mode 100644
index 00000000000..46f94f3a076
--- /dev/null
+++ b/dom/interfaces/html/nsIDOMHTMLMeterElement.idl
@@ -0,0 +1,64 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Vincent Lamotte
+ * Laurent Dulary
+ * Yoan Teboul
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIDOMHTMLElement.idl"
+
+/**
+ * The nsIDOMHTMLMeterElement interface is the interface to a HTML
+ * element.
+ *
+ * For more information on this interface, please see
+ * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#the-meter-element
+ */
+
+[scriptable, uuid(d4466510-8143-11e0-b278-0800200c9a66)]
+interface nsIDOMHTMLMeterElement : nsIDOMHTMLElement
+{
+ attribute double value;
+ attribute double min;
+ attribute double max;
+ attribute double low;
+ attribute double high;
+ attribute double optimum;
+ readonly attribute nsIDOMHTMLFormElement form;
+ /**
+ * The labels attribute will be done with bug 556743.
+ */
+ //readonly attribute NodeList labels;
+};
diff --git a/editor/libeditor/base/nsEditPropertyAtomList.h b/editor/libeditor/base/nsEditPropertyAtomList.h
index 6c463df4a6d..6b83cd3f2b5 100644
--- a/editor/libeditor/base/nsEditPropertyAtomList.h
+++ b/editor/libeditor/base/nsEditPropertyAtomList.h
@@ -114,6 +114,7 @@ EDITOR_ATOM(legend, "legend")
EDITOR_ATOM(li, "li")
EDITOR_ATOM(map, "map")
EDITOR_ATOM(mark, "mark")
+EDITOR_ATOM(meter, "meter")
EDITOR_ATOM(menuitem, "menuitem")
EDITOR_ATOM(mozdirty, "_moz_dirty")
EDITOR_ATOM(mozEditorBogusNode, "_moz_editor_bogus_node")
diff --git a/editor/libeditor/html/nsHTMLEditUtils.cpp b/editor/libeditor/html/nsHTMLEditUtils.cpp
index 865eea6ca41..ad52ebb8647 100644
--- a/editor/libeditor/html/nsHTMLEditUtils.cpp
+++ b/editor/libeditor/html/nsHTMLEditUtils.cpp
@@ -466,6 +466,7 @@ nsHTMLEditUtils::IsFormWidget(dom::Element* node)
|| (nodeAtom == nsEditProperty::output)
|| (nodeAtom == nsEditProperty::keygen)
|| (nodeAtom == nsEditProperty::progress)
+ || (nodeAtom == nsEditProperty::meter)
|| (nodeAtom == nsEditProperty::input);
}
@@ -517,7 +518,7 @@ nsHTMLEditUtils::SupportsAlignAttr(nsIDOMNode * aNode)
// strong, var
#define GROUP_PHRASE (1 << 4)
-// a, applet, basefont, bdo, br, font, iframe, img, map, object, output,
+// a, applet, basefont, bdo, br, font, iframe, img, map, meter, object, output,
// progress, q, script, span, sub, sup
#define GROUP_SPECIAL (1 << 5)
@@ -695,6 +696,7 @@ static const nsElementInfo kElements[eHTMLTag_userdefined] = {
ELEM(menu, true, true, GROUP_BLOCK, GROUP_LI | GROUP_FLOW_ELEMENT),
ELEM(menuitem, false, false, GROUP_NONE, GROUP_NONE),
ELEM(meta, false, false, GROUP_HEAD_CONTENT, GROUP_NONE),
+ ELEM(meter, true, false, GROUP_SPECIAL, GROUP_FLOW_ELEMENT),
ELEM(multicol, false, false, GROUP_NONE, GROUP_NONE),
ELEM(nav, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
ELEM(nobr, false, false, GROUP_NONE, GROUP_NONE),
diff --git a/gfx/src/nsThemeConstants.h b/gfx/src/nsThemeConstants.h
index 62c0ab567ea..8e946b3f14d 100644
--- a/gfx/src/nsThemeConstants.h
+++ b/gfx/src/nsThemeConstants.h
@@ -103,6 +103,12 @@
// A vertical progress chunk
#define NS_THEME_PROGRESSBAR_CHUNK_VERTICAL 54
+// A horizontal meter bar.
+#define NS_THEME_METERBAR 55
+
+// The meter bar's meter indicator
+#define NS_THEME_METERBAR_CHUNK 56
+
// A single tab in a tab widget.
#define NS_THEME_TAB 61
diff --git a/js/xpconnect/src/dom_quickstubs.qsconf b/js/xpconnect/src/dom_quickstubs.qsconf
index 4a1da7e979c..33299c38dcf 100644
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -282,6 +282,7 @@ members = [
'nsIDOMHTMLInputElement.selectionDirection',
'nsIDOMHTMLInputElement.setSelectionRange',
'nsIDOMHTMLLinkElement.disabled',
+ 'nsIDOMHTMLMeterElement.*',
'nsIDOMHTMLMenuElement.*',
'nsIDOMHTMLMenuItemElement.*',
'nsIDOMHTMLOptionElement.index',
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
index 6916943cf35..5cfa0148a3c 100644
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3380,7 +3380,8 @@ nsCSSFrameConstructor::FindHTMLData(Element* aElement,
SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame),
SIMPLE_TAG_CREATE(audio, NS_NewHTMLVideoFrame),
#endif
- SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame)
+ SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame),
+ SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame)
};
return FindDataByTag(aTag, aElement, aStyleContext, sHTMLData,
diff --git a/layout/forms/Makefile.in b/layout/forms/Makefile.in
index 7bd46b958ae..4a0b37b94eb 100644
--- a/layout/forms/Makefile.in
+++ b/layout/forms/Makefile.in
@@ -39,6 +39,7 @@ CPPSRCS = \
nsGfxCheckboxControlFrame.cpp \
nsGfxRadioControlFrame.cpp \
nsProgressFrame.cpp \
+ nsMeterFrame.cpp \
nsTextControlFrame.cpp \
nsHTMLButtonControlFrame.cpp \
nsImageControlFrame.cpp \
diff --git a/layout/forms/nsMeterFrame.cpp b/layout/forms/nsMeterFrame.cpp
new file mode 100644
index 00000000000..8d675c43cbc
--- /dev/null
+++ b/layout/forms/nsMeterFrame.cpp
@@ -0,0 +1,314 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mounir Lamouri
+ * Vincent Lamotte
+ * Laurent Dulary
+ * Yoan Teboul
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsMeterFrame.h"
+
+#include "nsIDOMHTMLMeterElement.h"
+#include "nsIContent.h"
+#include "prtypes.h"
+#include "nsPresContext.h"
+#include "nsGkAtoms.h"
+#include "nsINameSpaceManager.h"
+#include "nsIDocument.h"
+#include "nsIPresShell.h"
+#include "nsNodeInfoManager.h"
+#include "nsINodeInfo.h"
+#include "nsContentCreatorFunctions.h"
+#include "nsContentUtils.h"
+#include "nsFormControlFrame.h"
+#include "nsFontMetrics.h"
+#include "mozilla/dom/Element.h"
+
+
+nsIFrame*
+NS_NewMeterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
+{
+ return new (aPresShell) nsMeterFrame(aContext);
+}
+
+NS_IMPL_FRAMEARENA_HELPERS(nsMeterFrame)
+
+nsMeterFrame::nsMeterFrame(nsStyleContext* aContext)
+ : nsContainerFrame(aContext)
+ , mBarDiv(nsnull)
+{
+}
+
+nsMeterFrame::~nsMeterFrame()
+{
+}
+
+void
+nsMeterFrame::DestroyFrom(nsIFrame* aDestructRoot)
+{
+ NS_ASSERTION(!GetPrevContinuation(),
+ "nsMeterFrame should not have continuations; if it does we "
+ "need to call RegUnregAccessKey only for the first.");
+ nsFormControlFrame::RegUnRegAccessKey(static_cast(this), false);
+ nsContentUtils::DestroyAnonymousContent(&mBarDiv);
+ nsContainerFrame::DestroyFrom(aDestructRoot);
+}
+
+nsresult
+nsMeterFrame::CreateAnonymousContent(nsTArray& aElements)
+{
+ // Get the NodeInfoManager and tag necessary to create the meter bar div.
+ nsCOMPtr doc = mContent->GetDocument();
+
+ nsCOMPtr nodeInfo;
+ nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::div, nsnull,
+ kNameSpaceID_XHTML,
+ nsIDOMNode::ELEMENT_NODE);
+ NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
+
+ // Create the div.
+ nsresult rv = NS_NewHTMLElement(getter_AddRefs(mBarDiv), nodeInfo.forget(),
+ mozilla::dom::NOT_FROM_PARSER);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Associate ::-moz-meter-bar pseudo-element to the anonymous child.
+ nsCSSPseudoElements::Type pseudoType = nsCSSPseudoElements::ePseudo_mozMeterBar;
+ nsRefPtr newStyleContext = PresContext()->StyleSet()->
+ ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
+ GetStyleContext());
+
+ if (!aElements.AppendElement(ContentInfo(mBarDiv, newStyleContext))) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ return NS_OK;
+}
+
+void
+nsMeterFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
+ PRUint32 aFilter)
+{
+ aElements.MaybeAppendElement(mBarDiv);
+}
+
+NS_QUERYFRAME_HEAD(nsMeterFrame)
+ NS_QUERYFRAME_ENTRY(nsMeterFrame)
+ NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
+NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
+
+
+NS_IMETHODIMP nsMeterFrame::Reflow(nsPresContext* aPresContext,
+ nsHTMLReflowMetrics& aDesiredSize,
+ const nsHTMLReflowState& aReflowState,
+ nsReflowStatus& aStatus)
+{
+ DO_GLOBAL_REFLOW_COUNT("nsMeterFrame");
+ DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
+
+ NS_ASSERTION(mBarDiv, "Meter bar div must exist!");
+ NS_ASSERTION(!GetPrevContinuation(),
+ "nsMeterFrame should not have continuations; if it does we "
+ "need to call RegUnregAccessKey only for the first.");
+
+ if (mState & NS_FRAME_FIRST_REFLOW) {
+ nsFormControlFrame::RegUnRegAccessKey(this, true);
+ }
+
+ nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
+ NS_ASSERTION(barFrame, "The meter frame should have a child with a frame!");
+
+ ReflowBarFrame(barFrame, aPresContext, aReflowState, aStatus);
+
+ aDesiredSize.width = aReflowState.ComputedWidth() +
+ aReflowState.mComputedBorderPadding.LeftRight();
+ aDesiredSize.height = aReflowState.ComputedHeight() +
+ aReflowState.mComputedBorderPadding.TopBottom();
+ aDesiredSize.height = NS_CSS_MINMAX(aDesiredSize.height,
+ aReflowState.mComputedMinHeight,
+ aReflowState.mComputedMaxHeight);
+
+ aDesiredSize.SetOverflowAreasToDesiredBounds();
+ ConsiderChildOverflow(aDesiredSize.mOverflowAreas, barFrame);
+ FinishAndStoreOverflow(&aDesiredSize);
+
+ aStatus = NS_FRAME_COMPLETE;
+
+ NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
+
+ return NS_OK;
+}
+
+void
+nsMeterFrame::ReflowBarFrame(nsIFrame* aBarFrame,
+ nsPresContext* aPresContext,
+ const nsHTMLReflowState& aReflowState,
+ nsReflowStatus& aStatus)
+{
+ bool vertical = GetStyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL;
+ nsHTMLReflowState reflowState(aPresContext, aReflowState, aBarFrame,
+ nsSize(aReflowState.ComputedWidth(),
+ NS_UNCONSTRAINEDSIZE));
+ nscoord size = vertical ? aReflowState.ComputedHeight()
+ : aReflowState.ComputedWidth();
+ nscoord xoffset = aReflowState.mComputedBorderPadding.left;
+ nscoord yoffset = aReflowState.mComputedBorderPadding.top;
+
+ // NOTE: Introduce a new function getPosition in the content part ?
+ double position, max, min, value;
+ nsCOMPtr meterElement =
+ do_QueryInterface(mContent);
+
+ meterElement->GetMax(&max);
+ meterElement->GetMin(&min);
+ meterElement->GetValue(&value);
+
+ position = max - min;
+ position = position != 0 ? (value - min) / position : 1;
+
+ size = NSToCoordRound(size * position);
+
+ if (!vertical && GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
+ xoffset += aReflowState.ComputedWidth() - size;
+ }
+
+ // The bar position is *always* constrained.
+ if (vertical) {
+ // We want the bar to begin at the bottom.
+ yoffset += aReflowState.ComputedHeight() - size;
+
+ size -= reflowState.mComputedMargin.TopBottom() +
+ reflowState.mComputedBorderPadding.TopBottom();
+ size = NS_MAX(size, 0);
+ reflowState.SetComputedHeight(size);
+ } else {
+ size -= reflowState.mComputedMargin.LeftRight() +
+ reflowState.mComputedBorderPadding.LeftRight();
+ size = NS_MAX(size, 0);
+ reflowState.SetComputedWidth(size);
+ }
+
+ xoffset += reflowState.mComputedMargin.left;
+ yoffset += reflowState.mComputedMargin.top;
+
+ nsHTMLReflowMetrics barDesiredSize;
+ ReflowChild(aBarFrame, aPresContext, barDesiredSize, reflowState, xoffset,
+ yoffset, 0, aStatus);
+ FinishReflowChild(aBarFrame, aPresContext, &reflowState, barDesiredSize,
+ xoffset, yoffset, 0);
+}
+
+NS_IMETHODIMP
+nsMeterFrame::AttributeChanged(PRInt32 aNameSpaceID,
+ nsIAtom* aAttribute,
+ PRInt32 aModType)
+{
+ NS_ASSERTION(mBarDiv, "Meter bar div must exist!");
+
+ if (aNameSpaceID == kNameSpaceID_None &&
+ (aAttribute == nsGkAtoms::value ||
+ aAttribute == nsGkAtoms::max ||
+ aAttribute == nsGkAtoms::min )) {
+ nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
+ NS_ASSERTION(barFrame, "The meter frame should have a child with a frame!");
+ PresContext()->PresShell()->FrameNeedsReflow(barFrame,
+ nsIPresShell::eResize,
+ NS_FRAME_IS_DIRTY);
+ Invalidate(GetVisualOverflowRectRelativeToSelf());
+ }
+
+ return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
+ aModType);
+}
+
+nsSize
+nsMeterFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
+ nsSize aCBSize, nscoord aAvailableWidth,
+ nsSize aMargin, nsSize aBorder,
+ nsSize aPadding, bool aShrinkWrap)
+{
+ nsRefPtr fontMet;
+ NS_ENSURE_SUCCESS(nsLayoutUtils::GetFontMetricsForFrame(this,
+ getter_AddRefs(fontMet)),
+ nsSize(0, 0));
+
+ nsSize autoSize;
+ autoSize.height = autoSize.width = fontMet->Font().size; // 1em
+
+ if (GetStyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL) {
+ autoSize.height *= 5; // 5em
+ } else {
+ autoSize.width *= 5; // 5em
+ }
+
+ return autoSize;
+}
+
+nscoord
+nsMeterFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
+{
+ nsRefPtr fontMet;
+ NS_ENSURE_SUCCESS(
+ nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet)), 0);
+
+ nscoord minWidth = fontMet->Font().size; // 1em
+
+ if (GetStyleDisplay()->mOrient == NS_STYLE_ORIENT_HORIZONTAL) {
+ minWidth *= 5; // 5em
+ }
+
+ return minWidth;
+}
+
+nscoord
+nsMeterFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
+{
+ return GetMinWidth(aRenderingContext);
+}
+
+bool
+nsMeterFrame::ShouldUseNativeStyle() const
+{
+ // Use the native style if these conditions are satisfied:
+ // - both frames use the native appearance;
+ // - neither frame has author specified rules setting the border or the
+ // background.
+ return GetStyleDisplay()->mAppearance == NS_THEME_METERBAR &&
+ mBarDiv->GetPrimaryFrame()->GetStyleDisplay()->mAppearance == NS_THEME_METERBAR_CHUNK &&
+ !PresContext()->HasAuthorSpecifiedRules(const_cast(this),
+ NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND) &&
+ !PresContext()->HasAuthorSpecifiedRules(mBarDiv->GetPrimaryFrame(),
+ NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND);
+}
+
diff --git a/layout/forms/nsMeterFrame.h b/layout/forms/nsMeterFrame.h
new file mode 100644
index 00000000000..d3bc6316eed
--- /dev/null
+++ b/layout/forms/nsMeterFrame.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Vincent Lamotte
+ * Laurent Dulary
+ * Yoan Teboul
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsMeterFrame_h___
+#define nsMeterFrame_h___
+
+#include "nsContainerFrame.h"
+#include "nsIAnonymousContentCreator.h"
+#include "nsCOMPtr.h"
+
+class nsMeterFrame : public nsContainerFrame,
+ public nsIAnonymousContentCreator
+
+{
+public:
+ NS_DECL_QUERYFRAME_TARGET(nsMeterFrame)
+ NS_DECL_QUERYFRAME
+ NS_DECL_FRAMEARENA_HELPERS
+
+ nsMeterFrame(nsStyleContext* aContext);
+ virtual ~nsMeterFrame();
+
+ virtual void DestroyFrom(nsIFrame* aDestructRoot);
+
+ NS_IMETHOD Reflow(nsPresContext* aCX,
+ nsHTMLReflowMetrics& aDesiredSize,
+ const nsHTMLReflowState& aReflowState,
+ nsReflowStatus& aStatus);
+
+#ifdef NS_DEBUG
+ NS_IMETHOD GetFrameName(nsAString& aResult) const {
+ return MakeFrameName(NS_LITERAL_STRING("Meter"), aResult);
+ }
+#endif
+
+ virtual bool IsLeaf() const { return true; }
+
+ // nsIAnonymousContentCreator
+ virtual nsresult CreateAnonymousContent(nsTArray& aElements);
+ virtual void AppendAnonymousContentTo(nsBaseContentList& aElements,
+ PRUint32 aFilter);
+
+ NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
+ nsIAtom* aAttribute,
+ PRInt32 aModType);
+
+ virtual nsSize ComputeAutoSize(nsRenderingContext *aRenderingContext,
+ nsSize aCBSize, nscoord aAvailableWidth,
+ nsSize aMargin, nsSize aBorder,
+ nsSize aPadding, bool aShrinkWrap);
+
+ virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext);
+ virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext);
+
+ virtual bool IsFrameOfType(PRUint32 aFlags) const
+ {
+ return nsContainerFrame::IsFrameOfType(aFlags &
+ ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
+ }
+
+ /**
+ * Returns whether the frame and its child should use the native style.
+ */
+ bool ShouldUseNativeStyle() const;
+
+protected:
+ // Helper function which reflow the anonymous div frame.
+ void ReflowBarFrame(nsIFrame* aBarFrame,
+ nsPresContext* aPresContext,
+ const nsHTMLReflowState& aReflowState,
+ nsReflowStatus& aStatus);
+ /**
+ * The div used to show the meter bar.
+ * @see nsMeterFrame::CreateAnonymousContent
+ */
+ nsCOMPtr mBarDiv;
+};
+
+#endif
diff --git a/layout/generic/nsHTMLParts.h b/layout/generic/nsHTMLParts.h
index d4214c751e5..debf8c4eb5f 100644
--- a/layout/generic/nsHTMLParts.h
+++ b/layout/generic/nsHTMLParts.h
@@ -187,6 +187,8 @@ nsIFrame*
NS_NewComboboxControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags);
nsIFrame*
NS_NewProgressFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
+nsIFrame*
+NS_NewMeterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
// Table frame factories
nsIFrame*
diff --git a/layout/generic/nsQueryFrame.h b/layout/generic/nsQueryFrame.h
index e0474e9fe45..d377bac0854 100644
--- a/layout/generic/nsQueryFrame.h
+++ b/layout/generic/nsQueryFrame.h
@@ -141,6 +141,7 @@ public:
nsMenuBarFrame_id,
nsMenuFrame_id,
nsMenuPopupFrame_id,
+ nsMeterFrame_id,
nsObjectFrame_id,
nsPageBreakFrame_id,
nsPageContentFrame_id,
diff --git a/layout/reftests/forms/meter/bar-pseudo-element-ref.html b/layout/reftests/forms/meter/bar-pseudo-element-ref.html
new file mode 100644
index 00000000000..c9576fc40b7
--- /dev/null
+++ b/layout/reftests/forms/meter/bar-pseudo-element-ref.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+