tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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>;