style: Split collected @font-face / @counter-style rules per origin.

This commit is contained in:
Cameron McCormack 2017-08-10 17:20:50 +08:00
parent 1877cac477
commit 57622004ce
4 changed files with 120 additions and 47 deletions

View file

@ -114,7 +114,6 @@ use servo_url::ServoUrl;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData;
use std::mem as std_mem; use std::mem as std_mem;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::process; use std::process;
@ -1207,9 +1206,7 @@ impl LayoutThread {
author: &author_guard, author: &author_guard,
ua_or_user: &ua_or_user_guard, ua_or_user: &ua_or_user_guard,
}; };
let mut extra_data = ExtraStyleData { let mut extra_data = ExtraStyleData;
marker: PhantomData,
};
let needs_dirtying = self.stylist.update( let needs_dirtying = self.stylist.update(
StylesheetIterator(data.document_stylesheets.iter()), StylesheetIterator(data.document_stylesheets.iter()),
&guards, &guards,

View file

@ -4,10 +4,8 @@
//! Data needed to style a Gecko document. //! Data needed to style a Gecko document.
use Atom;
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use dom::TElement; use dom::TElement;
use gecko::rules::{CounterStyleRule, FontFaceRule};
use gecko_bindings::bindings::{self, RawServoStyleSet}; use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{ServoStyleSheet, StyleSheetInfo, ServoStyleSheetInner}; use gecko_bindings::structs::{ServoStyleSheet, StyleSheetInfo, ServoStyleSheetInner};
use gecko_bindings::structs::RawGeckoPresContextOwned; use gecko_bindings::structs::RawGeckoPresContextOwned;
@ -16,11 +14,10 @@ use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFF
use invalidation::media_queries::{MediaListKey, ToMediaListKey}; use invalidation::media_queries::{MediaListKey, ToMediaListKey};
use media_queries::{Device, MediaList}; use media_queries::{Device, MediaList};
use properties::ComputedValues; use properties::ComputedValues;
use selector_map::PrecomputedHashMap;
use servo_arc::Arc; use servo_arc::Arc;
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard}; use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
use stylesheet_set::StylesheetSet; use stylesheet_set::StylesheetSet;
use stylesheets::{Origin, StylesheetContents, StylesheetInDocument}; use stylesheets::{StylesheetContents, StylesheetInDocument};
use stylist::{ExtraStyleData, Stylist}; use stylist::{ExtraStyleData, Stylist};
/// Little wrapper to a Gecko style sheet. /// Little wrapper to a Gecko style sheet.
@ -120,11 +117,8 @@ pub struct PerDocumentStyleDataImpl {
/// List of stylesheets, mirrored from Gecko. /// List of stylesheets, mirrored from Gecko.
pub stylesheets: StylesheetSet<GeckoStyleSheet>, pub stylesheets: StylesheetSet<GeckoStyleSheet>,
/// List of effective font face rules. /// List of effective @font-face and @counter-style rules.
pub font_faces: Vec<(Arc<Locked<FontFaceRule>>, Origin)>, pub extra_style_data: ExtraStyleData,
/// Map for effective counter style rules.
pub counter_styles: PrecomputedHashMap<Atom, Arc<Locked<CounterStyleRule>>>,
} }
/// The data itself is an `AtomicRefCell`, which guarantees the proper semantics /// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
@ -142,8 +136,7 @@ impl PerDocumentStyleData {
PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl { PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
stylist: Stylist::new(device, quirks_mode.into()), stylist: Stylist::new(device, quirks_mode.into()),
stylesheets: StylesheetSet::new(), stylesheets: StylesheetSet::new(),
font_faces: vec![], extra_style_data: Default::default(),
counter_styles: PrecomputedHashMap::default(),
})) }))
} }
@ -169,11 +162,6 @@ impl PerDocumentStyleDataImpl {
return; return;
} }
let mut extra_data = ExtraStyleData {
font_faces: &mut self.font_faces,
counter_styles: &mut self.counter_styles,
};
let author_style_disabled = self.stylesheets.author_style_disabled(); let author_style_disabled = self.stylesheets.author_style_disabled();
self.stylist.clear(); self.stylist.clear();
let iter = self.stylesheets.flush(document_element); let iter = self.stylesheets.flush(document_element);
@ -183,7 +171,7 @@ impl PerDocumentStyleDataImpl {
/* ua_sheets = */ None, /* ua_sheets = */ None,
/* stylesheets_changed = */ true, /* stylesheets_changed = */ true,
author_style_disabled, author_style_disabled,
&mut extra_data &mut self.extra_style_data,
); );
} }

