script/dom/node/
layout_dom.rs1use std::borrow::Cow;
8
9use layout_api::{
10 GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType,
11 SVGElementData, SharedSelection,
12};
13use net_traits::image_cache::Image;
14use pixels::ImageMetadata;
15use script_bindings::codegen::InheritTypes::{
16 ElementTypeId, HTMLElementTypeId, SVGElementTypeId, SVGGraphicsElementTypeId,
17};
18use servo_base::id::{BrowsingContextId, PipelineId};
19use servo_url::ServoUrl;
20use style::dom::OpaqueNode;
21use style::selector_parser::PseudoElement;
22
23use crate::dom::bindings::inheritance::{CharacterDataTypeId, NodeTypeId};
24use crate::dom::bindings::root::{LayoutDom, ToLayout};
25use crate::dom::document::Document;
26use crate::dom::element::Element;
27use crate::dom::html::htmlcanvaselement::HTMLCanvasElement;
28use crate::dom::html::htmliframeelement::HTMLIFrameElement;
29use crate::dom::html::htmlimageelement::HTMLImageElement;
30use crate::dom::html::htmlslotelement::HTMLSlotElement;
31use crate::dom::html::htmltextareaelement::HTMLTextAreaElement;
32use crate::dom::html::htmlvideoelement::HTMLVideoElement;
33use crate::dom::html::input_element::HTMLInputElement;
34use crate::dom::shadowroot::ShadowRoot;
35use crate::dom::svg::svgsvgelement::SVGSVGElement;
36use crate::dom::text::Text;
37use crate::dom::{Node, NodeFlags};
38
39impl<'dom> LayoutDom<'dom, Node> {
40 #[inline]
41 #[expect(unsafe_code)]
42 pub(crate) fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
43 unsafe { self.unsafe_get().parent_node().get_inner_as_layout() }
44 }
45
46 #[inline]
47 pub(crate) fn type_id_for_layout(self) -> NodeTypeId {
48 self.unsafe_get().type_id()
49 }
50
51 #[inline]
52 pub(crate) fn is_element_for_layout(&self) -> bool {
53 (*self).is::<Element>()
54 }
55
56 pub(crate) fn is_text_node_for_layout(&self) -> bool {
57 matches!(
58 self.type_id_for_layout(),
59 NodeTypeId::CharacterData(CharacterDataTypeId::Text(..))
60 )
61 }
62
63 #[inline]
64 pub(crate) fn composed_parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
65 let parent = self.parent_node_ref();
66 if let Some(parent) = parent &&
67 let Some(shadow_root) = parent.downcast::<ShadowRoot>()
68 {
69 return Some(shadow_root.get_host_for_layout().upcast());
70 }
71 parent
72 }
73
74 #[inline]
75 pub(crate) fn traversal_parent(self) -> Option<LayoutDom<'dom, Element>> {
76 if let Some(assigned_slot) = self.assigned_slot_for_layout() {
77 return Some(assigned_slot.upcast());
78 }
79 let parent = self.parent_node_ref()?;
80 if let Some(shadow) = parent.downcast::<ShadowRoot>() {
81 return Some(shadow.get_host_for_layout());
82 };
83 parent.downcast()
84 }
85
86 #[inline]
87 #[expect(unsafe_code)]
88 pub(crate) fn first_child_ref(self) -> Option<LayoutDom<'dom, Node>> {
89 unsafe { self.unsafe_get().first_child().get_inner_as_layout() }
90 }
91
92 #[inline]
93 #[expect(unsafe_code)]
94 pub(crate) fn last_child_ref(self) -> Option<LayoutDom<'dom, Node>> {
95 unsafe { self.unsafe_get().last_child().get_inner_as_layout() }
96 }
97
98 #[inline]
99 #[expect(unsafe_code)]
100 pub(crate) fn prev_sibling_ref(self) -> Option<LayoutDom<'dom, Node>> {
101 unsafe { self.unsafe_get().prev_sibling().get_inner_as_layout() }
102 }
103
104 #[inline]
105 #[expect(unsafe_code)]
106 pub(crate) fn next_sibling_ref(self) -> Option<LayoutDom<'dom, Node>> {
107 unsafe { self.unsafe_get().next_sibling().get_inner_as_layout() }
108 }
109
110 #[inline]
111 #[expect(unsafe_code)]
112 pub(crate) fn owner_doc_for_layout(self) -> LayoutDom<'dom, Document> {
113 unsafe {
114 self.unsafe_get()
115 .get_owner_doc()
116 .get_inner_as_layout()
117 .unwrap()
118 }
119 }
120
121 #[inline]
122 #[expect(unsafe_code)]
123 pub(crate) fn containing_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>> {
124 unsafe {
125 self.unsafe_get()
126 .get_rare_data()
127 .borrow_for_layout()
128 .as_ref()?
129 .containing_shadow_root
130 .as_ref()
131 .map(|sr| sr.to_layout())
132 }
133 }
134
135 #[inline]
136 #[expect(unsafe_code)]
137 pub(crate) fn assigned_slot_for_layout(self) -> Option<LayoutDom<'dom, HTMLSlotElement>> {
138 unsafe {
139 self.unsafe_get()
140 .get_rare_data()
141 .borrow_for_layout()
142 .as_ref()?
143 .slottable_data
144 .assigned_slot
145 .as_ref()
146 .map(|assigned_slot| assigned_slot.to_layout())
147 }
148 }
149
150 #[inline]
155 #[expect(unsafe_code)]
156 pub(crate) unsafe fn get_flag(self, flag: NodeFlags) -> bool {
157 (self.unsafe_get()).flags().get().contains(flag)
158 }
159
160 #[inline]
161 #[expect(unsafe_code)]
162 pub(crate) unsafe fn set_flag(self, flag: NodeFlags, value: bool) {
163 let this = self.unsafe_get();
164 let mut flags = (this).flags().get();
165
166 if value {
167 flags.insert(flag);
168 } else {
169 flags.remove(flag);
170 }
171
172 (this).flags().set(flags);
173 }
174
175 #[inline]
176 #[expect(unsafe_code)]
177 pub(crate) fn layout_data(self) -> Option<&'dom GenericLayoutData> {
178 unsafe {
179 self.unsafe_get()
180 .layout_data()
181 .borrow_for_layout()
182 .as_deref()
183 }
184 }
185
186 #[inline]
194 #[expect(unsafe_code)]
195 pub(crate) unsafe fn initialize_layout_data(self, new_data: Box<GenericLayoutData>) {
196 let data = unsafe { self.unsafe_get().layout_data().borrow_mut_for_layout() };
197 debug_assert!(data.is_none());
198 *data = Some(new_data);
199 }
200
201 #[inline]
209 #[expect(unsafe_code)]
210 pub(crate) unsafe fn clear_layout_data(self) {
211 unsafe {
212 self.unsafe_get()
213 .layout_data()
214 .borrow_mut_for_layout()
215 .take();
216 }
217 }
218
219 pub(crate) fn is_single_line_text_inner_editor(&self) -> bool {
222 matches!(
223 self.implemented_pseudo_element(),
224 Some(PseudoElement::ServoTextControlInnerEditor)
225 )
226 }
227
228 pub(crate) fn is_text_container_of_single_line_input(&self) -> bool {
231 let is_single_line_text_inner_placeholder = matches!(
232 self.implemented_pseudo_element(),
233 Some(PseudoElement::Placeholder)
234 );
235 debug_assert!(
237 !is_single_line_text_inner_placeholder ||
238 self.containing_shadow_root_for_layout()
239 .map(|root| root.get_host_for_layout())
240 .map(|host| host.downcast::<HTMLInputElement>())
241 .is_some()
242 );
243
244 self.is_single_line_text_inner_editor() || is_single_line_text_inner_placeholder
245 }
246
247 pub(crate) fn text_content(self) -> Cow<'dom, str> {
248 self.downcast::<Text>()
249 .expect("Called LayoutDom::text_content on non-Text node!")
250 .upcast()
251 .data_for_layout()
252 .into()
253 }
254
255 pub(crate) fn selection(self) -> Option<SharedSelection> {
262 if let Some(input) = self.downcast::<HTMLInputElement>() {
263 return input.selection_for_layout();
264 }
265 if let Some(textarea) = self.downcast::<HTMLTextAreaElement>() {
266 return Some(textarea.selection_for_layout());
267 }
268
269 let shadow_root = self
270 .containing_shadow_root_for_layout()?
271 .get_host_for_layout();
272 if let Some(input) = shadow_root.downcast::<HTMLInputElement>() {
273 return input.selection_for_layout();
274 }
275 shadow_root
276 .downcast::<HTMLTextAreaElement>()
277 .map(|textarea| textarea.selection_for_layout())
278 }
279
280 pub(crate) fn image_url(self) -> Option<ServoUrl> {
281 self.downcast::<HTMLImageElement>()
282 .expect("not an image!")
283 .image_url()
284 }
285
286 pub(crate) fn image_data(self) -> Option<(Option<Image>, Option<ImageMetadata>)> {
287 self.downcast::<HTMLImageElement>().map(|e| e.image_data())
288 }
289
290 pub(crate) fn image_density(self) -> Option<f64> {
291 self.downcast::<HTMLImageElement>()
292 .expect("not an image!")
293 .image_density()
294 }
295
296 pub(crate) fn showing_broken_image_icon(self) -> bool {
297 self.downcast::<HTMLImageElement>()
298 .map(|image_element| image_element.showing_broken_image_icon())
299 .unwrap_or_default()
300 }
301
302 pub(crate) fn canvas_data(self) -> Option<HTMLCanvasData> {
303 self.downcast::<HTMLCanvasElement>()
304 .map(|canvas| canvas.data())
305 }
306
307 pub(crate) fn media_data(self) -> Option<HTMLMediaData> {
308 self.downcast::<HTMLVideoElement>()
309 .map(|media| media.data())
310 }
311
312 pub(crate) fn svg_data(self) -> Option<SVGElementData<'dom>> {
313 self.downcast::<SVGSVGElement>().map(|svg| svg.data())
314 }
315
316 pub(crate) fn iframe_browsing_context_id(self) -> Option<BrowsingContextId> {
317 self.downcast::<HTMLIFrameElement>()
318 .and_then(|iframe_element| iframe_element.browsing_context_id())
319 }
320
321 pub(crate) fn iframe_pipeline_id(self) -> Option<PipelineId> {
322 self.downcast::<HTMLIFrameElement>()
323 .and_then(|iframe_element| iframe_element.pipeline_id())
324 }
325
326 #[expect(unsafe_code)]
327 pub(crate) fn opaque(self) -> OpaqueNode {
328 unsafe { OpaqueNode(self.get_jsobject() as usize) }
329 }
330
331 #[expect(unsafe_code)]
332 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
333 unsafe {
334 self.unsafe_get()
335 .get_rare_data()
336 .borrow_for_layout()
337 .as_ref()
338 .and_then(|rare_data| rare_data.implemented_pseudo_element)
339 }
340 }
341
342 pub(crate) fn is_in_ua_widget(&self) -> bool {
343 self.unsafe_get().is_in_ua_widget()
344 }
345
346 pub(crate) fn is_root_of_user_agent_widget(&self) -> bool {
347 self.downcast::<Element>().is_some_and(|element| {
348 element
349 .get_shadow_root_for_layout()
350 .is_some_and(|shadow_root| shadow_root.is_user_agent_widget())
351 })
352 }
353}
354
355pub(crate) struct NodeTypeIdWrapper(pub(crate) NodeTypeId);
356
357impl From<NodeTypeIdWrapper> for LayoutNodeType {
358 #[inline(always)]
359 fn from(node_type: NodeTypeIdWrapper) -> LayoutNodeType {
360 match node_type.0 {
361 NodeTypeId::Element(e) => LayoutNodeType::Element(ElementTypeIdWrapper(e).into()),
362 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => LayoutNodeType::Text,
363 x => unreachable!("Layout should not traverse nodes of type {:?}", x),
364 }
365 }
366}
367
368struct ElementTypeIdWrapper(ElementTypeId);
369
370impl From<ElementTypeIdWrapper> for LayoutElementType {
371 #[inline(always)]
372 fn from(element_type: ElementTypeIdWrapper) -> LayoutElementType {
373 match element_type.0 {
374 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement) => {
375 LayoutElementType::HTMLBodyElement
376 },
377 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBRElement) => {
378 LayoutElementType::HTMLBRElement
379 },
380 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement) => {
381 LayoutElementType::HTMLCanvasElement
382 },
383 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHtmlElement) => {
384 LayoutElementType::HTMLHtmlElement
385 },
386 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement) => {
387 LayoutElementType::HTMLIFrameElement
388 },
389 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement) => {
390 LayoutElementType::HTMLImageElement
391 },
392 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMediaElement(_)) => {
393 LayoutElementType::HTMLMediaElement
394 },
395 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement) => {
396 LayoutElementType::HTMLInputElement
397 },
398 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptGroupElement) => {
399 LayoutElementType::HTMLOptGroupElement
400 },
401 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement) => {
402 LayoutElementType::HTMLOptionElement
403 },
404 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement) => {
405 LayoutElementType::HTMLObjectElement
406 },
407 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLParagraphElement) => {
408 LayoutElementType::HTMLParagraphElement
409 },
410 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLPreElement) => {
411 LayoutElementType::HTMLPreElement
412 },
413 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement) => {
414 LayoutElementType::HTMLSelectElement
415 },
416 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableCellElement) => {
417 LayoutElementType::HTMLTableCellElement
418 },
419 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement) => {
420 LayoutElementType::HTMLTableColElement
421 },
422 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement) => {
423 LayoutElementType::HTMLTableElement
424 },
425 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement) => {
426 LayoutElementType::HTMLTableRowElement
427 },
428 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableSectionElement) => {
429 LayoutElementType::HTMLTableSectionElement
430 },
431 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement) => {
432 LayoutElementType::HTMLTextAreaElement
433 },
434 ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
435 SVGGraphicsElementTypeId::SVGImageElement,
436 )) => LayoutElementType::SVGImageElement,
437 ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
438 SVGGraphicsElementTypeId::SVGSVGElement,
439 )) => LayoutElementType::SVGSVGElement,
440 _ => LayoutElementType::Element,
441 }
442 }
443}