diff options
3 files changed, 77 insertions, 97 deletions
diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index e6007abe68a..fe4dda0245d 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -763,19 +763,93 @@ impl<Impl: SelectorImpl> ToCss for Selector<Impl> { // NB: A parse-order iterator is a Rev<>, which doesn't expose as_slice(), // which we need for |split|. So we split by combinators on a match-order // sequence and then reverse. - let mut combinators = self.iter_raw_match_order().rev().filter(|x| x.is_combinator()); + + let mut combinators = self.iter_raw_match_order().rev().filter(|x| x.is_combinator()).peekable(); let compound_selectors = self.iter_raw_match_order().as_slice().split(|x| x.is_combinator()).rev(); let mut combinators_exhausted = false; for compound in compound_selectors { debug_assert!(!combinators_exhausted); - for item in compound.iter() { - item.to_css(dest)?; + + // https://drafts.csswg.org/cssom/#serializing-selectors + + if !compound.is_empty() { + // 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. + let (can_elide_namespace, first_non_namespace) = match &compound[0] { + &Component::ExplicitAnyNamespace | + &Component::ExplicitNoNamespace | + &Component::Namespace(_, _) => (false, 1), + &Component::DefaultNamespace(_) => (true, 1), + _ => (true, 0), + }; + 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 + } + (_, _) => (), + } + } + + // 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 + } + } + 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. match combinators.next() { Some(c) => c.to_css(dest)?, None => combinators_exhausted = true, }; + + // 4. If this is the last part of the chain of the selector and + // there is a pseudo-element, append "::" followed by the name of + // the pseudo-element, to s. + // + // (we handle this above) } Ok(()) diff --git a/tests/wpt/metadata-css/cssom-1_dev/html/serialize-namespaced-type-selectors.htm.ini b/tests/wpt/metadata-css/cssom-1_dev/html/serialize-namespaced-type-selectors.htm.ini deleted file mode 100644 index 965e00625c9..00000000000 --- a/tests/wpt/metadata-css/cssom-1_dev/html/serialize-namespaced-type-selectors.htm.ini +++ /dev/null @@ -1,47 +0,0 @@ -[serialize-namespaced-type-selectors.htm] - type: testharness - [Universal selector followed by class] - expected: FAIL - - [Universal selector followed by id] - expected: FAIL - - [Universal selector followed by pseudo class] - expected: FAIL - - [Universal selector followed by pseudo element] - expected: FAIL - - [Universal selector followed by attribute selector] - expected: FAIL - - [Universal selector in any namespace followed by class] - expected: FAIL - - [Universal selector in any namespace followed by id] - expected: FAIL - - [Universal selector in any namespace followed by pseudo class] - expected: FAIL - - [Universal selector in any namespace followed by pseudo element] - expected: FAIL - - [Universal selector in any namespace followed by attribute selector] - expected: FAIL - - [Universal selector with namespace equal to default namespace followed by class] - expected: FAIL - - [Universal selector with namespace equal to default namespace followed by id] - expected: FAIL - - [Universal selector with namespace equal to default namespace followed by pseudo class] - expected: FAIL - - [Universal selector with namespace equal to default namespace followed by pseudo element] - expected: FAIL - - [Universal selector with namespace equal to default namespace followed by attribute selector] - expected: FAIL - diff --git a/tests/wpt/metadata/cssom/serialize-namespaced-type-selectors.html.ini b/tests/wpt/metadata/cssom/serialize-namespaced-type-selectors.html.ini deleted file mode 100644 index ad037e747da..00000000000 --- a/tests/wpt/metadata/cssom/serialize-namespaced-type-selectors.html.ini +++ /dev/null @@ -1,47 +0,0 @@ -[serialize-namespaced-type-selectors.html] - type: testharness - [Universal selector followed by class] - expected: FAIL - - [Universal selector followed by id] - expected: FAIL - - [Universal selector followed by pseudo class] - expected: FAIL - - [Universal selector followed by pseudo element] - expected: FAIL - - [Universal selector followed by attribute selector] - expected: FAIL - - [Universal selector in any namespace followed by class] - expected: FAIL - - [Universal selector in any namespace followed by id] - expected: FAIL - - [Universal selector in any namespace followed by pseudo class] - expected: FAIL - - [Universal selector in any namespace followed by pseudo element] - expected: FAIL - - [Universal selector in any namespace followed by attribute selector] - expected: FAIL - - [Universal selector with namespace equal to default namespace followed by class] - expected: FAIL - - [Universal selector with namespace equal to default namespace followed by id] - expected: FAIL - - [Universal selector with namespace equal to default namespace followed by pseudo class] - expected: FAIL - - [Universal selector with namespace equal to default namespace followed by pseudo element] - expected: FAIL - - [Universal selector with namespace equal to default namespace followed by attribute selector] - expected: FAIL - |