diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index 4ad43d3594a..43596bfefb4 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -17,7 +17,8 @@ use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard}; use std::collections::HashMap; use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; -use stylesheets::{FontFaceRule, Origin, Stylesheet}; +use stylesheet_set::StylesheetSet; +use stylesheets::{FontFaceRule, Origin}; use stylist::{ExtraStyleData, Stylist}; /// The container for data that a Servo-backed Gecko document needs to style @@ -27,13 +28,7 @@ pub struct PerDocumentStyleDataImpl { pub stylist: Arc, /// List of stylesheets, mirrored from Gecko. - pub stylesheets: Vec>, - - /// Whether the stylesheets list above has changed since the last restyle. - pub stylesheets_changed: bool, - - /// Has author style been disabled? - pub author_style_disabled: bool, + pub stylesheets: StylesheetSet, // FIXME(bholley): Hook these up to something. /// Unused. Will go away when we actually implement transitions and @@ -66,9 +61,7 @@ impl PerDocumentStyleData { PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl { stylist: Arc::new(Stylist::new(device)), - stylesheets: vec![], - stylesheets_changed: true, - author_style_disabled: false, + stylesheets: StylesheetSet::new(), new_animations_sender: new_anims_sender, new_animations_receiver: new_anims_receiver, running_animations: Arc::new(RwLock::new(HashMap::new())), @@ -97,22 +90,25 @@ impl PerDocumentStyleDataImpl { let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); Arc::get_mut(&mut stylist.device).unwrap().reset(); } - self.stylesheets_changed = true; + self.stylesheets.force_dirty(); self.flush_stylesheets(guard); } /// Recreate the style data if the stylesheets have changed. pub fn flush_stylesheets(&mut self, guard: &SharedRwLockReadGuard) { - if self.stylesheets_changed { - let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); - let mut extra_data = ExtraStyleData { - font_faces: &mut self.font_faces, - author_style_disabled: Some(self.author_style_disabled), - }; - stylist.update(&self.stylesheets, &StylesheetGuards::same(guard), - None, true, &mut extra_data); - self.stylesheets_changed = false; + if !self.stylesheets.has_changed() { + return; } + + let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); + let mut extra_data = ExtraStyleData { + font_faces: &mut self.font_faces, + author_style_disabled: Some(self.stylesheets.author_style_disabled()), + }; + + stylist.update(&self.stylesheets.flush(), + &StylesheetGuards::same(guard), + None, true, &mut extra_data); } /// Get the default computed values for this document. diff --git a/components/style/lib.rs b/components/style/lib.rs index 41d03644acf..ec77062a53c 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -116,6 +116,7 @@ pub mod stylist; pub mod sequential; pub mod sink; pub mod str; +pub mod stylesheet_set; pub mod stylesheets; pub mod supports; pub mod thread_state; diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs new file mode 100644 index 00000000000..e1f782bbbbf --- /dev/null +++ b/components/style/stylesheet_set.rs @@ -0,0 +1,105 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! A centralized set of stylesheets for a document. + +use arc_ptr_eq; +use std::sync::Arc; +use stylesheets::Stylesheet; + +/// The set of stylesheets effective for a given document. +pub struct StylesheetSet { + /// The actual list of all the stylesheets that apply to the given document. + /// + /// This is only a list of top-level stylesheets, and as such it doesn't + /// include recursive `@import` rules. + stylesheets: Vec>, + + /// Whether the stylesheets list above has changed since the last restyle. + dirty: bool, + + /// Has author style been disabled? + author_style_disabled: bool, +} + +impl StylesheetSet { + /// Create a new empty StylesheetSet. + pub fn new() -> Self { + StylesheetSet { + stylesheets: vec![], + dirty: false, + author_style_disabled: false, + } + } + + /// Returns whether author styles have been disabled for the current + /// stylesheet set. + pub fn author_style_disabled(&self) -> bool { + self.author_style_disabled + } + + fn remove_stylesheet_if_present(&mut self, sheet: &Arc) { + self.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); + } + + /// Appends a new stylesheet to the current set. + pub fn append_stylesheet(&mut self, sheet: &Arc) { + self.remove_stylesheet_if_present(sheet); + self.stylesheets.push(sheet.clone()); + self.dirty = true; + } + + /// Prepend a new stylesheet to the current set. + pub fn prepend_stylesheet(&mut self, sheet: &Arc) { + self.remove_stylesheet_if_present(sheet); + self.stylesheets.insert(0, sheet.clone()); + self.dirty = true; + } + + /// Insert a given stylesheet before another stylesheet in the document. + pub fn insert_stylesheet_before(&mut self, + sheet: &Arc, + before: &Arc) { + self.remove_stylesheet_if_present(sheet); + let index = self.stylesheets.iter().position(|x| { + arc_ptr_eq(x, before) + }).expect("`before` stylesheet not found"); + self.stylesheets.insert(index, sheet.clone()); + self.dirty = true; + } + + /// Remove a given stylesheet from the set. + pub fn remove_stylesheet(&mut self, sheet: &Arc) { + self.remove_stylesheet_if_present(sheet); + self.dirty = true; + } + + /// Notes that the author style has been disabled for this document. + pub fn set_author_style_disabled(&mut self, disabled: bool) { + if self.author_style_disabled == disabled { + return; + } + self.author_style_disabled = disabled; + self.dirty = true; + } + + /// Returns whether the given set has changed from the last flush. + pub fn has_changed(&self) -> bool { + self.dirty + } + + /// Flush the current set, unmarking it as dirty. + pub fn flush(&mut self) -> &[Arc] { + self.dirty = false; + &self.stylesheets + } + + /// Mark the stylesheets as dirty, because something external may have + /// invalidated it. + /// + /// FIXME(emilio): Make this more granular. + pub fn force_dirty(&mut self) { + self.dirty = true; + } +} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 8c7d2175a16..f82d13ee02e 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -13,7 +13,6 @@ use std::env; use std::fmt::Write; use std::ptr; use std::sync::{Arc, Mutex}; -use style::arc_ptr_eq; use style::context::{QuirksMode, SharedStyleContext, StyleContext}; use style::context::{ThreadLocalStyleContext, ThreadLocalStyleContextCreationInfo}; use style::data::{ElementData, ElementStyles, RestyleData}; @@ -578,9 +577,7 @@ pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorr let guard = global_style_data.shared_lock.read(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let sheet = HasArcFFI::as_arc(&raw_sheet); - data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); - data.stylesheets.push(sheet.clone()); - data.stylesheets_changed = true; + data.stylesheets.append_stylesheet(sheet); if flush { data.flush_stylesheets(&guard); } @@ -594,9 +591,7 @@ pub extern "C" fn Servo_StyleSet_PrependStyleSheet(raw_data: RawServoStyleSetBor let guard = global_style_data.shared_lock.read(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let sheet = HasArcFFI::as_arc(&raw_sheet); - data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); - data.stylesheets.insert(0, sheet.clone()); - data.stylesheets_changed = true; + data.stylesheets.prepend_stylesheet(sheet); if flush { data.flush_stylesheets(&guard); } @@ -612,10 +607,7 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleS let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let sheet = HasArcFFI::as_arc(&raw_sheet); let reference = HasArcFFI::as_arc(&raw_reference); - data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); - let index = data.stylesheets.iter().position(|x| arc_ptr_eq(x, reference)).unwrap(); - data.stylesheets.insert(index, sheet.clone()); - data.stylesheets_changed = true; + data.stylesheets.insert_stylesheet_before(sheet, reference); if flush { data.flush_stylesheets(&guard); } @@ -629,8 +621,7 @@ pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(raw_data: RawServoStyleSetBorr let guard = global_style_data.shared_lock.read(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let sheet = HasArcFFI::as_arc(&raw_sheet); - data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); - data.stylesheets_changed = true; + data.stylesheets.remove_stylesheet(sheet); if flush { data.flush_stylesheets(&guard); } @@ -648,8 +639,8 @@ pub extern "C" fn Servo_StyleSet_FlushStyleSheets(raw_data: RawServoStyleSetBorr pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(raw_data: RawServoStyleSetBorrowed, author_style_disabled: bool) { let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - data.stylesheets_changed = true; - data.author_style_disabled = author_style_disabled; + data.stylesheets.force_dirty(); + data.stylesheets.set_author_style_disabled(author_style_disabled); } #[no_mangle]