diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index 2e1e17a2ebc..64252c79afc 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -108,18 +108,26 @@ impl PerDocumentStyleDataImpl { let author_style_disabled = self.stylesheets.author_style_disabled(); let mut stylesheets = Vec::>::new(); self.stylesheets.flush(&mut stylesheets); - stylist.update(stylesheets.as_slice(), - &StylesheetGuards::same(guard), - /* ua_sheets = */ None, - /* stylesheets_changed = */ true, - author_style_disabled, - &mut extra_data); + stylist.clear(); + stylist.rebuild(stylesheets.as_slice(), + &StylesheetGuards::same(guard), + /* ua_sheets = */ None, + /* stylesheets_changed = */ true, + author_style_disabled, + &mut extra_data); } /// Get the default computed values for this document. pub fn default_computed_values(&self) -> &Arc { self.stylist.device.default_computed_values_arc() } + + /// Clear the stylist. This will be a no-op if the stylist is + /// already cleared; the stylist handles that. + pub fn clear_stylist(&mut self) { + let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); + stylist.clear(); + } } unsafe impl HasFFI for PerDocumentStyleData { diff --git a/components/style/gecko/generated/bindings.rs b/components/style/gecko/generated/bindings.rs index d97acff7f06..8ac37b85138 100644 --- a/components/style/gecko/generated/bindings.rs +++ b/components/style/gecko/generated/bindings.rs @@ -1628,16 +1628,16 @@ extern "C" { extern "C" { pub fn Servo_StyleSet_AppendStyleSheet(set: RawServoStyleSetBorrowed, sheet: RawServoStyleSheetBorrowed, - unique_id: u32, flush: bool); + unique_id: u32); } extern "C" { pub fn Servo_StyleSet_PrependStyleSheet(set: RawServoStyleSetBorrowed, sheet: RawServoStyleSheetBorrowed, - unique_id: u32, flush: bool); + unique_id: u32); } extern "C" { pub fn Servo_StyleSet_RemoveStyleSheet(set: RawServoStyleSetBorrowed, - unique_id: u32, flush: bool); + unique_id: u32); } extern "C" { pub fn Servo_StyleSet_InsertStyleSheetBefore(set: @@ -1645,8 +1645,7 @@ extern "C" { sheet: RawServoStyleSheetBorrowed, unique_id: u32, - before_unique_id: u32, - flush: bool); + before_unique_id: u32); } extern "C" { pub fn Servo_StyleSet_FlushStyleSheets(set: RawServoStyleSetBorrowed); diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 1f2dee79ae3..4abc363200c 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -85,6 +85,10 @@ pub struct Stylist { /// If true, the device has changed, and the stylist needs to be updated. is_device_dirty: bool, + /// If true, the stylist is in a cleared state (e.g. just-constructed, or + /// had clear() called on it with no following rebuild()). + is_cleared: bool, + /// The current selector maps, after evaluating media /// rules against the current device. element_map: PerPseudoElementSelectorMap, @@ -163,13 +167,15 @@ impl<'a> ExtraStyleData<'a> { } impl Stylist { - /// Construct a new `Stylist`, using a given `Device`. + /// Construct a new `Stylist`, using a given `Device`. If more members are + /// added here, think about whether they should be reset in clear(). #[inline] pub fn new(device: Device) -> Self { let mut stylist = Stylist { viewport_constraints: None, device: Arc::new(device), is_device_dirty: true, + is_cleared: true, quirks_mode: QuirksMode::NoQuirks, element_map: PerPseudoElementSelectorMap::new(), @@ -219,22 +225,64 @@ impl Stylist { self.selectors_for_cache_revalidation.len() } - /// Update the stylist for the given document stylesheets, and optionally + /// Clear the stylist's state, effectively resetting it to more or less + /// the state Stylist::new creates. + /// + /// We preserve the state of the following members: + /// device: Someone might have set this on us. + /// quirks_mode: Again, someone might have set this on us. + /// num_rebuilds: clear() followed by rebuild() should just increment this + /// + /// We don't just use struct update syntax with Stylist::new(self.device) + /// beause for some of our members we can clear them instead of creating new + /// objects. This does cause unfortunate code duplication with + /// Stylist::new. + pub fn clear(&mut self) { + if self.is_cleared { + return + } + + self.is_cleared = true; + + self.viewport_constraints = None; + // preserve current device + self.is_device_dirty = true; + // preserve current quirks_mode value + self.element_map = PerPseudoElementSelectorMap::new(); + self.pseudos_map = Default::default(); + self.animations.clear(); // Or set to Default::default()? + self.precomputed_pseudo_element_decls = Default::default(); + self.rules_source_order = 0; + // We want to keep rule_tree around across stylist rebuilds. + self.dependencies.clear(); + self.selectors_for_cache_revalidation = SelectorMap::new(); + self.num_selectors = 0; + self.num_declarations = 0; + // preserve num_rebuilds value, since it should stay across + // clear()/rebuild() cycles. + } + + /// rebuild the stylist for the given document stylesheets, and optionally /// with a set of user agent stylesheets. /// /// This method resets all the style data each time the stylesheets change /// (which is indicated by the `stylesheets_changed` parameter), or the /// device is dirty, which means we need to re-evaluate media queries. - pub fn update<'a>(&mut self, - doc_stylesheets: &[Arc], - guards: &StylesheetGuards, - ua_stylesheets: Option<&UserAgentStylesheets>, - stylesheets_changed: bool, - author_style_disabled: bool, - extra_data: &mut ExtraStyleData<'a>) -> bool { + pub fn rebuild<'a>(&mut self, + doc_stylesheets: &[Arc], + guards: &StylesheetGuards, + ua_stylesheets: Option<&UserAgentStylesheets>, + stylesheets_changed: bool, + author_style_disabled: bool, + extra_data: &mut ExtraStyleData<'a>) -> bool { + debug_assert!(!self.is_cleared || self.is_device_dirty); + + self.is_cleared = false; + if !(self.is_device_dirty || stylesheets_changed) { return false; } + self.num_rebuilds += 1; let cascaded_rule = ViewportRule { @@ -251,21 +299,10 @@ impl Stylist { .account_for_viewport_rule(constraints); } - self.element_map = PerPseudoElementSelectorMap::new(); - self.pseudos_map = Default::default(); - self.animations = Default::default(); SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| { self.pseudos_map.insert(pseudo, PerPseudoElementSelectorMap::new()); }); - self.precomputed_pseudo_element_decls = Default::default(); - self.rules_source_order = 0; - self.dependencies.clear(); - self.animations.clear(); - self.selectors_for_cache_revalidation = SelectorMap::new(); - self.num_selectors = 0; - self.num_declarations = 0; - extra_data.clear_font_faces(); if let Some(ua_stylesheets) = ua_stylesheets { @@ -302,6 +339,27 @@ impl Stylist { true } + /// clear the stylist and then rebuild it. Chances are, you want to use + /// either clear() or rebuild(), with the latter done lazily, instead. + pub fn update<'a>(&mut self, + doc_stylesheets: &[Arc], + guards: &StylesheetGuards, + ua_stylesheets: Option<&UserAgentStylesheets>, + stylesheets_changed: bool, + author_style_disabled: bool, + extra_data: &mut ExtraStyleData<'a>) -> bool { + debug_assert!(!self.is_cleared || self.is_device_dirty); + + // We have to do a dirtiness check before clearing, because if + // we're not actually dirty we need to no-op here. + if !(self.is_device_dirty || stylesheets_changed) { + return false; + } + self.clear(); + self.rebuild(doc_stylesheets, guards, ua_stylesheets, stylesheets_changed, + author_style_disabled, extra_data) + } + fn add_stylesheet<'a>(&mut self, stylesheet: &Stylesheet, guard: &SharedRwLockReadGuard, extra_data: &mut ExtraStyleData<'a>) { if stylesheet.disabled() || !stylesheet.is_effective_for_device(&self.device, guard) { diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 1201b5acecb..906358fd48c 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -619,60 +619,40 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet #[no_mangle] pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorrowed, raw_sheet: RawServoStyleSheetBorrowed, - unique_id: u32, - flush: bool) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); + unique_id: u32) { let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let sheet = HasArcFFI::as_arc(&raw_sheet); data.stylesheets.append_stylesheet(sheet, unique_id); - if flush { - data.flush_stylesheets(&guard); - } + data.clear_stylist(); } #[no_mangle] pub extern "C" fn Servo_StyleSet_PrependStyleSheet(raw_data: RawServoStyleSetBorrowed, raw_sheet: RawServoStyleSheetBorrowed, - unique_id: u32, - flush: bool) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); + unique_id: u32) { let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let sheet = HasArcFFI::as_arc(&raw_sheet); data.stylesheets.prepend_stylesheet(sheet, unique_id); - if flush { - data.flush_stylesheets(&guard); - } + data.clear_stylist(); } #[no_mangle] pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleSetBorrowed, raw_sheet: RawServoStyleSheetBorrowed, unique_id: u32, - before_unique_id: u32, - flush: bool) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); + before_unique_id: u32) { let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let sheet = HasArcFFI::as_arc(&raw_sheet); data.stylesheets.insert_stylesheet_before(sheet, unique_id, before_unique_id); - if flush { - data.flush_stylesheets(&guard); - } + data.clear_stylist(); } #[no_mangle] pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(raw_data: RawServoStyleSetBorrowed, - unique_id: u32, - flush: bool) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); + unique_id: u32) { let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); data.stylesheets.remove_stylesheet(unique_id); - if flush { - data.flush_stylesheets(&guard); - } + data.clear_stylist(); } #[no_mangle] @@ -689,6 +669,7 @@ pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(raw_data: RawServoStyleS let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); data.stylesheets.force_dirty(); data.stylesheets.set_author_style_disabled(author_style_disabled); + data.clear_stylist(); } #[no_mangle]