tor-browser

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

stylist.rs (7367B)


      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 use cssparser::SourceLocation;
      6 use euclid::Scale;
      7 use euclid::Size2D;
      8 use selectors::parser::{AncestorHashes, Selector};
      9 use servo_arc::Arc;
     10 use style::context::QuirksMode;
     11 use style::media_queries::{Device, MediaType};
     12 use style::properties::{longhands, Importance};
     13 use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
     14 use style::selector_map::SelectorMap;
     15 use style::selector_parser::{SelectorImpl, SelectorParser};
     16 use style::shared_lock::SharedRwLock;
     17 use style::stylesheets::StyleRule;
     18 use style::stylist::needs_revalidation_for_testing;
     19 use style::stylist::{Rule, Stylist};
     20 use style::thread_state::{self, ThreadState};
     21 use stylo_atoms::Atom;
     22 
     23 /// Helper method to get some Rules from selector strings.
     24 /// Each sublist of the result contains the Rules for one StyleRule.
     25 fn get_mock_rules(css_selectors: &[&str]) -> (Vec<Vec<Rule>>, SharedRwLock) {
     26    let shared_lock = SharedRwLock::new();
     27    (
     28        css_selectors
     29            .iter()
     30            .enumerate()
     31            .map(|(i, selectors)| {
     32                let selectors =
     33                    SelectorParser::parse_author_origin_no_namespace(selectors).unwrap();
     34 
     35                let locked = Arc::new(shared_lock.wrap(StyleRule {
     36                    selectors: selectors,
     37                    block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
     38                        PropertyDeclaration::Display(longhands::display::SpecifiedValue::Block),
     39                        Importance::Normal,
     40                    ))),
     41                    source_location: SourceLocation { line: 0, column: 0 },
     42                }));
     43 
     44                let guard = shared_lock.read();
     45                let rule = locked.read_with(&guard);
     46                rule.selectors
     47                    .0
     48                    .iter()
     49                    .map(|s| {
     50                        Rule::new(
     51                            s.clone(),
     52                            AncestorHashes::new(s, QuirksMode::NoQuirks),
     53                            locked.clone(),
     54                            i as u32,
     55                        )
     56                    })
     57                    .collect()
     58            })
     59            .collect(),
     60        shared_lock,
     61    )
     62 }
     63 
     64 fn parse_selectors(selectors: &[&str]) -> Vec<Selector<SelectorImpl>> {
     65    selectors
     66        .iter()
     67        .map(|x| {
     68            SelectorParser::parse_author_origin_no_namespace(x)
     69                .unwrap()
     70                .0
     71                .into_iter()
     72                .nth(0)
     73                .unwrap()
     74        })
     75        .collect()
     76 }
     77 
     78 #[test]
     79 fn test_revalidation_selectors() {
     80    let test = parse_selectors(&[
     81        // Not revalidation selectors.
     82        "div",
     83        "div:not(.foo)",
     84        "div span",
     85        "div > span",
     86        // ID selectors.
     87        "#foo1",
     88        "#foo2::before",
     89        "#foo3 > span",
     90        "#foo1 > span", // FIXME(bz): This one should not be a
     91        // revalidation selector, since #foo1 should be in the
     92        // rule hash.
     93 
     94        // Attribute selectors.
     95        "div[foo]",
     96        "div:not([foo])",
     97        "div[foo = \"bar\"]",
     98        "div[foo ~= \"bar\"]",
     99        "div[foo |= \"bar\"]",
    100        "div[foo ^= \"bar\"]",
    101        "div[foo $= \"bar\"]",
    102        "div[foo *= \"bar\"]",
    103        "*|div[foo][bar = \"baz\"]",
    104        // Non-state-based pseudo-classes.
    105        "div:empty",
    106        "div:first-child",
    107        "div:last-child",
    108        "div:only-child",
    109        "div:nth-child(2)",
    110        "div:nth-last-child(2)",
    111        "div:nth-of-type(2)",
    112        "div:nth-last-of-type(2)",
    113        "div:first-of-type",
    114        "div:last-of-type",
    115        "div:only-of-type",
    116        // Note: it would be nice to test :moz-any and the various other non-TS
    117        // pseudo classes supported by gecko, but we don't have access to those
    118        // in these unit tests. :-(
    119 
    120        // Sibling combinators.
    121        "span + div",
    122        "span ~ div",
    123        // Selectors in the ancestor chain (needed for cousin sharing).
    124        "p:first-child span",
    125    ])
    126    .into_iter()
    127    .filter(|s| needs_revalidation_for_testing(&s))
    128    .collect::<Vec<_>>();
    129 
    130    let reference = parse_selectors(&[
    131        // ID selectors.
    132        "#foo3 > span",
    133        "#foo1 > span",
    134        // Attribute selectors.
    135        "div[foo]",
    136        "div:not([foo])",
    137        "div[foo = \"bar\"]",
    138        "div[foo ~= \"bar\"]",
    139        "div[foo |= \"bar\"]",
    140        "div[foo ^= \"bar\"]",
    141        "div[foo $= \"bar\"]",
    142        "div[foo *= \"bar\"]",
    143        "*|div[foo][bar = \"baz\"]",
    144        // Non-state-based pseudo-classes.
    145        "div:empty",
    146        "div:first-child",
    147        "div:last-child",
    148        "div:only-child",
    149        "div:nth-child(2)",
    150        "div:nth-last-child(2)",
    151        "div:nth-of-type(2)",
    152        "div:nth-last-of-type(2)",
    153        "div:first-of-type",
    154        "div:last-of-type",
    155        "div:only-of-type",
    156        // Sibling combinators.
    157        "span + div",
    158        "span ~ div",
    159        // Selectors in the ancestor chain (needed for cousin sharing).
    160        "p:first-child span",
    161    ])
    162    .into_iter()
    163    .collect::<Vec<_>>();
    164 
    165    assert_eq!(test.len(), reference.len());
    166    for (t, r) in test.into_iter().zip(reference.into_iter()) {
    167        assert_eq!(t, r)
    168    }
    169 }
    170 
    171 #[test]
    172 fn test_rule_ordering_same_specificity() {
    173    let (rules_list, _) = get_mock_rules(&["a.intro", "img.sidebar"]);
    174    let a = &rules_list[0][0];
    175    let b = &rules_list[1][0];
    176    assert!(
    177        (a.specificity(), a.source_order) < ((b.specificity(), b.source_order)),
    178        "The rule that comes later should win."
    179    );
    180 }
    181 
    182 #[test]
    183 fn test_insert() {
    184    let (rules_list, _) = get_mock_rules(&[".intro.foo", "#top"]);
    185    let mut selector_map = SelectorMap::new();
    186    selector_map
    187        .insert(rules_list[1][0].clone(), QuirksMode::NoQuirks)
    188        .expect("OOM");
    189    assert_eq!(
    190        1,
    191        selector_map
    192            .id_hash
    193            .get(&Atom::from("top"), QuirksMode::NoQuirks)
    194            .unwrap()[0]
    195            .source_order
    196    );
    197    selector_map
    198        .insert(rules_list[0][0].clone(), QuirksMode::NoQuirks)
    199        .expect("OOM");
    200    assert_eq!(
    201        0,
    202        selector_map
    203            .class_hash
    204            .get(&Atom::from("foo"), QuirksMode::NoQuirks)
    205            .unwrap()[0]
    206            .source_order
    207    );
    208    assert!(selector_map
    209        .class_hash
    210        .get(&Atom::from("intro"), QuirksMode::NoQuirks)
    211        .is_none());
    212 }
    213 
    214 fn mock_stylist() -> Stylist {
    215    let device = Device::new(
    216        MediaType::screen(),
    217        Size2D::new(0f32, 0f32),
    218        Scale::new(1.0),
    219    );
    220    Stylist::new(device, QuirksMode::NoQuirks)
    221 }
    222 
    223 #[test]
    224 fn test_stylist_device_accessors() {
    225    thread_state::initialize(ThreadState::LAYOUT);
    226    let stylist = mock_stylist();
    227    assert_eq!(stylist.device().media_type(), MediaType::screen());
    228    let mut stylist_mut = mock_stylist();
    229    assert_eq!(stylist_mut.device_mut().media_type(), MediaType::screen());
    230 }
    231 
    232 #[test]
    233 fn test_stylist_rule_tree_accessors() {
    234    thread_state::initialize(ThreadState::LAYOUT);
    235    let stylist = mock_stylist();
    236    stylist.rule_tree();
    237    stylist.rule_tree().root();
    238 }