aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020/fragment_tree/base.rs
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2023-04-30 20:21:58 +0200
committerMartin Robinson <mrobinson@igalia.com>2023-05-04 10:46:27 +0200
commit72302e2dae6c4726ae657f7b5b8b048f9f64ccf2 (patch)
tree307e1972dd46de70388bd9cba0f8589f05250226 /components/layout_2020/fragment_tree/base.rs
parent77a184a0e7379a63a0d9d8bf442d8dd5c3b5e307 (diff)
downloadservo-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.rs117
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
+ }
+}