style: Hook in the document invalidator.

Bug: 1409672
Reviewed-by: xidorn
MozReview-Commit-ID: EoSMrYPS7dl
This commit is contained in:
Emilio Cobos Álvarez 2018-01-16 15:14:39 +01:00
parent 75af7c0b41
commit 665690bba6
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
3 changed files with 69 additions and 16 deletions

View file

@ -30,20 +30,20 @@ impl Default for InvalidationMatchingData {
/// An invalidation processor for style changes due to state and attribute /// An invalidation processor for style changes due to state and attribute
/// changes. /// changes.
pub struct DocumentStateInvalidationProcessor<'a, E: TElement> { pub struct DocumentStateInvalidationProcessor<'a, E: TElement, I> {
// TODO(emilio): We might want to just run everything for every possible // TODO(emilio): We might want to just run everything for every possible
// binding along with the document data, or just apply the XBL stuff to the // binding along with the document data, or just apply the XBL stuff to the
// bound subtrees. // bound subtrees.
rules: &'a CascadeData, rules: I,
matching_context: MatchingContext<'a, E::Impl>, matching_context: MatchingContext<'a, E::Impl>,
document_states_changed: DocumentState, document_states_changed: DocumentState,
} }
impl<'a, E: TElement> DocumentStateInvalidationProcessor<'a, E> { impl<'a, E: TElement, I> DocumentStateInvalidationProcessor<'a, E, I> {
/// Creates a new DocumentStateInvalidationProcessor. /// Creates a new DocumentStateInvalidationProcessor.
#[inline] #[inline]
pub fn new( pub fn new(
rules: &'a CascadeData, rules: I,
document_states_changed: DocumentState, document_states_changed: DocumentState,
quirks_mode: QuirksMode, quirks_mode: QuirksMode,
) -> Self { ) -> Self {
@ -63,7 +63,11 @@ impl<'a, E: TElement> DocumentStateInvalidationProcessor<'a, E> {
} }
} }
impl<'a, E: TElement> InvalidationProcessor<'a, E> for DocumentStateInvalidationProcessor<'a, E> { impl<'a, E, I> InvalidationProcessor<'a, E> for DocumentStateInvalidationProcessor<'a, E, I>
where
E: TElement,
I: Iterator<Item = &'a CascadeData>,
{
fn collect_invalidations( fn collect_invalidations(
&mut self, &mut self,
_element: E, _element: E,
@ -71,8 +75,8 @@ impl<'a, E: TElement> InvalidationProcessor<'a, E> for DocumentStateInvalidation
_descendant_invalidations: &mut DescendantInvalidationLists<'a>, _descendant_invalidations: &mut DescendantInvalidationLists<'a>,
_sibling_invalidations: &mut InvalidationVector<'a>, _sibling_invalidations: &mut InvalidationVector<'a>,
) -> bool { ) -> bool {
let map = self.rules.invalidation_map(); for cascade_data in &mut self.rules {
let map = cascade_data.invalidation_map();
for dependency in &map.document_state_selectors { for dependency in &map.document_state_selectors {
if !dependency.state.intersects(self.document_states_changed) { if !dependency.state.intersects(self.document_states_changed) {
continue; continue;
@ -80,6 +84,7 @@ impl<'a, E: TElement> InvalidationProcessor<'a, E> for DocumentStateInvalidation
self_invalidations.push(Invalidation::new(&dependency.selector, 0)); self_invalidations.push(Invalidation::new(&dependency.selector, 0));
} }
}
false false
} }

View file

@ -534,6 +534,20 @@ where
let mut any_descendant = false; let mut any_descendant = false;
// NOTE(emilio): This should not be needed for Shadow DOM for normal
// element state / attribute invalidations (it's needed for XBL though,
// due to the weird way the anon content there works (it doesn't block
// combinators)).
//
// However, it's needed as of right now for document state invalidation,
// were we rely on iterating every element that ends up in the composed
// doc.
//
// Also, we could avoid having that special-case for document state
// invalidations if we invalidate for document state changes per
// subtree, though that's kind of annoying because we need to invalidate
// the shadow host subtree (to handle :host and ::slotted), and the
// actual shadow tree (to handle all other rules in the ShadowRoot).
if let Some(anon_content) = self.element.xbl_binding_anonymous_content() { if let Some(anon_content) = self.element.xbl_binding_anonymous_content() {
any_descendant |= any_descendant |=
self.invalidate_dom_descendants_of(anon_content, invalidations); self.invalidate_dom_descendants_of(anon_content, invalidations);

View file

@ -9,6 +9,7 @@ use malloc_size_of::MallocSizeOfOps;
use selectors::{Element, NthIndexCache}; use selectors::{Element, NthIndexCache};
use selectors::matching::{MatchingContext, MatchingMode, matches_selector}; use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
use servo_arc::{Arc, ArcBorrow, RawOffsetArc}; use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
use smallvec::SmallVec;
use std::cell::RefCell; use std::cell::RefCell;
use std::env; use std::env;
use std::fmt::Write; use std::fmt::Write;
@ -1774,7 +1775,6 @@ pub unsafe extern "C" fn Servo_SelectorList_QueryAll(
content_list: *mut structs::nsSimpleContentList, content_list: *mut structs::nsSimpleContentList,
may_use_invalidation: bool, may_use_invalidation: bool,
) { ) {
use smallvec::SmallVec;
use std::borrow::Borrow; use std::borrow::Borrow;
use style::dom_apis::{self, MayUseInvalidation, QueryAll}; use style::dom_apis::{self, MayUseInvalidation, QueryAll};
@ -2391,10 +2391,10 @@ pub extern "C" fn Servo_ComputedValues_EqualCustomProperties(
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(values: ServoStyleContextBorrowed, pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
rules: RawGeckoServoStyleRuleListBorrowedMut) { values: ServoStyleContextBorrowed,
use smallvec::SmallVec; rules: RawGeckoServoStyleRuleListBorrowedMut,
) {
let rule_node = match values.rules { let rule_node = match values.rules {
Some(ref r) => r, Some(ref r) => r,
None => return, None => return,
@ -4930,6 +4930,40 @@ pub extern "C" fn Servo_ParseCounterStyleName(
} }
} }
#[no_mangle]
pub unsafe extern "C" fn Servo_InvalidateStyleForDocStateChanges(
root: RawGeckoElementBorrowed,
raw_style_sets: *const nsTArray<RawServoStyleSetBorrowed>,
states_changed: u64,
) {
use style::invalidation::element::document_state::DocumentStateInvalidationProcessor;
use style::invalidation::element::invalidator::TreeStyleInvalidator;
let mut borrows = SmallVec::<[_; 20]>::with_capacity((*raw_style_sets).len());
for style_set in &**raw_style_sets {
borrows.push(PerDocumentStyleData::from_ffi(*style_set).borrow());
}
let root = GeckoElement(root);
let mut processor = DocumentStateInvalidationProcessor::new(
borrows.iter().flat_map(|b| b.stylist.iter_origins().map(|(data, _origin)| data)),
DocumentState::from_bits_truncate(states_changed),
root.as_node().owner_doc().quirks_mode(),
);
let result = TreeStyleInvalidator::new(
root,
/* stack_limit_checker = */ None,
&mut processor,
).invalidate();
debug_assert!(!result.has_invalidated_siblings(), "How in the world?");
if result.has_invalidated_descendants() {
bindings::Gecko_NoteDirtySubtreeForInvalidation(root.0);
} else if result.has_invalidated_self() {
bindings::Gecko_NoteDirtyElement(root.0);
}
}
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_ParseCounterStyleDescriptor( pub extern "C" fn Servo_ParseCounterStyleDescriptor(
descriptor: nsCSSCounterDesc, descriptor: nsCSSCounterDesc,