layout/fragment_tree/
base_fragment.rs1use std::ops::Deref;
6
7use app_units::Au;
8use atomic_refcell::AtomicRef;
9use bitflags::bitflags;
10use html5ever::local_name;
11use layout_api::combine_id_with_fragment_type;
12use layout_api::wrapper_traits::{
13 PseudoElementChain, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
14};
15use malloc_size_of::malloc_size_of_is_0;
16use malloc_size_of_derive::MallocSizeOf;
17use script::layout_dom::ServoThreadSafeLayoutNode;
18use servo_arc::Arc as ServoArc;
19use style::dom::OpaqueNode;
20use style::properties::ComputedValues;
21use style::selector_parser::PseudoElement;
22
23use crate::SharedStyle;
24use crate::dom_traversal::NodeAndStyleInfo;
25use crate::geom::PhysicalRect;
26
27pub(crate) enum BaseFragmentStyleRef<'a> {
28 Owned(&'a ServoArc<ComputedValues>),
29 Shared(AtomicRef<'a, ServoArc<ComputedValues>>),
30}
31
32impl<'a> Deref for BaseFragmentStyleRef<'a> {
33 type Target = ServoArc<ComputedValues>;
34
35 fn deref(&self) -> &Self::Target {
36 match self {
37 BaseFragmentStyleRef::Owned(style) => style,
38 BaseFragmentStyleRef::Shared(style_ref) => style_ref.deref(),
39 }
40 }
41}
42
43#[derive(Clone, MallocSizeOf)]
44pub(crate) enum BaseFragmentStyle {
45 Owned(ServoArc<ComputedValues>),
46 Shared(SharedStyle),
47}
48
49impl From<ServoArc<ComputedValues>> for BaseFragmentStyle {
50 fn from(style: ServoArc<ComputedValues>) -> Self {
51 BaseFragmentStyle::Owned(style)
52 }
53}
54
55impl From<SharedStyle> for BaseFragmentStyle {
56 fn from(style: SharedStyle) -> Self {
57 BaseFragmentStyle::Shared(style)
58 }
59}
60
61impl std::fmt::Debug for BaseFragmentStyle {
62 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 match self {
64 BaseFragmentStyle::Owned(..) => write!(formatter, "BaseFragmentStyle::Owned"),
65 BaseFragmentStyle::Shared(..) => write!(formatter, "BaseFragmentStyle::Shared"),
66 }
67 }
68}
69
70#[derive(Clone, Debug, Default, MallocSizeOf)]
71pub(crate) enum FragmentStatus {
72 #[default]
74 New,
75 StyleChanged,
77 Clean,
79}
80
81#[derive(Clone, Debug, MallocSizeOf)]
85pub(crate) struct BaseFragment {
86 pub tag: Option<Tag>,
90
91 pub flags: FragmentFlags,
94
95 pub style: BaseFragmentStyle,
98
99 pub rect: PhysicalRect<Au>,
103
104 pub status: FragmentStatus,
106}
107
108impl BaseFragment {
109 pub(crate) fn new(
110 base_fragment_info: BaseFragmentInfo,
111 style: BaseFragmentStyle,
112 rect: PhysicalRect<Au>,
113 ) -> Self {
114 Self {
115 tag: base_fragment_info.tag,
116 flags: base_fragment_info.flags,
117 style,
118 rect,
119 status: Default::default(),
120 }
121 }
122
123 pub(crate) fn is_anonymous(&self) -> bool {
124 self.tag.is_none()
125 }
126
127 pub(crate) fn repair_style(&mut self, style: &ServoArc<ComputedValues>) {
128 self.style = style.clone().into();
129 self.status = FragmentStatus::StyleChanged;
130 }
131
132 pub(crate) fn style<'a>(&'a self) -> BaseFragmentStyleRef<'a> {
133 match &self.style {
134 BaseFragmentStyle::Owned(computed_values) => {
135 BaseFragmentStyleRef::Owned(computed_values)
136 },
137 BaseFragmentStyle::Shared(shared_style) => {
138 BaseFragmentStyleRef::Shared(shared_style.borrow())
139 },
140 }
141 }
142}
143
144#[derive(Clone, Copy, Debug, MallocSizeOf)]
146pub(crate) struct BaseFragmentInfo {
147 pub tag: Option<Tag>,
149
150 pub flags: FragmentFlags,
152}
153
154impl BaseFragmentInfo {
155 pub(crate) fn anonymous() -> Self {
156 Self {
157 tag: None,
158 flags: FragmentFlags::empty(),
159 }
160 }
161
162 pub(crate) fn new_for_testing(id: usize) -> Self {
163 Self {
164 tag: Some(Tag {
165 node: OpaqueNode(id),
166 pseudo_element_chain: Default::default(),
167 }),
168 flags: FragmentFlags::empty(),
169 }
170 }
171
172 pub(crate) fn is_anonymous(&self) -> bool {
173 self.tag.is_none()
174 }
175}
176
177impl From<&NodeAndStyleInfo<'_>> for BaseFragmentInfo {
178 fn from(info: &NodeAndStyleInfo) -> Self {
179 info.node.into()
180 }
181}
182
183impl From<ServoThreadSafeLayoutNode<'_>> for BaseFragmentInfo {
184 fn from(node: ServoThreadSafeLayoutNode) -> Self {
185 let pseudo_element_chain = node.pseudo_element_chain();
186 let mut flags = FragmentFlags::empty();
187
188 if matches!(
194 pseudo_element_chain.innermost(),
195 Some(PseudoElement::ServoAnonymousBox) |
196 Some(PseudoElement::ServoAnonymousTable) |
197 Some(PseudoElement::ServoAnonymousTableCell) |
198 Some(PseudoElement::ServoAnonymousTableRow)
199 ) {
200 return Self::anonymous();
201 }
202
203 if let Some(element) = node.as_html_element() {
204 if element.is_body_element_of_html_element_root() {
205 flags.insert(FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT);
206 }
207
208 match element.get_local_name() {
209 &local_name!("br") => {
210 flags.insert(FragmentFlags::IS_BR_ELEMENT);
211 },
212 &local_name!("table") | &local_name!("th") | &local_name!("td") => {
213 flags.insert(FragmentFlags::IS_TABLE_TH_OR_TD_ELEMENT);
214 },
215 _ => {},
216 }
217
218 if ThreadSafeLayoutElement::is_root(&element) {
219 flags.insert(FragmentFlags::IS_ROOT_ELEMENT);
220 }
221 };
222
223 Self {
224 tag: Some(node.into()),
225 flags,
226 }
227 }
228}
229
230bitflags! {
231 #[derive(Clone, Copy, Debug)]
233 pub(crate) struct FragmentFlags: u16 {
234 const IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT = 1 << 0;
236 const IS_BR_ELEMENT = 1 << 1;
238 const IS_WIDGET = 1 << 2;
243 const IS_FLEX_OR_GRID_ITEM = 1 << 3;
245 const IS_REPLACED = 1 << 4;
248 const IS_TABLE_TH_OR_TD_ELEMENT = 1 << 5;
252 const IS_OUTSIDE_LIST_ITEM_MARKER = 1 << 6;
255 const DO_NOT_PAINT = 1 << 7;
259 const SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM = 1 << 8;
263 const IS_ROOT_ELEMENT = 1 << 9;
265 const PROPAGATED_OVERFLOW_TO_VIEWPORT = 1 << 10;
267 const IS_COLLAPSED = 1 << 11;
270
271 }
272}
273
274malloc_size_of_is_0!(FragmentFlags);
275
276#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
279pub(crate) struct Tag {
280 pub(crate) node: OpaqueNode,
281 pub(crate) pseudo_element_chain: PseudoElementChain,
282}
283
284impl Tag {
285 pub(crate) fn to_display_list_fragment_id(self) -> u64 {
286 combine_id_with_fragment_type(self.node.id(), self.pseudo_element_chain.primary.into())
287 }
288}
289
290impl From<ServoThreadSafeLayoutNode<'_>> for Tag {
291 fn from(node: ServoThreadSafeLayoutNode<'_>) -> Self {
292 Self {
293 node: node.opaque(),
294 pseudo_element_chain: node.pseudo_element_chain(),
295 }
296 }
297}