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