Pass through visited style for after change

When a transition update is needed during restyling, `get_after_change_style` is
called to re-cascade without transition rules, and this style is then used for
primary styling instead of the style just computed.

`get_after_change_style` used to ignore visited styles, so this meant that if a
transition update was needed, visited styles were effectively dropped.

To fix the crash here, we pass through the existing visited styles when
re-cascading as part of `get_after_change_style`.

MozReview-Commit-ID: 4HBQAdeJ38B
This commit is contained in:
J. Ryan Stinnett 2017-07-07 16:54:22 -05:00
parent 2278a3f981
commit 3463a9c210
4 changed files with 28 additions and 3 deletions

View file

@ -297,6 +297,11 @@ impl CascadeInputs {
self.visited_rules.take() self.visited_rules.take()
} }
/// Whether there are any visited values.
pub fn has_visited_values(&self) -> bool {
self.visited_values.is_some()
}
/// Gets a reference to the visited computed values. Panic if the element /// Gets a reference to the visited computed values. Panic if the element
/// does not have visited computed values. /// does not have visited computed values.
pub fn visited_values(&self) -> &Arc<ComputedValues> { pub fn visited_values(&self) -> &Arc<ComputedValues> {

View file

@ -577,6 +577,12 @@ trait PrivateMatchMethods: TElement {
} }
} }
// If there were visited values to insert, ensure they do in fact exist
// inside the new values.
debug_assert!(!cascade_visited.visited_values_for_insertion() ||
context.cascade_inputs().primary().has_visited_values() ==
new_values.has_visited_style());
// Set the new computed values. // Set the new computed values.
let primary_inputs = context.cascade_inputs_mut().primary_mut(); let primary_inputs = context.cascade_inputs_mut().primary_mut();
cascade_visited.set_primary_values(&mut data.styles, cascade_visited.set_primary_values(&mut data.styles,
@ -661,8 +667,9 @@ trait PrivateMatchMethods: TElement {
return None; return None;
} }
// This currently ignores visited styles, which seems acceptable, // This currently passes through visited styles, if they exist.
// as existing browsers don't appear to transition visited styles. // When fixing bug 868975, compute after change for visited styles as
// well, along with updating the rest of the animation processing.
Some(self.cascade_with_rules(context.shared, Some(self.cascade_with_rules(context.shared,
&context.thread_local.font_metrics_provider, &context.thread_local.font_metrics_provider,
&without_transition_rules, &without_transition_rules,
@ -670,7 +677,7 @@ trait PrivateMatchMethods: TElement {
CascadeTarget::Normal, CascadeTarget::Normal,
CascadeVisitedMode::Unvisited, CascadeVisitedMode::Unvisited,
/* parent_info = */ None, /* parent_info = */ None,
None)) primary_style.get_visited_style().cloned()))
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -716,6 +723,9 @@ trait PrivateMatchMethods: TElement {
use context::{CASCADE_RESULTS, CSS_ANIMATIONS, CSS_TRANSITIONS, EFFECT_PROPERTIES}; use context::{CASCADE_RESULTS, CSS_ANIMATIONS, CSS_TRANSITIONS, EFFECT_PROPERTIES};
use context::UpdateAnimationsTasks; use context::UpdateAnimationsTasks;
// Bug 868975: These steps should examine and update the visited styles
// in addition to the unvisited styles.
let mut tasks = UpdateAnimationsTasks::empty(); let mut tasks = UpdateAnimationsTasks::empty();
if self.needs_animations_update(context, old_values.as_ref(), new_values) { if self.needs_animations_update(context, old_values.as_ref(), new_values) {
tasks.insert(CSS_ANIMATIONS); tasks.insert(CSS_ANIMATIONS);

View file

@ -171,6 +171,11 @@ impl ComputedValues {
self.rules.as_ref().unwrap() self.rules.as_ref().unwrap()
} }
/// Whether there is a visited style.
pub fn has_visited_style(&self) -> bool {
self.visited_style.is_some()
}
/// Gets a reference to the visited style, if any. /// Gets a reference to the visited style, if any.
pub fn get_visited_style(&self) -> Option<<&Arc<ComputedValues>> { pub fn get_visited_style(&self) -> Option<<&Arc<ComputedValues>> {
self.visited_style.as_ref() self.visited_style.as_ref()

View file

@ -1908,6 +1908,11 @@ impl ComputedValues {
self.rules.as_ref().unwrap() self.rules.as_ref().unwrap()
} }
/// Whether there is a visited style.
pub fn has_visited_style(&self) -> bool {
self.visited_style.is_some()
}
/// Gets a reference to the visited style, if any. /// Gets a reference to the visited style, if any.
pub fn get_visited_style(&self) -> Option<<&Arc<ComputedValues>> { pub fn get_visited_style(&self) -> Option<<&Arc<ComputedValues>> {
self.visited_style.as_ref() self.visited_style.as_ref()