Bug 1427419 - Part 6: Move selector methods from inIDOMUtils to InspectorUtils. r?bz draft
authorCameron McCormack <cam@mcc.id.au>
Sat, 06 Jan 2018 15:08:13 +0800
changeset 716751 2316ed35d61347f60a2c1582855b9f059f89542a
parent 716750 93133eab27831bff4d2984bebdb1e60517f7d715
child 716752 da596c2c8eabe9bb358041c35b06ca8b0bb3d243
push id94496
push userbmo:cam@mcc.id.au
push dateSat, 06 Jan 2018 07:08:40 +0000
reviewersbz
bugs1427419
milestone59.0a1
Bug 1427419 - Part 6: Move selector methods from inIDOMUtils to InspectorUtils. r?bz MozReview-Commit-ID: 8FKRPeIijkC
devtools/server/actors/styles.js
devtools/server/css-logic.js
devtools/server/tests/mochitest/test_css-logic-specificity.html
dom/webidl/InspectorUtils.webidl
layout/inspector/InspectorUtils.h
layout/inspector/inDOMUtils.cpp
layout/inspector/inIDOMUtils.idl
layout/inspector/tests/test_selectormatcheselement.html
--- a/devtools/server/actors/styles.js
+++ b/devtools/server/actors/styles.js
@@ -674,18 +674,18 @@ var PageStyleActor = protocol.ActorClass
         let domRule = entry.rule.rawRule;
         let selectors = CssLogic.getSelectors(domRule);
         let element = entry.inherited ? entry.inherited.rawNode : node.rawNode;
 
         let {bindingElement, pseudo} =
             CssLogic.getBindingElementAndPseudo(element);
         entry.matchedSelectors = [];
         for (let i = 0; i < selectors.length; i++) {
-          if (DOMUtils.selectorMatchesElement(bindingElement, domRule, i,
-                                              pseudo)) {
+          if (InspectorUtils.selectorMatchesElement(bindingElement, domRule, i,
+                                                    pseudo)) {
             entry.matchedSelectors.push(selectors[i]);
           }
         }
       }
     }
 
     // Add all the keyframes rule associated with the element
     let computedStyle = this.cssLogic.computedStyle;
--- a/devtools/server/css-logic.js
+++ b/devtools/server/css-logic.js
@@ -24,18 +24,17 @@
  * - CssPropertyInfo contains style information for a single property for the
  *   highlighted element.
  * - CssSelectorInfo is a wrapper around CssSelector, which adds sorting with
  *   reference to the selected element.
  */
 
 "use strict";
 
