data.rs (7622B)
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 //! Data needed to style a Gecko document. 6 7 use crate::derives::*; 8 use crate::gecko_bindings::bindings; 9 use crate::gecko_bindings::structs::{ 10 self, ServoStyleSetSizes, StyleSheet as DomStyleSheet, StyleSheetInfo, 11 }; 12 use crate::invalidation::stylesheets::StylesheetInvalidationSet; 13 use crate::media_queries::{Device, MediaList}; 14 use crate::properties::ComputedValues; 15 use crate::shared_lock::{SharedRwLockReadGuard, StylesheetGuards}; 16 use crate::stylesheets::scope_rule::ImplicitScopeRoot; 17 use crate::stylesheets::{StylesheetContents, StylesheetInDocument}; 18 use crate::stylist::Stylist; 19 use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; 20 use malloc_size_of::MallocSizeOfOps; 21 use selectors::Element; 22 use servo_arc::Arc; 23 use std::fmt; 24 25 use super::wrapper::GeckoElement; 26 27 /// Little wrapper to a Gecko style sheet. 28 #[derive(Eq, PartialEq)] 29 pub struct GeckoStyleSheet(*const DomStyleSheet); 30 31 // NOTE(emilio): These are kind of a lie. We allow to make these Send + Sync so that other data 32 // structures can also be Send and Sync, but Gecko's stylesheets are main-thread-reference-counted. 33 // 34 // We assert that we reference-count in the right thread (in the Addref/Release implementations). 35 // Sending these to a different thread can't really happen (it could theoretically really happen if 36 // we allowed @import rules inside a nested style rule, but that can't happen per spec and would be 37 // a parser bug, caught by the asserts). 38 unsafe impl Send for GeckoStyleSheet {} 39 unsafe impl Sync for GeckoStyleSheet {} 40 41 impl fmt::Debug for GeckoStyleSheet { 42 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 43 let contents = self.raw_contents(); 44 formatter 45 .debug_struct("GeckoStyleSheet") 46 .field("origin", &contents.origin) 47 .field("url_data", &contents.url_data) 48 .finish() 49 } 50 } 51 52 impl GeckoStyleSheet { 53 /// Create a `GeckoStyleSheet` from a raw `DomStyleSheet` pointer. 54 #[inline] 55 pub unsafe fn new(s: *const DomStyleSheet) -> Self { 56 debug_assert!(!s.is_null()); 57 bindings::Gecko_StyleSheet_AddRef(s); 58 Self::from_addrefed(s) 59 } 60 61 /// Create a `GeckoStyleSheet` from a raw `DomStyleSheet` pointer that 62 /// already holds a strong reference. 63 #[inline] 64 pub unsafe fn from_addrefed(s: *const DomStyleSheet) -> Self { 65 assert!(!s.is_null()); 66 GeckoStyleSheet(s) 67 } 68 69 /// HACK(emilio): This is so that we can avoid crashing release due to 70 /// bug 1719963 and can hopefully get a useful report from fuzzers. 71 #[inline] 72 pub fn hack_is_null(&self) -> bool { 73 self.0.is_null() 74 } 75 76 /// Get the raw `StyleSheet` that we're wrapping. 77 pub fn raw(&self) -> &DomStyleSheet { 78 unsafe { &*self.0 } 79 } 80 81 fn inner(&self) -> &StyleSheetInfo { 82 unsafe { &*(self.raw().mInner as *const StyleSheetInfo) } 83 } 84 85 fn raw_contents(&self) -> &StylesheetContents { 86 debug_assert!(!self.inner().mContents.mRawPtr.is_null()); 87 unsafe { &*self.inner().mContents.mRawPtr } 88 } 89 } 90 91 impl Drop for GeckoStyleSheet { 92 fn drop(&mut self) { 93 unsafe { bindings::Gecko_StyleSheet_Release(self.0) }; 94 } 95 } 96 97 impl Clone for GeckoStyleSheet { 98 fn clone(&self) -> Self { 99 unsafe { bindings::Gecko_StyleSheet_AddRef(self.0) }; 100 GeckoStyleSheet(self.0) 101 } 102 } 103 104 impl StylesheetInDocument for GeckoStyleSheet { 105 fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { 106 use crate::gecko_bindings::structs::mozilla::dom::MediaList as DomMediaList; 107 unsafe { 108 let dom_media_list = self.raw().mMedia.mRawPtr as *const DomMediaList; 109 if dom_media_list.is_null() { 110 return None; 111 } 112 let list = &*(*dom_media_list).mRawList.mRawPtr; 113 Some(list.read_with(guard)) 114 } 115 } 116 117 // All the stylesheets Servo knows about are enabled, because that state is 118 // handled externally by Gecko. 119 #[inline] 120 fn enabled(&self) -> bool { 121 true 122 } 123 124 #[inline] 125 fn contents<'a>(&'a self, _: &'a SharedRwLockReadGuard) -> &'a StylesheetContents { 126 self.raw_contents() 127 } 128 129 fn implicit_scope_root(&self) -> Option<ImplicitScopeRoot> { 130 unsafe { 131 let result = bindings::Gecko_StyleSheet_ImplicitScopeRoot(self.0); 132 if result.mRoot.is_null() { 133 return if result.mConstructed { 134 Some(ImplicitScopeRoot::Constructed) 135 } else { 136 // Could be genuinely not attached, like user stylesheet. 137 None 138 }; 139 } 140 141 let root = GeckoElement(result.mRoot.as_ref().unwrap()).opaque(); 142 Some(if !result.mHost.is_null() { 143 let host = GeckoElement(result.mHost.as_ref().unwrap()).opaque(); 144 if host == root { 145 ImplicitScopeRoot::ShadowHost(root) 146 } else { 147 ImplicitScopeRoot::InShadowTree(root) 148 } 149 } else { 150 ImplicitScopeRoot::InLightTree(root) 151 }) 152 } 153 } 154 } 155 156 /// The container for data that a Servo-backed Gecko document needs to style 157 /// itself. 158 pub struct PerDocumentStyleDataImpl { 159 /// Rule processor. 160 pub stylist: Stylist, 161 162 /// A cache from element to resolved style. 163 pub undisplayed_style_cache: crate::traversal::UndisplayedStyleCache, 164 165 /// The generation for which our cache is valid. 166 pub undisplayed_style_cache_generation: u64, 167 } 168 169 /// The data itself is an `AtomicRefCell`, which guarantees the proper semantics 170 /// and unexpected races while trying to mutate it. 171 #[derive(Deref)] 172 pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>); 173 174 impl PerDocumentStyleData { 175 /// Create a `PerDocumentStyleData`. 176 pub fn new(document: *const structs::Document) -> Self { 177 let device = Device::new(document); 178 let quirks_mode = device.document().mCompatMode; 179 180 PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl { 181 stylist: Stylist::new(device, quirks_mode.into()), 182 undisplayed_style_cache: Default::default(), 183 undisplayed_style_cache_generation: 0, 184 })) 185 } 186 187 /// Get an immutable reference to this style data. 188 pub fn borrow(&self) -> AtomicRef<'_, PerDocumentStyleDataImpl> { 189 self.0.borrow() 190 } 191 192 /// Get an mutable reference to this style data. 193 pub fn borrow_mut(&self) -> AtomicRefMut<'_, PerDocumentStyleDataImpl> { 194 self.0.borrow_mut() 195 } 196 } 197 198 impl PerDocumentStyleDataImpl { 199 /// Recreate the style data if the stylesheets have changed. 200 pub fn flush_stylesheets( 201 &mut self, 202 guard: &SharedRwLockReadGuard, 203 ) -> StylesheetInvalidationSet { 204 self.stylist.flush(&StylesheetGuards::same(guard)) 205 } 206 207 /// Get the default computed values for this document. 208 pub fn default_computed_values(&self) -> &Arc<ComputedValues> { 209 self.stylist.device().default_computed_values_arc() 210 } 211 212 /// Measure heap usage. 213 pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) { 214 self.stylist.add_size_of(ops, sizes); 215 } 216 } 217 218 /// The gecko-specific AuthorStyles instantiation. 219 pub type AuthorStyles = crate::author_styles::AuthorStyles<GeckoStyleSheet>;