style: Split style sheet invalidations per-origin.

This commit is contained in:
Cameron McCormack 2017-08-12 15:34:38 +08:00
parent 321643ae61
commit f9d1a0e2d1

View file

@ -8,7 +8,7 @@ use dom::TElement;
use invalidation::stylesheets::StylesheetInvalidationSet; use invalidation::stylesheets::StylesheetInvalidationSet;
use shared_lock::SharedRwLockReadGuard; use shared_lock::SharedRwLockReadGuard;
use std::slice; use std::slice;
use stylesheets::StylesheetInDocument; use stylesheets::{PerOrigin, StylesheetInDocument};
use stylist::Stylist; use stylist::Stylist;
/// Entry for a StylesheetSet. We don't bother creating a constructor, because /// Entry for a StylesheetSet. We don't bother creating a constructor, because
@ -49,14 +49,11 @@ where
/// include recursive `@import` rules. /// include recursive `@import` rules.
entries: Vec<StylesheetSetEntry<S>>, entries: Vec<StylesheetSetEntry<S>>,
/// Whether the entries list above has changed since the last restyle. /// Per-origin stylesheet invalidation data.
dirty: bool, invalidation_data: PerOrigin<InvalidationData>,
/// Has author style been disabled? /// Has author style been disabled?
author_style_disabled: bool, author_style_disabled: bool,
/// The style invalidations that we still haven't processed.
invalidations: StylesheetInvalidationSet,
} }
impl<S> StylesheetSet<S> impl<S> StylesheetSet<S>
@ -67,9 +64,8 @@ where
pub fn new() -> Self { pub fn new() -> Self {
StylesheetSet { StylesheetSet {
entries: vec![], entries: vec![],
dirty: false, invalidation_data: Default::default(),
author_style_disabled: false, author_style_disabled: false,
invalidations: StylesheetInvalidationSet::new(),
} }
} }
@ -83,6 +79,18 @@ where
self.entries.retain(|entry| entry.sheet != *sheet); self.entries.retain(|entry| entry.sheet != *sheet);
} }
fn collect_invalidations_for(
&mut self,
stylist: &Stylist,
sheet: &S,
guard: &SharedRwLockReadGuard,
) {
let origin = sheet.contents(guard).origin;
let data = self.invalidation_data.borrow_mut_for_origin(&origin);
data.invalidations.collect_invalidations_for(stylist, sheet, guard);
data.dirty = true;
}
/// Appends a new stylesheet to the current set. /// Appends a new stylesheet to the current set.
pub fn append_stylesheet( pub fn append_stylesheet(
&mut self, &mut self,
@ -92,12 +100,7 @@ where
) { ) {
debug!("StylesheetSet::append_stylesheet"); debug!("StylesheetSet::append_stylesheet");
self.remove_stylesheet_if_present(&sheet); self.remove_stylesheet_if_present(&sheet);
self.invalidations.collect_invalidations_for( self.collect_invalidations_for(stylist, &sheet, guard);
stylist,
&sheet,
guard
);
self.dirty = true;
self.entries.push(StylesheetSetEntry { sheet }); self.entries.push(StylesheetSetEntry { sheet });
} }
@ -110,13 +113,8 @@ where
) { ) {
debug!("StylesheetSet::prepend_stylesheet"); debug!("StylesheetSet::prepend_stylesheet");
self.remove_stylesheet_if_present(&sheet); self.remove_stylesheet_if_present(&sheet);
self.invalidations.collect_invalidations_for( self.collect_invalidations_for(stylist, &sheet, guard);
stylist,
&sheet,
guard
);
self.entries.insert(0, StylesheetSetEntry { sheet }); self.entries.insert(0, StylesheetSetEntry { sheet });
self.dirty = true;
} }
/// Insert a given stylesheet before another stylesheet in the document. /// Insert a given stylesheet before another stylesheet in the document.
@ -132,13 +130,8 @@ where
let index = self.entries.iter().position(|entry| { let index = self.entries.iter().position(|entry| {
entry.sheet == before_sheet entry.sheet == before_sheet
}).expect("`before_sheet` stylesheet not found"); }).expect("`before_sheet` stylesheet not found");
self.invalidations.collect_invalidations_for( self.collect_invalidations_for(stylist, &sheet, guard);
stylist,
&sheet,
guard
);
self.entries.insert(index, StylesheetSetEntry { sheet }); self.entries.insert(index, StylesheetSetEntry { sheet });
self.dirty = true;
} }
/// Remove a given stylesheet from the set. /// Remove a given stylesheet from the set.
@ -150,12 +143,7 @@ where
) { ) {
debug!("StylesheetSet::remove_stylesheet"); debug!("StylesheetSet::remove_stylesheet");
self.remove_stylesheet_if_present(&sheet); self.remove_stylesheet_if_present(&sheet);
self.dirty = true; self.collect_invalidations_for(stylist, &sheet, guard);
self.invalidations.collect_invalidations_for(
stylist,
&sheet,
guard
);
} }
/// Notes that the author style has been disabled for this document. /// Notes that the author style has been disabled for this document.
@ -165,13 +153,15 @@ where
return; return;
} }
self.author_style_disabled = disabled; self.author_style_disabled = disabled;
self.dirty = true; self.invalidation_data.author.invalidations.invalidate_fully();
self.invalidations.invalidate_fully(); self.invalidation_data.author.dirty = true;
} }
/// Returns whether the given set has changed from the last flush. /// Returns whether the given set has changed from the last flush.
pub fn has_changed(&self) -> bool { pub fn has_changed(&self) -> bool {
self.dirty self.invalidation_data
.iter_origins()
.any(|(d, _)| d.dirty)
} }
/// Flush the current set, unmarking it as dirty, and returns an iterator /// Flush the current set, unmarking it as dirty, and returns an iterator
@ -184,10 +174,12 @@ where
E: TElement, E: TElement,
{ {
debug!("StylesheetSet::flush"); debug!("StylesheetSet::flush");
debug_assert!(self.dirty); debug_assert!(self.has_changed());
self.dirty = false; for data in self.invalidation_data.iter_mut_origins() {
self.invalidations.flush(document_element); data.0.invalidations.flush(document_element);
data.0.dirty = false;
}
self.iter() self.iter()
} }
@ -202,7 +194,28 @@ where
/// ///
/// FIXME(emilio): Make this more granular. /// FIXME(emilio): Make this more granular.
pub fn force_dirty(&mut self) { pub fn force_dirty(&mut self) {
self.dirty = true; for data in self.invalidation_data.iter_mut_origins() {
self.invalidations.invalidate_fully(); data.0.invalidations.invalidate_fully();
data.0.dirty = true;
}
}
}
struct InvalidationData {
/// The stylesheet invalidations for this origin that we still haven't
/// processed.
invalidations: StylesheetInvalidationSet,
/// Whether the sheets for this origin in the `StylesheetSet`'s entry list
/// has changed since the last restyle.
dirty: bool,
}
impl Default for InvalidationData {
fn default() -> Self {
InvalidationData {
invalidations: StylesheetInvalidationSet::new(),
dirty: false,
}
} }
} }