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

View file

@ -4,10 +4,8 @@
//! Data needed to style a Gecko document.
use Atom;
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use dom::TElement;
use gecko::rules::{CounterStyleRule, FontFaceRule};
use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{ServoStyleSheet, StyleSheetInfo, ServoStyleSheetInner};
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 media_queries::{Device, MediaList};
use properties::ComputedValues;
use selector_map::PrecomputedHashMap;
use servo_arc::Arc;
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
use stylesheet_set::StylesheetSet;
use stylesheets::{Origin, StylesheetContents, StylesheetInDocument};
use stylesheets::{StylesheetContents, StylesheetInDocument};
use stylist::{ExtraStyleData, Stylist};
/// Little wrapper to a Gecko style sheet.
@ -120,11 +117,8 @@ pub struct PerDocumentStyleDataImpl {
/// List of stylesheets, mirrored from Gecko.
pub stylesheets: StylesheetSet<GeckoStyleSheet>,
/// List of effective font face rules.
pub font_faces: Vec<(Arc<Locked<FontFaceRule>>, Origin)>,
/// Map for effective counter style rules.
pub counter_styles: PrecomputedHashMap<Atom, Arc<Locked<CounterStyleRule>>>,
/// List of effective @font-face and @counter-style rules.
pub extra_style_data: ExtraStyleData,
}
/// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
@ -142,8 +136,7 @@ impl PerDocumentStyleData {
PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
stylist: Stylist::new(device, quirks_mode.into()),
stylesheets: StylesheetSet::new(),
font_faces: vec![],
counter_styles: PrecomputedHashMap::default(),
extra_style_data: Default::default(),
}))
}
@ -169,11 +162,6 @@ impl PerDocumentStyleDataImpl {
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();
self.stylist.clear();
let iter = self.stylesheets.flush(document_element);
@ -183,7 +171,7 @@ impl PerDocumentStyleDataImpl {
/* ua_sheets = */ None,
/* stylesheets_changed = */ true,
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 smallvec::VecLike;
use std::fmt::Debug;
#[cfg(feature = "servo")]
use std::marker::PhantomData;
use style_traits::viewport::ViewportConstraints;
#[cfg(feature = "gecko")]
use stylesheets::{CounterStyleRule, FontFaceRule};
@ -112,27 +110,71 @@ pub struct Stylist {
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.
#[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.
pub font_faces: &'a mut Vec<(Arc<Locked<FontFaceRule>>, Origin)>,
pub font_faces: Vec<Arc<Locked<FontFaceRule>>>,
/// 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")]
impl<'a> ExtraStyleData<'a> {
impl ExtraStyleData {
/// 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) {
self.font_faces.clear();
self.counter_styles.clear();
}
/// Add the given @font-face rule.
fn add_font_face(&mut self, rule: &Arc<Locked<FontFaceRule>>, origin: Origin) {
self.font_faces.push((rule.clone(), origin));
fn add_font_face(&mut self, rule: &Arc<Locked<FontFaceRule>>) {
self.font_faces.push(rule.clone());
}
/// Add the given @counter-style rule.
@ -145,12 +187,10 @@ impl<'a> ExtraStyleData<'a> {
#[allow(missing_docs)]
#[cfg(feature = "servo")]
pub struct ExtraStyleData<'a> {
pub marker: PhantomData<&'a usize>,
}
pub struct ExtraStyleData;
#[cfg(feature = "servo")]
impl<'a> ExtraStyleData<'a> {
impl ExtraStyleData {
fn clear(&mut self) {}
}
@ -277,17 +317,17 @@ 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 rebuild<'a, 'b, I, S>(
pub fn rebuild<'a, I, S>(
&mut self,
doc_stylesheets: I,
guards: &StylesheetGuards,
ua_stylesheets: Option<&UserAgentStylesheets>,
stylesheets_changed: bool,
author_style_disabled: bool,
extra_data: &mut ExtraStyleData<'a>
extra_data: &mut ExtraStyleData
) -> bool
where
I: Iterator<Item = &'b S> + Clone,
I: Iterator<Item = &'a S> + Clone,
S: StylesheetInDocument + ToMediaListKey + 'static,
{
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
/// 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,
doc_stylesheets: I,
guards: &StylesheetGuards,
ua_stylesheets: Option<&UserAgentStylesheets>,
stylesheets_changed: bool,
author_style_disabled: bool,
extra_data: &mut ExtraStyleData<'a>
extra_data: &mut ExtraStyleData
) -> bool
where
I: Iterator<Item = &'b S> + Clone,
I: Iterator<Item = &'a S> + Clone,
S: StylesheetInDocument + ToMediaListKey + 'static,
{
debug_assert!(!self.is_cleared || self.is_device_dirty);
@ -382,11 +422,11 @@ impl Stylist {
author_style_disabled, extra_data)
}
fn add_stylesheet<'a, S>(
fn add_stylesheet<S>(
&mut self,
stylesheet: &S,
guard: &SharedRwLockReadGuard,
_extra_data: &mut ExtraStyleData<'a>
_extra_data: &mut ExtraStyleData
)
where
S: StylesheetInDocument + ToMediaListKey + 'static,
@ -506,11 +546,15 @@ impl Stylist {
}
#[cfg(feature = "gecko")]
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")]
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.
_ => {}
@ -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
/// origin.
#[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 std::env;
use std::fmt::Write;
use std::iter;
use std::ptr;
use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
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 guard = global_style_data.shared_lock.read();
unsafe { rules.set_len(data.font_faces.len() as u32) };
for (src, dest) in data.font_faces.iter().zip(rules.iter_mut()) {
let len: u32 = data.extra_style_data
.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.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,
name: *mut nsIAtom) -> *mut nsCSSCounterStyleRule {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let extra_data = &data.extra_style_data;
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| {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();