зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #18499 - style: add a TLS-based cache of reset style structs (from heycam:rule-cache); r=emilio
Rule cache <!-- Please describe your changes on the following line: --> This adds a TLS-based cache reset styles structs keyed off rule nodes. Reviewed in https://bugzilla.mozilla.org/show_bug.cgi?id=1367635 by me and Emilio. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 874cb0d9df44e62a78d427f22f234a13227d07f8 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 94d8df7014ae82e639bb93f209eea4605f7d8964
This commit is contained in:
Родитель
e595bb6c11
Коммит
e1fb3d1ec0
|
@ -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,8 @@ impl Expression {
|
|||
// TODO: pass the correct value here.
|
||||
quirks_mode: quirks_mode,
|
||||
for_smil_animation: false,
|
||||
for_non_inherited_property: None,
|
||||
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
|
||||
|
|
|
@ -316,6 +316,13 @@
|
|||
_ => panic!("entered the wrong cascade_property() implementation"),
|
||||
};
|
||||
|
||||
context.for_non_inherited_property =
|
||||
% if property.style_struct.inherited:
|
||||
None;
|
||||
% else:
|
||||
Some(LonghandId::${property.camel_case});
|
||||
% endif
|
||||
|
||||
% if not property.derived_from:
|
||||
match value {
|
||||
DeclaredValue::Value(specified_value) => {
|
||||
|
@ -324,6 +331,10 @@
|
|||
longhands::system_font::resolve_system_font(sf, context);
|
||||
}
|
||||
% endif
|
||||
% if not property.style_struct.inherited and 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
|
||||
|
@ -375,6 +386,9 @@
|
|||
CSSWideKeyword::Unset |
|
||||
% endif
|
||||
CSSWideKeyword::Inherit => {
|
||||
% if not property.style_struct.inherited:
|
||||
context.rule_cache_conditions.borrow_mut().set_uncacheable();
|
||||
% endif
|
||||
% if property.ident == "font_size":
|
||||
longhands::font_size::cascade_inherit_font_size(context);
|
||||
% else:
|
||||
|
|
|
@ -226,10 +226,24 @@ ${helpers.single_keyword("position", "static absolute relative fixed sticky",
|
|||
let ltr = context.style().writing_mode.is_bidi_ltr();
|
||||
// https://drafts.csswg.org/css-logical-props/#float-clear
|
||||
match *self {
|
||||
SpecifiedValue::inline_start if ltr => computed_value::T::left,
|
||||
SpecifiedValue::inline_start => computed_value::T::right,
|
||||
SpecifiedValue::inline_end if ltr => computed_value::T::right,
|
||||
SpecifiedValue::inline_end => computed_value::T::left,
|
||||
SpecifiedValue::inline_start => {
|
||||
context.rule_cache_conditions.borrow_mut()
|
||||
.set_writing_mode_dependency(context.builder.writing_mode);
|
||||
if ltr {
|
||||
computed_value::T::left
|
||||
} else {
|
||||
computed_value::T::right
|
||||
}
|
||||
}
|
||||
SpecifiedValue::inline_end => {
|
||||
context.rule_cache_conditions.borrow_mut()
|
||||
.set_writing_mode_dependency(context.builder.writing_mode);
|
||||
if ltr {
|
||||
computed_value::T::right
|
||||
} else {
|
||||
computed_value::T::left
|
||||
}
|
||||
}
|
||||
% for value in "none left right".split():
|
||||
SpecifiedValue::${value} => computed_value::T::${value},
|
||||
% endfor
|
||||
|
@ -264,10 +278,24 @@ ${helpers.single_keyword("position", "static absolute relative fixed sticky",
|
|||
let ltr = context.style().writing_mode.is_bidi_ltr();
|
||||
// https://drafts.csswg.org/css-logical-props/#float-clear
|
||||
match *self {
|
||||
SpecifiedValue::inline_start if ltr => computed_value::T::left,
|
||||
SpecifiedValue::inline_start => computed_value::T::right,
|
||||
SpecifiedValue::inline_end if ltr => computed_value::T::right,
|
||||
SpecifiedValue::inline_end => computed_value::T::left,
|
||||
SpecifiedValue::inline_start => {
|
||||
context.rule_cache_conditions.borrow_mut()
|
||||
.set_writing_mode_dependency(context.builder.writing_mode);
|
||||
if ltr {
|
||||
computed_value::T::left
|
||||
} else {
|
||||
computed_value::T::right
|
||||
}
|
||||
}
|
||||
SpecifiedValue::inline_end => {
|
||||
context.rule_cache_conditions.borrow_mut()
|
||||
.set_writing_mode_dependency(context.builder.writing_mode);
|
||||
if ltr {
|
||||
computed_value::T::right
|
||||
} else {
|
||||
computed_value::T::left
|
||||
}
|
||||
}
|
||||
% for value in "none left right both".split():
|
||||
SpecifiedValue::${value} => computed_value::T::${value},
|
||||
% endfor
|
||||
|
|
|
@ -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;
|
||||
|
@ -33,6 +34,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;
|
||||
|
@ -45,7 +47,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;
|
||||
|
||||
|
@ -625,6 +627,36 @@ impl LonghandId {
|
|||
LonghandId::Direction
|
||||
)
|
||||
}
|
||||
|
||||
/// Whether computed values of this property lossily convert any complex
|
||||
/// colors into RGBA colors.
|
||||
///
|
||||
/// In Gecko, there are some properties still that compute currentcolor
|
||||
/// down to an RGBA color at computed value time, instead of as
|
||||
/// `StyleComplexColor`s. For these properties, we must return `false`,
|
||||
/// so that we correctly avoid caching style data in the rule tree.
|
||||
pub fn stores_complex_colors_lossily(&self) -> bool {
|
||||
% if product == "gecko":
|
||||
matches!(*self,
|
||||
% for property in data.longhands:
|
||||
% if property.predefined_type == "RGBAColor":
|
||||
LonghandId::${property.camel_case} |
|
||||
% endif
|
||||
% endfor
|
||||
LonghandId::BackgroundImage |
|
||||
LonghandId::BorderImageSource |
|
||||
LonghandId::BoxShadow |
|
||||
LonghandId::MaskImage |
|
||||
LonghandId::MozBorderBottomColors |
|
||||
LonghandId::MozBorderLeftColors |
|
||||
LonghandId::MozBorderRightColors |
|
||||
LonghandId::MozBorderTopColors |
|
||||
LonghandId::TextShadow
|
||||
)
|
||||
% else:
|
||||
false
|
||||
% endif
|
||||
}
|
||||
}
|
||||
|
||||
/// An identifier for a given shorthand property.
|
||||
|
@ -2142,6 +2174,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.
|
||||
|
@ -2544,12 +2581,17 @@ 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>>,
|
||||
|
||||
/// The pseudo-element this style will represent.
|
||||
pseudo: Option<<&'a PseudoElement>,
|
||||
pub pseudo: Option<<&'a PseudoElement>,
|
||||
|
||||
/// Whether we have mutated any reset structs since the the last time
|
||||
/// `clear_modified_reset` was called. This is used to tell whether the
|
||||
/// `StyleAdjuster` did any work.
|
||||
modified_reset: bool,
|
||||
|
||||
/// The writing mode flags.
|
||||
///
|
||||
|
@ -2580,7 +2622,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());
|
||||
|
@ -2602,6 +2644,10 @@ impl<'a> StyleBuilder<'a> {
|
|||
reset_style
|
||||
};
|
||||
|
||||
if cascade_flags.contains(VISITED_DEPENDENT_ONLY) {
|
||||
flags.insert(IS_STYLE_IF_VISITED);
|
||||
}
|
||||
|
||||
StyleBuilder {
|
||||
device,
|
||||
parent_style,
|
||||
|
@ -2610,6 +2656,7 @@ impl<'a> StyleBuilder<'a> {
|
|||
reset_style,
|
||||
pseudo,
|
||||
rules,
|
||||
modified_reset: false,
|
||||
custom_properties,
|
||||
writing_mode,
|
||||
font_size_keyword,
|
||||
|
@ -2625,6 +2672,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(
|
||||
|
@ -2646,6 +2698,7 @@ impl<'a> StyleBuilder<'a> {
|
|||
inherited_style_ignoring_first_line: inherited_style,
|
||||
reset_style,
|
||||
pseudo,
|
||||
modified_reset: false,
|
||||
rules: None, // FIXME(emilio): Dubious...
|
||||
custom_properties: style_to_derive_from.custom_properties(),
|
||||
writing_mode: style_to_derive_from.writing_mode,
|
||||
|
@ -2660,6 +2713,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.
|
||||
|
@ -2669,11 +2732,13 @@ 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:
|
||||
self.flags.insert(::properties::computed_value_flags::INHERITS_RESET_STYLE);
|
||||
self.modified_reset = true;
|
||||
% endif
|
||||
|
||||
% if property.ident == "content":
|
||||
|
@ -2699,6 +2764,10 @@ impl<'a> StyleBuilder<'a> {
|
|||
let reset_struct =
|
||||
self.reset_style.get_${property.style_struct.name_lower}();
|
||||
|
||||
% if not property.style_struct.inherited:
|
||||
self.modified_reset = true;
|
||||
% endif
|
||||
|
||||
self.${property.style_struct.ident}.mutate()
|
||||
.reset_${property.ident}(
|
||||
reset_struct,
|
||||
|
@ -2715,6 +2784,10 @@ impl<'a> StyleBuilder<'a> {
|
|||
&mut self,
|
||||
value: longhands::${property.ident}::computed_value::T
|
||||
) {
|
||||
% if not property.style_struct.inherited:
|
||||
self.modified_reset = true;
|
||||
% endif
|
||||
|
||||
<% props_need_device = ["content", "list_style_type", "font_variant_alternates"] %>
|
||||
self.${property.style_struct.ident}.mutate()
|
||||
.set_${property.ident}(
|
||||
|
@ -2778,11 +2851,17 @@ impl<'a> StyleBuilder<'a> {
|
|||
|
||||
/// Gets a mutable view of the current `${style_struct.name}` style.
|
||||
pub fn mutate_${style_struct.name_lower}(&mut self) -> &mut style_structs::${style_struct.name} {
|
||||
% if not property.style_struct.inherited:
|
||||
self.modified_reset = true;
|
||||
% endif
|
||||
self.${style_struct.ident}.mutate()
|
||||
}
|
||||
|
||||
/// Gets a mutable view of the current `${style_struct.name}` style.
|
||||
pub fn take_${style_struct.name_lower}(&mut self) -> UniqueArc<style_structs::${style_struct.name}> {
|
||||
% if not property.style_struct.inherited:
|
||||
self.modified_reset = true;
|
||||
% endif
|
||||
self.${style_struct.ident}.take()
|
||||
}
|
||||
|
||||
|
@ -2831,6 +2910,16 @@ impl<'a> StyleBuilder<'a> {
|
|||
longhands::_moz_top_layer::computed_value::T::top)
|
||||
}
|
||||
|
||||
/// Clears the "have any reset structs been modified" flag.
|
||||
fn clear_modified_reset(&mut self) {
|
||||
self.modified_reset = false;
|
||||
}
|
||||
|
||||
/// Returns whether we have mutated any reset structs since the the last
|
||||
/// time `clear_modified_reset` was called.
|
||||
fn modified_reset(&self) -> bool {
|
||||
self.modified_reset
|
||||
}
|
||||
|
||||
/// Turns this `StyleBuilder` into a proper `ComputedValues` instance.
|
||||
pub fn build(self) -> Arc<ComputedValues> {
|
||||
|
@ -3015,7 +3104,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")]
|
||||
|
@ -3075,6 +3166,8 @@ pub fn cascade(
|
|||
font_metrics_provider,
|
||||
flags,
|
||||
quirks_mode,
|
||||
rule_cache,
|
||||
rule_cache_conditions,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -3093,6 +3186,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,
|
||||
|
@ -3149,11 +3244,13 @@ 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,
|
||||
for_non_inherited_property: None,
|
||||
font_metrics_provider,
|
||||
quirks_mode,
|
||||
rule_cache_conditions: RefCell::new(rule_cache_conditions),
|
||||
};
|
||||
|
||||
let ignore_colors = !device.use_document_colors();
|
||||
|
@ -3176,6 +3273,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
|
||||
|
@ -3186,6 +3284,10 @@ where
|
|||
for (declaration, cascade_level) in iter_declarations() {
|
||||
let mut declaration = match *declaration {
|
||||
PropertyDeclaration::WithVariables(id, ref unparsed) => {
|
||||
if !id.inherited() {
|
||||
context.rule_cache_conditions.borrow_mut()
|
||||
.set_uncacheable();
|
||||
}
|
||||
Cow::Owned(unparsed.substitute_variables(
|
||||
id,
|
||||
&context.builder.custom_properties,
|
||||
|
@ -3208,6 +3310,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.
|
||||
|
@ -3375,16 +3481,16 @@ 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;
|
||||
|
||||
{
|
||||
StyleAdjuster::new(&mut builder)
|
||||
.adjust(layout_parent_style, flags);
|
||||
}
|
||||
|
||||
% if product == "gecko":
|
||||
if let Some(ref mut bg) = builder.get_background_if_mutated() {
|
||||
bg.fill_arrays();
|
||||
|
@ -3404,6 +3510,22 @@ where
|
|||
}
|
||||
% endif
|
||||
|
||||
builder.clear_modified_reset();
|
||||
|
||||
StyleAdjuster::new(&mut builder)
|
||||
.adjust(layout_parent_style, flags);
|
||||
|
||||
if builder.modified_reset() || !apply_reset {
|
||||
// If we adjusted any reset structs, we can't cache this ComputedValues.
|
||||
//
|
||||
// Also, if we re-used existing reset structs, don't bother caching it
|
||||
// back again. (Aside from being wasted effort, it will be wrong, since
|
||||
// context.rule_cache_conditions won't be set appropriately if we
|
||||
// didn't compute those reset properties.)
|
||||
context.rule_cache_conditions.borrow_mut()
|
||||
.set_uncacheable();
|
||||
}
|
||||
|
||||
builder.build()
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/* 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 selector_parser::PseudoElement;
|
||||
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;
|
||||
}
|
||||
|
||||
// A pseudo-element with property restrictions can result in different
|
||||
// computed values if it's also used for a non-pseudo.
|
||||
if builder_with_early_props.pseudo
|
||||
.and_then(|p| p.property_restriction())
|
||||
.is_some() {
|
||||
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>,
|
||||
pseudo: Option<&PseudoElement>,
|
||||
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;
|
||||
}
|
||||
|
||||
// A pseudo-element with property restrictions can result in different
|
||||
// computed values if it's also used for a non-pseudo.
|
||||
if pseudo.and_then(|p| p.property_restriction()).is_some() {
|
||||
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,8 @@ impl Range<specified::Length> {
|
|||
cached_system_font: None,
|
||||
quirks_mode: quirks_mode,
|
||||
for_smil_animation: false,
|
||||
for_non_inherited_property: None,
|
||||
rule_cache_conditions: RefCell::new(&mut conditions),
|
||||
};
|
||||
|
||||
match *self {
|
||||
|
|
|
@ -574,10 +574,13 @@ where
|
|||
}
|
||||
|
||||
let implemented_pseudo = self.element.implemented_pseudo_element();
|
||||
let pseudo = pseudo.or(implemented_pseudo.as_ref());
|
||||
|
||||
let mut conditions = Default::default();
|
||||
let values =
|
||||
cascade(
|
||||
self.context.shared.stylist.device(),
|
||||
pseudo.or(implemented_pseudo.as_ref()),
|
||||
pseudo,
|
||||
rules.unwrap_or(self.context.shared.stylist.rule_tree().root()),
|
||||
&self.context.shared.guards,
|
||||
parent_style,
|
||||
|
@ -587,8 +590,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, pseudo, &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,8 @@ impl MaybeNew for ViewportConstraints {
|
|||
in_media_query: false,
|
||||
quirks_mode: quirks_mode,
|
||||
for_smil_animation: false,
|
||||
for_non_inherited_property: None,
|
||||
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(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -866,6 +866,10 @@ impl ToComputedValue for specified::MozLength {
|
|||
MozLength::LengthOrPercentageOrAuto(lopoa.to_computed_value(context))
|
||||
}
|
||||
specified::MozLength::ExtremumLength(ref ext) => {
|
||||
debug_assert!(context.for_non_inherited_property.is_some(),
|
||||
"should check whether we're a non-inherited property");
|
||||
context.rule_cache_conditions.borrow_mut()
|
||||
.set_writing_mode_dependency(context.builder.writing_mode);
|
||||
MozLength::ExtremumLength(ext.clone())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,12 @@ use font_metrics::FontMetricsProvider;
|
|||
use media_queries::Device;
|
||||
#[cfg(feature = "gecko")]
|
||||
use properties;
|
||||
use properties::{ComputedValues, StyleBuilder};
|
||||
use properties::{ComputedValues, LonghandId, 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,17 @@ 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 property we are computing a value for, if it is a non-inherited
|
||||
/// property. None if we are computed a value for an inherited property
|
||||
/// or not computing for a property at all (e.g. in a media query
|
||||
/// evaluation).
|
||||
pub for_non_inherited_property: Option<LonghandId>,
|
||||
|
||||
/// 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> {
|
||||
|
|
|
@ -249,18 +249,36 @@ fn convert_nscolor_to_computedcolor(color: nscolor) -> ComputedColor {
|
|||
impl ToComputedValue for Color {
|
||||
type ComputedValue = ComputedColor;
|
||||
|
||||
fn to_computed_value(&self, _context: &Context) -> ComputedColor {
|
||||
fn to_computed_value(&self, context: &Context) -> ComputedColor {
|
||||
match *self {
|
||||
Color::CurrentColor => ComputedColor::currentcolor(),
|
||||
Color::CurrentColor => {
|
||||
if let Some(longhand) = context.for_non_inherited_property {
|
||||
if longhand.stores_complex_colors_lossily() {
|
||||
context.rule_cache_conditions.borrow_mut()
|
||||
.set_uncacheable();
|
||||
}
|
||||
}
|
||||
ComputedColor::currentcolor()
|
||||
}
|
||||
Color::Numeric { ref parsed, .. } => ComputedColor::rgba(*parsed),
|
||||
Color::Complex(ref complex) => *complex,
|
||||
Color::Complex(ref complex) => {
|
||||
if complex.foreground_ratio != 0 {
|
||||
if let Some(longhand) = context.for_non_inherited_property {
|
||||
if longhand.stores_complex_colors_lossily() {
|
||||
context.rule_cache_conditions.borrow_mut()
|
||||
.set_uncacheable();
|
||||
}
|
||||
}
|
||||
}
|
||||
*complex
|
||||
}
|
||||
#[cfg(feature = "gecko")]
|
||||
Color::System(system) =>
|
||||
convert_nscolor_to_computedcolor(system.to_computed_value(_context)),
|
||||
convert_nscolor_to_computedcolor(system.to_computed_value(context)),
|
||||
#[cfg(feature = "gecko")]
|
||||
Color::Special(special) => {
|
||||
use self::gecko::SpecialColorKeyword as Keyword;
|
||||
let pres_context = _context.device().pres_context();
|
||||
let pres_context = context.device().pres_context();
|
||||
convert_nscolor_to_computedcolor(match special {
|
||||
Keyword::MozDefaultColor => pres_context.mDefaultColor,
|
||||
Keyword::MozDefaultBackgroundColor => pres_context.mBackgroundColor,
|
||||
|
@ -274,7 +292,7 @@ impl ToComputedValue for Color {
|
|||
use dom::TElement;
|
||||
use gecko::wrapper::GeckoElement;
|
||||
use gecko_bindings::bindings::Gecko_GetBody;
|
||||
let pres_context = _context.device().pres_context();
|
||||
let pres_context = context.device().pres_context();
|
||||
let body = unsafe { Gecko_GetBody(pres_context) }.map(GeckoElement);
|
||||
let data = body.as_ref().and_then(|wrap| wrap.borrow_data());
|
||||
if let Some(data) = data {
|
||||
|
|
|
@ -132,9 +132,18 @@ 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) => {
|
||||
if context.for_non_inherited_property.is_some() {
|
||||
context.rule_cache_conditions.borrow_mut().set_uncacheable();
|
||||
}
|
||||
let reference_size = match query_font_metrics(context, reference_font_size) {
|
||||
FontMetricsQueryResult::Available(metrics) => {
|
||||
metrics.x_height
|
||||
|
@ -152,6 +161,9 @@ impl FontRelativeLength {
|
|||
(reference_size, length)
|
||||
},
|
||||
FontRelativeLength::Ch(length) => {
|
||||
if context.for_non_inherited_property.is_some() {
|
||||
context.rule_cache_conditions.borrow_mut().set_uncacheable();
|
||||
}
|
||||
let reference_size = match query_font_metrics(context, reference_font_size) {
|
||||
FontMetricsQueryResult::Available(metrics) => {
|
||||
metrics.zero_advance_measure
|
||||
|
|
|
@ -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,8 @@ fn create_context<'a>(
|
|||
in_media_query: false,
|
||||
quirks_mode: per_doc_data.stylist.quirks_mode(),
|
||||
for_smil_animation,
|
||||
for_non_inherited_property: None,
|
||||
rule_cache_conditions: RefCell::new(rule_cache_conditions),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3269,6 +3274,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 +3282,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 +3363,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 +3401,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();
|
||||
|
|
Загрузка…
Ссылка в новой задаче