Move match and cascade temporaries to CurrentElementInfo

Before this change, the `ComputedStyle` struct that is part of permanent style
data per element holds 2 `StrongRuleNode`s (unvisited and visited) and 2
`Arc<ComputedValues>` (unvisited and visited).

Both rule nodes and the visited values don't actually need to be here.  This
patch moves these 3 to new temporary storage in `CascadeInputs` on
`CurrentElementInfo` during the match and cascade process.  Rule nodes are
pushed down inside the `ComputedValues` for later access after the cascade.
(Visited values were already available there.)

The permanent style data per element now has just the `Arc<ComputedValues>` for
itself and eager pseudo-elements (plus the `RestyleHint`).

MozReview-Commit-ID: 3wq52ERMpdi
This commit is contained in:
J. Ryan Stinnett 2017-06-13 12:51:37 -05:00
parent c3b2a2f4de
commit 2b5c56e6a8
19 changed files with 738 additions and 746 deletions

View file

@ -9,8 +9,8 @@
use applicable_declarations::ApplicableDeclarationList;
use cascade_info::CascadeInfo;
use context::{SelectorFlagsMap, SharedStyleContext, StyleContext};
use data::{ComputedStyle, ElementData, RestyleData};
use context::{CascadeInputs, SelectorFlagsMap, SharedStyleContext, StyleContext};
use data::{ElementData, ElementStyles, RestyleData};
use dom::{TElement, TNode};
use font_metrics::FontMetricsProvider;
use invalidation::element::restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_CSS_TRANSITIONS};
@ -146,55 +146,98 @@ pub enum CascadeVisitedMode {
/// depending on the current cascade mode.
impl CascadeVisitedMode {
/// Returns whether there is a rule node based on the cascade mode.
fn has_rules(&self, style: &ComputedStyle) -> bool {
/// Rules will be present after matching or pulled from a previous cascade
/// if no matching is expected. For visited, this means rules exist only
/// if a revelant link existed when matching was last done.
fn has_rules(&self, inputs: &CascadeInputs) -> bool {
match *self {
CascadeVisitedMode::Unvisited => true,
CascadeVisitedMode::Visited => style.has_visited_rules(),
CascadeVisitedMode::Unvisited => inputs.has_rules(),
CascadeVisitedMode::Visited => inputs.has_visited_rules(),
}
}
/// Returns the rule node based on the cascade mode.
fn rules<'a>(&self, style: &'a ComputedStyle) -> &'a StrongRuleNode {
fn rules<'a>(&self, inputs: &'a CascadeInputs) -> &'a StrongRuleNode {
match *self {
CascadeVisitedMode::Unvisited => &style.rules,
CascadeVisitedMode::Visited => style.visited_rules(),
CascadeVisitedMode::Unvisited => inputs.rules(),
CascadeVisitedMode::Visited => inputs.visited_rules(),
}
}
/// Returns a mutable rules node based on the cascade mode, if any.
fn get_rules_mut<'a>(&self, style: &'a mut ComputedStyle) -> Option<&'a mut StrongRuleNode> {
fn get_rules_mut<'a>(&self, inputs: &'a mut CascadeInputs) -> Option<&'a mut StrongRuleNode> {
match *self {
CascadeVisitedMode::Unvisited => Some(&mut style.rules),
CascadeVisitedMode::Visited => style.get_visited_rules_mut(),
CascadeVisitedMode::Unvisited => inputs.get_rules_mut(),
CascadeVisitedMode::Visited => inputs.get_visited_rules_mut(),
}
}
/// Returns the computed values based on the cascade mode. In visited mode,
/// visited values are only returned if they already exist. If they don't,
/// we fallback to the regular, unvisited styles.
fn values<'a>(&self, style: &'a ComputedStyle) -> &'a Arc<ComputedValues> {
let mut values = style.values();
fn values<'a>(&self, values: &'a Arc<ComputedValues>) -> &'a Arc<ComputedValues> {
if *self == CascadeVisitedMode::Visited && values.get_visited_style().is_some() {
values = values.visited_style();
return values.visited_style();
}
values
}
/// Set the computed values based on the cascade mode.
fn set_values(&self, style: &mut ComputedStyle, values: Arc<ComputedValues>) {
/// Set the primary computed values based on the cascade mode.
fn set_primary_values(&self,
styles: &mut ElementStyles,
inputs: &mut CascadeInputs,
values: Arc<ComputedValues>) {
// Unvisited values are stored in permanent storage on `ElementData`.
// Visited values are stored temporarily in `CascadeInputs` and then
// folded into the unvisited values when they cascade.
match *self {
CascadeVisitedMode::Unvisited => style.values = Some(values),
CascadeVisitedMode::Visited => style.set_visited_values(values),
CascadeVisitedMode::Unvisited => styles.primary = Some(values),
CascadeVisitedMode::Visited => inputs.set_visited_values(values),
}
}
/// Take the computed values based on the cascade mode.
fn take_values(&self, style: &mut ComputedStyle) -> Option<Arc<ComputedValues>> {
/// Set the primary computed values based on the cascade mode.
fn set_pseudo_values(&self,
styles: &mut ElementStyles,
inputs: &mut CascadeInputs,
pseudo: &PseudoElement,
values: Arc<ComputedValues>) {
// Unvisited values are stored in permanent storage on `ElementData`.
// Visited values are stored temporarily in `CascadeInputs` and then
// folded into the unvisited values when they cascade.
match *self {
CascadeVisitedMode::Unvisited => style.values.take(),
CascadeVisitedMode::Visited => style.take_visited_values(),
CascadeVisitedMode::Unvisited => styles.pseudos.set(pseudo, values),
CascadeVisitedMode::Visited => inputs.set_visited_values(values),
}
}
/// Take the primary computed values based on the cascade mode.
fn take_primary_values(&self,
styles: &mut ElementStyles,
inputs: &mut CascadeInputs)
-> Option<Arc<ComputedValues>> {
// Unvisited values are stored in permanent storage on `ElementData`.
// Visited values are stored temporarily in `CascadeInputs` and then
// folded into the unvisited values when they cascade.
match *self {
CascadeVisitedMode::Unvisited => styles.primary.take(),
CascadeVisitedMode::Visited => inputs.take_visited_values(),
}
}
/// Take the pseudo computed values based on the cascade mode.
fn take_pseudo_values(&self,
styles: &mut ElementStyles,
inputs: &mut CascadeInputs,
pseudo: &PseudoElement)
-> Option<Arc<ComputedValues>> {
// Unvisited values are stored in permanent storage on `ElementData`.
// Visited values are stored temporarily in `CascadeInputs` and then
// folded into the unvisited values when they cascade.
match *self {
CascadeVisitedMode::Unvisited => styles.pseudos.take(pseudo),
CascadeVisitedMode::Visited => inputs.take_visited_values(),
}
}
@ -246,7 +289,7 @@ trait PrivateMatchMethods: TElement {
};
let is_display_contents =
current.borrow_data().unwrap().styles().primary.values().is_display_contents();
current.borrow_data().unwrap().styles.primary().is_display_contents();
if !is_display_contents {
return current;
@ -254,11 +297,15 @@ trait PrivateMatchMethods: TElement {
}
}
/// A common path for the cascade used by both primary elements and eager
/// pseudo-elements after collecting the appropriate rules to use.
///
/// `primary_style` is expected to be Some for eager pseudo-elements.
fn cascade_with_rules(&self,
shared_context: &SharedStyleContext,
font_metrics_provider: &FontMetricsProvider,
rule_node: &StrongRuleNode,
primary_style: &ComputedStyle,
primary_style: Option<&Arc<ComputedValues>>,
cascade_target: CascadeTarget,
cascade_visited: CascadeVisitedMode,
visited_values_to_insert: Option<Arc<ComputedValues>>)
@ -294,13 +341,13 @@ trait PrivateMatchMethods: TElement {
// but not wanting to flush all of layout).
debug_assert!(cfg!(feature = "gecko") ||
parent_el.unwrap().has_current_styles(d));
&d.styles().primary
d.styles.primary()
});
parent_style.map(|s| cascade_visited.values(s))
}
CascadeTarget::EagerPseudo => {
parent_el = Some(self.clone());
Some(cascade_visited.values(primary_style))
Some(cascade_visited.values(primary_style.unwrap()))
}
};
@ -310,7 +357,7 @@ trait PrivateMatchMethods: TElement {
if style_to_inherit_from.map_or(false, |s| s.is_display_contents()) {
layout_parent_el = Some(layout_parent_el.unwrap().layout_parent());
layout_parent_data = layout_parent_el.as_ref().unwrap().borrow_data().unwrap();
layout_parent_style = Some(cascade_visited.values(&layout_parent_data.styles().primary));
layout_parent_style = Some(cascade_visited.values(layout_parent_data.styles.primary()));
}
let style_to_inherit_from = style_to_inherit_from.map(|x| &**x);
@ -349,14 +396,19 @@ trait PrivateMatchMethods: TElement {
values
}
/// A common path for the cascade used by both primary elements and eager
/// pseudo-elements.
///
/// `primary_style` is expected to be Some for eager pseudo-elements.
fn cascade_internal(&self,
context: &StyleContext<Self>,
primary_style: &ComputedStyle,
eager_pseudo_style: Option<&ComputedStyle>,
primary_style: Option<&Arc<ComputedValues>>,
primary_inputs: &CascadeInputs,
eager_pseudo_inputs: Option<&CascadeInputs>,
cascade_visited: CascadeVisitedMode)
-> Arc<ComputedValues> {
if let Some(pseudo) = self.implemented_pseudo_element() {
debug_assert!(eager_pseudo_style.is_none());
debug_assert!(eager_pseudo_inputs.is_none());
// This is an element-backed pseudo, just grab the styles from the
// parent if it's eager, and recascade otherwise.
@ -377,10 +429,10 @@ trait PrivateMatchMethods: TElement {
debug_assert!(pseudo.is_before_or_after());
let parent = self.parent_element().unwrap();
if !parent.may_have_animations() ||
primary_style.rules.get_animation_rules().is_empty() {
primary_inputs.rules().get_animation_rules().is_empty() {
let parent_data = parent.borrow_data().unwrap();
let pseudo_style =
parent_data.styles().pseudos.get(&pseudo).unwrap();
parent_data.styles.pseudos.get(&pseudo).unwrap();
let values = cascade_visited.values(pseudo_style);
return values.clone()
}
@ -390,18 +442,21 @@ trait PrivateMatchMethods: TElement {
// Find possible visited computed styles to insert within the regular
// computed values we are about to create.
let visited_values_to_insert = if cascade_visited.visited_values_for_insertion() {
match eager_pseudo_style {
match eager_pseudo_inputs {
Some(ref s) => s.clone_visited_values(),
None => primary_style.clone_visited_values(),
None => primary_inputs.clone_visited_values(),
}
} else {
None
};
// Grab the rule node.
let style = eager_pseudo_style.unwrap_or(primary_style);
let rule_node = cascade_visited.rules(style);
let cascade_target = if eager_pseudo_style.is_some() {
let inputs = eager_pseudo_inputs.unwrap_or(primary_inputs);
// We'd really like to take the rules here to avoid refcount traffic,
// but animation's usage of `apply_declarations` make this tricky.
// See bug 1375525.
let rule_node = cascade_visited.rules(inputs);
let cascade_target = if eager_pseudo_inputs.is_some() {
CascadeTarget::EagerPseudo
} else {
CascadeTarget::Normal
@ -426,23 +481,30 @@ trait PrivateMatchMethods: TElement {
-> ChildCascadeRequirement {
debug!("Cascade primary for {:?}, visited: {:?}", self, cascade_visited);
// Collect some values.
let (mut styles, restyle) = data.styles_and_restyle_mut();
let mut primary_style = &mut styles.primary;
// If there was no relevant link, we won't have any visited rules, so
// there may not be anything do for the visited case. This early return
// is especially important for the `cascade_primary_and_pseudos` path
// since we rely on the state of some previous matching run.
if !cascade_visited.has_rules(primary_style) {
return ChildCascadeRequirement::CanSkipCascade
}
let mut old_values = cascade_visited.take_values(primary_style);
let mut old_values = cascade_visited.take_primary_values(
&mut data.styles,
context.cascade_inputs_mut().primary_mut()
);
// Compute the new values.
let mut new_values = self.cascade_internal(context,
primary_style,
None,
cascade_visited);
let mut new_values = {
let primary_inputs = context.cascade_inputs().primary();
// If there was no relevant link at the time of matching, we won't
// have any visited rules, so there may not be anything do for the
// visited case. This early return is especially important for the
// `cascade_primary_and_pseudos` path since we rely on the state of
// some previous matching run.
if !cascade_visited.has_rules(primary_inputs) {
return ChildCascadeRequirement::CanSkipCascade
}
// Compute the new values.
self.cascade_internal(context,
None,
primary_inputs,
None,
cascade_visited)
};
// NB: Animations for pseudo-elements in Gecko are handled while
// traversing the pseudo-elements themselves.
@ -451,7 +513,6 @@ trait PrivateMatchMethods: TElement {
self.process_animations(context,
&mut old_values,
&mut new_values,
primary_style,
important_rules_changed);
}
@ -460,7 +521,7 @@ trait PrivateMatchMethods: TElement {
if cascade_visited.should_accumulate_damage() {
child_cascade_requirement =
self.accumulate_damage(&context.shared,
restyle,
&mut data.restyle,
old_values.as_ref().map(|v| v.as_ref()),
&new_values,
None);
@ -483,7 +544,10 @@ trait PrivateMatchMethods: TElement {
}
// Set the new computed values.
cascade_visited.set_values(primary_style, new_values);
let primary_inputs = context.cascade_inputs_mut().primary_mut();
cascade_visited.set_primary_values(&mut data.styles,
primary_inputs,
new_values);
// Return whether the damage indicates we must cascade new inherited
// values into children.
@ -498,31 +562,52 @@ trait PrivateMatchMethods: TElement {
pseudo: &PseudoElement,
cascade_visited: CascadeVisitedMode) {
debug_assert!(pseudo.is_eager());
let (mut styles, restyle) = data.styles_and_restyle_mut();
let mut pseudo_style = styles.pseudos.get_mut(pseudo).unwrap();
// If there was no relevant link, we won't have any visited rules, so
// there may not be anything do for the visited case. This early return
// is especially important for the `cascade_primary_and_pseudos` path
// since we rely on the state of some previous matching run.
if !cascade_visited.has_rules(pseudo_style) {
return
}
let old_values = cascade_visited.take_values(pseudo_style);
let new_values = self.cascade_internal(context,
&styles.primary,
Some(pseudo_style),
cascade_visited);
let old_values = cascade_visited.take_pseudo_values(
&mut data.styles,
context.cascade_inputs_mut().pseudos.get_mut(pseudo).unwrap(),
pseudo
);
let new_values = {
let pseudo_inputs = context.cascade_inputs().pseudos
.get(pseudo).unwrap();
// If there was no relevant link at the time of matching, we won't
// have any visited rules, so there may not be anything do for the
// visited case. This early return is especially important for the
// `cascade_primary_and_pseudos` path since we rely on the state of
// some previous matching run.
if !cascade_visited.has_rules(pseudo_inputs) {
return
}
// Primary inputs should already have rules populated since it's
// always processed before eager pseudos.
let primary_inputs = context.cascade_inputs().primary();
debug_assert!(cascade_visited.has_rules(primary_inputs));
self.cascade_internal(context,
data.styles.get_primary(),
primary_inputs,
Some(pseudo_inputs),
cascade_visited)
};
if cascade_visited.should_accumulate_damage() {
self.accumulate_damage(&context.shared,
restyle,
old_values.as_ref().map(|v| &**v),
&mut data.restyle,
old_values.as_ref().map(|v| v.as_ref()),
&new_values,
Some(pseudo));
}
cascade_visited.set_values(pseudo_style, new_values);
let pseudo_inputs = context.cascade_inputs_mut().pseudos
.get_mut(pseudo).unwrap();
cascade_visited.set_pseudo_values(&mut data.styles,
pseudo_inputs,
pseudo,
new_values);
}
/// get_after_change_style removes the transition rules from the ComputedValues.
@ -530,9 +615,9 @@ trait PrivateMatchMethods: TElement {
#[cfg(feature = "gecko")]
fn get_after_change_style(&self,
context: &mut StyleContext<Self>,
primary_style: &ComputedStyle)
primary_style: &Arc<ComputedValues>)
-> Option<Arc<ComputedValues>> {
let rule_node = &primary_style.rules;
let rule_node = primary_style.rules();
let without_transition_rules =
context.shared.stylist.rule_tree().remove_transition_rule_if_applicable(rule_node);
if without_transition_rules == *rule_node {
@ -546,7 +631,7 @@ trait PrivateMatchMethods: TElement {
Some(self.cascade_with_rules(context.shared,
&context.thread_local.font_metrics_provider,
&without_transition_rules,
primary_style,
Some(primary_style),
CascadeTarget::Normal,
CascadeVisitedMode::Unvisited,
None))
@ -586,7 +671,6 @@ trait PrivateMatchMethods: TElement {
context: &mut StyleContext<Self>,
old_values: &mut Option<Arc<ComputedValues>>,
new_values: &mut Arc<ComputedValues>,
primary_style: &ComputedStyle,
important_rules_changed: bool) {
use context::{CASCADE_RESULTS, CSS_ANIMATIONS, CSS_TRANSITIONS, EFFECT_PROPERTIES};
use context::UpdateAnimationsTasks;
@ -599,7 +683,7 @@ trait PrivateMatchMethods: TElement {
let before_change_style = if self.might_need_transitions_update(old_values.as_ref().map(|s| &**s),
new_values) {
let after_change_style = if self.has_css_transitions() {
self.get_after_change_style(context, primary_style)
self.get_after_change_style(context, new_values)
} else {
None
};
@ -652,7 +736,6 @@ trait PrivateMatchMethods: TElement {
context: &mut StyleContext<Self>,
old_values: &mut Option<Arc<ComputedValues>>,
new_values: &mut Arc<ComputedValues>,
_primary_style: &ComputedStyle,
_important_rules_changed: bool) {
use animation;
@ -857,7 +940,7 @@ pub trait MatchMethods : TElement {
CascadeVisitedMode::Unvisited);
// Match and cascade eager pseudo-elements.
if !data.styles().is_display_none() {
if !data.styles.is_display_none() {
self.match_pseudos(context, data, VisitedHandlingMode::AllLinksUnvisited);
// If there's a relevant link involved, match and cascade eager
@ -876,7 +959,7 @@ pub trait MatchMethods : TElement {
}
// If we have any pseudo elements, indicate so in the primary StyleRelations.
if !data.styles().pseudos.is_empty() {
if !data.styles.pseudos.is_empty() {
primary_results.relations |= AFFECTED_BY_PSEUDO_ELEMENTS;
}
@ -899,7 +982,7 @@ pub trait MatchMethods : TElement {
context.thread_local
.style_sharing_candidate_cache
.insert_if_possible(self,
data.styles().primary.values(),
data.styles.primary(),
primary_results.relations,
validation_data,
dom_depth);
@ -943,6 +1026,10 @@ pub trait MatchMethods : TElement {
{
debug!("Match primary for {:?}, visited: {:?}", self, visited_handling);
let mut primary_inputs = context.thread_local.current_element_info
.as_mut().unwrap()
.cascade_inputs.ensure_primary();
let only_default_rules = context.shared.traversal_flags.for_default_styles();
let implemented_pseudo = self.implemented_pseudo_element();
if let Some(ref pseudo) = implemented_pseudo {
@ -964,8 +1051,8 @@ pub trait MatchMethods : TElement {
let parent = self.parent_element().unwrap();
let parent_data = parent.borrow_data().unwrap();
let pseudo_style =
parent_data.styles().pseudos.get(&pseudo).unwrap();
let mut rules = pseudo_style.rules.clone();
parent_data.styles.pseudos.get(&pseudo).unwrap();
let mut rules = pseudo_style.rules().clone();
if parent.may_have_animations() {
let animation_rules = data.get_animation_rules();
@ -998,20 +1085,9 @@ pub trait MatchMethods : TElement {
self.has_animations() &&
data.has_styles() &&
data.important_rules_are_different(&rules,
&context.shared.guards);
&context.shared.guards);
let rules_changed = match visited_handling {
VisitedHandlingMode::AllLinksVisitedAndUnvisited => {
unreachable!("We should never try to selector match with \
AllLinksVisitedAndUnvisited");
},
VisitedHandlingMode::AllLinksUnvisited => {
data.set_primary_rules(rules)
},
VisitedHandlingMode::RelevantLinkVisited => {
data.styles_mut().primary.set_visited_rules(rules)
},
};
let rules_changed = primary_inputs.set_rules(visited_handling, rules);
return MatchingResults::new(rules_changed, important_rules_changed)
}
@ -1084,18 +1160,7 @@ pub trait MatchMethods : TElement {
&context.shared.guards
);
let rules_changed = match visited_handling {
VisitedHandlingMode::AllLinksVisitedAndUnvisited => {
unreachable!("We should never try to selector match with \
AllLinksVisitedAndUnvisited");
},
VisitedHandlingMode::AllLinksUnvisited => {
data.set_primary_rules(primary_rule_node)
},
VisitedHandlingMode::RelevantLinkVisited => {
data.styles_mut().primary.set_visited_rules(primary_rule_node)
},
};
let rules_changed = primary_inputs.set_rules(visited_handling, primary_rule_node);
MatchingResults::new_from_context(rules_changed,
important_rules_changed,
@ -1118,11 +1183,6 @@ pub trait MatchMethods : TElement {
let mut applicable_declarations = ApplicableDeclarationList::new();
let map = &mut context.thread_local.selector_flags;
let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| {
self.apply_selector_flags(map, element, flags);
};
// Borrow the stuff we need here so the borrow checker doesn't get mad
// at us later in the closure.
let stylist = &context.shared.stylist;
@ -1134,57 +1194,69 @@ pub trait MatchMethods : TElement {
RuleInclusion::All
};
let bloom_filter = context.thread_local.bloom_filter.filter();
let mut matching_context =
MatchingContext::new_for_visited(MatchingMode::ForStatelessPseudoElement,
Some(bloom_filter),
visited_handling,
context.shared.quirks_mode);
// Compute rule nodes for eagerly-cascaded pseudo-elements.
let mut matches_different_pseudos = false;
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
let bloom_filter = context.thread_local.bloom_filter.filter();
let mut matching_context =
MatchingContext::new_for_visited(MatchingMode::ForStatelessPseudoElement,
Some(bloom_filter),
visited_handling,
context.shared.quirks_mode);
// For pseudo-elements, we only try to match visited rules if there
// are also unvisited rules. (This matches Gecko's behavior.)
if visited_handling == VisitedHandlingMode::RelevantLinkVisited &&
!data.styles().pseudos.has(&pseudo) {
!context.cascade_inputs().pseudos.has(&pseudo) {
return
}
if !self.may_generate_pseudo(&pseudo, data.styles().primary.values()) {
if !self.may_generate_pseudo(&pseudo, data.styles.primary()) {
return;
}
debug_assert!(applicable_declarations.is_empty());
// NB: We handle animation rules for ::before and ::after when
// traversing them.
stylist.push_applicable_declarations(self,
Some(&pseudo),
None,
None,
AnimationRules(None, None),
rule_inclusion,
&mut applicable_declarations,
&mut matching_context,
&mut set_selector_flags);
{
let map = &mut context.thread_local.selector_flags;
let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| {
self.apply_selector_flags(map, element, flags);
};
let pseudos = &mut data.styles_mut().pseudos;
debug_assert!(applicable_declarations.is_empty());
// NB: We handle animation rules for ::before and ::after when
// traversing them.
stylist.push_applicable_declarations(self,
Some(&pseudo),
None,
None,
AnimationRules(None, None),
rule_inclusion,
&mut applicable_declarations,
&mut matching_context,
&mut set_selector_flags);
}
let pseudos = &mut context.thread_local.current_element_info
.as_mut().unwrap()
.cascade_inputs.pseudos;
if !applicable_declarations.is_empty() {
let rules = stylist.rule_tree().compute_rule_node(
&mut applicable_declarations,
&guards
);
matches_different_pseudos |= pseudos.add_rules(
matches_different_pseudos |= !data.styles.pseudos.has(&pseudo);
pseudos.add_rules(
&pseudo,
visited_handling,
rules
);
} else {
matches_different_pseudos |= pseudos.remove_rules(
matches_different_pseudos |= data.styles.pseudos.has(&pseudo);
pseudos.remove_rules(
&pseudo,
visited_handling
);
data.styles.pseudos.take(&pseudo);
}
});
@ -1292,14 +1364,13 @@ pub trait MatchMethods : TElement {
fn replace_rules(
&self,
replacements: RestyleHint,
context: &StyleContext<Self>,
data: &mut ElementData
context: &mut StyleContext<Self>,
) -> bool {
let mut result = false;
result |= self.replace_rules_internal(replacements, context, data,
result |= self.replace_rules_internal(replacements, context,
CascadeVisitedMode::Unvisited);
if !context.shared.traversal_flags.for_animation_only() {
result |= self.replace_rules_internal(replacements, context, data,
result |= self.replace_rules_internal(replacements, context,
CascadeVisitedMode::Visited);
}
result
@ -1312,8 +1383,7 @@ pub trait MatchMethods : TElement {
fn replace_rules_internal(
&self,
replacements: RestyleHint,
context: &StyleContext<Self>,
data: &mut ElementData,
context: &mut StyleContext<Self>,
cascade_visited: CascadeVisitedMode
) -> bool {
use properties::PropertyDeclarationBlock;
@ -1322,8 +1392,11 @@ pub trait MatchMethods : TElement {
debug_assert!(replacements.intersects(RestyleHint::replacements()) &&
(replacements & !RestyleHint::replacements()).is_empty());
let element_styles = &mut data.styles_mut();
let primary_rules = match cascade_visited.get_rules_mut(&mut element_styles.primary) {
let stylist = &context.shared.stylist;
let guards = &context.shared.guards;
let mut primary_inputs = context.cascade_inputs_mut().primary_mut();
let primary_rules = match cascade_visited.get_rules_mut(primary_inputs) {
Some(r) => r,
None => return false,
};
@ -1331,8 +1404,8 @@ pub trait MatchMethods : TElement {
let replace_rule_node = |level: CascadeLevel,
pdb: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
path: &mut StrongRuleNode| -> bool {
let new_node = context.shared.stylist.rule_tree()
.update_rule_at_level(level, pdb, path, &context.shared.guards);
let new_node = stylist.rule_tree()
.update_rule_at_level(level, pdb, path, guards);
match new_node {
Some(n) => {
*path = n;
@ -1455,8 +1528,9 @@ pub trait MatchMethods : TElement {
// which pseudos match), so now we can just iterate what we have. This
// does mean collecting owned pseudos, so that the borrow checker will
// let us pass the mutable |data| to the cascade function.
let matched_pseudos = data.styles().pseudos.keys();
let matched_pseudos = context.cascade_inputs().pseudos.keys();
for pseudo in matched_pseudos {
debug!("Cascade pseudo for {:?} {:?}", self, pseudo);
self.cascade_eager_pseudo(context, data, &pseudo, cascade_visited);
}
}
@ -1465,17 +1539,17 @@ pub trait MatchMethods : TElement {
fn get_base_style(&self,
shared_context: &SharedStyleContext,
font_metrics_provider: &FontMetricsProvider,
primary_style: &ComputedStyle,
pseudo_style: Option<&ComputedStyle>)
primary_style: &Arc<ComputedValues>,
pseudo_style: Option<&Arc<ComputedValues>>)
-> Arc<ComputedValues> {
let relevant_style = pseudo_style.unwrap_or(primary_style);
let rule_node = &relevant_style.rules;
let rule_node = relevant_style.rules();
let without_animation_rules =
shared_context.stylist.rule_tree().remove_animation_rules(rule_node);
if without_animation_rules == *rule_node {
// Note that unwrapping here is fine, because the style is
// only incomplete during the styling process.
return relevant_style.values.as_ref().unwrap().clone();
return relevant_style.clone();
}
// This currently ignores visited styles, which seems acceptable,
@ -1483,7 +1557,7 @@ pub trait MatchMethods : TElement {
self.cascade_with_rules(shared_context,
font_metrics_provider,
&without_animation_rules,
primary_style,
Some(primary_style),
CascadeTarget::Normal,
CascadeVisitedMode::Unvisited,
None)