style: Implement shadow part forwarding (minus invalidation).

Some of the stuff, in particular inside GeckoBindings stuff should be
refactored to be less ugly and duplicate a bit less code, but the rest of the
code should be landable as is.

Some invalidation changes are already needed because we weren't matching with
the right shadow host during invalidation (which made existing ::part() tests
fail).

Pending invalidation work:

 * Making exportparts work right on the snapshots.
 * Invalidating parts from descendant hosts.

They're not very hard but I need to think how to best implement it:

 * Maybe get rid of ShadowRoot::mParts and just walk DOM descendants in the
   Shadow DOM.

 * Maybe implement a ElementHasExportPartsAttr much like HasPartAttr and use
   that to keep the list of elements.

 * Maybe invalidate :host and ::part() together in here[1]

 * Maybe something else.

Opinions?

[1]: https://searchfox.org/mozilla-central/rev/131338e5017bc0283d86fb73844407b9a2155c98/servo/components/style/invalidation/element/invalidator.rs#561

Differential Revision: https://phabricator.services.mozilla.com/D53730
This commit is contained in:
Emilio Cobos Álvarez 2019-11-21 10:32:32 +00:00
parent 576883d538
commit e3009a4de9
No known key found for this signature in database
GPG key ID: E1152D0994E4BF8A
9 changed files with 180 additions and 47 deletions

View file

@ -79,7 +79,13 @@ where
continue;
}
self_invalidations.push(Invalidation::new(&dependency.selector, 0));
// We pass `None` as a scope, as document state selectors aren't
// affected by the current scope.
self_invalidations.push(Invalidation::new(
&dependency.selector,
/* scope = */ None,
0,
));
}
}

View file

@ -365,6 +365,16 @@ where
}
}
fn exported_part(&self, name: &Atom) -> Option<Atom> {
// FIXME(emilio): Implement for proper invalidation.
self.element.exported_part(name)
}
fn imported_part(&self, name: &Atom) -> Option<Atom> {
// FIXME(emilio): Implement for proper invalidation.
self.element.imported_part(name)
}
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
match self.snapshot() {
Some(snapshot) if snapshot.has_attrs() => snapshot.has_class(name, case_sensitivity),

View file

@ -8,6 +8,7 @@
use crate::context::StackLimitChecker;
use crate::dom::{TElement, TNode, TShadowRoot};
use crate::selector_parser::SelectorImpl;
use selectors::OpaqueElement;
use selectors::matching::matches_compound_selector_from;
use selectors::matching::{CompoundSelectorMatchingResult, MatchingContext};
use selectors::parser::{Combinator, Component, Selector};
@ -127,6 +128,8 @@ enum InvalidationKind {
#[derive(Clone)]
pub struct Invalidation<'a> {
selector: &'a Selector<SelectorImpl>,
/// The right shadow host from where the rule came from, if any.
scope: Option<OpaqueElement>,
/// The offset of the selector pointing to a compound selector.
///
/// This order is a "parse order" offset, that is, zero is the leftmost part
@ -143,9 +146,14 @@ pub struct Invalidation<'a> {
impl<'a> Invalidation<'a> {
/// Create a new invalidation for a given selector and offset.
pub fn new(selector: &'a Selector<SelectorImpl>, offset: usize) -> Self {
pub fn new(
selector: &'a Selector<SelectorImpl>,
scope: Option<OpaqueElement>,
offset: usize,
) -> Self {
Self {
selector,
scope,
offset,
matched_by_any_previous: false,
}
@ -483,6 +491,9 @@ where
let mut any = false;
let mut sibling_invalidations = InvalidationVector::new();
// FIXME(emilio): We also need to invalidate parts in descendant shadow
// hosts that have exportparts attributes.
for element in shadow.parts() {
any |= self.invalidate_child(
*element,
@ -721,12 +732,17 @@ where
self.element, invalidation, invalidation_kind
);
let matching_result = matches_compound_selector_from(
&invalidation.selector,
invalidation.offset,
self.processor.matching_context(),
&self.element,
);
let matching_result = {
let mut context = self.processor.matching_context();
context.current_host = invalidation.scope;
matches_compound_selector_from(
&invalidation.selector,
invalidation.offset,
context,
&self.element,
)
};
let mut invalidated_self = false;
let mut matched = false;
@ -809,6 +825,7 @@ where
let next_invalidation = Invalidation {
selector: invalidation.selector,
scope: invalidation.scope,
offset: next_combinator_offset + 1,
matched_by_any_previous: false,
};

View file

@ -457,6 +457,7 @@ where
let invalidation = Invalidation::new(
&dependency.selector,
self.matching_context.current_host.clone(),
dependency.selector.len() - dependency.selector_offset + 1,
);