diff --git a/servo/components/layout_thread/lib.rs b/servo/components/layout_thread/lib.rs index 9683afcbd299..286d49484f6d 100644 --- a/servo/components/layout_thread/lib.rs +++ b/servo/components/layout_thread/lib.rs @@ -1083,7 +1083,6 @@ impl LayoutThread { ua_or_user: &ua_or_user_guard, }; let mut extra_data = ExtraStyleData { - author_style_disabled: None, marker: PhantomData, }; let needs_dirtying = Arc::get_mut(&mut rw_data.stylist).unwrap().update( @@ -1091,6 +1090,7 @@ impl LayoutThread { &guards, Some(ua_stylesheets), data.stylesheets_changed, + /* author_styles_disabled = */ false, &mut extra_data); let needs_reflow = viewport_size_changed && !needs_dirtying; if needs_dirtying { diff --git a/servo/components/style/gecko/data.rs b/servo/components/style/gecko/data.rs index 4ad43d3594af..7efad2a9fbe7 100644 --- a/servo/components/style/gecko/data.rs +++ b/servo/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,29 @@ 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, + }; + + let author_style_disabled = self.stylesheets.author_style_disabled(); + let stylesheets = self.stylesheets.flush(); + stylist.update(stylesheets, + &StylesheetGuards::same(guard), + /* ua_sheets = */ None, + /* stylesheets_changed = */ true, + author_style_disabled, + &mut extra_data); } /// Get the default computed values for this document. diff --git a/servo/components/style/lib.rs b/servo/components/style/lib.rs index 41d03644acff..ec77062a53c0 100644 --- a/servo/components/style/lib.rs +++ b/servo/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/servo/components/style/stylesheet_set.rs b/servo/components/style/stylesheet_set.rs new file mode 100644 index 000000000000..e1f782bbbbf2 --- /dev/null +++ b/servo/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/servo/components/style/stylist.rs b/servo/components/style/stylist.rs index 76b12854b617..e3c500b8b371 100644 --- a/servo/components/style/stylist.rs +++ b/servo/components/style/stylist.rs @@ -78,9 +78,6 @@ pub struct Stylist { /// If true, the quirks-mode stylesheet is applied. quirks_mode: bool, - /// If true, authored styles are ignored. - author_style_disabled: bool, - /// If true, the device has changed, and the stylist needs to be updated. is_device_dirty: bool, @@ -137,10 +134,6 @@ pub struct ExtraStyleData<'a> { #[cfg(feature = "gecko")] pub font_faces: &'a mut Vec<(Arc>, Origin)>, - /// A parameter to change a setting to ignore author styles during update. - /// A None value indicates that update should use existing settings. - pub author_style_disabled: Option, - #[allow(missing_docs)] #[cfg(feature = "servo")] pub marker: PhantomData<&'a usize>, @@ -174,7 +167,6 @@ impl Stylist { device: Arc::new(device), is_device_dirty: true, quirks_mode: false, - author_style_disabled: false, element_map: PerPseudoElementSelectorMap::new(), pseudos_map: Default::default(), @@ -234,6 +226,7 @@ impl Stylist { guards: &StylesheetGuards, ua_stylesheets: Option<&UserAgentStylesheets>, stylesheets_changed: bool, + author_style_disabled: bool, extra_data: &mut ExtraStyleData<'a>) -> bool { if !(self.is_device_dirty || stylesheets_changed) { return false; @@ -282,15 +275,11 @@ impl Stylist { } } - // Absorb changes to author_style_disabled, if supplied. - if let Some(author_style_disabled) = extra_data.author_style_disabled { - self.author_style_disabled = author_style_disabled; - } - // Only use author stylesheets if author styles are enabled. - let author_style_enabled = !self.author_style_disabled; - let sheets_to_add = doc_stylesheets.iter().filter( - |&s| author_style_enabled || s.origin != Origin::Author); + let sheets_to_add = doc_stylesheets.iter().filter(|s| { + !author_style_disabled || s.origin != Origin::Author + }); + for ref stylesheet in sheets_to_add { self.add_stylesheet(stylesheet, guards.author, extra_data); } diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs index 3b9edccdde18..81c956c31878 100644 --- a/servo/ports/geckolib/glue.rs +++ b/servo/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]