style: Implement the non-functional :host selector.

Kinda tricky because :host only matches rules on the shadow root where the rules
come from. So we need to be careful during invalidation and style sharing.

I didn't use the non_ts_pseudo_class_list bits because as soon as we implement
the :host(..) bits we're going to need to special-case it anyway.

The general schema is the following:

 * Rightmost featureless :host selectors are handled inserting them in the
   host_rules hashmap. Note that we only insert featureless stuff there. We
   could insert all of them and just filter during matching, but that's slightly
   annoying.

 * The other selectors, like non-featureless :host or what not, are added to the
   normal cascade data. This is harmless, since the shadow host rules are never
   matched against the host, so we know they'll just never match, and avoids
   adding more special-cases.

 * Featureless :host selectors to the left of a combinator are handled during
   matching, in the special-case of next_element_for_combinator in selectors.
   This prevents this from being more invasive, and keeps the usual fast path
   slim, but it's a bit hard to match the spec and the implementation.

   We could keep a copy of the SelectorIter instead in the matching context to
   make the handling of featureless-ness explicit in match_non_ts_pseudo_class,
   but we'd still need the special-case anyway, so I'm not fond of it.

 * We take advantage of one thing that makes this sound. As you may have
   noticed, if you had `root` element which is a ShadowRoot, and you matched
   something like `div:host` against it, using a MatchingContext with
   current_host == root, we'd incorrectly report a match. But this is impossible
   due to the following constraints:

    * Shadow root rules aren't matched against the host during styling (except
      these featureless selectors).

    * DOM APIs' current_host needs to be the _containing_ host, not the element
      itself if you're a Shadow host.

Bug: 992245
Reviewed-by: xidorn
MozReview-Commit-ID: KayYNfTXb5h
This commit is contained in:
Emilio Cobos Álvarez 2018-04-07 19:46:00 +02:00
parent 5d6db35854
commit db5db13559
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
13 changed files with 241 additions and 136 deletions

View file

@ -466,15 +466,9 @@ where
// pseudo-classes are allowed to match it.
//
// Since we know that the parent is a shadow root, we necessarily
// are in a shadow tree of the host.
let all_selectors_could_match = selector.clone().all(|component| {
match *component {
Component::NonTSPseudoClass(ref pc) => pc.is_host(),
_ => false,
}
});
if !all_selectors_could_match {
// are in a shadow tree of the host, and the next selector will only
// match if the selector is a featureless :host selector.
if !selector.clone().is_featureless_host_selector() {
return None;
}
@ -820,6 +814,9 @@ where
flags_setter(element, ElementSelectorFlags::HAS_EMPTY_SELECTOR);
element.is_empty()
}
Component::Host => {
context.shared.shadow_host().map_or(false, |host| host == element.opaque())
}
Component::Scope => {
match context.shared.scope_element {
Some(ref scope_element) => element.opaque() == *scope_element,