layout: Support storing layout data for two-level nested pseudo-elements (#38678)

Add basic support for storing layout data for pseudo-elements nested to
up to two levels. This removes the last unstored layout result and fixes
a double-borrow issue. This change does not add properly parsing nor
styling of these element types, but does prepare for those changes which
must come from stylo.

Testing: This fixes a intermittent panic in
`tests/wpt/tests/css/css-lists/nested-marker-styling.html`
Fixes: #38177. 
Closes: #38183.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Martin Robinson 2025-08-14 15:41:34 +02:00 committed by GitHub
parent 43da933247
commit 99ce81cf64
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 273 additions and 177 deletions

View file

@ -4,10 +4,10 @@
use bitflags::bitflags;
use layout_api::combine_id_with_fragment_type;
use layout_api::wrapper_traits::PseudoElementChain;
use malloc_size_of::malloc_size_of_is_0;
use malloc_size_of_derive::MallocSizeOf;
use style::dom::OpaqueNode;
use style::selector_parser::PseudoElement;
/// This data structure stores fields that are common to all non-base
/// Fragment types and should generally be the first member of all
@ -114,23 +114,29 @@ malloc_size_of_is_0!(FragmentFlags);
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
pub(crate) struct Tag {
pub(crate) node: OpaqueNode,
pub(crate) pseudo: Option<PseudoElement>,
pub(crate) pseudo_element_chain: PseudoElementChain,
}
impl Tag {
/// Create a new Tag for a non-pseudo element. This is mainly used for
/// matching existing tags, since it does not accept an `info` argument.
pub(crate) fn new(node: OpaqueNode) -> Self {
Tag { node, pseudo: None }
Tag {
node,
pseudo_element_chain: Default::default(),
}
}
/// Create a new Tag for a pseudo element. This is mainly used for
/// matching existing tags, since it does not accept an `info` argument.
pub(crate) fn new_pseudo(node: OpaqueNode, pseudo: Option<PseudoElement>) -> Self {
Tag { node, pseudo }
pub(crate) fn new_pseudo(node: OpaqueNode, pseudo_element_chain: PseudoElementChain) -> Self {
Tag {
node,
pseudo_element_chain,
}
}
pub(crate) fn to_display_list_fragment_id(self) -> u64 {
combine_id_with_fragment_type(self.node.id(), self.pseudo.into())
combine_id_with_fragment_type(self.node.id(), self.pseudo_element_chain.primary.into())
}
}

View file

@ -71,8 +71,15 @@ impl FragmentTree {
fragment_tree.find(|fragment, _level, containing_block| {
if let Some(tag) = fragment.tag() {
invalid_animating_nodes.remove(&AnimationSetKey::new(tag.node, tag.pseudo));
invalid_image_animating_nodes.remove(&AnimationSetKey::new(tag.node, tag.pseudo));
// TODO: Support animations on nested pseudo-elements.
invalid_animating_nodes.remove(&AnimationSetKey::new(
tag.node,
tag.pseudo_element_chain.primary,
));
invalid_image_animating_nodes.remove(&AnimationSetKey::new(
tag.node,
tag.pseudo_element_chain.primary,
));
}
fragment.set_containing_block(containing_block);