mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
style: Add a TLS-based style struct caching mechanism.
This commit is contained in:
parent
298b1363ff
commit
c34c92e904
18 changed files with 278 additions and 13 deletions
|
@ -122,6 +122,12 @@ impl<T: ?Sized + 'static> PartialEq for NonZeroPtrMut<T> {
|
|||
|
||||
impl<T: ?Sized + 'static> Eq for NonZeroPtrMut<T> {}
|
||||
|
||||
impl<T: Sized + 'static> Hash for NonZeroPtrMut<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.ptr().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Arc<T: ?Sized + 'static> {
|
||||
p: NonZeroPtrMut<ArcInner<T>>,
|
||||
}
|
||||
|
|
|
@ -502,7 +502,9 @@ fn compute_style_for_animation_step(context: &SharedStyleContext,
|
|||
/* visited_style = */ None,
|
||||
font_metrics_provider,
|
||||
CascadeFlags::empty(),
|
||||
context.quirks_mode());
|
||||
context.quirks_mode(),
|
||||
/* rule_cache = */ None,
|
||||
&mut Default::default());
|
||||
computed
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ use parallel::{STACK_SAFETY_MARGIN_KB, STYLE_THREAD_STACK_SIZE_KB};
|
|||
#[cfg(feature = "servo")] use parking_lot::RwLock;
|
||||
use properties::ComputedValues;
|
||||
#[cfg(feature = "servo")] use properties::PropertyId;
|
||||
use rule_cache::RuleCache;
|
||||
use rule_tree::StrongRuleNode;
|
||||
use selector_parser::{EAGER_PSEUDO_COUNT, SnapshotMap};
|
||||
use selectors::matching::ElementSelectorFlags;
|
||||
|
@ -685,6 +686,8 @@ impl StackLimitChecker {
|
|||
pub struct ThreadLocalStyleContext<E: TElement> {
|
||||
/// A cache to share style among siblings.
|
||||
pub sharing_cache: StyleSharingCache<E>,
|
||||
/// A cache from matched properties to elements that match those.
|
||||
pub rule_cache: RuleCache,
|
||||
/// The bloom filter used to fast-reject selector-matching.
|
||||
pub bloom_filter: StyleBloom<E>,
|
||||
/// A channel on which new animations that have been triggered by style
|
||||
|
@ -722,6 +725,7 @@ impl<E: TElement> ThreadLocalStyleContext<E> {
|
|||
pub fn new(shared: &SharedStyleContext) -> Self {
|
||||
ThreadLocalStyleContext {
|
||||
sharing_cache: StyleSharingCache::new(),
|
||||
rule_cache: RuleCache::new(),
|
||||
bloom_filter: StyleBloom::new(),
|
||||
new_animations_sender: shared.local_context_creation_data.lock().unwrap().new_animations_sender.clone(),
|
||||
tasks: SequentialTaskList(Vec::new()),
|
||||
|
@ -739,6 +743,7 @@ impl<E: TElement> ThreadLocalStyleContext<E> {
|
|||
pub fn new(shared: &SharedStyleContext) -> Self {
|
||||
ThreadLocalStyleContext {
|
||||
sharing_cache: StyleSharingCache::new(),
|
||||
rule_cache: RuleCache::new(),
|
||||
bloom_filter: StyleBloom::new(),
|
||||
tasks: SequentialTaskList(Vec::new()),
|
||||
selector_flags: SelectorFlagsMap::new(),
|
||||
|
|
|
@ -23,7 +23,9 @@ use media_queries::MediaType;
|
|||
use parser::ParserContext;
|
||||
use properties::{ComputedValues, StyleBuilder};
|
||||
use properties::longhands::font_size;
|
||||
use rule_cache::RuleCacheConditions;
|
||||
use servo_arc::Arc;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::{self, Write};
|
||||
use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
|
||||
use str::starts_with_ignore_ascii_case;
|
||||
|
@ -694,6 +696,7 @@ impl Expression {
|
|||
|
||||
// http://dev.w3.org/csswg/mediaqueries3/#units
|
||||
// em units are relative to the initial font-size.
|
||||
let mut conditions = RuleCacheConditions::default();
|
||||
let context = computed::Context {
|
||||
is_root_element: false,
|
||||
builder: StyleBuilder::for_derived_style(device, default_values, None, None),
|
||||
|
@ -703,6 +706,7 @@ impl Expression {
|
|||
// TODO: pass the correct value here.
|
||||
quirks_mode: quirks_mode,
|
||||
for_smil_animation: false,
|
||||
rule_cache_conditions: RefCell::new(&mut conditions),
|
||||
};
|
||||
|
||||
let required_value = match self.value {
|
||||
|
|
|
@ -124,6 +124,7 @@ pub mod matching;
|
|||
pub mod media_queries;
|
||||
pub mod parallel;
|
||||
pub mod parser;
|
||||
pub mod rule_cache;
|
||||
pub mod rule_tree;
|
||||
pub mod scoped_tls;
|
||||
pub mod selector_map;
|
||||
|
|
|
@ -59,5 +59,8 @@ bitflags! {
|
|||
|
||||
/// Whether the child explicitly inherits any reset property.
|
||||
const INHERITS_RESET_STYLE = 1 << 8,
|
||||
|
||||
/// A flag to mark a style which is a visited style.
|
||||
const IS_STYLE_IF_VISITED = 1 << 9,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ use gecko::values::round_border_to_device_pixels;
|
|||
use logical_geometry::WritingMode;
|
||||
use media_queries::Device;
|
||||
use properties::animated_properties::TransitionProperty;
|
||||
use properties::computed_value_flags::ComputedValueFlags;
|
||||
use properties::computed_value_flags::*;
|
||||
use properties::{default_font_size_keyword, longhands, FontComputationData, Importance, LonghandId};
|
||||
use properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyDeclarationId};
|
||||
use rule_tree::StrongRuleNode;
|
||||
|
@ -259,6 +259,11 @@ impl ops::DerefMut for ComputedValues {
|
|||
}
|
||||
|
||||
impl ComputedValuesInner {
|
||||
/// Whether we're a visited style.
|
||||
pub fn is_style_if_visited(&self) -> bool {
|
||||
self.flags.contains(IS_STYLE_IF_VISITED)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_display_contents(&self) -> bool {
|
||||
self.get_box().clone_display() == longhands::display::computed_value::T::contents
|
||||
|
|
|
@ -322,6 +322,10 @@
|
|||
longhands::system_font::resolve_system_font(sf, context);
|
||||
}
|
||||
% endif
|
||||
% if property.logical:
|
||||
context.rule_cache_conditions.borrow_mut()
|
||||
.set_writing_mode_dependency(context.builder.writing_mode);
|
||||
% endif
|
||||
% if property.is_vector:
|
||||
// In the case of a vector property we want to pass
|
||||
// down an iterator so that this can be computed
|
||||
|
@ -363,6 +367,7 @@
|
|||
CSSWideKeyword::Unset |
|
||||
% endif
|
||||
CSSWideKeyword::Initial => {
|
||||
context.rule_cache_conditions.borrow_mut().set_uncacheable();
|
||||
% if property.ident == "font_size":
|
||||
longhands::font_size::cascade_initial_font_size(context);
|
||||
% else:
|
||||
|
|
|
@ -16,6 +16,7 @@ use smallbitvec::SmallBitVec;
|
|||
use std::borrow::Cow;
|
||||
use hash::HashSet;
|
||||
use std::{fmt, mem, ops};
|
||||
use std::cell::RefCell;
|
||||
#[cfg(feature = "gecko")] use std::ptr;
|
||||
|
||||
#[cfg(feature = "servo")] use cssparser::RGBA;
|
||||
|
@ -34,6 +35,7 @@ use media_queries::Device;
|
|||
use parser::ParserContext;
|
||||
use properties::animated_properties::AnimatableLonghand;
|
||||
#[cfg(feature = "gecko")] use properties::longhands::system_font::SystemFont;
|
||||
use rule_cache::{RuleCache, RuleCacheConditions};
|
||||
use selector_parser::PseudoElement;
|
||||
use selectors::parser::SelectorParseError;
|
||||
#[cfg(feature = "servo")] use servo_config::prefs::PREFS;
|
||||
|
@ -46,7 +48,7 @@ use values::generics::text::LineHeight;
|
|||
use values::computed;
|
||||
use values::computed::NonNegativeLength;
|
||||
use rule_tree::{CascadeLevel, StrongRuleNode};
|
||||
use self::computed_value_flags::ComputedValueFlags;
|
||||
use self::computed_value_flags::*;
|
||||
use style_adjuster::StyleAdjuster;
|
||||
#[cfg(feature = "servo")] use values::specified::BorderStyle;
|
||||
|
||||
|
@ -2156,6 +2158,11 @@ impl ComputedValuesInner {
|
|||
/// Servo for obvious reasons.
|
||||
pub fn has_moz_binding(&self) -> bool { false }
|
||||
|
||||
/// Whether we're a visited style.
|
||||
pub fn is_style_if_visited(&self) -> bool {
|
||||
self.flags.contains(IS_STYLE_IF_VISITED)
|
||||
}
|
||||
|
||||
/// Returns whether this style's display value is equal to contents.
|
||||
///
|
||||
/// Since this isn't supported in Servo, this is always false for Servo.
|
||||
|
@ -2558,7 +2565,7 @@ pub struct StyleBuilder<'a> {
|
|||
|
||||
/// The rule node representing the ordered list of rules matched for this
|
||||
/// node.
|
||||
rules: Option<StrongRuleNode>,
|
||||
pub rules: Option<StrongRuleNode>,
|
||||
|
||||
custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
|
||||
|
@ -2594,7 +2601,7 @@ impl<'a> StyleBuilder<'a> {
|
|||
custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
writing_mode: WritingMode,
|
||||
font_size_keyword: FontComputationData,
|
||||
flags: ComputedValueFlags,
|
||||
mut flags: ComputedValueFlags,
|
||||
visited_style: Option<Arc<ComputedValues>>,
|
||||
) -> Self {
|
||||
debug_assert_eq!(parent_style.is_some(), parent_style_ignoring_first_line.is_some());
|
||||
|
@ -2616,6 +2623,10 @@ impl<'a> StyleBuilder<'a> {
|
|||
reset_style
|
||||
};
|
||||
|
||||
if cascade_flags.contains(VISITED_DEPENDENT_ONLY) {
|
||||
flags.insert(IS_STYLE_IF_VISITED);
|
||||
}
|
||||
|
||||
StyleBuilder {
|
||||
device,
|
||||
parent_style,
|
||||
|
@ -2639,6 +2650,11 @@ impl<'a> StyleBuilder<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether we're a visited style.
|
||||
pub fn is_style_if_visited(&self) -> bool {
|
||||
self.flags.contains(IS_STYLE_IF_VISITED)
|
||||
}
|
||||
|
||||
/// Creates a StyleBuilder holding only references to the structs of `s`, in
|
||||
/// order to create a derived style.
|
||||
pub fn for_derived_style(
|
||||
|
@ -2674,6 +2690,16 @@ impl<'a> StyleBuilder<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Copy the reset properties from `style`.
|
||||
pub fn copy_reset_from(&mut self, style: &'a ComputedValues) {
|
||||
% for style_struct in data.active_style_structs():
|
||||
% if not style_struct.inherited:
|
||||
self.${style_struct.ident} =
|
||||
StyleStructRef::Borrowed(style.${style_struct.name_lower}_arc());
|
||||
% endif
|
||||
% endfor
|
||||
}
|
||||
|
||||
% for property in data.longhands:
|
||||
% if property.ident != "font_size":
|
||||
/// Inherit `${property.ident}` from our parent style.
|
||||
|
@ -2683,7 +2709,8 @@ impl<'a> StyleBuilder<'a> {
|
|||
% if property.style_struct.inherited:
|
||||
self.inherited_style.get_${property.style_struct.name_lower}();
|
||||
% else:
|
||||
self.inherited_style_ignoring_first_line.get_${property.style_struct.name_lower}();
|
||||
self.inherited_style_ignoring_first_line
|
||||
.get_${property.style_struct.name_lower}();
|
||||
% endif
|
||||
|
||||
% if not property.style_struct.inherited:
|
||||
|
@ -3029,7 +3056,9 @@ pub fn cascade(
|
|||
visited_style: Option<Arc<ComputedValues>>,
|
||||
font_metrics_provider: &FontMetricsProvider,
|
||||
flags: CascadeFlags,
|
||||
quirks_mode: QuirksMode
|
||||
quirks_mode: QuirksMode,
|
||||
rule_cache: Option<<&RuleCache>,
|
||||
rule_cache_conditions: &mut RuleCacheConditions,
|
||||
) -> Arc<ComputedValues> {
|
||||
debug_assert_eq!(parent_style.is_some(), parent_style_ignoring_first_line.is_some());
|
||||
#[cfg(feature = "gecko")]
|
||||
|
@ -3089,6 +3118,8 @@ pub fn cascade(
|
|||
font_metrics_provider,
|
||||
flags,
|
||||
quirks_mode,
|
||||
rule_cache,
|
||||
rule_cache_conditions,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -3107,6 +3138,8 @@ pub fn apply_declarations<'a, F, I>(
|
|||
font_metrics_provider: &FontMetricsProvider,
|
||||
flags: CascadeFlags,
|
||||
quirks_mode: QuirksMode,
|
||||
rule_cache: Option<<&RuleCache>,
|
||||
rule_cache_conditions: &mut RuleCacheConditions,
|
||||
) -> Arc<ComputedValues>
|
||||
where
|
||||
F: Fn() -> I,
|
||||
|
@ -3163,11 +3196,12 @@ where
|
|||
ComputedValueFlags::empty(),
|
||||
visited_style,
|
||||
),
|
||||
font_metrics_provider: font_metrics_provider,
|
||||
cached_system_font: None,
|
||||
in_media_query: false,
|
||||
quirks_mode: quirks_mode,
|
||||
for_smil_animation: false,
|
||||
font_metrics_provider,
|
||||
quirks_mode,
|
||||
rule_cache_conditions: RefCell::new(rule_cache_conditions),
|
||||
};
|
||||
|
||||
let ignore_colors = !device.use_document_colors();
|
||||
|
@ -3190,6 +3224,7 @@ where
|
|||
//
|
||||
// To improve i-cache behavior, we outline the individual functions and use
|
||||
// virtual dispatch instead.
|
||||
let mut apply_reset = true;
|
||||
% for category_to_cascade_now in ["early", "other"]:
|
||||
% if category_to_cascade_now == "early":
|
||||
// Pull these out so that we can compute them in a specific order
|
||||
|
@ -3222,6 +3257,10 @@ where
|
|||
continue
|
||||
}
|
||||
|
||||
if !apply_reset && !longhand_id.inherited() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// When document colors are disabled, skip properties that are
|
||||
// marked as ignored in that mode, if they come from a UA or
|
||||
// user style sheet.
|
||||
|
@ -3389,7 +3428,12 @@ where
|
|||
(CASCADE_PROPERTY[discriminant])(&size, &mut context);
|
||||
% endif
|
||||
}
|
||||
% endif
|
||||
|
||||
if let Some(style) = rule_cache.and_then(|c| c.find(&context.builder)) {
|
||||
context.builder.copy_reset_from(style);
|
||||
apply_reset = false;
|
||||
}
|
||||
% endif // category == "early"
|
||||
% endfor
|
||||
|
||||
let mut builder = context.builder;
|
||||
|
|
143
components/style/rule_cache.rs
Normal file
143
components/style/rule_cache.rs
Normal file
|
@ -0,0 +1,143 @@
|
|||
/* 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 cache from rule node to computed values, in order to cache reset
|
||||
//! properties.
|
||||
|
||||
use fnv::FnvHashMap;
|
||||
use logical_geometry::WritingMode;
|
||||
use properties::{ComputedValues, StyleBuilder};
|
||||
use rule_tree::StrongRuleNode;
|
||||
use servo_arc::Arc;
|
||||
use smallvec::SmallVec;
|
||||
use values::computed::NonNegativeLength;
|
||||
|
||||
/// The conditions for caching and matching a style in the rule cache.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct RuleCacheConditions {
|
||||
uncacheable: bool,
|
||||
font_size: Option<NonNegativeLength>,
|
||||
writing_mode: Option<WritingMode>,
|
||||
}
|
||||
|
||||
impl RuleCacheConditions {
|
||||
/// Sets the style as depending in the font-size value.
|
||||
pub fn set_font_size_dependency(&mut self, font_size: NonNegativeLength) {
|
||||
debug_assert!(self.font_size.map_or(true, |f| f == font_size));
|
||||
self.font_size = Some(font_size);
|
||||
}
|
||||
|
||||
/// Sets the style as uncacheable.
|
||||
pub fn set_uncacheable(&mut self) {
|
||||
self.uncacheable = true;
|
||||
}
|
||||
|
||||
/// Sets the style as depending in the writing-mode value `writing_mode`.
|
||||
pub fn set_writing_mode_dependency(&mut self, writing_mode: WritingMode) {
|
||||
debug_assert!(self.writing_mode.map_or(true, |wm| wm == writing_mode));
|
||||
self.writing_mode = Some(writing_mode);
|
||||
}
|
||||
|
||||
/// Returns whether the current style's reset properties are cacheable.
|
||||
fn cacheable(&self) -> bool {
|
||||
!self.uncacheable
|
||||
}
|
||||
|
||||
/// Returns whether `style` matches the conditions.
|
||||
fn matches(&self, style: &StyleBuilder) -> bool {
|
||||
if self.uncacheable {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(fs) = self.font_size {
|
||||
if style.get_font().clone_font_size() != fs {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(wm) = self.writing_mode {
|
||||
if style.writing_mode != wm {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// A TLS cache from rules matched to computed values.
|
||||
pub struct RuleCache {
|
||||
// FIXME(emilio): Consider using LRUCache or something like that?
|
||||
map: FnvHashMap<StrongRuleNode, SmallVec<[(RuleCacheConditions, Arc<ComputedValues>); 1]>>,
|
||||
}
|
||||
|
||||
impl RuleCache {
|
||||
/// Creates an empty `RuleCache`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
map: FnvHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds a node in the properties matched cache.
|
||||
///
|
||||
/// This needs to receive a `StyleBuilder` with the `early` properties
|
||||
/// already applied.
|
||||
pub fn find(
|
||||
&self,
|
||||
builder_with_early_props: &StyleBuilder,
|
||||
) -> Option<&ComputedValues> {
|
||||
if builder_with_early_props.is_style_if_visited() {
|
||||
// FIXME(emilio): We can probably do better, does it matter much?
|
||||
return None;
|
||||
}
|
||||
|
||||
let rules = match builder_with_early_props.rules {
|
||||
Some(ref rules) => rules,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
self.map.get(rules).and_then(|cached_values| {
|
||||
for &(ref conditions, ref values) in cached_values.iter() {
|
||||
if conditions.matches(builder_with_early_props) {
|
||||
debug!("Using cached reset style with conditions {:?}", conditions);
|
||||
return Some(&**values)
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
/// Inserts a node into the rules cache if possible.
|
||||
///
|
||||
/// Returns whether the style was inserted into the cache.
|
||||
pub fn insert_if_possible(
|
||||
&mut self,
|
||||
style: &Arc<ComputedValues>,
|
||||
conditions: &RuleCacheConditions,
|
||||
) -> bool {
|
||||
if !conditions.cacheable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if style.is_style_if_visited() {
|
||||
// FIXME(emilio): We can probably do better, does it matter much?
|
||||
return false;
|
||||
}
|
||||
|
||||
let rules = match style.rules {
|
||||
Some(ref r) => r.clone(),
|
||||
None => return false,
|
||||
};
|
||||
|
||||
debug!("Inserting cached reset style with conditions {:?}", conditions);
|
||||
self.map
|
||||
.entry(rules)
|
||||
.or_insert_with(SmallVec::new)
|
||||
.push((conditions.clone(), style.clone()));
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
}
|
|
@ -819,7 +819,7 @@ struct WeakRuleNode {
|
|||
}
|
||||
|
||||
/// A strong reference to a rule node.
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
pub struct StrongRuleNode {
|
||||
p: NonZeroPtrMut<RuleNode>,
|
||||
}
|
||||
|
|
|
@ -13,7 +13,9 @@ use media_queries::MediaType;
|
|||
use parser::ParserContext;
|
||||
use properties::{ComputedValues, StyleBuilder};
|
||||
use properties::longhands::font_size;
|
||||
use rule_cache::RuleCacheConditions;
|
||||
use selectors::parser::SelectorParseError;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
|
||||
use style_traits::{CSSPixel, DevicePixel, ToCss, ParseError};
|
||||
|
@ -244,6 +246,7 @@ pub enum Range<T> {
|
|||
impl Range<specified::Length> {
|
||||
fn to_computed_range(&self, device: &Device, quirks_mode: QuirksMode) -> Range<Au> {
|
||||
let default_values = device.default_computed_values();
|
||||
let mut conditions = RuleCacheConditions::default();
|
||||
// http://dev.w3.org/csswg/mediaqueries3/#units
|
||||
// em units are relative to the initial font-size.
|
||||
let context = computed::Context {
|
||||
|
@ -257,6 +260,7 @@ impl Range<specified::Length> {
|
|||
cached_system_font: None,
|
||||
quirks_mode: quirks_mode,
|
||||
for_smil_animation: false,
|
||||
rule_cache_conditions: RefCell::new(&mut conditions),
|
||||
};
|
||||
|
||||
match *self {
|
||||
|
|
|
@ -574,6 +574,7 @@ where
|
|||
}
|
||||
|
||||
let implemented_pseudo = self.element.implemented_pseudo_element();
|
||||
let mut conditions = Default::default();
|
||||
let values =
|
||||
cascade(
|
||||
self.context.shared.stylist.device(),
|
||||
|
@ -587,8 +588,15 @@ where
|
|||
&self.context.thread_local.font_metrics_provider,
|
||||
cascade_flags,
|
||||
self.context.shared.quirks_mode(),
|
||||
Some(&self.context.thread_local.rule_cache),
|
||||
&mut conditions,
|
||||
);
|
||||
|
||||
self.context
|
||||
.thread_local
|
||||
.rule_cache
|
||||
.insert_if_possible(&values, &conditions);
|
||||
|
||||
values
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,12 @@ use font_metrics::get_metrics_provider_for_product;
|
|||
use media_queries::Device;
|
||||
use parser::{ParserContext, ParserErrorContext};
|
||||
use properties::StyleBuilder;
|
||||
use rule_cache::RuleCacheConditions;
|
||||
use selectors::parser::SelectorParseError;
|
||||
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
|
||||
use std::ascii::AsciiExt;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::iter::Enumerate;
|
||||
use std::str::Chars;
|
||||
|
@ -707,6 +709,7 @@ impl MaybeNew for ViewportConstraints {
|
|||
|
||||
let default_values = device.default_computed_values();
|
||||
|
||||
let mut conditions = RuleCacheConditions::default();
|
||||
let context = Context {
|
||||
is_root_element: false,
|
||||
builder: StyleBuilder::for_derived_style(device, default_values, None, None),
|
||||
|
@ -715,6 +718,7 @@ impl MaybeNew for ViewportConstraints {
|
|||
in_media_query: false,
|
||||
quirks_mode: quirks_mode,
|
||||
for_smil_animation: false,
|
||||
rule_cache_conditions: RefCell::new(&mut conditions),
|
||||
};
|
||||
|
||||
// DEVICE-ADAPT § 9.3 Resolving 'extend-to-zoom'
|
||||
|
|
|
@ -771,6 +771,8 @@ impl Stylist {
|
|||
font_metrics,
|
||||
cascade_flags,
|
||||
self.quirks_mode,
|
||||
/* rule_cache = */ None,
|
||||
&mut Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -987,6 +989,8 @@ impl Stylist {
|
|||
font_metrics,
|
||||
cascade_flags,
|
||||
self.quirks_mode,
|
||||
/* rule_cache = */ None,
|
||||
&mut Default::default(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
|
@ -1012,6 +1016,8 @@ impl Stylist {
|
|||
font_metrics,
|
||||
cascade_flags,
|
||||
self.quirks_mode,
|
||||
/* rule_cache = */ None,
|
||||
&mut Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1625,6 +1631,8 @@ impl Stylist {
|
|||
&metrics,
|
||||
CascadeFlags::empty(),
|
||||
self.quirks_mode,
|
||||
/* rule_cache = */ None,
|
||||
&mut Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,11 @@ use media_queries::Device;
|
|||
#[cfg(feature = "gecko")]
|
||||
use properties;
|
||||
use properties::{ComputedValues, StyleBuilder};
|
||||
use rule_cache::RuleCacheConditions;
|
||||
#[cfg(feature = "servo")]
|
||||
use servo_url::ServoUrl;
|
||||
use std::{f32, fmt};
|
||||
use std::cell::RefCell;
|
||||
#[cfg(feature = "servo")]
|
||||
use std::sync::Arc;
|
||||
use style_traits::ToCss;
|
||||
|
@ -116,6 +118,11 @@ pub struct Context<'a> {
|
|||
/// This is used to allow certain properties to generate out-of-range
|
||||
/// values, which SMIL allows.
|
||||
pub for_smil_animation: bool,
|
||||
|
||||
/// The conditions to cache a rule node on the rule cache.
|
||||
///
|
||||
/// FIXME(emilio): Drop the refcell.
|
||||
pub rule_cache_conditions: RefCell<&'a mut RuleCacheConditions>,
|
||||
}
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
|
|
|
@ -131,6 +131,12 @@ impl FontRelativeLength {
|
|||
|
||||
match *self {
|
||||
FontRelativeLength::Em(length) => {
|
||||
if !matches!(base_size, FontBaseSize::InheritedStyle) {
|
||||
context.rule_cache_conditions.borrow_mut()
|
||||
.set_font_size_dependency(
|
||||
reference_font_size.into()
|
||||
);
|
||||
}
|
||||
(reference_font_size, length)
|
||||
},
|
||||
FontRelativeLength::Ex(length) => {
|
||||
|
|
|
@ -9,6 +9,7 @@ use malloc_size_of::MallocSizeOfOps;
|
|||
use selectors::Element;
|
||||
use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
|
||||
use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
|
||||
use std::cell::RefCell;
|
||||
use std::env;
|
||||
use std::fmt::Write;
|
||||
use std::iter;
|
||||
|
@ -116,6 +117,7 @@ use style::properties::PROHIBIT_DISPLAY_CONTENTS;
|
|||
use style::properties::animated_properties::{AnimatableLonghand, AnimationValue};
|
||||
use style::properties::animated_properties::compare_property_priority;
|
||||
use style::properties::parse_one_declaration_into;
|
||||
use style::rule_cache::RuleCacheConditions;
|
||||
use style::rule_tree::{CascadeLevel, StyleSource};
|
||||
use style::selector_parser::PseudoElementCascadeType;
|
||||
use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked};
|
||||
|
@ -3186,6 +3188,7 @@ fn create_context<'a>(
|
|||
parent_style: Option<&'a ComputedValues>,
|
||||
pseudo: Option<&'a PseudoElement>,
|
||||
for_smil_animation: bool,
|
||||
rule_cache_conditions: &'a mut RuleCacheConditions,
|
||||
) -> Context<'a> {
|
||||
Context {
|
||||
is_root_element: false,
|
||||
|
@ -3200,6 +3203,7 @@ fn create_context<'a>(
|
|||
in_media_query: false,
|
||||
quirks_mode: per_doc_data.stylist.quirks_mode(),
|
||||
for_smil_animation,
|
||||
rule_cache_conditions: RefCell::new(rule_cache_conditions),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3269,6 +3273,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis
|
|||
let parent_style = parent_data.as_ref().map(|d| d.styles.primary()).map(|x| &**x);
|
||||
|
||||
let pseudo = style.pseudo();
|
||||
let mut conditions = Default::default();
|
||||
let mut context = create_context(
|
||||
&data,
|
||||
&metrics,
|
||||
|
@ -3276,6 +3281,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis
|
|||
parent_style,
|
||||
pseudo.as_ref(),
|
||||
/* for_smil_animation = */ false,
|
||||
&mut conditions,
|
||||
);
|
||||
|
||||
let global_style_data = &*GLOBAL_STYLE_DATA;
|
||||
|
@ -3356,13 +3362,15 @@ pub extern "C" fn Servo_GetAnimationValues(declarations: RawServoDeclarationBloc
|
|||
let parent_style = parent_data.as_ref().map(|d| d.styles.primary()).map(|x| &**x);
|
||||
|
||||
let pseudo = style.pseudo();
|
||||
let mut conditions = Default::default();
|
||||
let mut context = create_context(
|
||||
&data,
|
||||
&metrics,
|
||||
&style,
|
||||
parent_style,
|
||||
pseudo.as_ref(),
|
||||
/* for_smil_animation = */ true
|
||||
/* for_smil_animation = */ true,
|
||||
&mut conditions,
|
||||
);
|
||||
|
||||
let default_values = data.default_computed_values();
|
||||
|
@ -3392,13 +3400,15 @@ pub extern "C" fn Servo_AnimationValue_Compute(element: RawGeckoElementBorrowed,
|
|||
let parent_style = parent_data.as_ref().map(|d| d.styles.primary()).map(|x| &**x);
|
||||
|
||||
let pseudo = style.pseudo();
|
||||
let mut conditions = Default::default();
|
||||
let mut context = create_context(
|
||||
&data,
|
||||
&metrics,
|
||||
style,
|
||||
parent_style,
|
||||
pseudo.as_ref(),
|
||||
/* for_smil_animation = */ false
|
||||
/* for_smil_animation = */ false,
|
||||
&mut conditions,
|
||||
);
|
||||
|
||||
let default_values = data.default_computed_values();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue