Skip to main content

apace_dom/node/
stylo_data.rs

1use std::fmt;
2use std::ops::Deref;
3use std::{cell::UnsafeCell, ops::DerefMut};
4use style::data::{ElementDataMut, ElementDataRef, ElementDataWrapper};
5use style::servo_arc::Arc;
6
7use crate::layout::damage::ALL_DAMAGE;
8
9/// Interior-mutable wrapper around `Option<ElementDataWrapper>`.
10///
11/// Encapsulates the `UnsafeCell` so that access sites don't need raw `unsafe` blocks.
12///
13/// Safety relies on:
14///   - Regular static-borrow checking for regular access, and on:
15///   - Stylo having exclusive access to nodes during style traversals
16///   - Stylo's thread-safe traversal model: `init`/`clear` only happen during exclusive-access phases
17pub struct StyloData {
18    inner: UnsafeCell<Option<ElementDataWrapper>>,
19}
20
21impl Default for StyloData {
22    fn default() -> Self {
23        Self {
24            inner: UnsafeCell::new(None),
25        }
26    }
27}
28
29impl fmt::Debug for StyloData {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        f.debug_struct("StyloData").finish_non_exhaustive()
32    }
33}
34
35impl Deref for StyloData {
36    type Target = Option<ElementDataWrapper>;
37    fn deref(&self) -> &Self::Target {
38        unsafe { &*self.inner.get() }
39    }
40}
41
42impl DerefMut for StyloData {
43    fn deref_mut(&mut self) -> &mut Self::Target {
44        self.inner.get_mut()
45    }
46}
47
48impl StyloData {
49    /// Whether element data has been initialized.
50    pub fn has_data(&self) -> bool {
51        unsafe { &*self.inner.get() }.is_some()
52    }
53
54    /// Borrow the element data immutably, if present.
55    pub fn get(&self) -> Option<ElementDataRef<'_>> {
56        self.as_ref().map(|w| w.borrow())
57    }
58
59    /// Borrow the element data mutably, if present.
60    pub fn get_mut(&mut self) -> Option<ElementDataMut<'_>> {
61        self.as_mut().map(|w| w.borrow_mut())
62    }
63
64    /// Initialize the element data ready for use (if it is not already initialized)
65    pub fn ensure_init_mut(&mut self) -> ElementDataMut<'_> {
66        // SAFETY:
67        // If we have exclusive access to self (implied by &mut self) then it safe to mutate self.
68        unsafe { self.ensure_init() }
69    }
70
71    pub fn primary_styles(&self) -> Option<StyleDataRef<'_>> {
72        let stylo_element_data = self.get();
73        if stylo_element_data
74            .as_ref()
75            .and_then(|d| d.styles.get_primary())
76            .is_some()
77        {
78            Some(StyleDataRef(self.get().unwrap()))
79        } else {
80            None
81        }
82    }
83
84    /// Borrow the primary computed style directly (rather than the `Arc` containing it).
85    pub fn computed_styles(&self) -> Option<ComputedStyleRef<'_>> {
86        self.primary_styles().map(ComputedStyleRef)
87    }
88
89    /// Get a mutable reference to the data
90    pub unsafe fn unsafe_stylo_only_mut(&self) -> Option<ElementDataMut<'_>> {
91        let opt = unsafe { &mut *self.inner.get() };
92        opt.as_mut().map(|w| w.borrow_mut())
93    }
94
95    /// Initialize the element data ready for use (if it is not already initialized)
96    ///
97    /// SAFETY:
98    /// There must be no outstanding borrows to this container or anything contained within it
99    /// when this method is called
100    pub unsafe fn ensure_init(&self) -> ElementDataMut<'_> {
101        if !self.has_data() {
102            unsafe { *self.inner.get() = Some(ElementDataWrapper::default()) };
103            let mut data_mut = unsafe { self.unsafe_stylo_only_mut() }.unwrap();
104            data_mut.damage = ALL_DAMAGE;
105            data_mut
106        } else {
107            unsafe { self.unsafe_stylo_only_mut() }.unwrap()
108        }
109    }
110
111    /// Clear the element data, returning to the uninitialized state.
112    ///
113    /// SAFETY:
114    /// There must be no outstanding borrows to this container or anything contained within it
115    /// when this method is called
116    pub unsafe fn clear(&self) {
117        unsafe { *self.inner.get() = None };
118    }
119}
120
121pub struct StyleDataRef<'a>(ElementDataRef<'a>);
122
123impl Deref for StyleDataRef<'_> {
124    type Target = Arc<style::properties::ComputedValues>;
125
126    fn deref(&self) -> &Self::Target {
127        self.0.styles.get_primary().unwrap()
128    }
129}
130
131/// Borrow of a node's stylo element data that `Deref`s directly to the primary
132/// [`ComputedValues`](style::properties::ComputedValues), suitable for wrapping
133/// in [`stylo_takia::TakiaStyloStyle`].
134pub struct ComputedStyleRef<'a>(StyleDataRef<'a>);
135
136impl Deref for ComputedStyleRef<'_> {
137    type Target = style::properties::ComputedValues;
138
139    fn deref(&self) -> &Self::Target {
140        self.0.0.styles.get_primary().unwrap()
141    }
142}