relative_selector.rs (55526B)
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 //! Invalidation of element styles relative selectors. 6 7 use crate::data::ElementData; 8 use crate::dom::{TElement, TNode}; 9 #[cfg(feature = "gecko")] 10 use crate::gecko_bindings::structs::ServoElementSnapshotTable; 11 use crate::invalidation::element::element_wrapper::ElementWrapper; 12 use crate::invalidation::element::invalidation_map::{ 13 AdditionalRelativeSelectorInvalidationMap, Dependency, DependencyInvalidationKind, 14 InvalidationMap, NormalDependencyInvalidationKind, RelativeDependencyInvalidationKind, 15 ScopeDependencyInvalidationKind, TSStateForInvalidation, 16 }; 17 use crate::invalidation::element::invalidator::{ 18 note_scope_dependency_force_at_subject, DescendantInvalidationLists, Invalidation, 19 InvalidationProcessor, InvalidationResult, InvalidationVector, SiblingTraversalMap, 20 TreeStyleInvalidator, 21 }; 22 use crate::invalidation::element::restyle_hints::RestyleHint; 23 use crate::invalidation::element::state_and_attributes::{ 24 check_dependency, dependency_may_be_relevant, invalidated_descendants, invalidated_self, 25 invalidated_sibling, push_invalidation, should_process_descendants, 26 }; 27 #[cfg(feature = "servo")] 28 use crate::selector_parser::SnapshotMap as ServoElementSnapshotTable; 29 use crate::stylist::{CascadeData, Stylist}; 30 use dom::ElementState; 31 use rustc_hash::FxHashMap; 32 use selectors::matching::{ 33 early_reject_by_local_name, matches_selector, ElementSelectorFlags, 34 IncludeStartingStyle, MatchingContext, MatchingForInvalidation, MatchingMode, 35 NeedsSelectorFlags, QuirksMode, SelectorCaches, VisitedHandlingMode, 36 }; 37 use selectors::parser::SelectorKey; 38 use selectors::OpaqueElement; 39 use smallvec::{smallvec, SmallVec}; 40 use std::ops::DerefMut; 41 42 /// Kind of DOM mutation this relative selector invalidation is being carried out in. 43 #[derive(Clone, Copy)] 44 pub enum DomMutationOperation { 45 /// Insertion operation, can cause side effect, but presumed already happened. 46 Insert, 47 /// Append operation, cannot cause side effect. 48 Append, 49 /// Removal operation, can cause side effect, but presumed already happened. Sibling relationships are destroyed. 50 Remove, 51 /// Invalidating for side effect of a DOM operation, for the previous sibling. 52 SideEffectPrevSibling, 53 /// Invalidating for side effect of a DOM operation, for the next sibling. 54 SideEffectNextSibling, 55 } 56 57 impl DomMutationOperation { 58 fn accept<E: TElement>(&self, d: &Dependency, e: E) -> bool { 59 match self { 60 Self::Insert | Self::Append | Self::Remove => { 61 !e.relative_selector_search_direction().is_empty() 62 }, 63 // `:has(+ .a + .b)` with `.anchor + .a + .remove + .b` - `.a` would be present 64 // in the search path. 65 Self::SideEffectPrevSibling => { 66 !e.relative_selector_search_direction().is_empty() 67 && d.right_combinator_is_next_sibling() 68 }, 69 // If an element is being removed and would cause next-sibling match to happen, 70 // e.g. `:has(+ .a)` with `.anchor + .remove + .a`, `.a` isn't yet searched 71 // for relative selector matching. 72 Self::SideEffectNextSibling => d.dependency_is_relative_with_single_next_sibling(), 73 } 74 } 75 76 fn is_side_effect(&self) -> bool { 77 match self { 78 Self::Insert | Self::Append | Self::Remove => false, 79 Self::SideEffectPrevSibling | Self::SideEffectNextSibling => true, 80 } 81 } 82 } 83 84 /// Context required to try and optimize away relative dependencies. 85 struct OptimizationContext<'a, E: TElement> { 86 sibling_traversal_map: &'a SiblingTraversalMap<E>, 87 quirks_mode: QuirksMode, 88 operation: DomMutationOperation, 89 } 90 91 impl<'a, E: TElement> OptimizationContext<'a, E> { 92 fn can_be_ignored( 93 &self, 94 is_subtree: bool, 95 element: E, 96 host: Option<OpaqueElement>, 97 dependency: &Dependency, 98 leftmost_collapse_offset: usize, 99 ) -> bool { 100 if is_subtree { 101 // Subtree elements don't have unaffected sibling to look at. 102 return false; 103 } 104 debug_assert!( 105 matches!( 106 dependency.invalidation_kind(), 107 DependencyInvalidationKind::Relative(..) 108 ), 109 "Non-relative selector being evaluated for optimization" 110 ); 111 // This optimization predecates on the fact that there may be a sibling that can readily 112 // "take over" this element. 113 let sibling = match self.sibling_traversal_map.prev_sibling_for(&element) { 114 None => { 115 if matches!(self.operation, DomMutationOperation::Append) { 116 return false; 117 } 118 match self.sibling_traversal_map.next_sibling_for(&element) { 119 Some(s) => s, 120 None => return false, 121 } 122 }, 123 Some(s) => s, 124 }; 125 { 126 // Run through the affected compund. 127 let mut iter = dependency.selector.iter_from(dependency.selector_offset); 128 while let Some(c) = iter.next() { 129 if c.has_indexed_selector_in_subject() { 130 // We do not calculate indices during invalidation as they're wasteful - as a side effect, 131 // such selectors always return true, breaking this optimization. Note that we only check 132 // this compound only because the check to skip compares against this element's sibling. 133 // i.e. Given `:has(:nth-child(2) .foo)`, we'd try to find `.foo`'s sibling, which 134 // shares `:nth-child` up the selector. 135 return false; 136 } 137 } 138 } 139 let dependency_is_rightmost = dependency.selector_offset == 0; 140 if !dependency_is_rightmost { 141 let combinator = dependency 142 .selector 143 .combinator_at_match_order(dependency.selector_offset - 1); 144 if combinator.is_ancestor() { 145 // We can safely ignore these, since we're about to traverse the 146 // rest of the affected tree anyway to find the rightmost invalidated element. 147 return true; 148 } 149 if combinator.is_sibling() && matches!(self.operation, DomMutationOperation::Append) { 150 // If we're at the top of the DOM tree being mutated, we can ignore it if the 151 // operation is append - we know we'll cover all the later siblings and their descendants. 152 return true; 153 } 154 } 155 156 // We have a situation like `:has(.item .item + .item + .item)`, where the first element in the sibling 157 // chain position (i.e. The element matched by the second `.item` from the left) mutates. By the time we 158 // get here, we've collapsed the 4 dependencies for each of `.item` position into one at the rightmost 159 // position. Before we look for a standin, we need to find which `.item` this element matches - Doing 160 // that would generate more work than it saves. 161 if dependency_is_rightmost 162 && leftmost_collapse_offset != dependency.selector_offset 163 && self 164 .sibling_traversal_map 165 .next_sibling_for(&element) 166 .is_some() 167 { 168 return false; 169 } 170 171 let mut caches = SelectorCaches::default(); 172 let mut matching_context = MatchingContext::new( 173 MatchingMode::Normal, 174 None, 175 &mut caches, 176 self.quirks_mode, 177 NeedsSelectorFlags::No, 178 MatchingForInvalidation::Yes, 179 ); 180 matching_context.current_host = host; 181 let sibling_matches = matches_selector( 182 &dependency.selector, 183 dependency.selector_offset, 184 None, 185 &sibling, 186 &mut matching_context, 187 ); 188 if sibling_matches { 189 // Remember that at this point, we know that the combinator to the right of this 190 // compound is a sibling combinator. Effectively, we've found a standin for the 191 // element we're mutating. 192 // e.g. Given `:has(... .a ~ .b ...)`, we're the mutating element matching `... .a`, 193 // if we find a sibling that matches the `... .a`, it can stand in for us. 194 debug_assert!( 195 dependency.next.is_some(), 196 "No relative selector outer dependency?" 197 ); 198 return dependency.next.as_ref().map_or(false, |deps| { 199 // ... However, if the standin sibling can be the anchor, we can't skip it, since 200 // that sibling should be invlidated to become the anchor. 201 let next = &deps.as_ref().slice()[0]; 202 !matches_selector( 203 &next.selector, 204 next.selector_offset, 205 None, 206 &sibling, 207 &mut matching_context, 208 ) 209 }); 210 } 211 // Ok, there's no standin element - but would this element have matched the upstream 212 // selector anyway? If we don't, either the match exists somewhere far from us 213 // (In which case our mutation doesn't really matter), or it doesn't exist at all, 214 // so we can just skip the invalidation. 215 let (combinator, prev_offset) = { 216 let mut iter = dependency.selector.iter_from(dependency.selector_offset); 217 let mut o = dependency.selector_offset; 218 while iter.next().is_some() { 219 o += 1; 220 } 221 let combinator = iter.next_sequence(); 222 o += 1; 223 debug_assert!( 224 combinator.is_some(), 225 "Should at least see a relative combinator" 226 ); 227 (combinator.unwrap(), o) 228 }; 229 if combinator.is_sibling() && prev_offset >= dependency.selector.len() - 1 { 230 // Hit the relative combinator - we don't have enough information to 231 // see if there's going to be a downstream match. 232 return false; 233 } 234 !matches_selector( 235 &dependency.selector, 236 dependency.selector_offset, 237 None, 238 &element, 239 &mut matching_context, 240 ) 241 } 242 } 243 244 /// Overall invalidator for handling relative selector invalidations. 245 pub struct RelativeSelectorInvalidator<'a, 'b, E> 246 where 247 E: TElement + 'a, 248 { 249 /// Element triggering the invalidation. 250 pub element: E, 251 /// Quirks mode of the current invalidation. 252 pub quirks_mode: QuirksMode, 253 /// Snapshot containing changes to invalidate against. 254 /// Can be None if it's a DOM mutation. 255 pub snapshot_table: Option<&'b ServoElementSnapshotTable>, 256 /// Callback to trigger when the subject element is invalidated. 257 pub invalidated: fn(E, &InvalidationResult), 258 /// The traversal map that should be used to process invalidations. 259 pub sibling_traversal_map: SiblingTraversalMap<E>, 260 /// Marker for 'a lifetime. 261 pub _marker: ::std::marker::PhantomData<&'a ()>, 262 } 263 264 struct RelativeSelectorInvalidation<'a> { 265 host: Option<OpaqueElement>, 266 kind: RelativeDependencyInvalidationKind, 267 dependency: &'a Dependency, 268 } 269 270 type ElementDependencies<'a> = SmallVec<[(Option<OpaqueElement>, &'a Dependency); 1]>; 271 type Dependencies<'a, E> = SmallVec<[(E, ElementDependencies<'a>); 1]>; 272 type AlreadyInvalidated<'a, E> = SmallVec<[AlreadyInvalidatedEntry<'a, E>; 2]>; 273 274 struct AlreadyInvalidatedEntry<'a, E> 275 where 276 E: TElement + 'a, 277 { 278 /// Element where the invalidation will begin. 279 element: E, 280 /// The current shadow host. 281 host: Option<OpaqueElement>, 282 /// Dependency chain for this invalidation. 283 dependency: &'a Dependency, 284 /// The offset, of the leftmost dependencies that this 285 /// invalidation collapsed. See the `update()` function 286 /// for more information. 287 leftmost_collapse_offset: usize, 288 } 289 290 impl<'a, E> AlreadyInvalidatedEntry<'a, E> 291 where 292 E: TElement + 'a, 293 { 294 fn new(element: E, host: Option<OpaqueElement>, dependency: &'a Dependency) -> Self { 295 Self { 296 element, 297 host, 298 dependency, 299 leftmost_collapse_offset: dependency.selector_offset, 300 } 301 } 302 303 /// Update this invalidation with a new invalidation that may collapse with it. 304 fn update(&mut self, element: E, host: Option<OpaqueElement>, dependency: &'a Dependency) { 305 // This dependency should invalidate the same way - Collapse the invalidation 306 // to a more general case so we don't do duplicate work. 307 // e.g. For `:has(.item .item + .item + .item)`, since the anchor would be located 308 // in the ancestor chain for any invalidation triggered by any `.item` compound, 309 // 4 entries can collapse into one - but keep track of the leftmost offset. 310 if self.dependency.selector_offset > dependency.selector_offset { 311 *self = Self { 312 element, 313 host, 314 dependency, 315 leftmost_collapse_offset: self.leftmost_collapse_offset, 316 }; 317 } else if self.leftmost_collapse_offset < dependency.selector_offset { 318 self.leftmost_collapse_offset = dependency.selector_offset; 319 } 320 } 321 } 322 323 /// Interface for collecting relative selector dependencies. 324 pub struct RelativeSelectorDependencyCollector<'a, E> 325 where 326 E: TElement, 327 { 328 /// Dependencies that need to run through the normal invalidation that may generate 329 /// a relative selector invalidation. 330 dependencies: FxHashMap<E, ElementDependencies<'a>>, 331 /// Dependencies that created an invalidation right away. 332 invalidations: AlreadyInvalidated<'a, E>, 333 /// The top element in the subtree being invalidated. 334 top: E, 335 /// Optional context that will be used to try and skip invalidations 336 /// by running selector matches. 337 optimization_context: Option<OptimizationContext<'a, E>>, 338 } 339 340 type Invalidations<'a> = SmallVec<[RelativeSelectorInvalidation<'a>; 1]>; 341 type InnerInvalidations<'a, E> = SmallVec<[(E, RelativeSelectorInvalidation<'a>); 1]>; 342 343 struct ToInvalidate<'a, E: TElement + 'a> { 344 /// Dependencies to run through normal invalidator. 345 dependencies: Dependencies<'a, E>, 346 /// Dependencies already invalidated. 347 invalidations: Invalidations<'a>, 348 } 349 350 impl<'a, E: TElement + 'a> Default for ToInvalidate<'a, E> { 351 fn default() -> Self { 352 Self { 353 dependencies: Dependencies::default(), 354 invalidations: Invalidations::default(), 355 } 356 } 357 } 358 359 fn invalidation_can_collapse( 360 a: &Dependency, 361 b: &Dependency, 362 allow_indexed_selectors: bool, 363 ) -> bool { 364 // We want to detect identical dependencies that occur at different 365 // compounds but has the identical compound in the same selector, 366 // e.g. :has(.item .item). 367 368 // If they trigger different invalidations, they shouldn't be collapsed. 369 if a.relative_invalidation_kind() != b.relative_invalidation_kind() { 370 return false; 371 } 372 373 // Not in the same selector, trivially skipped. 374 if SelectorKey::new(&a.selector) != SelectorKey::new(&b.selector) { 375 return false; 376 } 377 378 // Check that this is in the same nesting. 379 // TODO(dshin): @scope probably brings more subtleties... 380 let mut a_next = a.next.as_ref(); 381 let mut b_next = b.next.as_ref(); 382 while let (Some(a_deps), Some(b_deps)) = (a_next, b_next) { 383 // This is a bit subtle - but we don't need to do the checks we do at higher levels. 384 // Cases like `:is(.item .foo) :is(.item .foo)` where `.item` invalidates would 385 // point to different dependencies, pointing to the same outer selector, but 386 // differing in selector offset. 387 let a_n = &a_deps.as_ref().slice()[0]; 388 let b_n = &b_deps.as_ref().slice()[0]; 389 if SelectorKey::new(&a_n.selector) != SelectorKey::new(&b_n.selector) { 390 return false; 391 } 392 a_next = a_n.next.as_ref(); 393 b_next = b_n.next.as_ref(); 394 } 395 if a_next.is_some() || b_next.is_some() { 396 return false; 397 } 398 399 // Ok, now, do the compounds actually match? 400 // This can get expensive quickly, but we're assuming that: 401 // 402 // * In most cases, authors don't generally duplicate compounds in a selector, so 403 // this fails quickly 404 // * In cases where compounds are duplicated, reducing the number of invalidations 405 // has a payoff that offsets the comparison cost 406 // 407 // Note, `.a.b` != `.b.a` - doesn't affect correctness, though. 408 // TODO(dshin): Caching this may be worth it as well? 409 let mut a_iter = a.selector.iter_from(a.selector_offset); 410 let mut b_iter = b.selector.iter_from(b.selector_offset); 411 loop { 412 let a_component = a_iter.next(); 413 let b_component = b_iter.next(); 414 415 if a_component != b_component { 416 return false; 417 } 418 let Some(component) = a_component else { 419 return true; 420 }; 421 if !allow_indexed_selectors && component.has_indexed_selector_in_subject() { 422 // The element's positioning matters, so can't collapse. 423 return false; 424 } 425 } 426 } 427 428 impl<'a, E> RelativeSelectorDependencyCollector<'a, E> 429 where 430 E: TElement, 431 { 432 fn new(top: E, optimization_context: Option<OptimizationContext<'a, E>>) -> Self { 433 Self { 434 dependencies: FxHashMap::default(), 435 invalidations: AlreadyInvalidated::default(), 436 top, 437 optimization_context, 438 } 439 } 440 441 fn insert_invalidation( 442 &mut self, 443 element: E, 444 dependency: &'a Dependency, 445 host: Option<OpaqueElement>, 446 ) { 447 let in_subtree = element != self.top; 448 if let Some(entry) = self.invalidations.iter_mut().find(|entry| { 449 // If we're in the subtree of DOM manipulation - worrying the about positioning of this element 450 // is irrelevant, because the DOM structure is either completely new or about to go away. 451 let both_in_subtree = in_subtree && entry.element != self.top; 452 // If we're considering the same element for invalidation, their evaluation of the indexed selector 453 // is identical by definition. 454 let same_element = element == entry.element; 455 invalidation_can_collapse( 456 dependency, 457 entry.dependency, 458 both_in_subtree || same_element, 459 ) 460 }) { 461 entry.update(element, host, dependency) 462 } else { 463 self.invalidations 464 .push(AlreadyInvalidatedEntry::new(element, host, dependency)); 465 } 466 } 467 468 /// Add this dependency, if it is unique (i.e. Different outer dependency or same outer dependency 469 /// but requires a different invalidation traversal). 470 pub fn add_dependency( 471 &mut self, 472 dependency: &'a Dependency, 473 element: E, 474 host: Option<OpaqueElement>, 475 ) { 476 match dependency.invalidation_kind() { 477 DependencyInvalidationKind::FullSelector => unreachable!(), 478 DependencyInvalidationKind::Normal(..) | DependencyInvalidationKind::Scope(..) => { 479 self.dependencies 480 .entry(element) 481 .and_modify(|v| v.push((host, dependency))) 482 .or_default() 483 .push((host, dependency)); 484 }, 485 DependencyInvalidationKind::Relative(kind) => { 486 debug_assert!( 487 dependency.next.is_some(), 488 "Orphaned inner relative selector?" 489 ); 490 if element != self.top 491 && matches!( 492 kind, 493 RelativeDependencyInvalidationKind::Parent 494 | RelativeDependencyInvalidationKind::PrevSibling 495 | RelativeDependencyInvalidationKind::EarlierSibling 496 ) 497 { 498 return; 499 } 500 if early_reject_by_local_name( 501 &dependency.selector, 502 dependency.selector_offset, 503 &element, 504 ) { 505 return; 506 } 507 self.insert_invalidation(element, dependency, host); 508 }, 509 }; 510 } 511 512 /// Get the dependencies in a list format. 513 fn get(self) -> ToInvalidate<'a, E> { 514 let mut result = ToInvalidate::default(); 515 for invalidation in self.invalidations { 516 match invalidation.dependency.invalidation_kind() { 517 DependencyInvalidationKind::FullSelector => unreachable!(), 518 DependencyInvalidationKind::Normal(_) | DependencyInvalidationKind::Scope(_) => { 519 unreachable!("Inner selector in invalidation?") 520 }, 521 DependencyInvalidationKind::Relative(kind) => { 522 if let Some(context) = self.optimization_context.as_ref() { 523 if context.can_be_ignored( 524 invalidation.element != self.top, 525 invalidation.element, 526 invalidation.host, 527 invalidation.dependency, 528 invalidation.leftmost_collapse_offset, 529 ) { 530 continue; 531 } 532 } 533 let dependency = &invalidation.dependency.next.as_ref().unwrap().slice()[0]; 534 result.invalidations.push(RelativeSelectorInvalidation { 535 kind, 536 host: invalidation.host, 537 dependency, 538 }); 539 // We move the invalidation up to the top of the subtree to avoid unnecessary traveral, but 540 // this means that we need to take ancestor-earlier sibling invalidations into account, as 541 // they'd look into earlier siblings of the top of the subtree as well. 542 if invalidation.element != self.top 543 && matches!( 544 kind, 545 RelativeDependencyInvalidationKind::AncestorEarlierSibling 546 | RelativeDependencyInvalidationKind::AncestorPrevSibling 547 ) 548 { 549 result.invalidations.push(RelativeSelectorInvalidation { 550 kind: if matches!( 551 kind, 552 RelativeDependencyInvalidationKind::AncestorPrevSibling 553 ) { 554 RelativeDependencyInvalidationKind::PrevSibling 555 } else { 556 RelativeDependencyInvalidationKind::EarlierSibling 557 }, 558 host: invalidation.host, 559 dependency, 560 }); 561 } 562 }, 563 }; 564 } 565 for (key, element_dependencies) in self.dependencies { 566 // At least for now, we don't try to optimize away dependencies emitted from nested selectors. 567 result.dependencies.push((key, element_dependencies)); 568 } 569 result 570 } 571 572 fn collect_all_dependencies_for_element( 573 &mut self, 574 element: E, 575 scope: Option<OpaqueElement>, 576 quirks_mode: QuirksMode, 577 map: &'a InvalidationMap, 578 additional_relative_selector_invalidation_map: &'a AdditionalRelativeSelectorInvalidationMap, 579 operation: DomMutationOperation, 580 ) { 581 element 582 .id() 583 .map(|v| match map.id_to_selector.get(v, quirks_mode) { 584 Some(v) => { 585 for dependency in v { 586 if !operation.accept(dependency, element) { 587 continue; 588 } 589 self.add_dependency(dependency, element, scope); 590 } 591 }, 592 None => (), 593 }); 594 element.each_class(|v| match map.class_to_selector.get(v, quirks_mode) { 595 Some(v) => { 596 for dependency in v { 597 if !operation.accept(dependency, element) { 598 continue; 599 } 600 self.add_dependency(dependency, element, scope); 601 } 602 }, 603 None => (), 604 }); 605 element.each_custom_state(|v| match map.custom_state_affecting_selectors.get(v) { 606 Some(v) => { 607 for dependency in v { 608 if !operation.accept(dependency, element) { 609 continue; 610 } 611 self.add_dependency(dependency, element, scope); 612 } 613 }, 614 None => (), 615 }); 616 element.each_attr_name(|v| match map.other_attribute_affecting_selectors.get(v) { 617 Some(v) => { 618 for dependency in v { 619 if !operation.accept(dependency, element) { 620 continue; 621 } 622 self.add_dependency(dependency, element, scope); 623 } 624 }, 625 None => (), 626 }); 627 let state = element.state(); 628 map.state_affecting_selectors.lookup_with_additional( 629 element, 630 quirks_mode, 631 None, 632 &[], 633 ElementState::empty(), 634 |dependency| { 635 if !dependency.state.intersects(state) { 636 return true; 637 } 638 if !operation.accept(&dependency.dep, element) { 639 return true; 640 } 641 self.add_dependency(&dependency.dep, element, scope); 642 true 643 }, 644 ); 645 646 additional_relative_selector_invalidation_map 647 .ts_state_to_selector 648 .lookup_with_additional( 649 element, 650 quirks_mode, 651 None, 652 &[], 653 ElementState::empty(), 654 |dependency| { 655 if !operation.accept(&dependency.dep, element) { 656 return true; 657 } 658 // This section contain potential optimization for not running full invalidation - 659 // consult documentation in `TSStateForInvalidation`. 660 if dependency.state.may_be_optimized() { 661 if operation.is_side_effect() { 662 // Side effect operations act on element not being mutated, so they can't 663 // change the match outcome of these optimizable pseudoclasses. 664 return true; 665 } 666 debug_assert!( 667 self.optimization_context.is_some(), 668 "Optimization context not available for DOM mutation?" 669 ); 670 if dependency.state.contains(TSStateForInvalidation::EMPTY) 671 && element.first_element_child().is_some() 672 { 673 return true; 674 } 675 676 let sibling_traversal_map = self 677 .optimization_context 678 .as_ref() 679 .unwrap() 680 .sibling_traversal_map; 681 if dependency 682 .state 683 .contains(TSStateForInvalidation::NTH_EDGE_FIRST) 684 && sibling_traversal_map.prev_sibling_for(&element).is_some() 685 { 686 return true; 687 } 688 689 if dependency 690 .state 691 .contains(TSStateForInvalidation::NTH_EDGE_LAST) 692 && sibling_traversal_map.next_sibling_for(&element).is_some() 693 { 694 return true; 695 } 696 } 697 self.add_dependency(&dependency.dep, element, scope); 698 true 699 }, 700 ); 701 702 if let Some(v) = additional_relative_selector_invalidation_map 703 .type_to_selector 704 .get(element.local_name()) 705 { 706 for dependency in v { 707 if !operation.accept(dependency, element) { 708 continue; 709 } 710 self.add_dependency(dependency, element, scope); 711 } 712 } 713 714 for dependency in &additional_relative_selector_invalidation_map.any_to_selector { 715 if !operation.accept(dependency, element) { 716 continue; 717 } 718 self.add_dependency(dependency, element, scope); 719 } 720 } 721 722 fn is_empty(&self) -> bool { 723 self.invalidations.is_empty() && self.dependencies.is_empty() 724 } 725 } 726 727 impl<'a, 'b, E> RelativeSelectorInvalidator<'a, 'b, E> 728 where 729 E: TElement + 'a, 730 { 731 /// Gather relative selector dependencies for the given element, and invalidate as necessary. 732 #[inline(never)] 733 pub fn invalidate_relative_selectors_for_this<F>( 734 self, 735 stylist: &'a Stylist, 736 mut gather_dependencies: F, 737 ) where 738 F: FnMut( 739 &E, 740 Option<OpaqueElement>, 741 &'a CascadeData, 742 QuirksMode, 743 &mut RelativeSelectorDependencyCollector<'a, E>, 744 ), 745 { 746 let mut collector = RelativeSelectorDependencyCollector::new(self.element, None); 747 stylist.for_each_cascade_data_with_scope(self.element, |data, scope| { 748 let map = data.relative_invalidation_map_attributes(); 749 if !map.used { 750 return; 751 } 752 gather_dependencies( 753 &self.element, 754 scope.map(|e| e.opaque()), 755 data, 756 self.quirks_mode, 757 &mut collector, 758 ); 759 }); 760 if collector.is_empty() { 761 return; 762 } 763 self.invalidate_from_dependencies(collector.get()); 764 } 765 766 /// Gather relative selector dependencies for the given element (And its subtree) that mutated, and invalidate as necessary. 767 #[inline(never)] 768 pub fn invalidate_relative_selectors_for_dom_mutation( 769 self, 770 subtree: bool, 771 stylist: &'a Stylist, 772 inherited_search_path: ElementSelectorFlags, 773 operation: DomMutationOperation, 774 ) { 775 let mut collector = RelativeSelectorDependencyCollector::new( 776 self.element, 777 if operation.is_side_effect() { 778 None 779 } else { 780 Some(OptimizationContext { 781 sibling_traversal_map: &self.sibling_traversal_map, 782 quirks_mode: self.quirks_mode, 783 operation, 784 }) 785 }, 786 ); 787 let mut traverse_subtree = false; 788 self.element.apply_selector_flags(inherited_search_path); 789 stylist.for_each_cascade_data_with_scope(self.element, |data, scope| { 790 let map_attributes = data.relative_invalidation_map_attributes(); 791 if !map_attributes.used { 792 return; 793 } 794 let map = data.relative_selector_invalidation_map(); 795 traverse_subtree |= map_attributes.needs_ancestors_traversal; 796 collector.collect_all_dependencies_for_element( 797 self.element, 798 scope.map(|e| e.opaque()), 799 self.quirks_mode, 800 map, 801 map_attributes, 802 operation, 803 ); 804 }); 805 806 if subtree && traverse_subtree { 807 for node in self.element.as_node().dom_descendants() { 808 let descendant = match node.as_element() { 809 Some(e) => e, 810 None => continue, 811 }; 812 descendant.apply_selector_flags(inherited_search_path); 813 stylist.for_each_cascade_data_with_scope(descendant, |data, scope| { 814 let map_attributes = data.relative_invalidation_map_attributes(); 815 if !map_attributes.used { 816 return; 817 } 818 let map = data.relative_selector_invalidation_map(); 819 collector.collect_all_dependencies_for_element( 820 descendant, 821 scope.map(|e| e.opaque()), 822 self.quirks_mode, 823 map, 824 map_attributes, 825 operation, 826 ); 827 }); 828 } 829 } 830 if collector.is_empty() { 831 return; 832 } 833 self.invalidate_from_dependencies(collector.get()); 834 } 835 836 /// Carry out complete invalidation triggered by a relative selector invalidation. 837 fn invalidate_from_dependencies(&self, to_invalidate: ToInvalidate<'a, E>) { 838 for (element, dependencies) in to_invalidate.dependencies { 839 let mut selector_caches = SelectorCaches::default(); 840 let mut processor = RelativeSelectorInnerInvalidationProcessor::new( 841 self.quirks_mode, 842 self.snapshot_table, 843 &dependencies, 844 &mut selector_caches, 845 &self.sibling_traversal_map, 846 ); 847 TreeStyleInvalidator::new(element, None, &mut processor).invalidate(); 848 for (element, invalidation) in processor.take_invalidations() { 849 self.invalidate_upwards(element, &invalidation); 850 } 851 } 852 for invalidation in to_invalidate.invalidations { 853 self.invalidate_upwards(self.element, &invalidation); 854 } 855 } 856 857 fn invalidate_upwards(&self, element: E, invalidation: &RelativeSelectorInvalidation<'a>) { 858 // This contains the main reason for why relative selector invalidation is handled 859 // separately - It travels ancestor and/or earlier sibling direction. 860 match invalidation.kind { 861 RelativeDependencyInvalidationKind::Parent => { 862 element.parent_element().map(|e| { 863 if !Self::in_search_direction( 864 &e, 865 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR, 866 ) { 867 return; 868 } 869 self.handle_anchor(e, invalidation.dependency, invalidation.host); 870 }); 871 }, 872 RelativeDependencyInvalidationKind::Ancestors => { 873 let mut parent = element.parent_element(); 874 while let Some(par) = parent { 875 if !Self::in_search_direction( 876 &par, 877 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR, 878 ) { 879 return; 880 } 881 self.handle_anchor(par, invalidation.dependency, invalidation.host); 882 parent = par.parent_element(); 883 } 884 }, 885 RelativeDependencyInvalidationKind::PrevSibling => { 886 self.sibling_traversal_map 887 .prev_sibling_for(&element) 888 .map(|e| { 889 if !Self::in_search_direction( 890 &e, 891 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING, 892 ) { 893 return; 894 } 895 self.handle_anchor(e, invalidation.dependency, invalidation.host); 896 }); 897 }, 898 RelativeDependencyInvalidationKind::AncestorPrevSibling => { 899 let mut parent = element.parent_element(); 900 while let Some(par) = parent { 901 if !Self::in_search_direction( 902 &par, 903 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR, 904 ) { 905 return; 906 } 907 par.prev_sibling_element().map(|e| { 908 if !Self::in_search_direction( 909 &e, 910 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING, 911 ) { 912 return; 913 } 914 self.handle_anchor(e, invalidation.dependency, invalidation.host); 915 }); 916 parent = par.parent_element(); 917 } 918 }, 919 RelativeDependencyInvalidationKind::EarlierSibling => { 920 let mut sibling = self.sibling_traversal_map.prev_sibling_for(&element); 921 while let Some(sib) = sibling { 922 if !Self::in_search_direction( 923 &sib, 924 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING, 925 ) { 926 return; 927 } 928 self.handle_anchor(sib, invalidation.dependency, invalidation.host); 929 sibling = sib.prev_sibling_element(); 930 } 931 }, 932 RelativeDependencyInvalidationKind::AncestorEarlierSibling => { 933 let mut parent = element.parent_element(); 934 while let Some(par) = parent { 935 if !Self::in_search_direction( 936 &par, 937 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR, 938 ) { 939 return; 940 } 941 let mut sibling = par.prev_sibling_element(); 942 while let Some(sib) = sibling { 943 if !Self::in_search_direction( 944 &sib, 945 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING, 946 ) { 947 return; 948 } 949 self.handle_anchor(sib, invalidation.dependency, invalidation.host); 950 sibling = sib.prev_sibling_element(); 951 } 952 parent = par.parent_element(); 953 } 954 }, 955 } 956 } 957 958 /// Is this element in the direction of the given relative selector search path? 959 fn in_search_direction(element: &E, desired: ElementSelectorFlags) -> bool { 960 element 961 .relative_selector_search_direction() 962 .intersects(desired) 963 } 964 965 /// Handle a potential relative selector anchor. 966 fn handle_anchor( 967 &self, 968 element: E, 969 outer_dependency: &Dependency, 970 host: Option<OpaqueElement>, 971 ) { 972 let is_rightmost = Self::is_subject(outer_dependency); 973 if (is_rightmost 974 && !element.has_selector_flags(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR)) 975 || (!is_rightmost 976 && !element.has_selector_flags( 977 ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT, 978 )) 979 { 980 // If it was never a relative selector anchor, don't bother. 981 return; 982 } 983 let mut selector_caches = SelectorCaches::default(); 984 let matching_context = MatchingContext::<'_, E::Impl>::new_for_visited( 985 MatchingMode::Normal, 986 None, 987 &mut selector_caches, 988 VisitedHandlingMode::AllLinksVisitedAndUnvisited, 989 IncludeStartingStyle::No, 990 self.quirks_mode, 991 NeedsSelectorFlags::No, 992 MatchingForInvalidation::Yes, 993 ); 994 let mut data = match element.mutate_data() { 995 Some(data) => data, 996 None => return, 997 }; 998 let mut processor = RelativeSelectorOuterInvalidationProcessor { 999 element, 1000 host, 1001 data: data.deref_mut(), 1002 dependency: &*outer_dependency, 1003 matching_context, 1004 traversal_map: &self.sibling_traversal_map, 1005 }; 1006 let result = TreeStyleInvalidator::new(element, None, &mut processor).invalidate(); 1007 (self.invalidated)(element, &result); 1008 } 1009 1010 /// Does this relative selector dependency have its relative selector in the subject position? 1011 fn is_subject(outer_dependency: &Dependency) -> bool { 1012 debug_assert!( 1013 matches!( 1014 outer_dependency.invalidation_kind(), 1015 DependencyInvalidationKind::Normal(_) | DependencyInvalidationKind::Scope(_) 1016 ), 1017 "Outer selector of relative selector is relative?" 1018 ); 1019 1020 if let Some(x) = outer_dependency.next.as_ref() { 1021 // We only care to ensure that we're the subject in the outermost selector of the current 1022 // selector - Crossing over a scope invalidation would mean moving into a selector inside 1023 // the current scope block 1024 if matches!( 1025 outer_dependency.invalidation_kind(), 1026 DependencyInvalidationKind::Normal(..) 1027 ) { 1028 if !Self::is_subject(&x.as_ref().slice()[0]) { 1029 // Not subject in outer selector. 1030 return false; 1031 } 1032 } 1033 } 1034 outer_dependency 1035 .selector 1036 .is_rightmost(outer_dependency.selector_offset) 1037 } 1038 } 1039 1040 /// Blindly invalidate everything outside of a relative selector. 1041 /// Consider `:is(.a :has(.b) .c ~ .d) ~ .e .f`, where .b gets deleted. 1042 /// Since the tree mutated, we cannot rely on snapshots. 1043 pub struct RelativeSelectorOuterInvalidationProcessor<'a, 'b, E: TElement> { 1044 /// Element being invalidated. 1045 pub element: E, 1046 /// The current shadow host, if any. 1047 pub host: Option<OpaqueElement>, 1048 /// Data for the element being invalidated. 1049 pub data: &'a mut ElementData, 1050 /// Dependency to be processed. 1051 pub dependency: &'b Dependency, 1052 /// Matching context to use for invalidation. 1053 pub matching_context: MatchingContext<'a, E::Impl>, 1054 /// Traversal map for this invalidation. 1055 pub traversal_map: &'a SiblingTraversalMap<E>, 1056 } 1057 1058 impl<'a, 'b: 'a, E: 'a> InvalidationProcessor<'b, 'a, E> 1059 for RelativeSelectorOuterInvalidationProcessor<'a, 'b, E> 1060 where 1061 E: TElement, 1062 { 1063 fn invalidates_on_pseudo_element(&self) -> bool { 1064 true 1065 } 1066 1067 fn check_outer_dependency( 1068 &mut self, 1069 _dependency: &Dependency, 1070 _element: E, 1071 _: Option<OpaqueElement>, 1072 ) -> bool { 1073 // At this point, we know a relative selector invalidated, and are ignoring them. 1074 true 1075 } 1076 1077 fn matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl> { 1078 &mut self.matching_context 1079 } 1080 1081 fn sibling_traversal_map(&self) -> &SiblingTraversalMap<E> { 1082 self.traversal_map 1083 } 1084 1085 fn collect_invalidations( 1086 &mut self, 1087 element: E, 1088 _self_invalidations: &mut InvalidationVector<'b>, 1089 descendant_invalidations: &mut DescendantInvalidationLists<'b>, 1090 sibling_invalidations: &mut InvalidationVector<'b>, 1091 ) -> bool { 1092 debug_assert_eq!(element, self.element); 1093 debug_assert!( 1094 self.matching_context.matching_for_invalidation(), 1095 "Not matching for invalidation?" 1096 ); 1097 1098 // Ok, this element can potentially an anchor to the given dependency. 1099 // Before we do the potentially-costly ancestor/earlier sibling traversal, 1100 // See if it can actuall be an anchor by trying to match the "rest" of the selector 1101 // outside and to the left of `:has` in question. 1102 // e.g. Element under consideration can only be the anchor to `:has` in 1103 // `.foo .bar ~ .baz:has()`, iff it matches `.foo .bar ~ .baz`. 1104 let invalidated_self = { 1105 let mut invalidated = false; 1106 let mut dependencies_to_invalidate: SmallVec<[&Dependency; 1]> = 1107 smallvec![self.dependency]; 1108 while let Some(d) = dependencies_to_invalidate.pop() { 1109 debug_assert!( 1110 matches!( 1111 d.invalidation_kind(), 1112 DependencyInvalidationKind::Normal(_) 1113 | DependencyInvalidationKind::Scope(_) 1114 ), 1115 "Unexpected dependency kind" 1116 ); 1117 if !dependency_may_be_relevant(d, &element, false) { 1118 continue; 1119 } 1120 if !matches_selector( 1121 &d.selector, 1122 d.selector_offset, 1123 None, 1124 &element, 1125 self.matching_context(), 1126 ) { 1127 continue; 1128 } 1129 1130 let invalidation_kind = d.invalidation_kind(); 1131 1132 if let DependencyInvalidationKind::Scope(scope_kind) = invalidation_kind { 1133 if d.selector.is_rightmost(d.selector_offset) { 1134 if scope_kind == ScopeDependencyInvalidationKind::ScopeEnd { 1135 let invalidations = note_scope_dependency_force_at_subject( 1136 d, 1137 self.matching_context.current_host.clone(), 1138 self.matching_context.scope_element, 1139 false, 1140 ); 1141 descendant_invalidations 1142 .dom_descendants 1143 .extend(invalidations); 1144 1145 invalidated |= true; 1146 } else if let Some(ref next) = d.next { 1147 dependencies_to_invalidate.extend(next.as_ref().slice()); 1148 } 1149 continue; 1150 } 1151 } 1152 1153 if matches!( 1154 invalidation_kind, 1155 DependencyInvalidationKind::Normal(NormalDependencyInvalidationKind::Element) 1156 ) { 1157 if let Some(ref deps) = d.next { 1158 // Normal dependencies should only have one next 1159 dependencies_to_invalidate.push(&deps.as_ref().slice()[0]); 1160 continue; 1161 } 1162 invalidated |= true; 1163 continue; 1164 } 1165 debug_assert_ne!(d.selector_offset, 0); 1166 debug_assert_ne!(d.selector_offset, d.selector.len()); 1167 let invalidation = Invalidation::new(&d, self.host, None); 1168 invalidated |= push_invalidation( 1169 invalidation, 1170 d.invalidation_kind(), 1171 descendant_invalidations, 1172 sibling_invalidations, 1173 ); 1174 } 1175 invalidated 1176 }; 1177 1178 if invalidated_self { 1179 self.data.hint.insert(RestyleHint::RESTYLE_SELF); 1180 } 1181 invalidated_self 1182 } 1183 1184 fn should_process_descendants(&mut self, element: E) -> bool { 1185 if element == self.element { 1186 return should_process_descendants(&self.data); 1187 } 1188 1189 match element.borrow_data() { 1190 Some(d) => should_process_descendants(&d), 1191 None => return false, 1192 } 1193 } 1194 1195 fn recursion_limit_exceeded(&mut self, _element: E) { 1196 unreachable!("Unexpected recursion limit"); 1197 } 1198 1199 fn invalidated_descendants(&mut self, element: E, child: E) { 1200 invalidated_descendants(element, child) 1201 } 1202 1203 fn invalidated_self(&mut self, element: E) { 1204 debug_assert_ne!(element, self.element); 1205 invalidated_self(element); 1206 } 1207 1208 fn invalidated_sibling(&mut self, element: E, of: E) { 1209 debug_assert_ne!(element, self.element); 1210 invalidated_sibling(element, of); 1211 } 1212 } 1213 1214 /// Invalidation for the selector(s) inside a relative selector. 1215 pub struct RelativeSelectorInnerInvalidationProcessor<'a, 'b, 'c, E> 1216 where 1217 E: TElement + 'a, 1218 { 1219 /// Matching context to be used. 1220 matching_context: MatchingContext<'b, E::Impl>, 1221 /// Table of snapshots. 1222 snapshot_table: Option<&'c ServoElementSnapshotTable>, 1223 /// Incoming dependencies to be processed. 1224 dependencies: &'c ElementDependencies<'a>, 1225 /// Generated invalidations. 1226 invalidations: InnerInvalidations<'a, E>, 1227 /// Traversal map for this invalidation. 1228 traversal_map: &'b SiblingTraversalMap<E>, 1229 } 1230 1231 impl<'a, 'b, 'c, E> RelativeSelectorInnerInvalidationProcessor<'a, 'b, 'c, E> 1232 where 1233 E: TElement + 'a, 1234 { 1235 fn new( 1236 quirks_mode: QuirksMode, 1237 snapshot_table: Option<&'c ServoElementSnapshotTable>, 1238 dependencies: &'c ElementDependencies<'a>, 1239 selector_caches: &'b mut SelectorCaches, 1240 traversal_map: &'b SiblingTraversalMap<E>, 1241 ) -> Self { 1242 let matching_context = MatchingContext::new_for_visited( 1243 MatchingMode::Normal, 1244 None, 1245 selector_caches, 1246 VisitedHandlingMode::AllLinksVisitedAndUnvisited, 1247 IncludeStartingStyle::No, 1248 quirks_mode, 1249 NeedsSelectorFlags::No, 1250 MatchingForInvalidation::Yes, 1251 ); 1252 Self { 1253 matching_context, 1254 snapshot_table, 1255 dependencies, 1256 invalidations: InnerInvalidations::default(), 1257 traversal_map, 1258 } 1259 } 1260 1261 fn note_dependency( 1262 &mut self, 1263 element: E, 1264 host: Option<OpaqueElement>, 1265 dependency: &'a Dependency, 1266 descendant_invalidations: &mut DescendantInvalidationLists<'a>, 1267 sibling_invalidations: &mut InvalidationVector<'a>, 1268 ) { 1269 match dependency.invalidation_kind() { 1270 DependencyInvalidationKind::FullSelector => unreachable!(), 1271 DependencyInvalidationKind::Normal(_) | DependencyInvalidationKind::Scope(_) => (), 1272 DependencyInvalidationKind::Relative(kind) => { 1273 self.found_relative_selector_invalidation(element, kind, dependency); 1274 return; 1275 }, 1276 } 1277 if matches!( 1278 dependency.normal_invalidation_kind(), 1279 NormalDependencyInvalidationKind::Element 1280 ) { 1281 // Ok, keep heading outwards. 1282 debug_assert!( 1283 dependency.next.is_some(), 1284 "Orphaned inner selector dependency?" 1285 ); 1286 if let Some(next) = dependency.next.as_ref() { 1287 self.note_dependency( 1288 element, 1289 host, 1290 &next.as_ref().slice()[0], 1291 descendant_invalidations, 1292 sibling_invalidations, 1293 ); 1294 } 1295 return; 1296 } 1297 let invalidation = Invalidation::new(&dependency, None, None); 1298 match dependency.normal_invalidation_kind() { 1299 NormalDependencyInvalidationKind::Descendants => { 1300 // Descendant invalidations are simplified due to pseudo-elements not being available within the relative selector. 1301 descendant_invalidations.dom_descendants.push(invalidation) 1302 }, 1303 NormalDependencyInvalidationKind::Siblings => sibling_invalidations.push(invalidation), 1304 // Note(dshin, bug 1940212): Nesting can enabling stuffing pseudo-elements into :has, like `::marker { :has(&) }`. 1305 // Ideally, we can just not insert the dependency into the invalidation map, but the necessary selector information 1306 // for this (i.e. `HAS_PSEUDO`) is filtered out in `replace_parent_selector` through 1307 // `SelectorFlags::forbidden_for_nesting`, so just ignoring such dependencies here is the best we can do. 1308 _ => (), 1309 } 1310 } 1311 1312 /// Take the generated invalidations. 1313 fn take_invalidations(self) -> InnerInvalidations<'a, E> { 1314 self.invalidations 1315 } 1316 } 1317 1318 impl<'a, 'b, 'c, E> InvalidationProcessor<'a, 'b, E> 1319 for RelativeSelectorInnerInvalidationProcessor<'a, 'b, 'c, E> 1320 where 1321 E: TElement + 'a, 1322 { 1323 fn check_outer_dependency( 1324 &mut self, 1325 dependency: &Dependency, 1326 element: E, 1327 _: Option<OpaqueElement>, 1328 ) -> bool { 1329 if let Some(snapshot_table) = self.snapshot_table { 1330 let wrapper = ElementWrapper::new(element, snapshot_table); 1331 return check_dependency( 1332 dependency, 1333 &element, 1334 &wrapper, 1335 &mut self.matching_context, 1336 None, 1337 ); 1338 } 1339 // Just invalidate if we don't have a snapshot. 1340 true 1341 } 1342 1343 fn matching_context(&mut self) -> &mut MatchingContext<'b, E::Impl> { 1344 return &mut self.matching_context; 1345 } 1346 1347 fn collect_invalidations( 1348 &mut self, 1349 element: E, 1350 _self_invalidations: &mut InvalidationVector<'a>, 1351 descendant_invalidations: &mut DescendantInvalidationLists<'a>, 1352 sibling_invalidations: &mut InvalidationVector<'a>, 1353 ) -> bool { 1354 for (scope, dependency) in self.dependencies { 1355 self.note_dependency( 1356 element, 1357 *scope, 1358 dependency, 1359 descendant_invalidations, 1360 sibling_invalidations, 1361 ) 1362 } 1363 false 1364 } 1365 1366 fn should_process_descendants(&mut self, _element: E) -> bool { 1367 true 1368 } 1369 1370 fn recursion_limit_exceeded(&mut self, _element: E) { 1371 unreachable!("Unexpected recursion limit"); 1372 } 1373 1374 // Don't do anything for normal invalidations. 1375 fn invalidated_self(&mut self, _element: E) {} 1376 fn invalidated_sibling(&mut self, _sibling: E, _of: E) {} 1377 fn invalidated_descendants(&mut self, _element: E, _child: E) {} 1378 1379 fn found_relative_selector_invalidation( 1380 &mut self, 1381 element: E, 1382 kind: RelativeDependencyInvalidationKind, 1383 dep: &'a Dependency, 1384 ) { 1385 debug_assert!(dep.next.is_some(), "Orphaned inners selector?"); 1386 if element.relative_selector_search_direction().is_empty() { 1387 return; 1388 } 1389 self.invalidations.push(( 1390 element, 1391 RelativeSelectorInvalidation { 1392 host: self.matching_context.current_host, 1393 kind, 1394 dependency: &dep.next.as_ref().unwrap().as_ref().slice()[0], 1395 }, 1396 )); 1397 } 1398 1399 fn sibling_traversal_map(&self) -> &SiblingTraversalMap<E> { 1400 &self.traversal_map 1401 } 1402 }