-const { Cc, Ci, Cu } = require("chrome");
-const DevToolsUtils = require("devtools/shared/DevToolsUtils");
+const { Cu } = require("chrome");
 const nodeConstants = require("devtools/shared/dom-node-constants");
 const {
   getBindingElementAndPseudo,
   getCSSStyleRules,
   l10n,
   isContentStylesheet,
   shortSource,
   FILTER,
@@ -470,17 +469,17 @@ CssLogic.prototype = {
    *        The index of the selector within the DOMRule.
    * @return {boolean}
    *         true if the given selector matches the highlighted element or any
    *         of its parents, otherwise false is returned.
    */
   selectorMatchesElement: function (domRule, idx) {
     let element = this.viewedElement;
     do {
-      if (domUtils.selectorMatchesElement(element, domRule, idx)) {
+      if (InspectorUtils.selectorMatchesElement(element, domRule, idx)) {
         return true;
       }
     } while ((element = element.parentNode) &&
              element.nodeType === nodeConstants.ELEMENT_NODE);
 
     return false;
   },
 
@@ -636,19 +635,19 @@ CssLogic.getShortName = function (elemen
  * @param {DOMRule} domRule
  *        The DOMRule to parse.
  * @return {Array}
  *         An array of string selectors.
  */
 CssLogic.getSelectors = function (domRule) {
   let selectors = [];
 
-  let len = domUtils.getSelectorCount(domRule);
+  let len = InspectorUtils.getSelectorCount(domRule);
   for (let i = 0; i < len; i++) {
-    let text = domUtils.getSelectorText(domRule, i);
+    let text = InspectorUtils.getSelectorText(domRule, i);
     selectors.push(text);
   }
   return selectors;
 };
 
 /**
  * Given a node, check to see if it is a ::before or ::after element.
  * If so, return the node that is accessible from within the document
@@ -1125,18 +1124,18 @@ CssSelector.prototype = {
       // directly. @see http://www.w3.org/TR/CSS2/cascade.html#specificity
       return 0x40000000;
     }
 
     if (this._specificity) {
       return this._specificity;
     }
 
-    this._specificity = domUtils.getSpecificity(this.cssRule.domRule,
-                                                this.selectorIndex);
+    this._specificity = InspectorUtils.getSpecificity(this.cssRule.domRule,
+                                                      this.selectorIndex);
 
     return this._specificity;
   },
 
   toString: function () {
     return this.text;
   },
 };
@@ -1479,12 +1478,8 @@ CssSelectorInfo.prototype = {
 
     return 0;
   },
 
   toString: function () {
     return this.selector + " -> " + this.value;
   },
 };
-
-DevToolsUtils.defineLazyGetter(this, "domUtils", function () {
-  return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
-});
--- a/devtools/server/tests/mochitest/test_css-logic-specificity.html
+++ b/devtools/server/tests/mochitest/test_css-logic-specificity.html
@@ -14,16 +14,17 @@ Test that css-logic calculates CSS speci
 
   window.onload = function () {
     const {utils: Cu, classes: Cc, interfaces: Ci} = Components;
 
     const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
     const {CssLogic, CssSelector} = require("devtools/server/css-logic");
     const DOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"]
                        .getService(Ci.inIDOMUtils);
+    const InspectorUtils = SpecialPowers.InspectorUtils;
 
     const TEST_DATA = [
       {text: "*", expected: 0},
       {text: "LI", expected: 1},
       {text: "UL LI", expected: 2},
       {text: "UL OL + LI", expected: 3},
       {text: "H1 + [REL=\"up\"]", expected: 1025},
       {text: "UL OL LI.red", expected: 1027},
@@ -62,18 +63,18 @@ Test that css-logic calculates CSS speci
 
     info("Iterating over the test selectors");
     for (let i = 0; i < selectors.length; i++) {
       let selectorText = selectors[i];
       info("Testing selector " + selectorText);
 
       let selector = new CssSelector(cssRule, selectorText, i);
       let expected = getExpectedSpecificity(selectorText);
-      let specificity = DOMUtils.getSpecificity(selector.cssRule,
-                                                selector.selectorIndex);
+      let specificity = InspectorUtils.getSpecificity(selector.cssRule,
+                                                      selector.selectorIndex);
       is(specificity, expected,
         'Selector "' + selectorText + '" has a specificity of ' + expected);
     }
 
     info("Testing specificity of element.style");
     let colorProp = cssLogic.getPropertyInfo("background");
     is(colorProp.matchedSelectors[0].specificity, 0x40000000,
        "Element styles have specificity of 0x40000000 (1073741824).");
--- a/dom/webidl/InspectorUtils.webidl
+++ b/dom/webidl/InspectorUtils.webidl
@@ -14,16 +14,26 @@ namespace InspectorUtils {
   sequence<StyleSheet> getAllStyleSheets(Document document);
   sequence<CSSRule> getCSSStyleRules(
     Element element,
     [TreatNullAs=EmptyString] optional DOMString pseudo = "");
   unsigned long getRuleLine(CSSRule rule);
   unsigned long getRuleColumn(CSSRule rule);
   unsigned long getRelativeRuleLine(CSSRule rule);
   [NewObject] CSSLexer getCSSLexer(DOMString text);
+  unsigned long getSelectorCount(CSSStyleRule rule);
+  [Throws] DOMString getSelectorText(CSSStyleRule rule,
+                                     unsigned long selectorIndex);
+  [Throws] unsigned long long getSpecificity(CSSStyleRule rule,
+                                             unsigned long selectorIndex);
+  [Throws] boolean selectorMatchesElement(
+      Element element,
+      CSSStyleRule rule,
+      unsigned long selectorIndex,
+      [TreatNullAs=EmptyString] optional DOMString pseudo = "");
 };
 
 dictionary InspectorRGBTriple {
   /*
    * NOTE: Using octet for RGB components is not generally OK, because
    * they can be outside the 0-255 range, but for backwards-compatible
    * named colors (which is what we use this dictionary for) the 0-255
    * assumption is fine.
--- a/layout/inspector/InspectorUtils.h
+++ b/layout/inspector/InspectorUtils.h
@@ -64,16 +64,44 @@ public:
    * @param aRule the rule to examine
    * @return the line number of the rule, possibly relative to the
    *         <style> element
    */
   static uint32_t GetRelativeRuleLine(GlobalObject& aGlobal, css::Rule& aRule);
 
   static CSSLexer* GetCSSLexer(GlobalObject& aGlobal, const nsAString& aText);
 
+  // Utilities for working with selectors.  We don't have a JS OM representation
+  // of a single selector or a selector list yet, but given a rule we can index
+  // into the selector list.
+  //
+  // These methods would probably make more sense being [ChromeOnly] APIs on
+  // CSSStyleRule itself (bug 1428245).
+  static uint32_t GetSelectorCount(GlobalObject& aGlobal,
+                                   BindingStyleRule& aRule);
+
+  // For all three functions below, aSelectorIndex is 0-based
+  static void GetSelectorText(GlobalObject& aGlobal,
+                              BindingStyleRule& aRule,
+                              uint32_t aSelectorIndex,
+                              nsString& aText,
+                              ErrorResult& aRv);
+  static uint64_t GetSpecificity(GlobalObject& aGlobal,
+                                 BindingStyleRule& aRule,
+                                 uint32_t aSelectorIndex,
+                                 ErrorResult& aRv);
+  // Note: This does not handle scoped selectors correctly, because it has no
+  // idea what the right scope is.
+  static bool SelectorMatchesElement(GlobalObject& aGlobal,
+                                     Element& aElement,
+                                     BindingStyleRule& aRule,
+                                     uint32_t aSelectorIndex,
+                                     const nsAString& aPseudo,
+                                     ErrorResult& aRv);
+
 private:
   static already_AddRefed<nsStyleContext>
     GetCleanStyleContextForElement(Element* aElement, nsAtom* aPseudo);
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/layout/inspector/inDOMUtils.cpp
+++ b/layout/inspector/inDOMUtils.cpp
@@ -300,43 +300,16 @@ InspectorUtils::GetCSSStyleRules(GlobalO
         aResult.AppendElement(rule);
       } else {
         MOZ_ASSERT_UNREACHABLE("We should be able to map a raw rule to a rule");
       }
     }
   }
 }
 
-} // namespace dom
-} // namespace mozilla
-
-static already_AddRefed<BindingStyleRule>
-GetRuleFromDOMRule(nsIDOMCSSStyleRule *aRule, ErrorResult& rv)
-{
-  nsCOMPtr<nsICSSStyleRuleDOMWrapper> rule = do_QueryInterface(aRule);
-  if (!rule) {
-    rv.Throw(NS_ERROR_INVALID_POINTER);
-    return nullptr;
-  }
-
-  RefPtr<BindingStyleRule> cssrule;
-  rv = rule->GetCSSStyleRule(getter_AddRefs(cssrule));
-  if (rv.Failed()) {
-    return nullptr;
-  }
-
-  if (!cssrule) {
-    rv.Throw(NS_ERROR_FAILURE);
-  }
-  return cssrule.forget();
-}
-
-namespace mozilla {
-namespace dom {
-
 /* static */ uint32_t
 InspectorUtils::GetRuleLine(GlobalObject& aGlobal, css::Rule& aRule)
 {
   return aRule.GetLineNumber();
 }
 
 /* static */ uint32_t
 InspectorUtils::GetRuleColumn(GlobalObject& aGlobal, css::Rule& aRule)
@@ -364,78 +337,60 @@ InspectorUtils::GetRelativeRuleLine(Glob
 }
 
 /* static */ CSSLexer*
 InspectorUtils::GetCSSLexer(GlobalObject& aGlobal, const nsAString& aText)
 {
   return new CSSLexer(aText);
 }
 
-} // namespace dom
-} // namespace mozilla
-
-NS_IMETHODIMP
-inDOMUtils::GetSelectorCount(nsIDOMCSSStyleRule* aRule, uint32_t *aCount)
+/* static */ uint32_t
+InspectorUtils::GetSelectorCount(GlobalObject& aGlobal,
+                                 BindingStyleRule& aRule)
 {
-  ErrorResult rv;
-  RefPtr<BindingStyleRule> rule = GetRuleFromDOMRule(aRule, rv);
-  if (rv.Failed()) {
-    return rv.StealNSResult();
-  }
-
-  *aCount = rule->GetSelectorCount();
-
-  return NS_OK;
+  return aRule.GetSelectorCount();
 }
 
