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 }