Bug 1216234 - add inIDOMUtils.getCSSPseudoElementNames; r=heycam,pbrosset
☠☠ backed out by 0edf9ec8ff4c ☠ ☠
authorTom Tromey <tromey@mozilla.com>
Mon, 09 Nov 2015 07:01:00 +0100
changeset 271931 f1d90a17ebcc54c3b3b6ad0399dc580357c4c037
parent 271930 f31804a5d5a4c8a1556ade1309947beee938c0f4
child 271932 d041722de44b55f6dbf591a7fefadc70120db007
push id29658
push usercbook@mozilla.com
push dateWed, 11 Nov 2015 11:08:38 +0000
treeherdermozilla-central@754119dfb99f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam, pbrosset
bugs1216234
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1216234 - add inIDOMUtils.getCSSPseudoElementNames; r=heycam,pbrosset
devtools/client/styleinspector/rule-view.js
devtools/client/styleinspector/test/browser_ruleview_user-agent-styles.js
devtools/server/actors/styles.js
devtools/server/tests/mochitest/test_styles-applied.html
devtools/shared/styleinspector/css-logic.js
layout/inspector/inDOMUtils.cpp
layout/inspector/inIDOMUtils.idl
layout/inspector/tests/mochitest.ini
layout/inspector/tests/test_getCSSPseudoElementNames.html
--- a/devtools/client/styleinspector/rule-view.js
+++ b/devtools/client/styleinspector/rule-view.js
@@ -8,18 +8,17 @@
 
 const {Cc, Ci, Cu} = require("chrome");
 const promise = require("promise");
 const {setTimeout, clearTimeout} =
       Cu.import("resource://gre/modules/Timer.jsm", {});
 const {CssLogic} = require("devtools/shared/styleinspector/css-logic");
 const {InplaceEditor, editableField, editableItem} =
       require("devtools/client/shared/inplace-editor");
