Bug 1391169 Part 1: Servo-side change Selector to_css function to handle combinators in between universal selectors. draft
authorBrad Werth <bwerth@mozilla.com>
Fri, 25 Aug 2017 13:53:23 -0700
changeset 654554 6f79d8bb470dd10053fb39f82904cd260b910571
parent 654351 e2efa420beb1a578c7350ba925c82230da6b1267
child 654555 5cd3d01cecbbc062af1d59a69c8bfda0d2a1c18a
push id76597
push userbwerth@mozilla.com
push dateMon, 28 Aug 2017 23:22:54 +0000
bugs1391169
milestone57.0a1
Bug 1391169 Part 1: Servo-side change Selector to_css function to handle combinators in between universal selectors. MozReview-Commit-ID: EyVrSAICPm
servo/components/selectors/parser.rs
servo/tests/unit/style/parsing/selectors.rs
--- a/servo/components/selectors/parser.rs
+++ b/servo/components/selectors/parser.rs
@@ -777,66 +777,70 @@ impl<Impl: SelectorImpl> ToCss for Selec
                 // 1. If there is only one simple selector in the compound selectors
                 //    which is a universal selector, append the result of
                 //    serializing the universal selector to s.
                 //
                 // Check if `!compound.empty()` first--this can happen if we have
                 // something like `... > ::before`, because we store `>` and `::`
                 // both as combinators internally.
                 //
-                // If we are in this case, we continue to the next iteration of the
-                // `for compound in compound_selectors` loop.
+                // If we are in this case, after we have serialized the universal
+                // selector, we skip Step 2 and continue with the algorithm.
                 let (can_elide_namespace, first_non_namespace) = match &compound[0] {
                     &Component::ExplicitAnyNamespace |
                     &Component::ExplicitNoNamespace |
                     &Component::Namespace(_, _) => (false, 1),
                     &Component::DefaultNamespace(_) => (true, 1),
                     _ => (true, 0),
                 };
+                let mut perform_step_2 = true;
                 if first_non_namespace == compound.len() - 1 {
                     match (combinators.peek(), &compound[first_non_namespace]) {
                         // We have to be careful here, because if there is a pseudo
                         // element "combinator" there isn't really just the one
                         // simple selector. Technically this compound selector
                         // contains the pseudo element selector as
                         // well--Combinator::PseudoElement doesn't exist in the
                         // spec.
                         (Some(&&Component::Combinator(Combinator::PseudoElement)), _) => (),
                         (_, &Component::ExplicitUniversalType) => {
                             // Iterate over everything so we serialize the namespace
                             // too.
                             for simple in compound.iter() {
                                 simple.to_css(dest)?;
                             }
-                            continue
+                            // Skip step 2, which is an "otherwise".
+                            perform_step_2 = false;
                         }
                         (_, _) => (),
                     }
                 }
 
                 // 2. Otherwise, for each simple selector in the compound selectors
                 //    that is not a universal selector of which the namespace prefix
                 //    maps to a namespace that is not the default namespace
                 //    serialize the simple selector and append the result to s.
                 //
                 // See https://github.com/w3c/csswg-drafts/issues/1606, which is
                 // proposing to change this to match up with the behavior asserted
                 // in cssom/serialize-namespaced-type-selectors.html, which the
                 // following code tries to match.
-                for simple in compound.iter() {
-                    if let Component::ExplicitUniversalType = *simple {
-                        // Can't have a namespace followed by a pseudo-element
-                        // selector followed by a universal selector in the same
-                        // compound selector, so we don't have to worry about the
-                        // real namespace being in a different `compound`.
-                        if can_elide_namespace {
-                            continue
+                if perform_step_2 {
+                    for simple in compound.iter() {
+                        if let Component::ExplicitUniversalType = *simple {
+                            // Can't have a namespace followed by a pseudo-element
+                            // selector followed by a universal selector in the same
+                            // compound selector, so we don't have to worry about the
+                            // real namespace being in a different `compound`.
+                            if can_elide_namespace {
+                                continue
+                            }
                         }
+                        simple.to_css(dest)?;
                     }
-                    simple.to_css(dest)?;
                 }
             }
 
             // 3. If this is not the last part of the chain of the selector
             //    append a single SPACE (U+0020), followed by the combinator
             //    ">", "+", "~", ">>", "||", as appropriate, followed by another
             //    single SPACE (U+0020) if the combinator was not whitespace, to
             //    s.
--- a/servo/tests/unit/style/parsing/selectors.rs
+++ b/servo/tests/unit/style/parsing/selectors.rs
@@ -20,9 +20,11 @@ fn parse_selector<'i, 't>(input: &mut Pa
 }
 
 #[test]
 fn test_selectors() {
     assert_roundtrip!(parse_selector, "div");
     assert_roundtrip!(parse_selector, "svg|circle");
     assert_roundtrip!(parse_selector, "p:before", "p::before");
     assert_roundtrip!(parse_selector, "[border=\"0\"]:-servo-nonzero-border ~ ::-servo-details-summary");
+    assert_roundtrip!(parse_selector, "* > *");
+    assert_roundtrip!(parse_selector, "*|* + *", "* + *");
 }