-NS_IMETHODIMP
-inDOMUtils::GetSelectorText(nsIDOMCSSStyleRule* aRule,
-                            uint32_t aSelectorIndex,
-                            nsAString& aText)
+/* static */ void
+InspectorUtils::GetSelectorText(GlobalObject& aGlobal,
+                                BindingStyleRule& aRule,
+                                uint32_t aSelectorIndex,
+                                nsString& aText,
+                                ErrorResult& aRv)
 {
-  ErrorResult rv;
-  RefPtr<BindingStyleRule> rule = GetRuleFromDOMRule(aRule, rv);
-  MOZ_ASSERT(!rv.Failed(), "How could we get a selector but not a rule?");
-
-  return rule->GetSelectorText(aSelectorIndex, aText);
+  aRv = aRule.GetSelectorText(aSelectorIndex, aText);
 }
 
-NS_IMETHODIMP
-inDOMUtils::GetSpecificity(nsIDOMCSSStyleRule* aRule,
-                           uint32_t aSelectorIndex,
-                           uint64_t* aSpecificity)
+/* static */ uint64_t
+InspectorUtils::GetSpecificity(GlobalObject& aGlobal,
+                               BindingStyleRule& aRule,
+                               uint32_t aSelectorIndex,
+                               ErrorResult& aRv)
 {
-  ErrorResult rv;
-  RefPtr<BindingStyleRule> rule = GetRuleFromDOMRule(aRule, rv);
-  if (rv.Failed()) {
-    return rv.StealNSResult();
-  }
-
-  return rule->GetSpecificity(aSelectorIndex, aSpecificity);
+  uint64_t s;
+  aRv = aRule.GetSpecificity(aSelectorIndex, &s);
+  return s;
 }
 
