layout_api/layout_node.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5#![expect(unsafe_code)]
6#![deny(missing_docs)]
7
8use std::fmt::Debug;
9
10use atomic_refcell::AtomicRef;
11use net_traits::image_cache::Image;
12use pixels::ImageMetadata;
13use servo_arc::Arc;
14use servo_base::cross_process_instant::CrossProcessInstant;
15use servo_base::id::{BrowsingContextId, PipelineId};
16use servo_base::text::{RangeAny, Utf32CodeUnits};
17use servo_url::ServoUrl;
18use style::context::SharedStyleContext;
19use style::dom::{NodeInfo, OpaqueNode, TNode};
20use style::properties::ComputedValues;
21use style::selector_parser::PseudoElement;
22
23use crate::layout_dom::{DangerousStyleNodeOf, LayoutElementOf, LayoutNodeOf};
24use crate::pseudo_element_chain::PseudoElementChain;
25use crate::{
26 GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutDataTrait, LayoutDomTypeBundle,
27 LayoutNodeType, SVGElementData,
28};
29
30/// A trait that exposes a DOM nodes to layout. Implementors of this trait must abide by certain
31/// safety requirements. Layout will only ever access and mutate each node from a single thread
32/// at a time, though children may be used in parallel from other threads. That is why this trait
33/// does not allow access to parent nodes, as it would make it easy to cause race conditions and
34/// memory errors.
35///
36/// Note that the related [`DangerousStyleNode`] trait *may* access parent nodes, which is why
37/// that API is marked as `unsafe` here. In general [`DangerousStyleNode`] should only be used
38/// when interfacing with the `stylo` and `selectors`.
39pub trait LayoutNode<'dom>: Copy + Debug + NodeInfo + Send + Sync {
40 /// The concrete implementation of [`LayoutDomTypeBundle`] implemented in `script`.
41 type ConcreteTypeBundle: LayoutDomTypeBundle<'dom>;
42
43 /// Creates a new `LayoutNode` for the same `LayoutNode` with a different pseudo-element type.
44 ///
45 /// Returns `None` if this pseudo doesn't apply to the given element for one of
46 /// the following reasons:
47 ///
48 /// 1. This node is not an element.
49 /// 2. `pseudo` is eager and is not defined in the stylesheet. In this case, there
50 /// is not reason to process the pseudo element at all.
51 /// 3. `pseudo` is for `::servo-details-content` and
52 /// it doesn't apply to this element, either because it isn't a details or is
53 /// in the wrong state.
54 fn with_pseudo(&self, pseudo_element_type: PseudoElement) -> Option<Self>;
55
56 /// Returns the [`PseudoElementChain`] for this [`LayoutElement`].
57 fn pseudo_element_chain(&self) -> PseudoElementChain;
58
59 /// Returns access to a version of this LayoutNode that can be used by stylo
60 /// and selectors. This is dangerous as it allows more access to ancestors nodes
61 /// than LayoutNode. This should *only* be used when handing a node to stylo
62 /// or selectors.
63 ///
64 /// # Safety
65 ///
66 /// This should only ever be called from the main script thread. It is never
67 /// okay to explicitly create a node for style while any layout worker threads
68 /// are running.
69 unsafe fn dangerous_style_node(self) -> DangerousStyleNodeOf<'dom, Self::ConcreteTypeBundle>;
70
71 /// Returns access to the DOM parent node of this node. This *does not* take
72 /// into account shadow tree children and slottables. For that use
73 /// [`Self::dangerous_flat_tree_parent`].
74 ///
75 /// # Safety
76 ///
77 /// This should only ever be called from the main script thread. It is never
78 /// okay to explicitly access the parent node while any layout worker threads
79 /// are running.
80 unsafe fn dangerous_dom_parent(self) -> Option<Self>;
81
82 /// Returns access to the flat tree parent node of this node. This takes
83 /// into account shadow tree children and slottables.
84 ///
85 /// # Safety
86 ///
87 /// This should only ever be called from the main script thread. It is never
88 /// okay to explicitly access the parent node while any layout worker threads
89 /// are running.
90 unsafe fn dangerous_flat_tree_parent(self) -> Option<Self>;
91
92 /// Returns access to the flat tree parent node of this node considering pseudo
93 /// elements. The parent of a pseudo-element is found by removing the innermost
94 /// pseudo-element from its pseudo-element chain.
95 ///
96 /// # Safety
97 ///
98 /// This should only ever be called from the main script thread. It is never
99 /// okay to explicitly access the parent node while any layout worker threads
100 /// are running.
101 unsafe fn dangerous_flat_tree_parent_considering_pseudos(self) -> Option<Self>;
102
103 /// Get the layout data of this node, attempting to downcast it to the desired type.
104 /// Returns None if there is no layout data or it isn't of the desired type.
105 fn layout_data(&self) -> Option<&'dom GenericLayoutData>;
106
107 /// Returns whether the node is connected.
108 fn is_connected(&self) -> bool;
109
110 /// Converts self into an `OpaqueNode`.
111 fn opaque(&self) -> OpaqueNode;
112
113 /// Returns the type ID of this node. Returns `None` if this is a pseudo-element; otherwise,
114 /// returns `Some`.
115 fn type_id(&self) -> Option<LayoutNodeType>;
116
117 /// Initialize this node with empty opaque layout data.
118 fn initialize_layout_data<RequestedLayoutDataType: LayoutDataTrait>(&self);
119
120 /// Returns an iterator over this node's children in the [flat tree]. This
121 /// takes into account shadow tree children and slottables.
122 ///
123 /// [flat tree]: https://drafts.csswg.org/css-shadow-1/#flat-tree
124 fn flat_tree_children(&self) -> impl Iterator<Item = Self> + Sized;
125
126 /// Returns an iterator over this node's children in the DOM. This
127 /// *does not* take shadow roots and assigned slottables into account.
128 /// For that use [`Self::flat_tree_children`].
129 fn dom_children(&self) -> impl Iterator<Item = Self> + Sized;
130
131 /// Returns a [`LayoutElement`] if this is an element in the HTML namespace, None otherwise.
132 fn as_html_element(&self) -> Option<LayoutElementOf<'dom, Self::ConcreteTypeBundle>>;
133
134 /// Returns a [`LayoutElement`] if this is an element.
135 fn as_element(&self) -> Option<LayoutElementOf<'dom, Self::ConcreteTypeBundle>>;
136
137 /// Returns the computed style for the given node, properly handling pseudo-elements. For
138 /// elements this returns their style and for other nodes, this returns the style of the parent
139 /// element, if one exists.
140 ///
141 /// # Panics
142 ///
143 /// - Calling this method will panic it is an element has no style data, whether because
144 /// styling has not run yet or was not run for this element.
145 /// - Calling this method will panic if it is a non-element node without a parent element.
146 fn style(&self, context: &SharedStyleContext) -> Arc<ComputedValues>;
147
148 /// Returns the style for a text node. This is computed on the fly from the
149 /// parent style to avoid traversing text nodes in the style system.
150 ///
151 /// # Safety
152 ///
153 /// Note that this does require accessing the parent, which this interface
154 /// technically forbids. But accessing the parent is only unsafe insofar as
155 /// it can be used to reach siblings and cousins. A simple immutable borrow
156 /// of the parent data is fine, since the bottom-up traversal will not process
157 /// the parent until all the children have been processed.
158 ///
159 /// # Panics
160 ///
161 /// - Calling this method will panic if the parent element has no style data, whether
162 /// because styling has not run yet or was not run for this element.
163 /// - Calling this method will panic if it is a non-element node without a parent element.
164 fn parent_style(&self, context: &SharedStyleContext) -> Arc<ComputedValues>;
165
166 /// Returns the computed `:selected` style for the given node, properly handling
167 /// pseudo-elements. For elements this returns their style and for other nodes, this
168 /// returns the selected style of the parent element, if one exists.
169 ///
170 /// # Panics
171 ///
172 /// - Calling this method will panic it is an element has no style data, whether because
173 /// styling has not run yet or was not run for this element.
174 /// - Calling this method will panic if it is a non-element node without a parent element.
175 fn selected_style(&self, context: &SharedStyleContext) -> Arc<ComputedValues>;
176
177 /// Get the text content of this node, if it is a text node.
178 ///
179 /// # Panics
180 ///
181 /// This method will panic if called on a node that is not a DOM text node.
182 fn text_content(self) -> AtomicRef<'dom, str>;
183
184 /// For a text node, returns which range of this text is part of the document selection
185 ///
186 /// Returned offsets are counted in `char`s in the `self.text_content()` string.
187 fn text_node_selection(&self) -> Option<RangeAny<Utf32CodeUnits>>;
188
189 /// For a text node, whether a caret should be painted when the selection is an empty range
190 /// (start == end)
191 fn text_node_paints_caret(&self) -> bool;
192
193 /// For a text node, whether a caret placeholder should be inserted in the box tree.
194 /// Caret placeholders are used as a place to draw text carets in otherwise empty
195 /// elements (such as `<input>` fields). In addition, this forces the creation of an
196 /// inline formatting context for empty text nodes and the allocation of the line
197 /// strut height during layout to ensure that empty `<input>` fields render properly.
198 fn text_node_needs_caret_placeholder(&self) -> bool;
199
200 /// If this is an image element, returns its URL. If this is not an image element, fails.
201 fn image_url(&self) -> Option<ServoUrl>;
202
203 /// If this is an image element, returns the time when image request finished loading.
204 fn load_time(&self) -> Option<CrossProcessInstant>;
205
206 /// If this is an image element, returns its current-pixel-density. If this is not an image element, fails.
207 fn image_density(&self) -> Option<f64>;
208
209 /// If this is an image element, returns its image data. Otherwise, returns `None`.
210 fn image_data(&self) -> Option<(Option<Image>, Option<ImageMetadata>)>;
211
212 /// Whether or not this node is selected when it is interpreted as a replaced element.
213 fn replaced_is_selected(&self) -> bool;
214
215 /// Whether or not this is an image element that is showing a broken image icon.
216 fn showing_broken_image_icon(&self) -> bool;
217
218 /// Return the [`HTMLCanvas`] data for this node, if it is a canvas.
219 fn canvas_data(&self) -> Option<HTMLCanvasData>;
220
221 /// Return the [`SVGElementData`] for this node, if it is an SVG subtree.
222 fn svg_data(&self) -> Option<SVGElementData<'dom>>;
223
224 /// Return the [`HTMLMediaData`] for this node, if it is a media element.
225 fn media_data(&self) -> Option<HTMLMediaData>;
226
227 /// If this node is an iframe element, returns its browsing context ID. If this node is
228 /// not an iframe element, fails. Returns None if there is no nested browsing context.
229 fn iframe_browsing_context_id(&self) -> Option<BrowsingContextId>;
230
231 /// If this node is an iframe element, returns its pipeline ID. If this node is
232 /// not an iframe element, fails. Returns None if there is no nested browsing context.
233 fn iframe_pipeline_id(&self) -> Option<PipelineId>;
234
235 /// Return the table span property if it is an element that supports it.
236 fn table_span(&self) -> Option<u32>;
237
238 /// Return the table colspan property if it is an element that supports it.
239 fn table_colspan(&self) -> Option<u32>;
240
241 /// Return the table rowspan property if it is an element that supports it.
242 fn table_rowspan(&self) -> Option<u32>;
243
244 /// Whether this is a container for the text within a single-line text input. This
245 /// is used to solve the special case of line height for a text entry widget.
246 /// <https://html.spec.whatwg.org/multipage/#the-input-element-as-a-text-entry-widget>
247 fn is_single_line_text_input(&self) -> bool;
248
249 /// Whether or not this [`LayoutNode`] is in a user agent widget shadow DOM.
250 fn is_root_of_user_agent_widget(&self) -> bool;
251
252 /// Set whether or not this node has an active pseudo-element style with a `content`
253 /// attribute that uses `attr`.
254 fn set_uses_content_attribute_with_attr(&self, _uses_content_attribute_with_attr: bool);
255}
256
257/// A node that can be passed to `stylo` and `selectors` that allows accessing the
258/// parent node. We consider this to be too dangerous for normal layout, so it is
259/// reserved only for using `stylo` and `selectors`.
260///
261/// If you are not interfacing with `stylo` and `selectors` you *should not* use this
262/// type, unless you know what you are doing.
263pub trait DangerousStyleNode<'dom>: TNode + Sized + NodeInfo + Send + Sync {
264 /// The concrete implementation of [`LayoutDomTypeBundle`] implemented in `script`.
265 type ConcreteTypeBundle: LayoutDomTypeBundle<'dom>;
266 /// Get a handle to the original "safe" version of this node, a [`LayoutNode`] implementation.
267 fn layout_node(&self) -> LayoutNodeOf<'dom, Self::ConcreteTypeBundle>;
268}