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, MallocSizeOf)]
74pub(crate) struct BaseFragment {
75 pub tag: Option<Tag>,
79
80 pub flags: FragmentFlags,
83
84 pub style: BaseFragmentStyle,
87
88 pub rect: PhysicalRect<Au>,
92}
93
94impl BaseFragment {
95 pub(crate) fn new(
96 base_fragment_info: BaseFragmentInfo,
97 style: BaseFragmentStyle,
98 rect: PhysicalRect<Au>,
99 ) -> Self {
100 Self {
101 tag: base_fragment_info.tag,
102 flags: base_fragment_info.flags,
103 style,
104 rect,
105 }
106 }
107
108 pub(crate) fn is_anonymous(&self) -> bool {
109 self.tag.is_none()
110 }
111
112 pub(crate) fn repair_style(&mut self, style: &ServoArc<ComputedValues>) {
113 self.style = style.clone().into();
114 }
115
116 pub(crate) fn style<'a>(&'a self) -> BaseFragmentStyleRef<'a> {
117 match &self.style {
118 BaseFragmentStyle::Owned(computed_values) => {
119 BaseFragmentStyleRef::Owned(computed_values)
120 },
121 BaseFragmentStyle::Shared(shared_style) => {
122 BaseFragmentStyleRef::Shared(shared_style.borrow())
123 },
124 }
125 }
126}
127
128#[derive(Clone, Copy, Debug, MallocSizeOf)]
130pub(crate) struct BaseFragmentInfo {
131 pub tag: Option<Tag>,
133
134 pub flags: FragmentFlags,
136}
137
138impl BaseFragmentInfo {
139 pub(crate) fn anonymous() -> Self {
140 Self {
141 tag: None,
142 flags: FragmentFlags::empty(),
143 }
144 }
145
146 pub(crate) fn new_for_testing(id: usize) -> Self {
147 Self {
148 tag: Some(Tag {
149 node: OpaqueNode(id),
150 pseudo_element_chain: Default::default(),
151 }),
152 flags: FragmentFlags::empty(),
153 }
154 }
155
156 pub(crate) fn is_anonymous(&self) -> bool {
157 self.tag.is_none()
158 }
159}
160
161impl From<&NodeAndStyleInfo<'_>> for BaseFragmentInfo {
162 fn from(info: &NodeAndStyleInfo) -> Self {
163 info.node.into()
164 }
165}
166
167impl From<ServoThreadSafeLayoutNode<'_>> for BaseFragmentInfo {
168 fn from(node: ServoThreadSafeLayoutNode) -> Self {
169 let pseudo_element_chain = node.pseudo_element_chain();
170 let mut flags = FragmentFlags::empty();
171
172 if matches!(
178 pseudo_element_chain.innermost(),
179 Some(PseudoElement::ServoAnonymousBox) |
180 Some(PseudoElement::ServoAnonymousTable) |
181 Some(PseudoElement::ServoAnonymousTableCell) |
182 Some(PseudoElement::ServoAnonymousTableRow)
183 ) {
184 return Self::anonymous();
185 }
186
187 if let Some(element) = node.as_html_element() {
188 if element.is_body_element_of_html_element_root() {
189 flags.insert(FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT);
190 }
191
192 match element.get_local_name() {
193 &local_name!("br") => {
194 flags.insert(FragmentFlags::IS_BR_ELEMENT);
195 },
196 &local_name!("table") | &local_name!("th") | &local_name!("td") => {
197 flags.insert(FragmentFlags::IS_TABLE_TH_OR_TD_ELEMENT);
198 },
199 _ => {},
200 }
201
202 if ThreadSafeLayoutElement::is_root(&element) {
203 flags.insert(FragmentFlags::IS_ROOT_ELEMENT);
204 }
205 };
206
207 Self {
208 tag: Some(node.into()),
209 flags,
210 }
211 }
212}
213
214bitflags! {
215 #[derive(Clone, Copy, Debug)]
217 pub(crate) struct FragmentFlags: u16 {
218 const IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT = 1 << 0;
220 const IS_BR_ELEMENT = 1 << 1;
222 const IS_WIDGET = 1 << 2;
227 const IS_FLEX_OR_GRID_ITEM = 1 << 3;
229 const IS_REPLACED = 1 << 4;
232 const IS_TABLE_TH_OR_TD_ELEMENT = 1 << 5;
236 const IS_OUTSIDE_LIST_ITEM_MARKER = 1 << 6;
239 const DO_NOT_PAINT = 1 << 7;
243 const SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM = 1 << 8;
247 const IS_ROOT_ELEMENT = 1 << 9;
249 const PROPAGATED_OVERFLOW_TO_VIEWPORT = 1 << 10;
251 const IS_COLLAPSED = 1 << 11;
254
255 }
256}
257
258malloc_size_of_is_0!(FragmentFlags);
259
260#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
263pub(crate) struct Tag {
264 pub(crate) node: OpaqueNode,
265 pub(crate) pseudo_element_chain: PseudoElementChain,
266}
267
268impl Tag {
269 pub(crate) fn to_display_list_fragment_id(self) -> u64 {
270 combine_id_with_fragment_type(self.node.id(), self.pseudo_element_chain.primary.into())
271 }
272}
273
274impl From<ServoThreadSafeLayoutNode<'_>> for Tag {
275 fn from(node: ServoThreadSafeLayoutNode<'_>) -> Self {
276 Self {
277 node: node.opaque(),
278 pseudo_element_chain: node.pseudo_element_chain(),
279 }
280 }
281}