-const {ELEMENT_STYLE, PSEUDO_ELEMENTS} =
-      require("devtools/server/actors/styles");
+const {ELEMENT_STYLE} = require("devtools/server/actors/styles");
 const {OutputParser} = require("devtools/shared/output-parser");
 const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/utils");
 const {
   createChild,
   appendText,
   advanceValidate,
   blurOnMultipleProperties,
   promiseWarn,
@@ -4054,8 +4053,12 @@ XPCOMUtils.defineLazyGetter(this, "_stri
 
 XPCOMUtils.defineLazyGetter(this, "domUtils", function() {
   return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 });
 
 loader.lazyGetter(this, "AutocompletePopup", function() {
   return require("devtools/client/shared/autocomplete-popup").AutocompletePopup;
 });
+
+loader.lazyGetter(this, "PSEUDO_ELEMENTS", () => {
+  return domUtils.getCSSPseudoElementNames();
+});
--- a/devtools/client/styleinspector/test/browser_ruleview_user-agent-styles.js
+++ b/devtools/client/styleinspector/test/browser_ruleview_user-agent-styles.js
@@ -155,16 +155,24 @@ function* compareAppliedStylesWithUI(ins
 
   let entries = yield inspector.pageStyle.getApplied(
     inspector.selection.nodeFront, {
     inherited: true,
     matchedSelectors: true,
     filter: filter
   });
 
+  // We may see multiple entries that map to a given rule; filter the
+  // duplicates here to match what the UI does.
+  let entryMap = new Map();
+  for (let entry of entries) {
+    entryMap.set(entry.rule, entry);
+  }
+  entries = [...entryMap.values()];
+
   let elementStyle = view._elementStyle;
   is(elementStyle.rules.length, entries.length,
     "Should have correct number of rules (" + entries.length + ")");
 
   entries = entries.sort((a, b) => {
     return (a.pseudoElement || "z") > (b.pseudoElement || "z");
   });
 
--- a/devtools/server/actors/styles.js
+++ b/devtools/server/actors/styles.js
@@ -7,17 +7,16 @@
 
 const {Cc, Ci, Cu} = require("chrome");
 const promise = require("promise");
 const protocol = require("devtools/server/protocol");
 const {Arg, Option, method, RetVal, types} = protocol;
 const events = require("sdk/event/core");
 const {Class} = require("sdk/core/heritage");
 const {LongStringActor} = require("devtools/server/actors/string");
-const {PSEUDO_ELEMENT_SET} = require("devtools/shared/styleinspector/css-logic");
 
 // This will also add the "stylesheet" actor type for protocol.js to recognize
 const {UPDATE_PRESERVING_RULES, UPDATE_GENERAL} =
       require("devtools/server/actors/stylesheets");
 
 loader.lazyGetter(this, "CssLogic", () => {
   return require("devtools/shared/styleinspector/css-logic").CssLogic;
 });
@@ -30,34 +29,22 @@ loader.lazyGetter(this, "RuleRewriter", 
 });
 
 // The PageStyle actor flattens the DOM CSS objects a little bit, merging
 // Rules and their Styles into one actor.  For elements (which have a style
 // but no associated rule) we fake a rule with the following style id.
 const ELEMENT_STYLE = 100;
 exports.ELEMENT_STYLE = ELEMENT_STYLE;
 
-// Not included since these are uneditable by the user.
-// See https://hg.mozilla.org/mozilla-central/file/696a4ad5d011/layout/style/nsCSSPseudoElementList.h#l74
-PSEUDO_ELEMENT_SET.delete(":-moz-meter-bar");
-PSEUDO_ELEMENT_SET.delete(":-moz-list-bullet");
-PSEUDO_ELEMENT_SET.delete(":-moz-list-number");
-PSEUDO_ELEMENT_SET.delete(":-moz-focus-inner");
-PSEUDO_ELEMENT_SET.delete(":-moz-focus-outer");
-PSEUDO_ELEMENT_SET.delete(":-moz-math-anonymous");
-PSEUDO_ELEMENT_SET.delete(":-moz-math-stretchy");
-
-const PSEUDO_ELEMENTS = Array.from(PSEUDO_ELEMENT_SET);
-
-exports.PSEUDO_ELEMENTS = PSEUDO_ELEMENTS;
-
 // When gathering rules to read for pseudo elements, we will skip
 // :before and :after, which are handled as a special case.
-const PSEUDO_ELEMENTS_TO_READ = PSEUDO_ELEMENTS.filter(pseudo => {
-  return pseudo !== ":before" && pseudo !== ":after";
+loader.lazyGetter(this, "PSEUDO_ELEMENTS_TO_READ", () => {
+  return DOMUtils.getCSSPseudoElementNames().filter(pseudo => {
+    return pseudo !== ":before" && pseudo !== ":after";
+  });
 });
 
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 const FONT_PREVIEW_TEXT = "Abc";
 const FONT_PREVIEW_FONT_SIZE = 40;
 const FONT_PREVIEW_FILLSTYLE = "black";
 const NORMAL_FONT_WEIGHT = 400;
 const BOLD_FONT_WEIGHT = 700;
--- a/devtools/server/tests/mochitest/test_styles-applied.html
+++ b/devtools/server/tests/mochitest/test_styles-applied.html
@@ -80,17 +80,17 @@ addTest(function inheritedSystemStyles()
     // If our system stylesheets are prone to churn, this might be a fragile
     // test.  If you're here because of that I apologize, file a bug
     // and we can find a different way to test.
 
     ok(!applied[1].inherited, "Entry 1 should not be inherited");
     ok(!applied[1].rule.parentStyleSheet.system, "Entry 1 should be a system style");
     is(applied[1].rule.type, 1, "Entry 1 should be a rule style");
 
-    is(applied.length, 8, "Should have 8 rules.");
+    is(applied.length, 11, "Should have 11 rules.");
   }).then(runNextTest));
 });
 
 addTest(function noInheritedStyles() {
   promiseDone(gWalker.querySelector(gWalker.rootNode, "#test-node").then(node => {
     return gStyles.getApplied(node, { inherited: false, filter: "user" });
   }).then(applied => {
     ok(!applied[0].inherited, "Entry 0 should be uninherited");
--- a/devtools/shared/styleinspector/css-logic.js
+++ b/devtools/shared/styleinspector/css-logic.js
@@ -38,46 +38,16 @@
  * @constructor
  */
 
 const { Cc, Ci, Cu } = require("chrome");
 const Services = require("Services");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const { getRootBindingParent } = require("devtools/shared/layout/utils");
 
-var pseudos = new Set([
-  ":after",
-  ":before",
-  ":first-letter",
-  ":first-line",
-  ":selection",
-  ":-moz-color-swatch",
-  ":-moz-focus-inner",
-  ":-moz-focus-outer",
-  ":-moz-list-bullet",
-  ":-moz-list-number",
-  ":-moz-math-anonymous",
-  ":-moz-math-stretchy",
-  ":-moz-meter-bar",
-  ":-moz-number-spin-box",
-  ":-moz-number-spin-down",
-  ":-moz-number-spin-up",
-  ":-moz-number-text",
-  ":-moz-number-wrapper",
-  ":-moz-placeholder",
-  ":-moz-progress-bar",
-  ":-moz-range-progress",
-  ":-moz-range-thumb",
-  ":-moz-range-track",
-  ":-moz-selection"
-]);
-
-const PSEUDO_ELEMENT_SET = pseudos;
-exports.PSEUDO_ELEMENT_SET = PSEUDO_ELEMENT_SET;
-
 // This should be ok because none of the functions that use this should be used
 // on the worker thread, where Cu is not available.
 if (Cu) {
   Cu.importGlobalProperties(["CSS"]);
 }
 
 function CssLogic()
 {
@@ -1674,28 +1644,16 @@ CssSelector.prototype = {
    * stylesheet.
    */
   get ruleLine()
   {
     return this.cssRule.line;
   },
 
   /**
-   * Retrieve the pseudo-elements that we support. This list should match the
-   * elements specified in layout/style/nsCSSPseudoElementList.h
-   */
-  get pseudoElements()
-  {
-    if (!CssSelector._pseudoElements) {
-      CssSelector._pseudoElements = PSEUDO_ELEMENT_SET;
-    }
-    return CssSelector._pseudoElements;
-  },
-
-  /**
    * Retrieve specificity information for the current selector.
    *
    * @see http://www.w3.org/TR/css3-selectors/#specificity
    * @see http://www.w3.org/TR/CSS2/selector.html
    *
    * @return {Number} The selector's specificity.
    */
   get specificity()
--- a/layout/inspector/inDOMUtils.cpp
+++ b/layout/inspector/inDOMUtils.cpp
@@ -1187,16 +1187,39 @@ GetStatesForPseudoClass(const nsAString&
     return EventStates();
   }
   // Our array above is long enough that indexing into it with
   // NotPseudoClass is ok.
   return sPseudoClassStates[nsCSSPseudoClasses::GetPseudoType(atom)];
 }
 
 NS_IMETHODIMP
+inDOMUtils::GetCSSPseudoElementNames(uint32_t* aLength, char16_t*** aNames)
+{
+  nsTArray<nsIAtom*> array;
+
+  for (int i = 0; i < nsCSSPseudoElements::ePseudo_PseudoElementCount; ++i) {
+    nsCSSPseudoElements::Type type = static_cast<nsCSSPseudoElements::Type>(i);
+    if (!nsCSSPseudoElements::PseudoElementIsUASheetOnly(type)) {
+      nsIAtom* atom = nsCSSPseudoElements::GetPseudoAtom(type);
+      array.AppendElement(atom);
+    }
+  }
+
+  *aLength = array.Length();
+  char16_t** ret =
+    static_cast<char16_t**>(moz_xmalloc(*aLength * sizeof(char16_t*)));
+  for (uint32_t i = 0; i < *aLength; ++i) {
+    ret[i] = ToNewUnicode(nsDependentAtomString(array[i]));
+  }
+  *aNames = ret;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 inDOMUtils::AddPseudoClassLock(nsIDOMElement *aElement,
                                const nsAString &aPseudoClass)
 {
   EventStates state = GetStatesForPseudoClass(aPseudoClass);
   if (state.IsEmpty()) {
     return NS_OK;
   }
 
--- a/layout/inspector/inIDOMUtils.idl
+++ b/layout/inspector/inIDOMUtils.idl
@@ -12,17 +12,17 @@ interface nsIDOMDocument;
 interface nsIDOMCSSRule;
 interface nsIDOMCSSStyleRule;
 interface nsIDOMNode;
 interface nsIDOMNodeList;
 interface nsIDOMFontFaceList;
 interface nsIDOMRange;
 interface nsIDOMCSSStyleSheet;
 
-[scriptable, uuid(d67c0463-592e-4d7c-b67e-923ee3f6c643)]
+[scriptable, uuid(ec3dc3d5-41d1-4d08-ace5-7e944de6614d)]
 interface inIDOMUtils : nsISupports
 {
   // CSS utilities
   void getAllStyleSheets (in nsIDOMDocument aDoc,
                           [optional] out unsigned long aLength,
                           [array, size_is (aLength), retval] out nsISupports aSheets);
   nsISupportsArray getCSSStyleRules(in nsIDOMElement aElement, [optional] in DOMString aPseudo);
 
@@ -157,16 +157,27 @@ interface inIDOMUtils : nsISupports
   nsIArray getBindingURLs(in nsIDOMElement aElement);
 
   // content state utilities
   unsigned long long getContentState(in nsIDOMElement aElement);
   void setContentState(in nsIDOMElement aElement, in unsigned long long aState);
 
   nsIDOMFontFaceList getUsedFontFaces(in nsIDOMRange aRange);
 
+  /**
+   * Get the names of all the supported pseudo-elements.
+   * Pseudo-elements which are only accepted in UA style sheets are
+   * not included.
+   *
+   * @param {unsigned long} aCount the number of items returned
+   * @param {wstring[]} aNames the names
+   */
+  void getCSSPseudoElementNames([optional] out unsigned long aCount,
+                                [retval, array, size_is(aCount)] out wstring aNames);
+
   // pseudo-class style locking methods. aPseudoClass must be a valid pseudo-class
   // selector string, e.g. ":hover". ":-moz-any-link" and non-event-state
   // pseudo-classes are ignored.
   void addPseudoClassLock(in nsIDOMElement aElement, in DOMString aPseudoClass);
   void removePseudoClassLock(in nsIDOMElement aElement, in DOMString aPseudoClass);
   bool hasPseudoClassLock(in nsIDOMElement aElement, in DOMString aPseudoClass);
   void clearPseudoClassLocks(in nsIDOMElement aElement);
 
--- a/layout/inspector/tests/mochitest.ini
+++ b/layout/inspector/tests/mochitest.ini
@@ -14,15 +14,16 @@ support-files =
 [test_bug609549.xhtml]
 [test_bug806192.html]
 [test_bug856317.html]
 [test_bug877690.html]
 [test_bug1006595.html]
 [test_color_to_rgba.html]
 [test_css_property_is_shorthand.html]
 [test_css_property_is_valid.html]
+[test_getCSSPseudoElementNames.html]
 [test_getRelativeRuleLine.html]
 [test_get_all_style_sheets.html]
 [test_is_valid_css_color.html]
 [test_isinheritableproperty.html]
 [test_parseStyleSheet.html]
 [test_parseStyleSheetImport.html]
 [test_selectormatcheselement.html]
new file mode 100644
--- /dev/null
+++ b/layout/inspector/tests/test_getCSSPseudoElementNames.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test inDOMUtils::getCSSPseudoElementNames</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript;version=1.8">
+  let utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
+                           .getService(SpecialPowers.Ci.inIDOMUtils);
+
+  let expected = new Set([
+    ":after",
+    ":before",
+    ":first-letter",
+    ":first-line",
+    ":-moz-color-swatch",
+    ":-moz-focus-inner",
+    ":-moz-focus-outer",
+    ":-moz-list-bullet",
+    ":-moz-list-number",
+    ":-moz-math-anonymous",
+    ":-moz-meter-bar",
+    ":-moz-placeholder",
+    ":-moz-progress-bar",
+    ":-moz-range-progress",
+    ":-moz-range-thumb",
+    ":-moz-range-track",
+    ":-moz-selection",
+  ]);
+
+  let names = utils.getCSSPseudoElementNames();
+  for (let name of names) {
+    ok(expected.has(name), name + " is included");
+    expected.delete(name);
+  }
+
+  if (expected.size > 0) {
+    todo_is(expected.size, 0,
+            "ideally all pseudo-element names would be listed in this test");
+    for (let extra of expected) {
+      info("extra element: " + extra);
+    }
+  }
+
+  </script>
+</head>
+<body>
+<h1>Test inDOMUtils::getCSSPseudoElementNames</h1>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>