/
githubmirror
/
servo
Обзор
Документация
Войти
/
githubmirror
/
servo
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
components/shared/layout/layout_element.rs
150 строк
7 KB
Martin Robinson
layout_api: Use a "type bundle" to encapsulate all layout DOM types (#44454)
25 апр 2026, 12:21
Не верифицирован
25 апр 2026, 12:21
1a9808d
Код
Авторство
О чём код?
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #![expect(unsafe_code)] #![deny(missing_docs)] use std::fmt::Debug; use html5ever::{LocalName, Namespace}; use servo_arc::Arc; use style::attr::AttrValue; use style::context::SharedStyleContext; use style::data::{ElementDataMut, ElementDataRef}; use style::dom::TElement; use style::properties::ComputedValues; use style::selector_parser::{PseudoElement, SelectorImpl}; use crate::layout_dom::{DangerousStyleElementOf, LayoutElementOf, LayoutNodeOf}; use crate::{LayoutDataTrait, LayoutDomTypeBundle, LayoutNodeType, PseudoElementChain, StyleData}; /// A trait that exposes a DOM element to layout. Implementors of this trait must abide by certain /// safety requirements. Layout will only ever access and mutate each element from a single thread /// at a time, though children may be used in parallel from other threads. That is why this trait /// does not allow access to parent nodes, as it would make it easy to cause race conditions and /// memory errors. /// /// Note that the related [`DangerousStyleElement`] trait *may* access parent nodes, which is why /// that API is marked as `unsafe` here. In general [`DangerousStyleElement`] should only be used /// when interfacing with the `stylo` and `selectors`. pub trait LayoutElement<'dom>: Copy + Debug + Send + Sync { /// The concrete implementation of [`LayoutDomTypeBundle`] implemented in `script`. type ConcreteTypeBundle: LayoutDomTypeBundle<'dom>; /// Creates a new `LayoutElement` for the same `LayoutElement` /// with a different pseudo-element type. /// /// Returns `None` if this pseudo doesn't apply to the given element for one of /// the following reasons: /// /// 1. `pseudo` is eager and is not defined in the stylesheet. In this case, there /// is not reason to process the pseudo element at all. /// 2. `pseudo` is for `::servo-details-content` and /// it doesn't apply to this element, either because it isn't a details or is /// in the wrong state. fn with_pseudo(&self, pseudo: PseudoElement) -> Option<Self>; /// Returns the [`PseudoElementChain`] for this [`LayoutElement`]. fn pseudo_element_chain(&self) -> PseudoElementChain; /// Return this [`LayoutElement`] as a [`LayoutNode`], preserving the internal /// pseudo-element chain. fn as_node(&self) -> LayoutNodeOf<'dom, Self::ConcreteTypeBundle>; /// Returns access to a version of this LayoutElement that can be used by stylo /// and selectors. This is dangerous as it allows more access to ancestor nodes /// that might be in the process of being read or written to in other threads. /// This should *only* be used when handing a node to stylo or selectors. /// /// # Safety /// /// This should only ever be called from the main script thread. It is never /// okay to explicitly create a node for style while any layout worker threads /// are running. unsafe fn dangerous_style_element( self, ) -> DangerousStyleElementOf<'dom, Self::ConcreteTypeBundle>; /// Initialize this node with empty style and opaque layout data. fn initialize_style_and_layout_data<RequestedLayoutDataType: LayoutDataTrait>(&self); /// Unset the snapshot flags on the underlying DOM object for this element. fn unset_snapshot_flags(&self); /// Set the snapshot flags on the underlying DOM object for this element. fn set_has_snapshot(&self); /// Get the [`StyleData`] for this [`LayoutElement`]. fn style_data(self) -> Option<&'dom StyleData>; /// Returns the type ID of this node. /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`. fn type_id(&self) -> Option<LayoutNodeType>; /// Get the local name of this element. See /// <https://dom.spec.whatwg.org/#concept-element-local-name>. fn local_name(&self) -> &LocalName; /// Get the attribute with the given `namespace` and `name` as an [`AttrValue`] if it /// exists, otherwise return `None`. fn attribute(&self, namespace: &Namespace, name: &LocalName) -> Option<&AttrValue>; /// Get the attribute with the given `namespace` and `name` as an [`AttrValue`] if it /// exists and converting the result to a `&str`, otherwise return `None`. fn attribute_as_str<'a>(&'a self, namespace: &Namespace, name: &LocalName) -> Option<&'a str>; /// Get a reference to the inner [`ElementDataRef`] for this element's [`StyleData`]. This will /// panic if the element is unstyled. fn element_data(&self) -> ElementDataRef<'dom>; /// Get a mutable reference to the inner [`ElementDataRef`] for this element's [`StyleData`]. /// This will panic if the element is unstyled. fn element_data_mut(&self) -> ElementDataMut<'dom>; /// Returns the computed style for the given element, properly handling pseudo-elements. /// /// # Panics /// /// Calling this method will panic if the element has no style data, whether because styling has /// not run yet or was not run for this element. fn style(&self, context: &SharedStyleContext) -> Arc<ComputedValues>; /// Returns `true` if this [`LayoutElement`] is a shadow DOM host and `false` otherwise. fn is_shadow_host(&self) -> bool; /// Returns whether this node is a body element of an HTML element root /// in an HTML document. /// /// Note that this does require accessing the parent, which this interface /// technically forbids. But accessing the parent is only unsafe insofar as /// it can be used to reach siblings and cousins. A simple immutable borrow /// of the parent data is fine, since the bottom-up traversal will not process /// the parent until all the children have been processed. fn is_body_element_of_html_element_root(&self) -> bool; /// Returns `true` if this [`LayoutNode`] is any kind of HTML element inside an HTML document /// and `false` otherwise. fn is_html_element_in_html_document(&self) -> bool; /// Returns whether this node is the root element in an HTML document element. /// /// Note that, like `Self::is_body_element_of_html_element_root`, this accesses the parent. /// As in that case, since this is an immutable borrow, we do not violate thread safety. fn is_root(&self) -> bool; } /// An element that can be passed to `stylo` and `selectors` that allows accessing the /// parent node. We consider this to be too dangerous for normal layout, so it is /// reserved only for using `stylo` and `selectors`. /// /// If you are not interfacing with `stylo` and `selectors` you *should not* use this /// type, unless you know what you are doing. pub trait DangerousStyleElement<'dom>: TElement + ::selectors::Element<Impl = SelectorImpl> + Send + Sync { /// The concrete implementation of [`LayoutDomTypeBundle`] implemented in `script`. type ConcreteTypeBundle: LayoutDomTypeBundle<'dom>; /// Get a handle to the original "safe" version of this element, a [`LayoutElement`]. fn layout_element(&self) -> LayoutElementOf<'dom, Self::ConcreteTypeBundle>; }