From 39e836966edf5d9f38ac39224ef32f1601163cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 24 May 2017 02:31:59 +0200 Subject: [PATCH] Bug 1357583: style: Hook up the invalidator in the StyleSheetSet. r=heycam MozReview-Commit-ID: IhgKAovTJMX --- components/style/gecko/data.rs | 13 ++++- components/style/gecko_string_cache/mod.rs | 6 +- components/style/invalidation/mod.rs | 23 +++++++- components/style/stylesheet_set.rs | 64 +++++++++++++++++++--- ports/geckolib/glue.rs | 33 +++++++++-- 5 files changed, 117 insertions(+), 22 deletions(-) diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index 88c94a2870f..e67ee47b03a 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -6,8 +6,10 @@ use Atom; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; +use dom::TElement; use fnv::FnvHashMap; use gecko::rules::{CounterStyleRule, FontFaceRule}; +use gecko::wrapper::GeckoElement; use gecko_bindings::bindings::RawServoStyleSet; use gecko_bindings::structs::RawGeckoPresContextOwned; use gecko_bindings::structs::nsIDocument; @@ -74,11 +76,15 @@ impl PerDocumentStyleDataImpl { pub fn reset_device(&mut self, guard: &SharedRwLockReadGuard) { Arc::get_mut(self.stylist.device_mut()).unwrap().reset(); self.stylesheets.force_dirty(); - self.flush_stylesheets(guard); + self.flush_stylesheets::(guard, None); } /// Recreate the style data if the stylesheets have changed. - pub fn flush_stylesheets(&mut self, guard: &SharedRwLockReadGuard) { + pub fn flush_stylesheets(&mut self, + guard: &SharedRwLockReadGuard, + document_element: Option) + where E: TElement, + { if !self.stylesheets.has_changed() { return; } @@ -90,7 +96,8 @@ impl PerDocumentStyleDataImpl { let author_style_disabled = self.stylesheets.author_style_disabled(); self.stylist.clear(); - self.stylist.rebuild(self.stylesheets.flush(), + let iter = self.stylesheets.flush(document_element); + self.stylist.rebuild(iter, &StylesheetGuards::same(guard), /* ua_sheets = */ None, /* stylesheets_changed = */ true, diff --git a/components/style/gecko_string_cache/mod.rs b/components/style/gecko_string_cache/mod.rs index 4973428f1e8..436c9e988f2 100644 --- a/components/style/gecko_string_cache/mod.rs +++ b/components/style/gecko_string_cache/mod.rs @@ -34,9 +34,9 @@ pub mod namespace; pub use self::namespace::{Namespace, WeakNamespace}; -macro_rules! local_name { - ($s: tt) => { atom!($s) } -} +// macro_rules! local_name { +// ($s: tt) => { atom!($s) } +// } /// A strong reference to a Gecko atom. #[derive(PartialEq, Eq)] diff --git a/components/style/invalidation/mod.rs b/components/style/invalidation/mod.rs index 34d7ff559d0..a1fecd63d9d 100644 --- a/components/style/invalidation/mod.rs +++ b/components/style/invalidation/mod.rs @@ -51,7 +51,8 @@ impl InvalidationScope { /// A set of invalidations due to stylesheet additions. /// -/// TODO(emilio): We might be able to do the same analysis for removals too? +/// TODO(emilio): We might be able to do the same analysis for removals and +/// media query changes too? pub struct StylesheetInvalidationSet { /// The style scopes we know we have to restyle so far. invalid_scopes: FnvHashSet, @@ -68,6 +69,12 @@ impl StylesheetInvalidationSet { } } + /// Mark the DOM tree styles' as fully invalid. + pub fn invalidate_fully(&mut self) { + self.invalid_scopes.clear(); + self.fully_invalid = true; + } + /// Analyze the given stylesheet, and collect invalidations from their /// rules, in order to avoid doing a full restyle when we style the document /// next time. @@ -89,13 +96,25 @@ impl StylesheetInvalidationSet { guard); } + /// Clears the invalidation set, invalidating elements as needed if + /// `document_element` is provided. + pub fn flush(&mut self, document_element: Option) + where E: TElement, + { + if let Some(e) = document_element { + self.process_invalidations_in_subtree(e); + } + self.invalid_scopes.clear(); + self.fully_invalid = false; + } + /// Process style invalidations in a given subtree, that is, look for all /// the relevant scopes in the subtree, and mark as dirty only the relevant /// ones. /// /// Returns whether it invalidated at least one element's style. #[allow(unsafe_code)] - pub fn process_invalidations_in_subtree(&self, element: E) -> bool + fn process_invalidations_in_subtree(&self, element: E) -> bool where E: TElement, { let mut data = match element.mutate_data() { diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index c21084892a7..93b14dbe7a4 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -4,9 +4,13 @@ //! A centralized set of stylesheets for a document. +use dom::TElement; +use invalidation::StylesheetInvalidationSet; +use shared_lock::SharedRwLockReadGuard; use std::slice; use stylearc::Arc; use stylesheets::Stylesheet; +use stylist::Stylist; /// Entry for a StylesheetSet. We don't bother creating a constructor, because /// there's no sensible defaults for the member variables. @@ -40,6 +44,9 @@ pub struct StylesheetSet { /// Has author style been disabled? author_style_disabled: bool, + + /// The style invalidations that we still haven't processed. + invalidations: StylesheetInvalidationSet, } impl StylesheetSet { @@ -49,6 +56,7 @@ impl StylesheetSet { entries: vec![], dirty: false, author_style_disabled: false, + invalidations: StylesheetInvalidationSet::new(), } } @@ -63,32 +71,54 @@ impl StylesheetSet { } /// Appends a new stylesheet to the current set. - pub fn append_stylesheet(&mut self, sheet: &Arc, - unique_id: u64) { + pub fn append_stylesheet( + &mut self, + stylist: &Stylist, + sheet: &Arc, + unique_id: u64, + guard: &SharedRwLockReadGuard) + { self.remove_stylesheet_if_present(unique_id); self.entries.push(StylesheetSetEntry { unique_id: unique_id, sheet: sheet.clone(), }); self.dirty = true; + self.invalidations.collect_invalidations_for( + stylist, + sheet, + guard) } /// Prepend a new stylesheet to the current set. - pub fn prepend_stylesheet(&mut self, sheet: &Arc, - unique_id: u64) { + pub fn prepend_stylesheet( + &mut self, + stylist: &Stylist, + sheet: &Arc, + unique_id: u64, + guard: &SharedRwLockReadGuard) + { self.remove_stylesheet_if_present(unique_id); self.entries.insert(0, StylesheetSetEntry { unique_id: unique_id, sheet: sheet.clone(), }); self.dirty = true; + self.invalidations.collect_invalidations_for( + stylist, + sheet, + guard) } /// Insert a given stylesheet before another stylesheet in the document. - pub fn insert_stylesheet_before(&mut self, - sheet: &Arc, - unique_id: u64, - before_unique_id: u64) { + pub fn insert_stylesheet_before( + &mut self, + stylist: &Stylist, + sheet: &Arc, + unique_id: u64, + before_unique_id: u64, + guard: &SharedRwLockReadGuard) + { self.remove_stylesheet_if_present(unique_id); let index = self.entries.iter().position(|x| { x.unique_id == before_unique_id @@ -98,12 +128,18 @@ impl StylesheetSet { sheet: sheet.clone(), }); self.dirty = true; + self.invalidations.collect_invalidations_for( + stylist, + sheet, + guard) } /// Remove a given stylesheet from the set. pub fn remove_stylesheet(&mut self, unique_id: u64) { self.remove_stylesheet_if_present(unique_id); self.dirty = true; + // FIXME(emilio): We can do better! + self.invalidations.invalidate_fully(); } /// Notes that the author style has been disabled for this document. @@ -113,6 +149,7 @@ impl StylesheetSet { } self.author_style_disabled = disabled; self.dirty = true; + self.invalidations.invalidate_fully(); } /// Returns whether the given set has changed from the last flush. @@ -122,8 +159,16 @@ impl StylesheetSet { /// Flush the current set, unmarking it as dirty, and returns an iterator /// over the new stylesheet list. - pub fn flush(&mut self) -> StylesheetIterator { + pub fn flush(&mut self, + document_element: Option) + -> StylesheetIterator + where E: TElement, + { + debug_assert!(self.dirty); + self.dirty = false; + self.invalidations.flush(document_element); + StylesheetIterator(self.entries.iter()) } @@ -133,5 +178,6 @@ impl StylesheetSet { /// FIXME(emilio): Make this more granular. pub fn force_dirty(&mut self) { self.dirty = true; + self.invalidations.invalidate_fully(); } } diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 73ea3226316..37c9c70f6aa 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -732,9 +732,16 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorrowed, raw_sheet: RawServoStyleSheetBorrowed, unique_id: u64) { + let global_style_data = &*GLOBAL_STYLE_DATA; let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); + let mut data = &mut *data; let sheet = HasArcFFI::as_arc(&raw_sheet); - data.stylesheets.append_stylesheet(sheet, unique_id); + let guard = global_style_data.shared_lock.read(); + data.stylesheets.append_stylesheet( + &data.stylist, + sheet, + unique_id, + &guard); data.clear_stylist(); } @@ -742,9 +749,16 @@ pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorr pub extern "C" fn Servo_StyleSet_PrependStyleSheet(raw_data: RawServoStyleSetBorrowed, raw_sheet: RawServoStyleSheetBorrowed, unique_id: u64) { + let global_style_data = &*GLOBAL_STYLE_DATA; let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); + let mut data = &mut *data; let sheet = HasArcFFI::as_arc(&raw_sheet); - data.stylesheets.prepend_stylesheet(sheet, unique_id); + let guard = global_style_data.shared_lock.read(); + data.stylesheets.prepend_stylesheet( + &data.stylist, + sheet, + unique_id, + &guard); data.clear_stylist(); } @@ -753,9 +767,17 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleS raw_sheet: RawServoStyleSheetBorrowed, unique_id: u64, before_unique_id: u64) { + let global_style_data = &*GLOBAL_STYLE_DATA; let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); + let mut data = &mut *data; let sheet = HasArcFFI::as_arc(&raw_sheet); - data.stylesheets.insert_stylesheet_before(sheet, unique_id, before_unique_id); + let guard = global_style_data.shared_lock.read(); + data.stylesheets.insert_stylesheet_before( + &data.stylist, + sheet, + unique_id, + before_unique_id, + &guard); data.clear_stylist(); } @@ -770,12 +792,13 @@ pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(raw_data: RawServoStyleSetBorr #[no_mangle] pub extern "C" fn Servo_StyleSet_FlushStyleSheets( raw_data: RawServoStyleSetBorrowed, - doc_element: RawServoElementBorrowedOrNull) + doc_element: RawGeckoElementBorrowedOrNull) { let global_style_data = &*GLOBAL_STYLE_DATA; let guard = global_style_data.shared_lock.read(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - data.flush_stylesheets(&guard); + let doc_element = doc_element.map(GeckoElement); + data.flush_stylesheets(&guard, doc_element); } #[no_mangle]