mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
Make sure to compute visited style if our parent has visited style.
Part 4 of the fix for Gecko bug 1364242: https://bugzilla.mozilla.org/show_bug.cgi?id=1364242
This commit is contained in:
parent
759038e687
commit
824139e615
1 changed files with 50 additions and 5 deletions
|
@ -151,7 +151,10 @@ impl CascadeVisitedMode {
|
||||||
fn rules<'a>(&self, inputs: &'a CascadeInputs) -> &'a StrongRuleNode {
|
fn rules<'a>(&self, inputs: &'a CascadeInputs) -> &'a StrongRuleNode {
|
||||||
match *self {
|
match *self {
|
||||||
CascadeVisitedMode::Unvisited => inputs.rules(),
|
CascadeVisitedMode::Unvisited => inputs.rules(),
|
||||||
CascadeVisitedMode::Visited => inputs.visited_rules(),
|
CascadeVisitedMode::Visited => match inputs.get_visited_rules() {
|
||||||
|
Some(rules) => rules,
|
||||||
|
None => inputs.rules(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,6 +317,9 @@ trait PrivateMatchMethods: TElement {
|
||||||
/// pseudo-elements after collecting the appropriate rules to use.
|
/// pseudo-elements after collecting the appropriate rules to use.
|
||||||
///
|
///
|
||||||
/// `primary_style` is expected to be Some for eager pseudo-elements.
|
/// `primary_style` is expected to be Some for eager pseudo-elements.
|
||||||
|
///
|
||||||
|
/// `parent_info` is our style parent and its primary style, if
|
||||||
|
/// it's already been computed.
|
||||||
fn cascade_with_rules(&self,
|
fn cascade_with_rules(&self,
|
||||||
shared_context: &SharedStyleContext,
|
shared_context: &SharedStyleContext,
|
||||||
font_metrics_provider: &FontMetricsProvider,
|
font_metrics_provider: &FontMetricsProvider,
|
||||||
|
@ -321,6 +327,7 @@ trait PrivateMatchMethods: TElement {
|
||||||
primary_style: Option<&Arc<ComputedValues>>,
|
primary_style: Option<&Arc<ComputedValues>>,
|
||||||
cascade_target: CascadeTarget,
|
cascade_target: CascadeTarget,
|
||||||
cascade_visited: CascadeVisitedMode,
|
cascade_visited: CascadeVisitedMode,
|
||||||
|
parent_info: Option<&ParentElementAndStyle<Self>>,
|
||||||
visited_values_to_insert: Option<Arc<ComputedValues>>)
|
visited_values_to_insert: Option<Arc<ComputedValues>>)
|
||||||
-> Arc<ComputedValues> {
|
-> Arc<ComputedValues> {
|
||||||
let mut cascade_info = CascadeInfo::new();
|
let mut cascade_info = CascadeInfo::new();
|
||||||
|
@ -343,9 +350,15 @@ trait PrivateMatchMethods: TElement {
|
||||||
let element_and_style; // So parent_el and style_to_inherit_from are known live.
|
let element_and_style; // So parent_el and style_to_inherit_from are known live.
|
||||||
let style_to_inherit_from = match cascade_target {
|
let style_to_inherit_from = match cascade_target {
|
||||||
CascadeTarget::Normal => {
|
CascadeTarget::Normal => {
|
||||||
element_and_style = self.get_inherited_style_and_parent();
|
let info = match parent_info {
|
||||||
parent_el = element_and_style.element;
|
Some(element_and_style) => element_and_style,
|
||||||
element_and_style.style.as_ref().map(|s| cascade_visited.values(s))
|
None => {
|
||||||
|
element_and_style = self.get_inherited_style_and_parent();
|
||||||
|
&element_and_style
|
||||||
|
}
|
||||||
|
};
|
||||||
|
parent_el = info.element;
|
||||||
|
info.style.as_ref().map(|s| cascade_visited.values(s))
|
||||||
}
|
}
|
||||||
CascadeTarget::EagerPseudo => {
|
CascadeTarget::EagerPseudo => {
|
||||||
parent_el = Some(self.clone());
|
parent_el = Some(self.clone());
|
||||||
|
@ -402,11 +415,15 @@ trait PrivateMatchMethods: TElement {
|
||||||
/// pseudo-elements.
|
/// pseudo-elements.
|
||||||
///
|
///
|
||||||
/// `primary_style` is expected to be Some for eager pseudo-elements.
|
/// `primary_style` is expected to be Some for eager pseudo-elements.
|
||||||
|
///
|
||||||
|
/// `parent_info` is our style parent and its primary style, if
|
||||||
|
/// it's already been computed.
|
||||||
fn cascade_internal(&self,
|
fn cascade_internal(&self,
|
||||||
context: &StyleContext<Self>,
|
context: &StyleContext<Self>,
|
||||||
primary_style: Option<&Arc<ComputedValues>>,
|
primary_style: Option<&Arc<ComputedValues>>,
|
||||||
primary_inputs: &CascadeInputs,
|
primary_inputs: &CascadeInputs,
|
||||||
eager_pseudo_inputs: Option<&CascadeInputs>,
|
eager_pseudo_inputs: Option<&CascadeInputs>,
|
||||||
|
parent_info: Option<&ParentElementAndStyle<Self>>,
|
||||||
cascade_visited: CascadeVisitedMode)
|
cascade_visited: CascadeVisitedMode)
|
||||||
-> Arc<ComputedValues> {
|
-> Arc<ComputedValues> {
|
||||||
if let Some(pseudo) = self.implemented_pseudo_element() {
|
if let Some(pseudo) = self.implemented_pseudo_element() {
|
||||||
|
@ -470,15 +487,19 @@ trait PrivateMatchMethods: TElement {
|
||||||
primary_style,
|
primary_style,
|
||||||
cascade_target,
|
cascade_target,
|
||||||
cascade_visited,
|
cascade_visited,
|
||||||
|
parent_info,
|
||||||
visited_values_to_insert)
|
visited_values_to_insert)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes values and damage for the primary style of an element, setting
|
/// Computes values and damage for the primary style of an element, setting
|
||||||
/// them on the ElementData.
|
/// them on the ElementData.
|
||||||
|
///
|
||||||
|
/// `parent_info` is our style parent and its primary style.
|
||||||
fn cascade_primary(&self,
|
fn cascade_primary(&self,
|
||||||
context: &mut StyleContext<Self>,
|
context: &mut StyleContext<Self>,
|
||||||
data: &mut ElementData,
|
data: &mut ElementData,
|
||||||
important_rules_changed: bool,
|
important_rules_changed: bool,
|
||||||
|
parent_info: &ParentElementAndStyle<Self>,
|
||||||
cascade_visited: CascadeVisitedMode)
|
cascade_visited: CascadeVisitedMode)
|
||||||
-> ChildCascadeRequirement {
|
-> ChildCascadeRequirement {
|
||||||
debug!("Cascade primary for {:?}, visited: {:?}", self, cascade_visited);
|
debug!("Cascade primary for {:?}, visited: {:?}", self, cascade_visited);
|
||||||
|
@ -496,7 +517,10 @@ trait PrivateMatchMethods: TElement {
|
||||||
// visited case. This early return is especially important for the
|
// visited case. This early return is especially important for the
|
||||||
// `cascade_primary_and_pseudos` path since we rely on the state of
|
// `cascade_primary_and_pseudos` path since we rely on the state of
|
||||||
// some previous matching run.
|
// some previous matching run.
|
||||||
if !cascade_visited.has_rules(primary_inputs) {
|
//
|
||||||
|
// Note that we cannot take this early return if our parent has
|
||||||
|
// visited style, because then we too have visited style.
|
||||||
|
if !cascade_visited.has_rules(primary_inputs) && !parent_info.has_visited_style() {
|
||||||
return ChildCascadeRequirement::CanSkipCascade
|
return ChildCascadeRequirement::CanSkipCascade
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,6 +529,7 @@ trait PrivateMatchMethods: TElement {
|
||||||
None,
|
None,
|
||||||
primary_inputs,
|
primary_inputs,
|
||||||
None,
|
None,
|
||||||
|
/* parent_info = */ None,
|
||||||
cascade_visited)
|
cascade_visited)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -593,6 +618,7 @@ trait PrivateMatchMethods: TElement {
|
||||||
data.styles.get_primary(),
|
data.styles.get_primary(),
|
||||||
primary_inputs,
|
primary_inputs,
|
||||||
Some(pseudo_inputs),
|
Some(pseudo_inputs),
|
||||||
|
/* parent_info = */ None,
|
||||||
cascade_visited)
|
cascade_visited)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -636,6 +662,7 @@ trait PrivateMatchMethods: TElement {
|
||||||
Some(primary_style),
|
Some(primary_style),
|
||||||
CascadeTarget::Normal,
|
CascadeTarget::Normal,
|
||||||
CascadeVisitedMode::Unvisited,
|
CascadeVisitedMode::Unvisited,
|
||||||
|
/* parent_info = */ None,
|
||||||
None))
|
None))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,6 +926,12 @@ struct ParentElementAndStyle<E: TElement> {
|
||||||
style: Option<Arc<ComputedValues>>,
|
style: Option<Arc<ComputedValues>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: TElement> ParentElementAndStyle<E> {
|
||||||
|
fn has_visited_style(&self) -> bool {
|
||||||
|
self.style.as_ref().map_or(false, |v| { v.get_visited_style().is_some() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Collects the outputs of the primary matching process, including the rule
|
/// Collects the outputs of the primary matching process, including the rule
|
||||||
/// node and other associated data.
|
/// node and other associated data.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -966,13 +999,21 @@ pub trait MatchMethods : TElement {
|
||||||
let relevant_link_found = primary_results.relevant_link_found;
|
let relevant_link_found = primary_results.relevant_link_found;
|
||||||
if relevant_link_found {
|
if relevant_link_found {
|
||||||
self.match_primary(context, data, VisitedHandlingMode::RelevantLinkVisited);
|
self.match_primary(context, data, VisitedHandlingMode::RelevantLinkVisited);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Even if there is no relevant link, we need to cascade visited styles
|
||||||
|
// if our parent has visited styles.
|
||||||
|
let parent_and_styles = self.get_inherited_style_and_parent();
|
||||||
|
if relevant_link_found || parent_and_styles.has_visited_style() {
|
||||||
self.cascade_primary(context, data, important_rules_changed,
|
self.cascade_primary(context, data, important_rules_changed,
|
||||||
|
&parent_and_styles,
|
||||||
CascadeVisitedMode::Visited);
|
CascadeVisitedMode::Visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cascade properties and compute primary values.
|
// Cascade properties and compute primary values.
|
||||||
let child_cascade_requirement =
|
let child_cascade_requirement =
|
||||||
self.cascade_primary(context, data, important_rules_changed,
|
self.cascade_primary(context, data, important_rules_changed,
|
||||||
|
&parent_and_styles,
|
||||||
CascadeVisitedMode::Unvisited);
|
CascadeVisitedMode::Unvisited);
|
||||||
|
|
||||||
// Match and cascade eager pseudo-elements.
|
// Match and cascade eager pseudo-elements.
|
||||||
|
@ -1039,10 +1080,13 @@ pub trait MatchMethods : TElement {
|
||||||
// visited ComputedValues are placed within the regular ComputedValues,
|
// visited ComputedValues are placed within the regular ComputedValues,
|
||||||
// which is immutable after the cascade. If there aren't any visited
|
// which is immutable after the cascade. If there aren't any visited
|
||||||
// rules, these calls will return without cascading.
|
// rules, these calls will return without cascading.
|
||||||
|
let parent_and_styles = self.get_inherited_style_and_parent();
|
||||||
self.cascade_primary(context, &mut data, important_rules_changed,
|
self.cascade_primary(context, &mut data, important_rules_changed,
|
||||||
|
&parent_and_styles,
|
||||||
CascadeVisitedMode::Visited);
|
CascadeVisitedMode::Visited);
|
||||||
let child_cascade_requirement =
|
let child_cascade_requirement =
|
||||||
self.cascade_primary(context, &mut data, important_rules_changed,
|
self.cascade_primary(context, &mut data, important_rules_changed,
|
||||||
|
&parent_and_styles,
|
||||||
CascadeVisitedMode::Unvisited);
|
CascadeVisitedMode::Unvisited);
|
||||||
self.cascade_pseudos(context, &mut data, CascadeVisitedMode::Visited);
|
self.cascade_pseudos(context, &mut data, CascadeVisitedMode::Visited);
|
||||||
self.cascade_pseudos(context, &mut data, CascadeVisitedMode::Unvisited);
|
self.cascade_pseudos(context, &mut data, CascadeVisitedMode::Unvisited);
|
||||||
|
@ -1611,6 +1655,7 @@ pub trait MatchMethods : TElement {
|
||||||
Some(primary_style),
|
Some(primary_style),
|
||||||
CascadeTarget::Normal,
|
CascadeTarget::Normal,
|
||||||
CascadeVisitedMode::Unvisited,
|
CascadeVisitedMode::Unvisited,
|
||||||
|
/* parent_info = */ None,
|
||||||
None)
|
None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue