diff options
author | Martin Robinson <mrobinson@igalia.com> | 2023-04-30 20:21:58 +0200 |
---|---|---|
committer | Martin Robinson <mrobinson@igalia.com> | 2023-05-04 10:46:27 +0200 |
commit | 72302e2dae6c4726ae657f7b5b8b048f9f64ccf2 (patch) | |
tree | 307e1972dd46de70388bd9cba0f8589f05250226 /components/layout_2020/fragment_tree/base.rs | |
parent | 77a184a0e7379a63a0d9d8bf442d8dd5c3b5e307 (diff) | |
download | servo-72302e2dae6c4726ae657f7b5b8b048f9f64ccf2.tar.gz servo-72302e2dae6c4726ae657f7b5b8b048f9f64ccf2.zip |
Detect body elements during layout
During layout it is often useful, for various specification reasons, to
know if an element is the `<body>` element of an `<html>` element root. There
are a couple places where a brittle heuristic is used to detect `<body>`
elements. This information is going to be even more important to
properly handle `<html>` elements that inherit their overflow property from
their `<body>` children.
Implementing this properly requires updating the DOM wrapper interface.
This check does reach up to the parent of thread-safe nodes, but this is
essentially the same kind of operation that `parent_style()` does, so is
ostensibly safe.
This change should not change any behavior and is just a preparation
step for properly handle `<body>` overflow.
Diffstat (limited to 'components/layout_2020/fragment_tree/base.rs')
-rw-r--r-- | components/layout_2020/fragment_tree/base.rs | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/components/layout_2020/fragment_tree/base.rs b/components/layout_2020/fragment_tree/base.rs new file mode 100644 index 00000000000..d9271a7a0f6 --- /dev/null +++ b/components/layout_2020/fragment_tree/base.rs @@ -0,0 +1,117 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::layout_debug::DebugId; +use bitflags::bitflags; +use gfx_traits::{combine_id_with_fragment_type, FragmentType}; +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 +/// concrete fragments. +#[derive(Debug, Serialize)] +pub(crate) struct BaseFragment { + /// A tag which identifies the DOM node and pseudo element of this + /// Fragment's content. If this fragment isn't related to any DOM + /// node at all, the tag will be None. + pub tag: Option<Tag>, + + /// An id used to uniquely identify this Fragment in debug builds. + pub debug_id: DebugId, + + /// Flags which various information about this fragment used during + /// layout. + pub flags: FragmentFlags, +} + +impl BaseFragment { + pub(crate) fn anonymous() -> Self { + BaseFragment { + tag: None, + debug_id: DebugId::new(), + flags: FragmentFlags::empty(), + } + } + + /// Returns true if this fragment is non-anonymous and it is for the given + /// OpaqueNode, regardless of the pseudo element. + pub(crate) fn is_for_node(&self, node: OpaqueNode) -> bool { + self.tag.map(|tag| tag.node == node).unwrap_or(false) + } +} + +/// Information necessary to construct a new BaseFragment. +#[derive(Clone, Copy, Debug, Serialize)] +pub(crate) struct BaseFragmentInfo { + /// The tag to use for the new BaseFragment. + pub tag: Tag, + + /// The flags to use for the new BaseFragment. + pub flags: FragmentFlags, +} + +impl BaseFragmentInfo { + pub(crate) fn new_for_node(node: OpaqueNode) -> Self { + Self { + tag: Tag::new(node), + flags: FragmentFlags::empty(), + } + } +} + +impl From<BaseFragmentInfo> for BaseFragment { + fn from(info: BaseFragmentInfo) -> Self { + Self { + tag: Some(info.tag), + debug_id: DebugId::new(), + flags: info.flags, + } + } +} + +bitflags! { + #[doc = "Flags used to track various information about a DOM node during layout."] + #[derive(Serialize)] + pub(crate) struct FragmentFlags: u8 { + #[doc = "Whether or not this node is a body element on an HTML document."] + const IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT = 0b00000001; + } +} + +/// A data structure used to hold DOM and pseudo-element information about +/// a particular layout object. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)] +pub(crate) struct Tag { + pub(crate) node: OpaqueNode, + pub(crate) pseudo: Option<PseudoElement>, +} + +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 } + } + + /// 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 } + } + + /// Returns true if this tag is for a pseudo element. + pub(crate) fn is_pseudo(&self) -> bool { + self.pseudo.is_some() + } + + pub(crate) fn to_display_list_fragment_id(&self) -> u64 { + let fragment_type = match self.pseudo { + Some(PseudoElement::Before) => FragmentType::BeforePseudoContent, + Some(PseudoElement::After) => FragmentType::AfterPseudoContent, + _ => FragmentType::FragmentBody, + }; + combine_id_with_fragment_type(self.node.id() as usize, fragment_type) as u64 + } +} |