Bug 1364377: Fix inheritance of NAC, and selector-matching of pseudo-implementing NAC. r=bholley

MozReview-Commit-ID: DjSyaWHq1Xj
Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
This commit is contained in:
Emilio Cobos Álvarez 2017-05-12 12:14:09 +02:00
parent 58253f545b
commit 2ffffcfdce
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
3 changed files with 59 additions and 8 deletions

View file

@ -325,6 +325,21 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
} }
} }
/// Returns the parent element we should inherit from.
///
/// This is pretty much always the parent element itself, except in the case
/// of Gecko's Native Anonymous Content, which may need to find the closest
/// non-NAC ancestor.
fn inheritance_parent(&self) -> Option<Self> {
self.parent_element()
}
/// For a given NAC element, return the closest non-NAC ancestor, which is
/// guaranteed to exist.
fn closest_non_native_anonymous_ancestor(&self) -> Option<Self> {
unreachable!("Servo doesn't know about NAC");
}
/// Get this element's style attribute. /// Get this element's style attribute.
fn style_attribute(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>>; fn style_attribute(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>>;

View file

@ -526,6 +526,32 @@ impl<'le> TElement for GeckoElement<'le> {
type ConcreteNode = GeckoNode<'le>; type ConcreteNode = GeckoNode<'le>;
type FontMetricsProvider = GeckoFontMetricsProvider; type FontMetricsProvider = GeckoFontMetricsProvider;
fn inheritance_parent(&self) -> Option<Self> {
if self.is_native_anonymous() {
return self.closest_non_native_anonymous_ancestor();
}
return self.parent_element();
}
fn closest_non_native_anonymous_ancestor(&self) -> Option<Self> {
debug_assert!(self.is_native_anonymous());
let mut parent = match self.parent_element() {
Some(e) => e,
None => return None,
};
loop {
if !parent.is_native_anonymous() {
return Some(parent);
}
parent = match parent.parent_element() {
Some(p) => p,
None => return None,
};
}
}
fn as_node(&self) -> Self::ConcreteNode { fn as_node(&self) -> Self::ConcreteNode {
unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) } unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
} }

View file

@ -33,8 +33,10 @@ use stylist::ApplicableDeclarationBlock;
/// The way a style should be inherited. /// The way a style should be inherited.
enum InheritMode { enum InheritMode {
/// Inherit from the parent element, as normal CSS dictates. /// Inherit from the parent element, as normal CSS dictates, _or_ from the
FromParentElement, /// closest non-Native Anonymous element in case this is Native Anonymous
/// Content.
Normal,
/// Inherit from the primary style, this is used while computing eager /// Inherit from the primary style, this is used while computing eager
/// pseudos, like ::before and ::after when we're traversing the parent. /// pseudos, like ::before and ::after when we're traversing the parent.
FromPrimaryStyle, FromPrimaryStyle,
@ -423,8 +425,8 @@ trait PrivateMatchMethods: TElement {
let parent_el; let parent_el;
let parent_data; let parent_data;
let style_to_inherit_from = match inherit_mode { let style_to_inherit_from = match inherit_mode {
InheritMode::FromParentElement => { InheritMode::Normal => {
parent_el = self.parent_element(); parent_el = self.inheritance_parent();
parent_data = parent_el.as_ref().and_then(|e| e.borrow_data()); parent_data = parent_el.as_ref().and_then(|e| e.borrow_data());
let parent_values = parent_data.as_ref().map(|d| { let parent_values = parent_data.as_ref().map(|d| {
// Sometimes Gecko eagerly styles things without processing // Sometimes Gecko eagerly styles things without processing
@ -500,7 +502,7 @@ trait PrivateMatchMethods: TElement {
let inherit_mode = if eager_pseudo_style.is_some() { let inherit_mode = if eager_pseudo_style.is_some() {
InheritMode::FromPrimaryStyle InheritMode::FromPrimaryStyle
} else { } else {
InheritMode::FromParentElement InheritMode::Normal
}; };
self.cascade_with_rules(context.shared, self.cascade_with_rules(context.shared,
@ -623,7 +625,7 @@ trait PrivateMatchMethods: TElement {
&context.thread_local.font_metrics_provider, &context.thread_local.font_metrics_provider,
&without_transition_rules, &without_transition_rules,
primary_style, primary_style,
InheritMode::FromParentElement)) InheritMode::Normal))
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -1002,8 +1004,16 @@ pub trait MatchMethods : TElement {
self.apply_selector_flags(map, element, flags); self.apply_selector_flags(map, element, flags);
}; };
let selector_matching_target = match implemented_pseudo {
Some(..) => {
self.closest_non_native_anonymous_ancestor()
.expect("Pseudo-element without non-NAC parent?")
},
None => *self,
};
// Compute the primary rule node. // Compute the primary rule node.
*relations = stylist.push_applicable_declarations(self, *relations = stylist.push_applicable_declarations(&selector_matching_target,
Some(bloom), Some(bloom),
style_attribute, style_attribute,
smil_override, smil_override,
@ -1448,7 +1458,7 @@ pub trait MatchMethods : TElement {
font_metrics_provider, font_metrics_provider,
&without_animation_rules, &without_animation_rules,
primary_style, primary_style,
InheritMode::FromParentElement) InheritMode::Normal)
} }
} }