From ab46a0bbe011c71034a7beec9a6e189a774ef9a8 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Mon, 9 Oct 2017 17:01:15 +1100 Subject: [PATCH] Add support for :scope pseudo-class --- components/selectors/builder.rs | 2 +- components/selectors/context.rs | 15 +++++++++++++++ components/selectors/matching.rs | 6 ++++++ components/selectors/parser.rs | 3 +++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/components/selectors/builder.rs b/components/selectors/builder.rs index 99a8f086915..c996a6a6491 100644 --- a/components/selectors/builder.rs +++ b/components/selectors/builder.rs @@ -284,7 +284,7 @@ fn complex_selector_specificity(mut iter: slice::Iter>) Component::FirstChild | Component::LastChild | Component::OnlyChild | Component::Root | - Component::Empty | + Component::Empty | Component::Scope | Component::NthChild(..) | Component::NthLastChild(..) | Component::NthOfType(..) | diff --git a/components/selectors/context.rs b/components/selectors/context.rs index c67ef6638cc..894cc31b15d 100644 --- a/components/selectors/context.rs +++ b/components/selectors/context.rs @@ -5,6 +5,7 @@ use attr::CaseSensitivity; use bloom::BloomFilter; use nth_index_cache::NthIndexCache; +use tree::OpaqueElement; /// What kind of selector matching mode we should use. /// @@ -88,6 +89,19 @@ pub struct MatchingContext<'a> { /// only.) pub relevant_link_found: bool, + /// The element which is going to match :scope pseudo-class. It can be + /// either one :scope element, or the scoping element. + /// + /// Note that, although in theory there can be multiple :scope elements, + /// in current specs, at most one is specified, and when there is one, + /// scoping element is not relevant anymore, so we use a single field for + /// them. + /// + /// When this is None, :scope will match the root element. + /// + /// See https://drafts.csswg.org/selectors-4/#scope-pseudo + pub scope_element: Option, + quirks_mode: QuirksMode, classes_and_ids_case_sensitivity: CaseSensitivity, } @@ -125,6 +139,7 @@ impl<'a> MatchingContext<'a> { quirks_mode, relevant_link_found: false, classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(), + scope_element: None, } } diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs index ff0dd40b484..875ac2862e6 100644 --- a/components/selectors/matching.rs +++ b/components/selectors/matching.rs @@ -724,6 +724,12 @@ fn matches_simple_selector( flags_setter(element, HAS_EMPTY_SELECTOR); element.is_empty() } + Component::Scope => { + match context.shared.scope_element { + Some(ref scope_element) => element.opaque() == *scope_element, + None => element.is_root(), + } + } Component::NthChild(a, b) => { matches_generic_nth_child(element, context, a, b, false, false, flags_setter) } diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index b020a04fd03..44ff450aa3e 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -673,6 +673,7 @@ pub enum Component { FirstChild, LastChild, OnlyChild, Root, Empty, + Scope, NthChild(i32, i32), NthLastChild(i32, i32), NthOfType(i32, i32), @@ -969,6 +970,7 @@ impl ToCss for Component { OnlyChild => dest.write_str(":only-child"), Root => dest.write_str(":root"), Empty => dest.write_str(":empty"), + Scope => dest.write_str(":scope"), FirstOfType => dest.write_str(":first-of-type"), LastOfType => dest.write_str(":last-of-type"), OnlyOfType => dest.write_str(":only-of-type"), @@ -1699,6 +1701,7 @@ fn parse_simple_pseudo_class<'i, P, E, Impl>(parser: &P, name: CowRcStr<'i>) "only-child" => Ok(Component::OnlyChild), "root" => Ok(Component::Root), "empty" => Ok(Component::Empty), + "scope" => Ok(Component::Scope), "first-of-type" => Ok(Component::FirstOfType), "last-of-type" => Ok(Component::LastOfType), "only-of-type" => Ok(Component::OnlyOfType),