Bug 1481949 - Use querySelectorAll instead of a treeWalker for finding radios underneath a radiogroup;r=timdream
authorBrian Grinstead <bgrinstead@mozilla.com>
Mon, 01 Oct 2018 20:35:35 +0000
changeset 487423 05e791fb2c6b2fe7f967adf86e55517231bcf59d
parent 487422 b82060ff3299da0ac4bd497251c0f995ef857f12
child 487424 84c7bfa3a0f53f5504fa2add39e0100e48664f26
push id246
push userfmarier@mozilla.com
push dateSat, 13 Oct 2018 00:15:40 +0000
reviewerstimdream
bugs1481949
milestone64.0a1
Bug 1481949 - Use querySelectorAll instead of a treeWalker for finding radios underneath a radiogroup;r=timdream This is faster. It does drop support for skipping non-XUL-namespaced radiogroup tags, but we don't have or plan to have HTML namespaced radiogroups in the same document as a XUL-namespaced radiogroup. Differential Revision: https://phabricator.services.mozilla.com/D7255
toolkit/content/widgets/radio.js
toolkit/content/widgets/radio.xml
--- a/toolkit/content/widgets/radio.js
+++ b/toolkit/content/widgets/radio.js
@@ -306,56 +306,36 @@ class MozRadiogroup extends MozBaseContr
     }
   }
 
   _getRadioChildren() {
     if (this._radioChildren)
       return this._radioChildren;
 
     var radioChildren = [];
-    var doc = this.ownerDocument;
 
     if (this.hasChildNodes()) {
-      // Don't store the collected child nodes immediately,
-      // collecting the child nodes could trigger constructors
-      // which would blow away our list.
-
-      var iterator = doc.createTreeWalker(this,
-        NodeFilter.SHOW_ELEMENT,
-        this._filterRadioGroup);
-      while (iterator.nextNode())
-        radioChildren.push(iterator.currentNode);
-      return this._radioChildren = radioChildren;
+      return this._radioChildren = [...this.querySelectorAll("radio")]
+        .filter(r => r.control == this);
     }
 
     // We don't have child nodes.
     const XUL_NS = "http://www.mozilla.org/keymaster/" +
       "gatekeeper/there.is.only.xul";
-    var elems = doc.getElementsByAttribute("group", this.id);
+
+    var elems = this.ownerDocument.getElementsByAttribute("group", this.id);
     for (var i = 0; i < elems.length; i++) {
       if ((elems[i].namespaceURI == XUL_NS) &&
         (elems[i].localName == "radio")) {
         radioChildren.push(elems[i]);
       }
     }
     return this._radioChildren = radioChildren;
   }
 
-  _filterRadioGroup(node) {
-    switch (node.localName) {
-      case "radio":
-        return NodeFilter.FILTER_ACCEPT;
-      case "template":
-      case "radiogroup":
-        return NodeFilter.FILTER_REJECT;
-      default:
-        return NodeFilter.FILTER_SKIP;
-    }
-  }
-
   getIndexOfItem(item) {
     return this._getRadioChildren().indexOf(item);
   }
 
   getItemAtIndex(index) {
     var children = this._getRadioChildren();
     return (index >= 0 && index < children.length) ? children[index] : null;
   }
--- a/toolkit/content/widgets/radio.xml
+++ b/toolkit/content/widgets/radio.xml
@@ -52,36 +52,28 @@
             return this.hasAttribute("selected");
           ]]>
         </getter>
       </property>
       <property name="radioGroup" readonly="true" onget="return this.control"/>
       <property name="control" readonly="true">
         <getter>
         <![CDATA[
-          const XUL_NS = "http://www.mozilla.org/keymaster/"
-                       + "gatekeeper/there.is.only.xul";
-          var parent = this.parentNode;
-          while (parent) {
-            if ((parent.namespaceURI == XUL_NS) &&
-                (parent.localName == "radiogroup")) {
-              return parent;
-            }
-            parent = parent.parentNode;
+          var radiogroup = this.closest("radiogroup");
+          if (radiogroup) {
+            return radiogroup;
           }
 
           var group = this.getAttribute("group");
           if (!group) {
             return null;
           }
 
-          parent = this.ownerDocument.getElementById(group);
-          if (!parent ||
-              (parent.namespaceURI != XUL_NS) ||
-              (parent.localName != "radiogroup")) {
+          var parent = this.ownerDocument.getElementById(group);
+          if (!parent || parent.localName != "radiogroup") {
             parent = null;
           }
           return parent;
         ]]>
         </getter>
       </property>
     </implementation>
     <handlers>