View file

@ -36,8 +36,6 @@ use servo_arc::{Arc, ArcBorrow};
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use smallvec::VecLike; use smallvec::VecLike;
use std::fmt::Debug; use std::fmt::Debug;
#[cfg(feature = "servo")]
use std::marker::PhantomData;
use style_traits::viewport::ViewportConstraints; use style_traits::viewport::ViewportConstraints;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use stylesheets::{CounterStyleRule, FontFaceRule}; use stylesheets::{CounterStyleRule, FontFaceRule};
@ -112,27 +110,71 @@ pub struct Stylist {
num_rebuilds: usize, num_rebuilds: usize,
} }
/// This struct holds data which user of Stylist may want to extract /// This struct holds data which users of Stylist may want to extract
/// from stylesheets which can be done at the same time as updating. /// from stylesheets which can be done at the same time as updating.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub struct ExtraStyleData<'a> { #[derive(Default)]
pub struct ExtraStyleData {
/// Extra data from user agent stylesheets
user_agent: PerOriginExtraStyleData,
/// Extra data from author stylesheets
author: PerOriginExtraStyleData,
/// Extra data from user stylesheets
user: PerOriginExtraStyleData,
}
/// This struct holds data which users of Stylist may want to extract
/// from stylesheets which can be done at the same time as updating.
#[cfg(feature = "gecko")]
#[derive(Default)]
pub struct PerOriginExtraStyleData {
/// A list of effective font-face rules and their origin. /// A list of effective font-face rules and their origin.
pub font_faces: &'a mut Vec<(Arc<Locked<FontFaceRule>>, Origin)>, pub font_faces: Vec<Arc<Locked<FontFaceRule>>>,
/// A map of effective counter-style rules. /// A map of effective counter-style rules.
pub counter_styles: &'a mut PrecomputedHashMap<Atom, Arc<Locked<CounterStyleRule>>>, pub counter_styles: PrecomputedHashMap<Atom, Arc<Locked<CounterStyleRule>>>,
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl<'a> ExtraStyleData<'a> { impl ExtraStyleData {
/// Clear the internal data. /// Clear the internal data.
pub fn clear(&mut self) {
self.user_agent.clear();
self.author.clear();
self.user.clear();
}
/// Returns a reference to the per-origin extra style data for
/// the specified origin.
#[inline]
pub fn borrow_mut_for_origin(&mut self, origin: &Origin) -> &mut PerOriginExtraStyleData {
match *origin {
Origin::UserAgent => &mut self.user_agent,
Origin::Author => &mut self.author,
Origin::User => &mut self.user,
}
}
/// Iterates over the per-origin extra style data, from highest level (user)
/// to lowest (user agent).
pub fn iter_origins(&self) -> ExtraStyleDataIter {
ExtraStyleDataIter {
extra_style_data: &self,
cur: 0,
}
}
}
#[cfg(feature = "gecko")]
impl PerOriginExtraStyleData {
/// Clears the stored @font-face and @counter-style rules.
fn clear(&mut self) { fn clear(&mut self) {
self.font_faces.clear(); self.font_faces.clear();
self.counter_styles.clear(); self.counter_styles.clear();
} }
/// Add the given @font-face rule. /// Add the given @font-face rule.
fn add_font_face(&mut self, rule: &Arc<Locked<FontFaceRule>>, origin: Origin) { fn add_font_face(&mut self, rule: &Arc<Locked<FontFaceRule>>) {
self.font_faces.push((rule.clone(), origin)); self.font_faces.push(rule.clone());
} }
/// Add the given @counter-style rule. /// Add the given @counter-style rule.
@ -145,12 +187,10 @@ impl<'a> ExtraStyleData<'a> {
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub struct ExtraStyleData<'a> { pub struct ExtraStyleData;
pub marker: PhantomData<&'a usize>,
}
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
impl<'a> ExtraStyleData<'a> { impl ExtraStyleData {
fn clear(&mut self) {} fn clear(&mut self) {}
} }
@ -277,17 +317,17 @@ impl Stylist {
/// This method resets all the style data each time the stylesheets change /// This method resets all the style data each time the stylesheets change
/// (which is indicated by the `stylesheets_changed` parameter), or the /// (which is indicated by the `stylesheets_changed` parameter), or the
/// device is dirty, which means we need to re-evaluate media queries. /// device is dirty, which means we need to re-evaluate media queries.
pub fn rebuild<'a, 'b, I, S>( pub fn rebuild<'a, I, S>(
&mut self, &mut self,
doc_stylesheets: I, doc_stylesheets: I,
guards: &StylesheetGuards, guards: &StylesheetGuards,
ua_stylesheets: Option<&UserAgentStylesheets>, ua_stylesheets: Option<&UserAgentStylesheets>,
stylesheets_changed: bool, stylesheets_changed: bool,
author_style_disabled: bool, author_style_disabled: bool,
extra_data: &mut ExtraStyleData<'a> extra_data: &mut ExtraStyleData
) -> bool ) -> bool
where where
I: Iterator<Item = &'b S> + Clone, I: Iterator<Item = &'a S> + Clone,
S: StylesheetInDocument + ToMediaListKey + 'static, S: StylesheetInDocument + ToMediaListKey + 'static,
{ {
debug_assert!(!self.is_cleared || self.is_device_dirty); debug_assert!(!self.is_cleared || self.is_device_dirty);
@ -357,17 +397,17 @@ impl Stylist {
/// clear the stylist and then rebuild it. Chances are, you want to use /// clear the stylist and then rebuild it. Chances are, you want to use
/// either clear() or rebuild(), with the latter done lazily, instead. /// either clear() or rebuild(), with the latter done lazily, instead.
pub fn update<'a, 'b, I, S>( pub fn update<'a, I, S>(
&mut self, &mut self,
doc_stylesheets: I, doc_stylesheets: I,
guards: &StylesheetGuards, guards: &StylesheetGuards,
ua_stylesheets: Option<&UserAgentStylesheets>, ua_stylesheets: Option<&UserAgentStylesheets>,
stylesheets_changed: bool, stylesheets_changed: bool,
author_style_disabled: bool, author_style_disabled: bool,
extra_data: &mut ExtraStyleData<'a> extra_data: &mut ExtraStyleData
) -> bool ) -> bool
where where
I: Iterator<Item = &'b S> + Clone, I: Iterator<Item = &'a S> + Clone,
S: StylesheetInDocument + ToMediaListKey + 'static, S: StylesheetInDocument + ToMediaListKey + 'static,
{ {
debug_assert!(!self.is_cleared || self.is_device_dirty); debug_assert!(!self.is_cleared || self.is_device_dirty);
@ -382,11 +422,11 @@ impl Stylist {
author_style_disabled, extra_data) author_style_disabled, extra_data)
} }
fn add_stylesheet<'a, S>( fn add_stylesheet<S>(
&mut self, &mut self,
stylesheet: &S, stylesheet: &S,
guard: &SharedRwLockReadGuard, guard: &SharedRwLockReadGuard,
_extra_data: &mut ExtraStyleData<'a> _extra_data: &mut ExtraStyleData
) )
where where
S: StylesheetInDocument + ToMediaListKey + 'static, S: StylesheetInDocument + ToMediaListKey + 'static,
@ -506,11 +546,15 @@ impl Stylist {
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
CssRule::FontFace(ref rule) => { CssRule::FontFace(ref rule) => {
_extra_data.add_font_face(&rule, origin); _extra_data
.borrow_mut_for_origin(&origin)
.add_font_face(&rule);
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
CssRule::CounterStyle(ref rule) => { CssRule::CounterStyle(ref rule) => {
_extra_data.add_counter_style(guard, &rule); _extra_data
.borrow_mut_for_origin(&origin)
.add_counter_style(guard, &rule);
} }
// We don't care about any other rule. // We don't care about any other rule.
_ => {} _ => {}
@ -1628,6 +1672,33 @@ impl<'a> Iterator for CascadeDataIter<'a> {
} }
} }
/// Iterator over `PerOriginExtraStyleData`, from highest level (user) to lowest
/// (user agent).
///
/// We rely on this specific order for correctly looking up the @font-face
/// and @counter-style rules.
#[cfg(feature = "gecko")]
pub struct ExtraStyleDataIter<'a> {
extra_style_data: &'a ExtraStyleData,
cur: usize,
}
#[cfg(feature = "gecko")]
impl<'a> Iterator for ExtraStyleDataIter<'a> {
type Item = (&'a PerOriginExtraStyleData, Origin);
fn next(&mut self) -> Option<(&'a PerOriginExtraStyleData, Origin)> {
let result = match self.cur {
0 => (&self.extra_style_data.user, Origin::User),
1 => (&self.extra_style_data.author, Origin::Author),
2 => (&self.extra_style_data.user_agent, Origin::UserAgent),
_ => return None,
};
self.cur += 1;
Some(result)
}
}
/// Data resulting from performing the CSS cascade that is specific to a given /// Data resulting from performing the CSS cascade that is specific to a given
/// origin. /// origin.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]

View file

@ -10,6 +10,7 @@ use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
use servo_arc::{Arc, ArcBorrow, RawOffsetArc}; use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
use std::env; use std::env;
use std::fmt::Write; use std::fmt::Write;
use std::iter;
use std::ptr; use std::ptr;
use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext}; use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
use style::context::ThreadLocalStyleContext; use style::context::ThreadLocalStyleContext;
@ -3422,8 +3423,17 @@ pub extern "C" fn Servo_StyleSet_GetFontFaceRules(raw_data: RawServoStyleSetBorr
let global_style_data = &*GLOBAL_STYLE_DATA; let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read(); let guard = global_style_data.shared_lock.read();
unsafe { rules.set_len(data.font_faces.len() as u32) }; let len: u32 = data.extra_style_data
for (src, dest) in data.font_faces.iter().zip(rules.iter_mut()) { .iter_origins()
.map(|(d, _)| d.font_faces.len() as u32)
.sum();
let font_face_iter = data.extra_style_data
.iter_origins()
.flat_map(|(d, o)| d.font_faces.iter().zip(iter::repeat(o)));
unsafe { rules.set_len(len) };
for (src, dest) in font_face_iter.zip(rules.iter_mut()) {
dest.mRule = src.0.read_with(&guard).clone().forget(); dest.mRule = src.0.read_with(&guard).clone().forget();
dest.mSheetType = src.1.into(); dest.mSheetType = src.1.into();
} }
@ -3433,8 +3443,15 @@ pub extern "C" fn Servo_StyleSet_GetFontFaceRules(raw_data: RawServoStyleSetBorr
pub extern "C" fn Servo_StyleSet_GetCounterStyleRule(raw_data: RawServoStyleSetBorrowed, pub extern "C" fn Servo_StyleSet_GetCounterStyleRule(raw_data: RawServoStyleSetBorrowed,
name: *mut nsIAtom) -> *mut nsCSSCounterStyleRule { name: *mut nsIAtom) -> *mut nsCSSCounterStyleRule {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let extra_data = &data.extra_style_data;
unsafe { unsafe {
Atom::with(name, |name| data.counter_styles.get(name)) Atom::with(name, |name| {
extra_data
.iter_origins()
.filter_map(|(d, _)| d.counter_styles.get(name))
.next()
})
}.map(|rule| { }.map(|rule| {
let global_style_data = &*GLOBAL_STYLE_DATA; let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read(); let guard = global_style_data.shared_lock.read();