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}