From 01e986f2e6404a2d4b0542d734f28f352e85709a Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Thu, 30 Mar 2017 10:44:17 +1100 Subject: [PATCH] Record effective @font-face rules when updating stylist. --- components/layout_thread/lib.rs | 9 +++-- components/style/gecko/data.rs | 16 ++++++--- components/style/stylist.rs | 63 +++++++++++++++++++++++++++------ 3 files changed, 71 insertions(+), 17 deletions(-) diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 629e5ff6a73..74c95499006 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -98,6 +98,7 @@ use servo_url::ServoUrl; use std::borrow::ToOwned; use std::collections::HashMap; use std::hash::BuildHasherDefault; +use std::marker::PhantomData; use std::mem as std_mem; use std::ops::{Deref, DerefMut}; use std::process; @@ -116,7 +117,7 @@ use style::parser::ParserContextExtraData; use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW}; use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards}; use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets}; -use style::stylist::Stylist; +use style::stylist::{ExtraStyleData, Stylist}; use style::thread_state; use style::timer::Timer; use style::traversal::{DomTraversal, TraversalDriver, TraversalFlags}; @@ -1078,11 +1079,15 @@ impl LayoutThread { author: &author_guard, ua_or_user: &ua_or_user_guard, }; + let mut extra_data = ExtraStyleData { + marker: PhantomData, + }; let needs_dirtying = Arc::get_mut(&mut rw_data.stylist).unwrap().update( &data.document_stylesheets, &guards, Some(ua_stylesheets), - data.stylesheets_changed); + data.stylesheets_changed, + &mut extra_data); let needs_reflow = viewport_size_changed && !needs_dirtying; if needs_dirtying { if let Some(mut d) = element.mutate_data() { diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index a1ef6db3e2e..b3b6402f0c9 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -13,12 +13,12 @@ use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; use media_queries::Device; use parking_lot::RwLock; use properties::ComputedValues; -use shared_lock::{StylesheetGuards, SharedRwLockReadGuard}; +use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard}; use std::collections::HashMap; use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; -use stylesheets::Stylesheet; -use stylist::Stylist; +use stylesheets::{FontFaceRule, Origin, Stylesheet}; +use stylist::{ExtraStyleData, Stylist}; /// The container for data that a Servo-backed Gecko document needs to style /// itself. @@ -45,6 +45,9 @@ pub struct PerDocumentStyleDataImpl { /// Unused. Will go away when we actually implement transitions and /// animations properly. pub expired_animations: Arc>>>, + + /// List of effective font face rules. + pub font_faces: Vec<(Arc>, Origin)>, } /// The data itself is an `AtomicRefCell`, which guarantees the proper semantics @@ -66,6 +69,7 @@ impl PerDocumentStyleData { new_animations_receiver: new_anims_receiver, running_animations: Arc::new(RwLock::new(HashMap::new())), expired_animations: Arc::new(RwLock::new(HashMap::new())), + font_faces: vec![], })) } @@ -97,7 +101,11 @@ impl PerDocumentStyleDataImpl { pub fn flush_stylesheets(&mut self, guard: &SharedRwLockReadGuard) { if self.stylesheets_changed { let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); - stylist.update(&self.stylesheets, &StylesheetGuards::same(guard), None, true); + let mut extra_data = ExtraStyleData { + font_faces: &mut self.font_faces, + }; + stylist.update(&self.stylesheets, &StylesheetGuards::same(guard), + None, true, &mut extra_data); self.stylesheets_changed = false; } } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 8ed915125d2..f93d76a5879 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -34,9 +34,11 @@ use std::borrow::Borrow; use std::collections::HashMap; use std::fmt; use std::hash::Hash; +#[cfg(feature = "servo")] +use std::marker::PhantomData; use std::sync::Arc; use style_traits::viewport::ViewportConstraints; -use stylesheets::{CssRule, Origin, StyleRule, Stylesheet, UserAgentStylesheets}; +use stylesheets::{CssRule, FontFaceRule, Origin, StyleRule, Stylesheet, UserAgentStylesheets}; use thread_state; use viewport::{self, MaybeNew, ViewportRule}; @@ -118,6 +120,37 @@ pub struct Stylist { non_common_style_affecting_attributes_selectors: Vec>, } +/// This struct holds data which user of Stylist may want to extract +/// from stylesheets which can be done at the same time as updating. +pub struct ExtraStyleData<'a> { + /// A list of effective font-face rules and their origin. + #[cfg(feature = "gecko")] + pub font_faces: &'a mut Vec<(Arc>, Origin)>, + + #[allow(missing_docs)] + #[cfg(feature = "servo")] + pub marker: PhantomData<&'a usize>, +} + +#[cfg(feature = "gecko")] +impl<'a> ExtraStyleData<'a> { + /// Clear the internal @font-face rule list. + fn clear_font_faces(&mut self) { + self.font_faces.clear(); + } + + /// Add the given @font-face rule. + fn add_font_face(&mut self, rule: &Arc>, origin: Origin) { + self.font_faces.push((rule.clone(), origin)); + } +} + +#[cfg(feature = "servo")] +impl<'a> ExtraStyleData<'a> { + fn clear_font_faces(&mut self) {} + fn add_font_face(&mut self, _: &Arc>, _: Origin) {} +} + impl Stylist { /// Construct a new `Stylist`, using a given `Device`. #[inline] @@ -156,11 +189,12 @@ impl Stylist { /// 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(&mut self, - doc_stylesheets: &[Arc], - guards: &StylesheetGuards, - ua_stylesheets: Option<&UserAgentStylesheets>, - stylesheets_changed: bool) -> bool { + pub fn update<'a>(&mut self, + doc_stylesheets: &[Arc], + guards: &StylesheetGuards, + ua_stylesheets: Option<&UserAgentStylesheets>, + stylesheets_changed: bool, + extra_data: &mut ExtraStyleData<'a>) -> bool { if !(self.is_device_dirty || stylesheets_changed) { return false; } @@ -194,18 +228,21 @@ impl Stylist { self.sibling_affecting_selectors.clear(); self.non_common_style_affecting_attributes_selectors.clear(); + extra_data.clear_font_faces(); + if let Some(ua_stylesheets) = ua_stylesheets { for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets { - self.add_stylesheet(&stylesheet, guards.ua_or_user); + self.add_stylesheet(&stylesheet, guards.ua_or_user, extra_data); } if self.quirks_mode { - self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet, guards.ua_or_user); + self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet, + guards.ua_or_user, extra_data); } } for ref stylesheet in doc_stylesheets.iter() { - self.add_stylesheet(stylesheet, guards.author); + self.add_stylesheet(stylesheet, guards.author, extra_data); } debug!("Stylist stats:"); @@ -230,7 +267,8 @@ impl Stylist { true } - fn add_stylesheet(&mut self, stylesheet: &Stylesheet, guard: &SharedRwLockReadGuard) { + 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) { return; } @@ -274,7 +312,7 @@ impl Stylist { } CssRule::Import(ref import) => { let import = import.read_with(guard); - self.add_stylesheet(&import.stylesheet, guard) + self.add_stylesheet(&import.stylesheet, guard, extra_data) } CssRule::Keyframes(ref keyframes_rule) => { let keyframes_rule = keyframes_rule.read_with(guard); @@ -284,6 +322,9 @@ impl Stylist { debug!("Found valid keyframe animation: {:?}", animation); self.animations.insert(keyframes_rule.name.clone(), animation); } + CssRule::FontFace(ref rule) => { + extra_data.add_font_face(&rule, stylesheet.origin); + } // We don't care about any other rule. _ => {} }