tor-browser

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

snapshot.rs (6327B)


      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 //! A gecko snapshot, that stores the element attributes and state before they
      6 //! change in order to properly calculate restyle hints.
      7 
      8 use crate::dom::TElement;
      9 use crate::gecko::snapshot_helpers;
     10 use crate::gecko::wrapper::GeckoElement;
     11 use crate::gecko_bindings::bindings;
     12 use crate::gecko_bindings::structs::ServoElementSnapshot;
     13 use crate::gecko_bindings::structs::ServoElementSnapshotFlags as Flags;
     14 use crate::gecko_bindings::structs::ServoElementSnapshotTable;
     15 use crate::invalidation::element::element_wrapper::ElementSnapshot;
     16 use crate::selector_parser::AttrValue;
     17 use crate::string_cache::{Atom, Namespace};
     18 use crate::values::{AtomIdent, AtomString};
     19 use crate::LocalName;
     20 use crate::WeakAtom;
     21 use dom::ElementState;
     22 use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
     23 
     24 /// A snapshot of a Gecko element.
     25 pub type GeckoElementSnapshot = ServoElementSnapshot;
     26 
     27 /// A map from elements to snapshots for Gecko's style back-end.
     28 pub type SnapshotMap = ServoElementSnapshotTable;
     29 
     30 impl SnapshotMap {
     31    /// Gets the snapshot for this element, if any.
     32    ///
     33    /// FIXME(emilio): The transmute() business we do here is kind of nasty, but
     34    /// it's a consequence of the map being a OpaqueNode -> Snapshot table in
     35    /// Servo and an Element -> Snapshot table in Gecko.
     36    ///
     37    /// We should be able to make this a more type-safe with type annotations by
     38    /// making SnapshotMap a trait and moving the implementations outside, but
     39    /// that's a pain because it implies parameterizing SharedStyleContext.
     40    pub fn get<E: TElement>(&self, element: &E) -> Option<&GeckoElementSnapshot> {
     41        debug_assert!(element.has_snapshot());
     42 
     43        unsafe {
     44            let element = ::std::mem::transmute::<&E, &GeckoElement>(element);
     45            bindings::Gecko_GetElementSnapshot(self, element.0).as_ref()
     46        }
     47    }
     48 }
     49 
     50 impl GeckoElementSnapshot {
     51    #[inline]
     52    fn has_any(&self, flags: Flags) -> bool {
     53        (self.mContains as u8 & flags as u8) != 0
     54    }
     55 
     56    /// Returns true if the snapshot has stored state for pseudo-classes
     57    /// that depend on things other than `ElementState`.
     58    #[inline]
     59    pub fn has_other_pseudo_class_state(&self) -> bool {
     60        self.has_any(Flags::OtherPseudoClassState)
     61    }
     62 
     63    /// Returns true if the snapshot recorded an id change.
     64    #[inline]
     65    pub fn id_changed(&self) -> bool {
     66        self.mIdAttributeChanged()
     67    }
     68 
     69    /// Returns true if the snapshot recorded a class attribute change.
     70    #[inline]
     71    pub fn class_changed(&self) -> bool {
     72        self.mClassAttributeChanged()
     73    }
     74 
     75    /// Executes the callback once for each attribute that changed.
     76    #[inline]
     77    pub fn each_attr_changed<F>(&self, mut callback: F)
     78    where
     79        F: FnMut(&AtomIdent),
     80    {
     81        for attr in self.mChangedAttrNames.iter() {
     82            unsafe { AtomIdent::with(attr.mRawPtr, &mut callback) }
     83        }
     84    }
     85 
     86    /// selectors::Element::attr_matches
     87    pub fn attr_matches(
     88        &self,
     89        ns: &NamespaceConstraint<&Namespace>,
     90        local_name: &LocalName,
     91        operation: &AttrSelectorOperation<&AttrValue>,
     92    ) -> bool {
     93        snapshot_helpers::attr_matches(&self.mAttrs, ns, local_name, operation)
     94    }
     95 }
     96 
     97 impl ElementSnapshot for GeckoElementSnapshot {
     98    fn debug_list_attributes(&self) -> String {
     99        use nsstring::nsCString;
    100        let mut string = nsCString::new();
    101        unsafe {
    102            bindings::Gecko_Snapshot_DebugListAttributes(self, &mut string);
    103        }
    104        String::from_utf8_lossy(&*string).into_owned()
    105    }
    106 
    107    fn state(&self) -> Option<ElementState> {
    108        if self.has_any(Flags::State) {
    109            Some(ElementState::from_bits_retain(self.mState))
    110        } else {
    111            None
    112        }
    113    }
    114 
    115    #[inline]
    116    fn has_attrs(&self) -> bool {
    117        self.has_any(Flags::Attributes)
    118    }
    119 
    120    #[inline]
    121    fn id_attr(&self) -> Option<&WeakAtom> {
    122        if !self.has_any(Flags::Id) {
    123            return None;
    124        }
    125 
    126        snapshot_helpers::get_id(&*self.mAttrs)
    127    }
    128 
    129    #[inline]
    130    fn is_part(&self, name: &AtomIdent) -> bool {
    131        let attr = match snapshot_helpers::find_attr(&*self.mAttrs, &atom!("part")) {
    132            Some(attr) => attr,
    133            None => return false,
    134        };
    135 
    136        snapshot_helpers::has_class_or_part(name, CaseSensitivity::CaseSensitive, attr)
    137    }
    138 
    139    #[inline]
    140    fn imported_part(&self, name: &AtomIdent) -> Option<AtomIdent> {
    141        snapshot_helpers::imported_part(&*self.mAttrs, name)
    142    }
    143 
    144    #[inline]
    145    fn has_class(&self, name: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
    146        if !self.has_any(Flags::MaybeClass) {
    147            return false;
    148        }
    149 
    150        snapshot_helpers::has_class_or_part(name, case_sensitivity, &self.mClass)
    151    }
    152 
    153    #[inline]
    154    fn each_class<F>(&self, callback: F)
    155    where
    156        F: FnMut(&AtomIdent),
    157    {
    158        if !self.has_any(Flags::MaybeClass) {
    159            return;
    160        }
    161 
    162        snapshot_helpers::each_class_or_part(&self.mClass, callback)
    163    }
    164 
    165    #[inline]
    166    fn lang_attr(&self) -> Option<AtomString> {
    167        let ptr = unsafe { bindings::Gecko_SnapshotLangValue(self) };
    168        if ptr.is_null() {
    169            None
    170        } else {
    171            Some(AtomString(unsafe { Atom::from_addrefed(ptr) }))
    172        }
    173    }
    174 
    175    /// Returns true if the snapshot has stored state for custom states
    176    #[inline]
    177    fn has_custom_states(&self) -> bool {
    178        self.has_any(Flags::CustomState)
    179    }
    180 
    181    /// Returns true if the snapshot has a given CustomState
    182    #[inline]
    183    fn has_custom_state(&self, state: &AtomIdent) -> bool {
    184        unsafe {
    185            self.mCustomStates
    186                .iter()
    187                .any(|setstate| AtomIdent::with(setstate.mRawPtr, |setstate| state == setstate))
    188        }
    189    }
    190 
    191    #[inline]
    192    fn each_custom_state<F>(&self, mut callback: F)
    193    where
    194        F: FnMut(&AtomIdent),
    195    {
    196        unsafe {
    197            for atom in self.mCustomStates.iter() {
    198                AtomIdent::with(atom.mRawPtr, &mut callback)
    199            }
    200        }
    201    }
    202 }