Skip to main content

style/rule_tree/
source.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(unsafe_code)]
6
7use crate::derives::*;
8use crate::properties::PropertyDeclarationBlock;
9use crate::shared_lock::{Locked, SharedRwLockReadGuard};
10use servo_arc::{Arc, ArcBorrow};
11use std::io::Write;
12use std::ptr;
13
14/// A style source for the rule node. It is a declaration block that may come from either a style
15/// rule or a standalone block like animations / transitions / smil / preshints / style attr...
16///
17/// Keeping the style rule around would provide more debugability, but also causes more
18/// pointer-chasing in the common code-path, which is undesired. If needed, we could keep it around
19/// in debug builds or something along those lines.
20#[derive(Clone, Debug)]
21pub struct StyleSource(Arc<Locked<PropertyDeclarationBlock>>);
22
23/// A borrowed version of `StyleSource`.
24///
25/// This is what we use during selector matching, so that we only need to touch the refcount of
26/// the declarations when we actually insert them in the rule tree.
27#[derive(Clone, Copy, Debug, MallocSizeOf)]
28pub struct StyleSourceBorrow<'a>(ArcBorrow<'a, Locked<PropertyDeclarationBlock>>);
29
30// The declaration block is measured as part of the stylesheet (or as part of whatever object owns
31// it, like the element for the style attribute).
32malloc_size_of::malloc_size_of_is_0!(StyleSource);
33
34impl PartialEq for StyleSource {
35    fn eq(&self, other: &Self) -> bool {
36        Arc::ptr_eq(&self.0, &other.0)
37    }
38}
39
40impl<'a> PartialEq for StyleSourceBorrow<'a> {
41    fn eq(&self, other: &Self) -> bool {
42        ArcBorrow::ptr_eq(&self.0, &other.0)
43    }
44}
45
46impl<'a> StyleSourceBorrow<'a> {
47    /// Creates a borrowed style source from a borrowed declaration block.
48    #[inline]
49    pub fn from_declarations(decls: ArcBorrow<'a, Locked<PropertyDeclarationBlock>>) -> Self {
50        Self(decls)
51    }
52
53    /// Creates an owned style source from this borrow, bumping the refcount.
54    #[inline]
55    pub fn to_owned(&self) -> StyleSource {
56        StyleSource(self.0.clone_arc())
57    }
58
59    #[inline]
60    pub(super) fn key(&self) -> ptr::NonNull<()> {
61        ptr::NonNull::from(self.0.get()).cast()
62    }
63
64    /// Read the style source guard, and obtain thus read access to the underlying property
65    /// declaration block.
66    #[inline]
67    pub fn read<'b>(&self, guard: &'b SharedRwLockReadGuard) -> &'b PropertyDeclarationBlock
68    where
69        'a: 'b,
70    {
71        self.0.get().read_with(guard)
72    }
73}
74
75impl StyleSource {
76    #[inline]
77    pub(super) fn key(&self) -> ptr::NonNull<()> {
78        ptr::NonNull::from(&*self.0).cast()
79    }
80
81    /// Borrows this style source.
82    #[inline]
83    pub fn borrow(&self) -> StyleSourceBorrow<'_> {
84        StyleSourceBorrow(self.0.borrow_arc())
85    }
86
87    /// Creates a StyleSource from a PropertyDeclarationBlock.
88    #[inline]
89    pub fn from_declarations(decls: Arc<Locked<PropertyDeclarationBlock>>) -> Self {
90        Self(decls)
91    }
92
93    pub(super) fn dump<W: Write>(&self, guard: &SharedRwLockReadGuard, writer: &mut W) {
94        let _ = write!(writer, "  -> {:?}", self.read(guard).declarations());
95    }
96
97    /// Read the style source guard, and obtain thus read access to the
98    /// underlying property declaration block.
99    #[inline]
100    pub fn read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a PropertyDeclarationBlock {
101        self.0.read_with(guard)
102    }
103
104    /// Returns the declaration block if applicable, otherwise None.
105    #[inline]
106    pub fn get(&self) -> &Arc<Locked<PropertyDeclarationBlock>> {
107        &self.0
108    }
109
110    /// Marks this block as part of the rule tree.
111    #[inline]
112    pub fn mark_in_rule_tree(&self) {
113        use std::sync::atomic::Ordering;
114        if self.0.is_static() {
115            // For static pointers, it doesn't matter whether we might be in the rule tree or not,
116            // because those are not mutable.
117            return;
118        }
119        // SAFETY: We're only accessing a relaxed atomic inside the locked object, which we know
120        // is alive. In theory, we could/should track that boolean outside of the
121        // Locked<PropertyDeclarationBlock>, but that is kind of a PITA.
122        #[allow(unsafe_code)]
123        unsafe {
124            // Load before storing: the flag is never cleared, so after the first mark every
125            // store is redundant, and an unconditional store would still take the cache line
126            // exclusive and invalidate it for every other thread reading this block.
127            let immutable = &self.0.read_unchecked().immutable;
128            if !immutable.load(Ordering::Relaxed) {
129                immutable.store(true, Ordering::Relaxed);
130            }
131        }
132    }
133}