mirror of
https://github.com/servo/servo.git
synced 2025-07-31 19:20:22 +01:00
style: Invalidate parts in nested shadow trees correctly.
Differential Revision: https://phabricator.services.mozilla.com/D54010
This commit is contained in:
parent
e3009a4de9
commit
f8ceb5cb84
6 changed files with 104 additions and 43 deletions
|
@ -523,6 +523,9 @@ pub trait TElement:
|
|||
/// Returns whether this element has a `part` attribute.
|
||||
fn has_part_attr(&self) -> bool;
|
||||
|
||||
/// Returns whether this element exports any part from its shadow tree.
|
||||
fn exports_any_part(&self) -> bool;
|
||||
|
||||
/// The ID for this element.
|
||||
fn id(&self) -> Option<&WeakAtom>;
|
||||
|
||||
|
|
|
@ -193,6 +193,16 @@ impl ElementSnapshot for GeckoElementSnapshot {
|
|||
snapshot_helpers::has_class_or_part(name, CaseSensitivity::CaseSensitive, attr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn exported_part(&self, name: &Atom) -> Option<Atom> {
|
||||
snapshot_helpers::exported_part(&*self.mAttrs, name)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn imported_part(&self, name: &Atom) -> Option<Atom> {
|
||||
snapshot_helpers::imported_part(&*self.mAttrs, name)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
||||
if !self.has_any(Flags::MaybeClass) {
|
||||
|
|
|
@ -82,6 +82,26 @@ pub fn get_id(attrs: &[structs::AttrArray_InternalAttr]) -> Option<&WeakAtom> {
|
|||
Some(unsafe { get_id_from_attr(find_attr(attrs, &atom!("id"))?) })
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) fn exported_part(attrs: &[structs::AttrArray_InternalAttr], name: &Atom) -> Option<Atom> {
|
||||
let attr = find_attr(attrs, &atom!("exportparts"))?;
|
||||
let atom = unsafe { bindings::Gecko_Element_ExportedPart(attr, name.as_ptr()) };
|
||||
if atom.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(unsafe { Atom::from_raw(atom) })
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) fn imported_part(attrs: &[structs::AttrArray_InternalAttr], name: &Atom) -> Option<Atom> {
|
||||
let attr = find_attr(attrs, &atom!("exportparts"))?;
|
||||
let atom = unsafe { bindings::Gecko_Element_ImportedPart(attr, name.as_ptr()) };
|
||||
if atom.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(unsafe { Atom::from_raw(atom) })
|
||||
}
|
||||
|
||||
/// Given a class or part name, a case sensitivity, and an array of attributes,
|
||||
/// returns whether the attribute has that name.
|
||||
#[inline(always)]
|
||||
|
|
|
@ -1244,8 +1244,12 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
|
||||
#[inline]
|
||||
fn has_part_attr(&self) -> bool {
|
||||
self.as_node()
|
||||
.get_bool_flag(nsINode_BooleanFlag::ElementHasPart)
|
||||
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasPart)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn exports_any_part(&self) -> bool {
|
||||
snapshot_helpers::find_attr(self.attrs(), &atom!("exportparts")).is_some()
|
||||
}
|
||||
|
||||
// FIXME(emilio): we should probably just return a reference to the Atom.
|
||||
|
@ -2217,25 +2221,13 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn imported_part(&self, name: &Atom) -> Option<Atom> {
|
||||
let imported = unsafe {
|
||||
bindings::Gecko_Element_ImportedPart(self.0, name.as_ptr())
|
||||
};
|
||||
if imported.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(unsafe { Atom::from_raw(imported) })
|
||||
fn exported_part(&self, name: &Atom) -> Option<Atom> {
|
||||
snapshot_helpers::exported_part(self.attrs(), name)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn exported_part(&self, name: &Atom) -> Option<Atom> {
|
||||
let exported = unsafe {
|
||||
bindings::Gecko_Element_ExportedPart(self.0, name.as_ptr())
|
||||
};
|
||||
if exported.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(unsafe { Atom::from_raw(exported) })
|
||||
fn imported_part(&self, name: &Atom) -> Option<Atom> {
|
||||
snapshot_helpers::imported_part(self.attrs(), name)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
|
@ -62,6 +62,12 @@ pub trait ElementSnapshot: Sized {
|
|||
/// called if `has_attrs()` returns true.
|
||||
fn is_part(&self, name: &Atom) -> bool;
|
||||
|
||||
/// See Element::exported_part.
|
||||
fn exported_part(&self, name: &Atom) -> Option<Atom>;
|
||||
|
||||
/// See Element::imported_part.
|
||||
fn imported_part(&self, name: &Atom) -> Option<Atom>;
|
||||
|
||||
/// A callback that should be called for each class of the snapshot. Should
|
||||
/// only be called if `has_attrs()` returns true.
|
||||
fn each_class<F>(&self, _: F)
|
||||
|
@ -366,13 +372,17 @@ where
|
|||
}
|
||||
|
||||
fn exported_part(&self, name: &Atom) -> Option<Atom> {
|
||||
// FIXME(emilio): Implement for proper invalidation.
|
||||
self.element.exported_part(name)
|
||||
match self.snapshot() {
|
||||
Some(snapshot) if snapshot.has_attrs() => snapshot.exported_part(name),
|
||||
_ => self.element.exported_part(name),
|
||||
}
|
||||
}
|
||||
|
||||
fn imported_part(&self, name: &Atom) -> Option<Atom> {
|
||||
// FIXME(emilio): Implement for proper invalidation.
|
||||
self.element.imported_part(name)
|
||||
match self.snapshot() {
|
||||
Some(snapshot) if snapshot.has_attrs() => snapshot.imported_part(name),
|
||||
_ => self.element.imported_part(name),
|
||||
}
|
||||
}
|
||||
|
||||
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
||||
|
|
|
@ -129,6 +129,10 @@ enum InvalidationKind {
|
|||
pub struct Invalidation<'a> {
|
||||
selector: &'a Selector<SelectorImpl>,
|
||||
/// The right shadow host from where the rule came from, if any.
|
||||
///
|
||||
/// This is needed to ensure that we match the selector with the right
|
||||
/// state, as whether some selectors like :host and ::part() match depends
|
||||
/// on it.
|
||||
scope: Option<OpaqueElement>,
|
||||
/// The offset of the selector pointing to a compound selector.
|
||||
///
|
||||
|
@ -479,24 +483,25 @@ where
|
|||
any_descendant
|
||||
}
|
||||
|
||||
fn invalidate_parts(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
|
||||
if invalidations.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let shadow = match self.element.shadow_root() {
|
||||
Some(s) => s,
|
||||
None => return false,
|
||||
};
|
||||
fn invalidate_parts_in_shadow_tree(
|
||||
&mut self,
|
||||
shadow: <E::ConcreteNode as TNode>::ConcreteShadowRoot,
|
||||
invalidations: &[Invalidation<'b>],
|
||||
) -> bool {
|
||||
debug_assert!(!invalidations.is_empty());
|
||||
|
||||
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() {
|
||||
for node in shadow.as_node().dom_descendants() {
|
||||
let element = match node.as_element() {
|
||||
Some(e) => e,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if element.has_part_attr() {
|
||||
any |= self.invalidate_child(
|
||||
*element,
|
||||
element,
|
||||
invalidations,
|
||||
&mut sibling_invalidations,
|
||||
DescendantInvalidationKind::Part,
|
||||
|
@ -508,9 +513,30 @@ where
|
|||
sibling_invalidations
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(shadow) = element.shadow_root() {
|
||||
if element.exports_any_part() {
|
||||
any |= self.invalidate_parts_in_shadow_tree(shadow, invalidations)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
any
|
||||
}
|
||||
|
||||
fn invalidate_parts(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
|
||||
if invalidations.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let shadow = match self.element.shadow_root() {
|
||||
Some(s) => s,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
self.invalidate_parts_in_shadow_tree(shadow, invalidations)
|
||||
}
|
||||
|
||||
fn invalidate_slotted_elements(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
|
||||
if invalidations.is_empty() {
|
||||
return false;
|
||||
|
@ -733,7 +759,7 @@ where
|
|||
);
|
||||
|
||||
let matching_result = {
|
||||
let mut context = self.processor.matching_context();
|
||||
let context = self.processor.matching_context();
|
||||
context.current_host = invalidation.scope;
|
||||
|
||||
matches_compound_selector_from(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue