tor-browser

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

checks.rs (6241B)


      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 //! Different checks done during the style sharing process in order to determine
      6 //! quickly whether it's worth to share style, and whether two different
      7 //! elements can indeed share the same style.
      8 
      9 use crate::bloom::StyleBloom;
     10 use crate::context::SharedStyleContext;
     11 use crate::dom::TElement;
     12 use crate::sharing::{StyleSharingCandidate, StyleSharingTarget};
     13 use selectors::matching::SelectorCaches;
     14 
     15 /// Determines whether a target and a candidate have compatible parents for
     16 /// sharing.
     17 pub fn parents_allow_sharing<E>(
     18    target: &mut StyleSharingTarget<E>,
     19    candidate: &mut StyleSharingCandidate<E>,
     20 ) -> bool
     21 where
     22    E: TElement,
     23 {
     24    // If the identity of the parent style isn't equal, we can't share. We check
     25    // this first, because the result is cached.
     26    if target.parent_style_identity() != candidate.parent_style_identity() {
     27        return false;
     28    }
     29 
     30    // Siblings can always share.
     31    let parent = target.inheritance_parent().unwrap();
     32    let candidate_parent = candidate.element.inheritance_parent().unwrap();
     33    if parent == candidate_parent {
     34        return true;
     35    }
     36 
     37    // If a parent element was already styled and we traversed past it without
     38    // restyling it, that may be because our clever invalidation logic was able
     39    // to prove that the styles of that element would remain unchanged despite
     40    // changes to the id or class attributes. However, style sharing relies in
     41    // the strong guarantee that all the classes and ids up the respective parent
     42    // chains are identical. As such, if we skipped styling for one (or both) of
     43    // the parents on this traversal, we can't share styles across cousins.
     44    //
     45    // This is a somewhat conservative check. We could tighten it by having the
     46    // invalidation logic explicitly flag elements for which it ellided styling.
     47    let parent_data = parent.borrow_data().unwrap();
     48    let candidate_parent_data = candidate_parent.borrow_data().unwrap();
     49    if !parent_data.safe_for_cousin_sharing() || !candidate_parent_data.safe_for_cousin_sharing() {
     50        return false;
     51    }
     52 
     53    true
     54 }
     55 
     56 /// Whether two elements have the same style attribute.
     57 ///
     58 /// First checks pointer identity (fast path), then falls back to value comparison.
     59 pub fn have_same_style_attribute<E>(
     60    target: &mut StyleSharingTarget<E>,
     61    candidate: &mut StyleSharingCandidate<E>,
     62    shared_context: &SharedStyleContext,
     63 ) -> bool
     64 where
     65    E: TElement,
     66 {
     67    match (target.style_attribute(), candidate.style_attribute()) {
     68        (None, None) => true,
     69        (Some(_), None) | (None, Some(_)) => false,
     70        (Some(a), Some(b)) => {
     71            if std::ptr::eq(&*a, &*b) {
     72                return true;
     73            }
     74            let guard = shared_context.guards.author;
     75            *a.read_with(guard) == *b.read_with(guard)
     76        },
     77    }
     78 }
     79 
     80 /// Whether two elements have the same same presentational attributes.
     81 pub fn have_same_presentational_hints<E>(
     82    target: &mut StyleSharingTarget<E>,
     83    candidate: &mut StyleSharingCandidate<E>,
     84 ) -> bool
     85 where
     86    E: TElement,
     87 {
     88    target.pres_hints() == candidate.pres_hints()
     89 }
     90 
     91 /// Whether a given element has the same class attribute as a given candidate.
     92 ///
     93 /// We don't try to share style across elements with different class attributes.
     94 pub fn have_same_class<E>(
     95    target: &mut StyleSharingTarget<E>,
     96    candidate: &mut StyleSharingCandidate<E>,
     97 ) -> bool
     98 where
     99    E: TElement,
    100 {
    101    target.class_list() == candidate.class_list()
    102 }
    103 
    104 /// Whether a given element has the same part attribute as a given candidate.
    105 ///
    106 /// We don't try to share style across elements with different part attributes.
    107 pub fn have_same_parts<E>(
    108    target: &mut StyleSharingTarget<E>,
    109    candidate: &mut StyleSharingCandidate<E>,
    110 ) -> bool
    111 where
    112    E: TElement,
    113 {
    114    target.part_list() == candidate.part_list()
    115 }
    116 
    117 /// Whether a given element and a candidate match the same set of "revalidation"
    118 /// selectors.
    119 ///
    120 /// Revalidation selectors are those that depend on the DOM structure, like
    121 /// :first-child, etc, or on attributes that we don't check off-hand (pretty
    122 /// much every attribute selector except `id` and `class`.
    123 #[inline]
    124 pub fn revalidate<E>(
    125    target: &mut StyleSharingTarget<E>,
    126    candidate: &mut StyleSharingCandidate<E>,
    127    shared_context: &SharedStyleContext,
    128    bloom: &StyleBloom<E>,
    129    selector_caches: &mut SelectorCaches,
    130 ) -> bool
    131 where
    132    E: TElement,
    133 {
    134    let stylist = &shared_context.stylist;
    135 
    136    let for_element = target.revalidation_match_results(stylist, bloom, selector_caches);
    137 
    138    let for_candidate = candidate.revalidation_match_results(stylist, bloom, selector_caches);
    139 
    140    for_element == for_candidate
    141 }
    142 
    143 /// Whether a given element and a candidate share a set of scope activations
    144 /// for revalidation.
    145 #[inline]
    146 pub fn revalidate_scope<E>(
    147    target: &mut StyleSharingTarget<E>,
    148    candidate: &mut StyleSharingCandidate<E>,
    149    shared_context: &SharedStyleContext,
    150    selector_caches: &mut SelectorCaches,
    151 ) -> bool
    152 where
    153    E: TElement,
    154 {
    155    let stylist = &shared_context.stylist;
    156    let for_element = target.scope_revalidation_results(stylist, selector_caches);
    157    let for_candidate = candidate.scope_revalidation_results(stylist, selector_caches);
    158 
    159    for_element == for_candidate
    160 }
    161 
    162 /// Checks whether we might have rules for either of the two ids.
    163 #[inline]
    164 pub fn may_match_different_id_rules<E>(
    165    shared_context: &SharedStyleContext,
    166    element: E,
    167    candidate: E,
    168 ) -> bool
    169 where
    170    E: TElement,
    171 {
    172    let element_id = element.id();
    173    let candidate_id = candidate.id();
    174 
    175    if element_id == candidate_id {
    176        return false;
    177    }
    178 
    179    let stylist = &shared_context.stylist;
    180 
    181    let may_have_rules_for_element = match element_id {
    182        Some(id) => stylist.may_have_rules_for_id(id, element),
    183        None => false,
    184    };
    185 
    186    if may_have_rules_for_element {
    187        return true;
    188    }
    189 
    190    match candidate_id {
    191        Some(id) => stylist.may_have_rules_for_id(id, candidate),
    192        None => false,
    193    }
    194 }