-NS_IMETHODIMP
-inDOMUtils::SelectorMatchesElement(nsIDOMElement* aElement,
-                                   nsIDOMCSSStyleRule* aRule,
-                                   uint32_t aSelectorIndex,
-                                   const nsAString& aPseudo,
-                                   bool* aMatches)
+/* static */ bool
+InspectorUtils::SelectorMatchesElement(GlobalObject& aGlobalObject,
+                                       Element& aElement,
+                                       BindingStyleRule& aRule,
+                                       uint32_t aSelectorIndex,
+                                       const nsAString& aPseudo,
+                                       ErrorResult& aRv)
 {
-  nsCOMPtr<Element> element = do_QueryInterface(aElement);
-  NS_ENSURE_ARG_POINTER(element);
+  bool result = false;
+  aRv = aRule.SelectorMatchesElement(&aElement, aSelectorIndex, aPseudo,
+                                     &result);
+  return result;
+}
 
-  ErrorResult rv;
-  RefPtr<BindingStyleRule> rule = GetRuleFromDOMRule(aRule, rv);
-  if (rv.Failed()) {
-    return rv.StealNSResult();
-  }
-
-  return rule->SelectorMatchesElement(element, aSelectorIndex, aPseudo,
-                                      aMatches);
-}
+} // namespace dom
+} // namespace mozilla
 
 NS_IMETHODIMP
 inDOMUtils::IsInheritedProperty(const nsAString &aPropertyName, bool *_retval)
 {
   nsCSSPropertyID prop = nsCSSProps::
     LookupProperty(aPropertyName, CSSEnabledState::eIgnoreEnabledState);
   if (prop == eCSSProperty_UNKNOWN) {
     *_retval = false;
--- a/layout/inspector/inIDOMUtils.idl
+++ b/layout/inspector/inIDOMUtils.idl
@@ -15,35 +15,16 @@ interface nsIDOMNode;
 interface nsIDOMNodeList;
 interface nsIDOMFontFaceList;
 interface nsIDOMRange;
 interface nsIDOMCSSStyleSheet;
 
 [scriptable, uuid(362e98c3-82c2-4ad8-8dcb-00e8e4eab497)]
 interface inIDOMUtils : nsISupports
 {
-  // Utilities for working with selectors.  We don't have a JS OM representation
-  // of a single selector or a selector list yet, but given a rule we can index
-  // into the selector list.
-  //
-  // This is a somewhat backwards API; once we move StyleRule to WebIDL we
-  // should consider using [ChromeOnly] APIs on that.
-  unsigned long getSelectorCount(in nsIDOMCSSStyleRule aRule);
-  // For all three functions below, aSelectorIndex is 0-based
-  AString getSelectorText(in nsIDOMCSSStyleRule aRule,
-                          in unsigned long aSelectorIndex);
-  unsigned long long getSpecificity(in nsIDOMCSSStyleRule aRule,
-                                    in unsigned long aSelectorIndex);
-  // Note: This does not handle scoped selectors correctly, because it has no
-  // idea what the right scope is.
-  bool selectorMatchesElement(in nsIDOMElement aElement,
-                              in nsIDOMCSSStyleRule aRule,
-                              in unsigned long aSelectorIndex,
-                              [optional] in DOMString aPseudo);
-
   // Utilities for working with CSS properties
   //
   // Returns true if the string names a property that is inherited by default.
   bool isInheritedProperty(in AString aPropertyName);
 
   // Get a list of all our supported property names.  Optionally
   // shorthands can be excluded or property aliases included.
   const unsigned long EXCLUDE_SHORTHANDS = (1<<0);
--- a/layout/inspector/tests/test_selectormatcheselement.html
+++ b/layout/inspector/tests/test_selectormatcheselement.html
@@ -36,54 +36,51 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 <div id="foo">foo content</div>
 <pre id="test">
 <script type="application/javascript">
 
 const InspectorUtils = SpecialPowers.InspectorUtils;
 
 function do_test() {
-  var utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
-    .getService(SpecialPowers.Ci.inIDOMUtils);
-
   var element = document.querySelector("#foo");
 
   var elementRules = InspectorUtils.getCSSStyleRules(element);
   var elementRule = elementRules[elementRules.length - 1];
 
-  is (utils.selectorMatchesElement(element, elementRule, 0), true,
+  is (InspectorUtils.selectorMatchesElement(element, elementRule, 0), true,
     "Matches #foo");
-  is (utils.selectorMatchesElement(element, elementRule, 1), false,
+  is (InspectorUtils.selectorMatchesElement(element, elementRule, 1), false,
     "Doesn't match #bar");
-  is (utils.selectorMatchesElement(element, elementRule, 0, ":bogus"), false,
+  is (InspectorUtils.selectorMatchesElement(element, elementRule, 0, ":bogus"), false,
     "Doesn't match #foo with a bogus pseudo");
-  is (utils.selectorMatchesElement(element, elementRule, 2, ":bogus"), false,
+  is (InspectorUtils.selectorMatchesElement(element, elementRule, 2, ":bogus"), false,
     "Doesn't match #foo::before with bogus pseudo");
-  is (utils.selectorMatchesElement(element, elementRule, 0, ":after"), false,
+  is (InspectorUtils.selectorMatchesElement(element, elementRule, 0, ":after"), false,
     "Does match #foo::before with the :after pseudo");
 
   checkPseudo(":before");
   checkPseudo(":after");
   checkPseudo(":first-letter");
   checkPseudo(":first-line");
 
   SimpleTest.finish();
 
   function checkPseudo(pseudo) {
     var rules = InspectorUtils.getCSSStyleRules(element, pseudo);
     var rule = rules[rules.length - 1];
 
-    is (utils.selectorMatchesElement(element, rule, 0), false,
+    is (InspectorUtils.selectorMatchesElement(element, rule, 0), false,
       "Doesn't match without " + pseudo);
-    is (utils.selectorMatchesElement(element, rule, 1), false,
+    is (InspectorUtils.selectorMatchesElement(element, rule, 1), false,
       "Doesn't match without " + pseudo);
 
-    is (utils.selectorMatchesElement(element, rule, 0, pseudo), true,
+    is (InspectorUtils.selectorMatchesElement(element, rule, 0, pseudo), true,
       "Matches on #foo" + pseudo);
-    is (utils.selectorMatchesElement(element, rule, 1, pseudo), false,
+    is (InspectorUtils.selectorMatchesElement(element, rule, 1, pseudo), false,
       "Doesn't match on #bar" + pseudo);
   }
 }
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(do_test);
 
 </script>