layout/fragment_tree/
base_fragment.rs1use bitflags::bitflags;
6use html5ever::local_name;
7use layout_api::wrapper_traits::{
8 PseudoElementChain, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
9};
10use layout_api::{LayoutElementType, LayoutNodeType, combine_id_with_fragment_type};
11use malloc_size_of::malloc_size_of_is_0;
12use malloc_size_of_derive::MallocSizeOf;
13use script::layout_dom::ServoThreadSafeLayoutNode;
14use style::dom::OpaqueNode;
15use style::selector_parser::PseudoElement;
16
17use crate::dom_traversal::NodeAndStyleInfo;
18
19#[derive(Clone, Debug, MallocSizeOf)]
23pub(crate) struct BaseFragment {
24 pub tag: Option<Tag>,
28
29 pub flags: FragmentFlags,
32}
33
34impl BaseFragment {
35 pub(crate) fn anonymous() -> Self {
36 BaseFragment {
37 tag: None,
38 flags: FragmentFlags::empty(),
39 }
40 }
41
42 pub(crate) fn is_anonymous(&self) -> bool {
43 self.tag.is_none()
44 }
45}
46
47#[derive(Clone, Copy, Debug, MallocSizeOf)]
49pub(crate) struct BaseFragmentInfo {
50 pub tag: Option<Tag>,
52
53 pub flags: FragmentFlags,
55}
56
57impl BaseFragmentInfo {
58 pub(crate) fn anonymous() -> Self {
59 Self {
60 tag: None,
61 flags: FragmentFlags::empty(),
62 }
63 }
64
65 pub(crate) fn new_for_testing(id: usize) -> Self {
66 Self {
67 tag: Some(Tag {
68 node: OpaqueNode(id),
69 pseudo_element_chain: Default::default(),
70 }),
71 flags: FragmentFlags::empty(),
72 }
73 }
74}
75
76impl From<&NodeAndStyleInfo<'_>> for BaseFragmentInfo {
77 fn from(info: &NodeAndStyleInfo) -> Self {
78 info.node.into()
79 }
80}
81
82impl From<ServoThreadSafeLayoutNode<'_>> for BaseFragmentInfo {
83 fn from(node: ServoThreadSafeLayoutNode) -> Self {
84 let pseudo_element_chain = node.pseudo_element_chain();
85 let mut flags = FragmentFlags::empty();
86
87 if matches!(
93 pseudo_element_chain.innermost(),
94 Some(PseudoElement::ServoAnonymousBox) |
95 Some(PseudoElement::ServoAnonymousTable) |
96 Some(PseudoElement::ServoAnonymousTableCell) |
97 Some(PseudoElement::ServoAnonymousTableRow)
98 ) {
99 return Self::anonymous();
100 }
101
102 if let Some(element) = node.as_html_element() {
103 if element.is_body_element_of_html_element_root() {
104 flags.insert(FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT);
105 }
106
107 match element.get_local_name() {
108 &local_name!("br") => {
109 flags.insert(FragmentFlags::IS_BR_ELEMENT);
110 },
111 &local_name!("table") | &local_name!("th") | &local_name!("td") => {
112 flags.insert(FragmentFlags::IS_TABLE_TH_OR_TD_ELEMENT);
113 },
114 _ => {},
115 }
116
117 if matches!(
118 element.type_id(),
119 Some(LayoutNodeType::Element(
120 LayoutElementType::HTMLInputElement | LayoutElementType::HTMLTextAreaElement
121 ))
122 ) {
123 flags.insert(FragmentFlags::IS_TEXT_CONTROL);
124 }
125
126 if ThreadSafeLayoutElement::is_root(&element) {
127 flags.insert(FragmentFlags::IS_ROOT_ELEMENT);
128 }
129 };
130
131 Self {
132 tag: Some(node.into()),
133 flags,
134 }
135 }
136}
137
138impl From<BaseFragmentInfo> for BaseFragment {
139 fn from(info: BaseFragmentInfo) -> Self {
140 Self {
141 tag: info.tag,
142 flags: info.flags,
143 }
144 }
145}
146
147bitflags! {
148 #[derive(Clone, Copy, Debug)]
150 pub(crate) struct FragmentFlags: u16 {
151 const IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT = 1 << 0;
153 const IS_BR_ELEMENT = 1 << 1;
155 const IS_TEXT_CONTROL = 1 << 2;
157 const IS_FLEX_OR_GRID_ITEM = 1 << 3;
159 const IS_REPLACED = 1 << 4;
162 const IS_TABLE_TH_OR_TD_ELEMENT = 1 << 5;
166 const IS_OUTSIDE_LIST_ITEM_MARKER = 1 << 6;
169 const DO_NOT_PAINT = 1 << 7;
173 const SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM = 1 << 8;
177 const IS_ROOT_ELEMENT = 1 << 9;
179 const PROPAGATED_OVERFLOW_TO_VIEWPORT = 1 << 10;
181 const IS_COLLAPSED = 1 << 11;
184
185 }
186}
187
188malloc_size_of_is_0!(FragmentFlags);
189
190#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
193pub(crate) struct Tag {
194 pub(crate) node: OpaqueNode,
195 pub(crate) pseudo_element_chain: PseudoElementChain,
196}
197
198impl Tag {
199 pub(crate) fn to_display_list_fragment_id(self) -> u64 {
200 combine_id_with_fragment_type(self.node.id(), self.pseudo_element_chain.primary.into())
201 }
202}
203
204impl From<ServoThreadSafeLayoutNode<'_>> for Tag {
205 fn from(node: ServoThreadSafeLayoutNode<'_>) -> Self {
206 Self {
207 node: node.opaque(),
208 pseudo_element_chain: node.pseudo_element_chain(),
209 }
210 }
211}