script/layout_dom/
servo_dangerous_style_document.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#![deny(missing_docs)]
6
7use layout_api::DangerousStyleElement;
8use selectors::matching::QuirksMode;
9use style::dom::{TDocument, TNode};
10use style::shared_lock::{
11    SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard as StyleSharedRwLockReadGuard,
12};
13use style::stylist::Stylist;
14use style::values::AtomIdent;
15
16use crate::dom::bindings::root::LayoutDom;
17use crate::dom::document::Document;
18use crate::layout_dom::{ServoDangerousStyleElement, ServoDangerousStyleNode, ServoLayoutElement};
19
20/// A wrapper around documents that ensures layout can only ever access safe properties.
21///
22/// TODO: This should become a trait like `LayoutNode`.
23#[derive(Clone, Copy)]
24pub struct ServoDangerousStyleDocument<'dom> {
25    /// The wrapped private DOM Document
26    document: LayoutDom<'dom, Document>,
27}
28
29impl<'dom> From<LayoutDom<'dom, Document>> for ServoDangerousStyleDocument<'dom> {
30    fn from(document: LayoutDom<'dom, Document>) -> Self {
31        Self { document }
32    }
33}
34
35impl<'dom> ::style::dom::TDocument for ServoDangerousStyleDocument<'dom> {
36    type ConcreteNode = ServoDangerousStyleNode<'dom>;
37
38    fn as_node(&self) -> ServoDangerousStyleNode<'dom> {
39        self.document.upcast().into()
40    }
41
42    fn quirks_mode(&self) -> QuirksMode {
43        self.document.quirks_mode()
44    }
45
46    fn is_html_document(&self) -> bool {
47        self.document.is_html_document_for_layout()
48    }
49
50    fn shared_lock(&self) -> &StyleSharedRwLock {
51        self.document.style_shared_lock()
52    }
53
54    fn elements_with_id<'a>(
55        &self,
56        id: &AtomIdent,
57    ) -> Result<&'a [ServoDangerousStyleElement<'dom>], ()>
58    where
59        Self: 'a,
60    {
61        let elements_with_id = self.document.elements_with_id(&id.0);
62
63        // SAFETY: ServoDangerousStyleElement is known to have the same layout and alignment as
64        // LayoutDom<Element>.
65        #[expect(unsafe_code)]
66        let result = unsafe {
67            std::slice::from_raw_parts(
68                elements_with_id.as_ptr() as *const ServoDangerousStyleElement<'dom>,
69                elements_with_id.len(),
70            )
71        };
72        Ok(result)
73    }
74}
75
76impl<'dom> ServoDangerousStyleDocument<'dom> {
77    /// Get the root node for this [`ServoDangerousStyleDocument`].
78    pub fn root_element(&self) -> Option<ServoLayoutElement<'dom>> {
79        self.as_node()
80            .dom_children()
81            .flat_map(|n| n.as_element())
82            .next()
83            .map(|element| element.layout_element())
84    }
85
86    /// Get the shared style lock for styling with Stylo for this [`ServoDangerousStyleDocument`].
87    pub fn style_shared_lock(&self) -> &StyleSharedRwLock {
88        self.document.style_shared_lock()
89    }
90
91    /// Flush the the stylesheets of all descendant shadow roots.
92    pub fn flush_shadow_root_stylesheets_if_necessary(
93        &self,
94        stylist: &mut Stylist,
95        guard: &StyleSharedRwLockReadGuard,
96    ) {
97        self.document
98            .flush_shadow_root_stylesheets_if_necessary(stylist, guard);
99    }
100}