layout: Always build Tag and BaseFragmentInfo with ServoThreadSafeLayoutNode (#38680)

This cleanup makes the interface a bit simpler and prevents problems
where the pseudo-element information is not passed by accident.

Testing: This should not change behavior, so is covered by existing
tests.

---------

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Martin Robinson 2025-08-18 05:19:09 -07:00 committed by GitHub
parent 8743a11ba4
commit 6fdf40dce7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 117 additions and 116 deletions

View file

@ -3,11 +3,18 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use bitflags::bitflags;
use layout_api::combine_id_with_fragment_type;
use layout_api::wrapper_traits::PseudoElementChain;
use html5ever::local_name;
use layout_api::wrapper_traits::{
PseudoElementChain, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
};
use layout_api::{LayoutElementType, LayoutNodeType, combine_id_with_fragment_type};
use malloc_size_of::malloc_size_of_is_0;
use malloc_size_of_derive::MallocSizeOf;
use script::layout_dom::ServoThreadSafeLayoutNode;
use style::dom::OpaqueNode;
use style::selector_parser::PseudoElement;
use crate::dom_traversal::NodeAndStyleInfo;
/// This data structure stores fields that are common to all non-base
/// Fragment types and should generally be the first member of all
@ -48,19 +55,84 @@ pub(crate) struct BaseFragmentInfo {
}
impl BaseFragmentInfo {
pub(crate) fn new_for_node(node: OpaqueNode) -> Self {
Self {
tag: Some(Tag::new(node)),
flags: FragmentFlags::empty(),
}
}
pub(crate) fn anonymous() -> Self {
Self {
tag: None,
flags: FragmentFlags::empty(),
}
}
pub(crate) fn new_for_testing(id: usize) -> Self {
Self {
tag: Some(Tag {
node: OpaqueNode(id),
pseudo_element_chain: Default::default(),
}),
flags: FragmentFlags::empty(),
}
}
}
impl From<&NodeAndStyleInfo<'_>> for BaseFragmentInfo {
fn from(info: &NodeAndStyleInfo) -> Self {
info.node.into()
}
}
impl From<ServoThreadSafeLayoutNode<'_>> for BaseFragmentInfo {
fn from(node: ServoThreadSafeLayoutNode) -> Self {
let pseudo_element_chain = node.pseudo_element_chain();
let mut flags = FragmentFlags::empty();
// Anonymous boxes should not have a tag, because they should not take part in hit testing.
//
// TODO(mrobinson): It seems that anonymous boxes should take part in hit testing in some
// cases, but currently this means that the order of hit test results isn't as expected for
// some WPT tests. This needs more investigation.
if matches!(
pseudo_element_chain.innermost(),
Some(PseudoElement::ServoAnonymousBox) |
Some(PseudoElement::ServoAnonymousTable) |
Some(PseudoElement::ServoAnonymousTableCell) |
Some(PseudoElement::ServoAnonymousTableRow)
) {
return Self::anonymous();
}
if let Some(element) = node.as_html_element() {
if element.is_body_element_of_html_element_root() {
flags.insert(FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT);
}
match element.get_local_name() {
&local_name!("br") => {
flags.insert(FragmentFlags::IS_BR_ELEMENT);
},
&local_name!("table") | &local_name!("th") | &local_name!("td") => {
flags.insert(FragmentFlags::IS_TABLE_TH_OR_TD_ELEMENT);
},
_ => {},
}
if matches!(
element.type_id(),
Some(LayoutNodeType::Element(
LayoutElementType::HTMLInputElement | LayoutElementType::HTMLTextAreaElement
))
) {
flags.insert(FragmentFlags::IS_TEXT_CONTROL);
}
if ThreadSafeLayoutElement::is_root(&element) {
flags.insert(FragmentFlags::IS_ROOT_ELEMENT);
}
};
Self {
tag: Some(node.into()),
flags,
}
}
}
impl From<BaseFragmentInfo> for BaseFragment {
@ -118,25 +190,16 @@ pub(crate) struct Tag {
}
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_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_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_element_chain.primary.into())
}
}
impl From<ServoThreadSafeLayoutNode<'_>> for Tag {
fn from(node: ServoThreadSafeLayoutNode<'_>) -> Self {
Self {
node: node.opaque(),
pseudo_element_chain: node.pseudo_element_chain(),
}
}
}