Skip to main content

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