Bug 962628. Make '+' and '~' combinators work at the top level of an anonymous content forest. r=heycam
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 23 Jan 2014 15:18:06 -0500
changeset 164888 f88b13e2ae0acddbe78c7de8df85d227e4ce0ece
parent 164887 e864fca8c73e674ef18930d61d53387c4094f7c5
child 164889 bb4066993a6a3c523728b8a0fc3c9ad12c95b840
push id38851
push userbzbarsky@mozilla.com
push dateThu, 23 Jan 2014 20:18:36 +0000
treeherdermozilla-inbound@fbb3ea68c86e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs962628
milestone29.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 962628. Make '+' and '~' combinators work at the top level of an anonymous content forest. r=heycam
layout/reftests/css-selectors/reftest.list
layout/reftests/css-selectors/sibling-combinators-on-anon-content-1.xhtml
layout/reftests/css-selectors/sibling-combinators-on-anon-content-2.xhtml
layout/reftests/css-selectors/sibling-combinators-on-anon-content-ref.xhtml
layout/style/nsCSSRuleProcessor.cpp
--- a/layout/reftests/css-selectors/reftest.list
+++ b/layout/reftests/css-selectors/reftest.list
@@ -1,2 +1,4 @@
 == state-dependent-in-any.html state-dependent-in-any-ref.html
 == attr-case-insensitive-1.html attr-case-insensitive-1-ref.html
+== sibling-combinators-on-anon-content-1.xhtml sibling-combinators-on-anon-content-ref.xhtml
+== sibling-combinators-on-anon-content-2.xhtml sibling-combinators-on-anon-content-ref.xhtml
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-selectors/sibling-combinators-on-anon-content-1.xhtml
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <bindings xmlns="http://www.mozilla.org/xbl"
+              xmlns:html="http://www.w3.org/1999/xhtml">
+      <binding id="x">
+        <content>
+          <html:span class="a"></html:span>
+          <html:span class="b">This should be green</html:span>
+          <children/>
+        </content>
+      </binding>
+    </bindings>
+    <style>
+      #foo { -moz-binding: url("#x"); }
+      .a + .b { color: green; }
+    </style>
+  </head>
+  <body>
+    <span id="foo"></span>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-selectors/sibling-combinators-on-anon-content-2.xhtml
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" reftest-wait="">
+  <head>
+    <bindings xmlns="http://www.mozilla.org/xbl"
+              xmlns:html="http://www.w3.org/1999/xhtml">
+      <binding id="x">
+        <content>
+          <html:span class="a">Some text</html:span>
+          <html:span class="b">This should be green</html:span>
+          <children/>
+        </content>
+        <implementation>
+          <method name="nixText">
+            <body>
+              document.getAnonymousNodes(this)[0].textContent = "";
+            </body>
+          </method>
+        </implementation>
+      </binding>
+    </bindings>
+    <style>
+      #foo { -moz-binding: url("#x"); }
+      .a:empty + .b { color: green; }
+    </style>
+  </head>
+  <body>
+    <span id="foo"></span>
+    <script>
+      window.onload = function() {
+        var el = document.getElementById("foo");
+        // Flush its layout
+        el.offsetWidth;
+        el.nixText();
+        document.documentElement.className = "";
+      }
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-selectors/sibling-combinators-on-anon-content-ref.xhtml
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <style>
+      .a + .b { color: green; }
+    </style>
+  </head>
+  <body>
+    <span><span class="a"></span>
+          <span class="b">This should be green</span></span>
+  </body>
+</html>
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -2327,24 +2327,17 @@ static bool SelectorMatchesTree(Element*
         char16_t('~') == selector->mOperator) {
       // The relevant link must be an ancestor of the node being matched.
       aLookForRelevantLink = false;
       nsIContent* parent = prevElement->GetParent();
       if (parent) {
         if (aTreeMatchContext.mForStyling)
           parent->SetFlags(NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
 
-        int32_t index = parent->IndexOf(prevElement);
-        while (0 <= --index) {
-          nsIContent* content = parent->GetChildAt(index);
-          if (content->IsElement()) {
-            element = content->AsElement();
-            break;
-          }
-        }
+        element = prevElement->GetPreviousElementSibling();
       }
     }
     // for descendant combinators and child combinators, the element
     // to test against is the parent
     else {
       nsIContent *content = prevElement->GetParent();
       // GetParent could return a document fragment; we only want
       // element parents.