mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 00:05:36 +00:00
Bug 1646811 - servo: Add animation and transition support for pseudo-elements.
This change extends the DocumentAnimationSet to hold animations for pseudo-elements. Since pseudo-elements in Servo are not in the DOM like in Gecko, they need to be handled a bit carefully in stylo. When a pseudo-element has an animation, recascade the style. Finally, this change passes the pseudo-element string properly to animation events. Fixes: #10316 Depends on D80242 Differential Revision: https://phabricator.services.mozilla.com/D80243
This commit is contained in:
parent
d406afe4e6
commit
0346b7de29
@ -19,6 +19,7 @@ use crate::properties::{
|
||||
PropertyDeclarationId,
|
||||
};
|
||||
use crate::rule_tree::CascadeLevel;
|
||||
use crate::selector_parser::PseudoElement;
|
||||
use crate::shared_lock::{Locked, SharedRwLock};
|
||||
use crate::style_resolver::StyleResolverForElement;
|
||||
use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue};
|
||||
@ -1138,7 +1139,39 @@ impl ElementAnimationSet {
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
|
||||
/// A key that is used to identify nodes in the `DocumentAnimationSet`.
|
||||
pub struct AnimationSetKey(pub OpaqueNode);
|
||||
pub struct AnimationSetKey {
|
||||
/// The node for this `AnimationSetKey`.
|
||||
pub node: OpaqueNode,
|
||||
/// The pseudo element for this `AnimationSetKey`. If `None` this key will
|
||||
/// refer to the main content for its node.
|
||||
pub pseudo_element: Option<PseudoElement>,
|
||||
}
|
||||
|
||||
impl AnimationSetKey {
|
||||
/// Create a new key given a node and optional pseudo element.
|
||||
pub fn new(node: OpaqueNode, pseudo_element: Option<PseudoElement>) -> Self {
|
||||
AnimationSetKey {
|
||||
node,
|
||||
pseudo_element,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new key for the main content of this node.
|
||||
pub fn new_for_non_pseudo(node: OpaqueNode) -> Self {
|
||||
AnimationSetKey {
|
||||
node,
|
||||
pseudo_element: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new key for given node and pseudo element.
|
||||
pub fn new_for_pseudo(node: OpaqueNode, pseudo_element: PseudoElement) -> Self {
|
||||
AnimationSetKey {
|
||||
node,
|
||||
pseudo_element: Some(pseudo_element),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, MallocSizeOf)]
|
||||
/// A set of animations for a document.
|
||||
@ -1154,8 +1187,7 @@ impl DocumentAnimationSet {
|
||||
self.sets
|
||||
.read()
|
||||
.get(key)
|
||||
.map(|set| set.has_active_animation())
|
||||
.unwrap_or(false)
|
||||
.map_or(false, |set| set.has_active_animation())
|
||||
}
|
||||
|
||||
/// Return whether or not the provided node has active CSS transitions.
|
||||
@ -1163,8 +1195,7 @@ impl DocumentAnimationSet {
|
||||
self.sets
|
||||
.read()
|
||||
.get(key)
|
||||
.map(|set| set.has_active_transition())
|
||||
.unwrap_or(false)
|
||||
.map_or(false, |set| set.has_active_transition())
|
||||
}
|
||||
|
||||
/// Return a locked PropertyDeclarationBlock with animation values for the given
|
||||
@ -1202,6 +1233,58 @@ impl DocumentAnimationSet {
|
||||
Arc::new(shared_lock.wrap(block))
|
||||
})
|
||||
}
|
||||
|
||||
/// Get all the animation declarations for the given key, returning an empty
|
||||
/// `AnimationAndTransitionDeclarations` if there are no animations.
|
||||
pub(crate) fn get_all_declarations(
|
||||
&self,
|
||||
key: &AnimationSetKey,
|
||||
time: f64,
|
||||
shared_lock: &SharedRwLock,
|
||||
) -> AnimationAndTransitionDeclarations {
|
||||
let sets = self.sets.read();
|
||||
let set = match sets.get(key) {
|
||||
Some(set) => set,
|
||||
None => return Default::default(),
|
||||
};
|
||||
|
||||
let animations = set.get_value_map_for_active_animations(time).map(|map| {
|
||||
let block = PropertyDeclarationBlock::from_animation_value_map(&map);
|
||||
Arc::new(shared_lock.wrap(block))
|
||||
});
|
||||
let transitions = set.get_value_map_for_active_transitions(time).map(|map| {
|
||||
let block = PropertyDeclarationBlock::from_animation_value_map(&map);
|
||||
Arc::new(shared_lock.wrap(block))
|
||||
});
|
||||
AnimationAndTransitionDeclarations {
|
||||
animations,
|
||||
transitions,
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancel all animations for set at the given key.
|
||||
pub(crate) fn cancel_all_animations_for_key(&self, key: &AnimationSetKey) {
|
||||
if let Some(set) = self.sets.write().get_mut(key) {
|
||||
set.cancel_all_animations();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of property declarations for a node, including animations and
|
||||
/// transitions.
|
||||
#[derive(Default)]
|
||||
pub struct AnimationAndTransitionDeclarations {
|
||||
/// Declarations for animations.
|
||||
pub animations: Option<Arc<Locked<PropertyDeclarationBlock>>>,
|
||||
/// Declarations for transitions.
|
||||
pub transitions: Option<Arc<Locked<PropertyDeclarationBlock>>>,
|
||||
}
|
||||
|
||||
impl AnimationAndTransitionDeclarations {
|
||||
/// Whether or not this `AnimationAndTransitionDeclarations` is empty.
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.animations.is_none() && self.transitions.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Kick off any new transitions for this node and return all of the properties that are
|
||||
|
@ -750,12 +750,23 @@ pub trait TElement:
|
||||
/// or are scheduled to do so in the future.
|
||||
fn has_animations(&self, context: &SharedStyleContext) -> bool;
|
||||
|
||||
/// Returns true if the element has a CSS animation.
|
||||
fn has_css_animations(&self, context: &SharedStyleContext) -> bool;
|
||||
/// Returns true if the element has a CSS animation. The `context` and `pseudo_element`
|
||||
/// arguments are only used by Servo, since it stores animations globally and pseudo-elements
|
||||
/// are not in the DOM.
|
||||
fn has_css_animations(
|
||||
&self,
|
||||
context: &SharedStyleContext,
|
||||
pseudo_element: Option<PseudoElement>,
|
||||
) -> bool;
|
||||
|
||||
/// Returns true if the element has a CSS transition (including running transitions and
|
||||
/// completed transitions).
|
||||
fn has_css_transitions(&self, context: &SharedStyleContext) -> bool;
|
||||
/// completed transitions). The `context` and `pseudo_element` arguments are only used
|
||||
/// by Servo, since it stores animations globally and pseudo-elements are not in the DOM.
|
||||
fn has_css_transitions(
|
||||
&self,
|
||||
context: &SharedStyleContext,
|
||||
pseudo_element: Option<PseudoElement>,
|
||||
) -> bool;
|
||||
|
||||
/// Returns true if the element has animation restyle hints.
|
||||
fn has_animation_restyle_hints(&self) -> bool {
|
||||
|
@ -1520,11 +1520,11 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||
self.may_have_animations() && unsafe { Gecko_ElementHasAnimations(self.0) }
|
||||
}
|
||||
|
||||
fn has_css_animations(&self, _: &SharedStyleContext) -> bool {
|
||||
fn has_css_animations(&self, _: &SharedStyleContext, _: Option<PseudoElement>) -> bool {
|
||||
self.may_have_animations() && unsafe { Gecko_ElementHasCSSAnimations(self.0) }
|
||||
}
|
||||
|
||||
fn has_css_transitions(&self, _: &SharedStyleContext) -> bool {
|
||||
fn has_css_transitions(&self, _: &SharedStyleContext, _: Option<PseudoElement>) -> bool {
|
||||
self.may_have_animations() && unsafe { Gecko_ElementHasCSSTransitions(self.0) }
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
use crate::computed_value_flags::ComputedValueFlags;
|
||||
use crate::context::{CascadeInputs, ElementCascadeInputs, QuirksMode, SelectorFlagsMap};
|
||||
use crate::context::{SharedStyleContext, StyleContext};
|
||||
use crate::data::ElementData;
|
||||
use crate::data::{ElementData, ElementStyles};
|
||||
use crate::dom::TElement;
|
||||
#[cfg(feature = "servo")]
|
||||
use crate::dom::TNode;
|
||||
@ -90,13 +90,13 @@ enum CascadeVisitedMode {
|
||||
|
||||
trait PrivateMatchMethods: TElement {
|
||||
fn replace_single_rule_node(
|
||||
context: &mut StyleContext<Self>,
|
||||
context: &SharedStyleContext,
|
||||
level: CascadeLevel,
|
||||
pdb: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
|
||||
path: &mut StrongRuleNode,
|
||||
) -> bool {
|
||||
let stylist = &context.shared.stylist;
|
||||
let guards = &context.shared.guards;
|
||||
let stylist = &context.stylist;
|
||||
let guards = &context.guards;
|
||||
|
||||
let mut important_rules_changed = false;
|
||||
let new_node = stylist.rule_tree().update_rule_at_level(
|
||||
@ -143,13 +143,13 @@ trait PrivateMatchMethods: TElement {
|
||||
if replacements.contains(RestyleHint::RESTYLE_STYLE_ATTRIBUTE) {
|
||||
let style_attribute = self.style_attribute();
|
||||
result |= Self::replace_single_rule_node(
|
||||
context,
|
||||
context.shared,
|
||||
CascadeLevel::same_tree_author_normal(),
|
||||
style_attribute,
|
||||
primary_rules,
|
||||
);
|
||||
result |= Self::replace_single_rule_node(
|
||||
context,
|
||||
context.shared,
|
||||
CascadeLevel::same_tree_author_important(),
|
||||
style_attribute,
|
||||
primary_rules,
|
||||
@ -170,7 +170,7 @@ trait PrivateMatchMethods: TElement {
|
||||
|
||||
if replacements.contains(RestyleHint::RESTYLE_SMIL) {
|
||||
Self::replace_single_rule_node(
|
||||
context,
|
||||
context.shared,
|
||||
CascadeLevel::SMILOverride,
|
||||
self.smil_override(),
|
||||
primary_rules,
|
||||
@ -179,7 +179,7 @@ trait PrivateMatchMethods: TElement {
|
||||
|
||||
if replacements.contains(RestyleHint::RESTYLE_CSS_TRANSITIONS) {
|
||||
Self::replace_single_rule_node(
|
||||
context,
|
||||
context.shared,
|
||||
CascadeLevel::Transitions,
|
||||
self.transition_rule(&context.shared)
|
||||
.as_ref()
|
||||
@ -190,7 +190,7 @@ trait PrivateMatchMethods: TElement {
|
||||
|
||||
if replacements.contains(RestyleHint::RESTYLE_CSS_ANIMATIONS) {
|
||||
Self::replace_single_rule_node(
|
||||
context,
|
||||
context.shared,
|
||||
CascadeLevel::Animations,
|
||||
self.animation_rule(&context.shared)
|
||||
.as_ref()
|
||||
@ -245,11 +245,12 @@ trait PrivateMatchMethods: TElement {
|
||||
context: &mut StyleContext<Self>,
|
||||
old_style: Option<&ComputedValues>,
|
||||
new_style: &ComputedValues,
|
||||
pseudo_element: Option<PseudoElement>,
|
||||
) -> bool {
|
||||
let new_box_style = new_style.get_box();
|
||||
let new_style_specifies_animations = new_box_style.specifies_animations();
|
||||
|
||||
let has_animations = self.has_css_animations(&context.shared);
|
||||
let has_animations = self.has_css_animations(&context.shared, pseudo_element);
|
||||
if !new_style_specifies_animations && !has_animations {
|
||||
return false;
|
||||
}
|
||||
@ -326,6 +327,7 @@ trait PrivateMatchMethods: TElement {
|
||||
context: &StyleContext<Self>,
|
||||
old_style: Option<&ComputedValues>,
|
||||
new_style: &ComputedValues,
|
||||
pseudo_element: Option<PseudoElement>,
|
||||
) -> bool {
|
||||
let old_style = match old_style {
|
||||
Some(v) => v,
|
||||
@ -333,7 +335,9 @@ trait PrivateMatchMethods: TElement {
|
||||
};
|
||||
|
||||
let new_box_style = new_style.get_box();
|
||||
if !self.has_css_transitions(context.shared) && !new_box_style.specifies_transitions() {
|
||||
if !self.has_css_transitions(context.shared, pseudo_element) &&
|
||||
!new_box_style.specifies_transitions()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -379,7 +383,7 @@ trait PrivateMatchMethods: TElement {
|
||||
fn process_animations(
|
||||
&self,
|
||||
context: &mut StyleContext<Self>,
|
||||
old_values: &mut Option<Arc<ComputedValues>>,
|
||||
old_styles: &mut ElementStyles,
|
||||
new_styles: &mut ResolvedElementStyles,
|
||||
restyle_hint: RestyleHint,
|
||||
important_rules_changed: bool,
|
||||
@ -401,7 +405,12 @@ trait PrivateMatchMethods: TElement {
|
||||
// in addition to the unvisited styles.
|
||||
|
||||
let mut tasks = UpdateAnimationsTasks::empty();
|
||||
if self.needs_animations_update(context, old_values.as_ref().map(|s| &**s), new_values) {
|
||||
if self.needs_animations_update(
|
||||
context,
|
||||
old_values.as_ref().map(|s| &**s),
|
||||
new_values,
|
||||
/* pseudo_element = */ None,
|
||||
) {
|
||||
tasks.insert(UpdateAnimationsTasks::CSS_ANIMATIONS);
|
||||
}
|
||||
|
||||
@ -409,6 +418,7 @@ trait PrivateMatchMethods: TElement {
|
||||
context,
|
||||
old_values.as_ref().map(|s| &**s),
|
||||
new_values,
|
||||
/* pseudo_element = */ None,
|
||||
) {
|
||||
let after_change_style = if self.has_css_transitions(context.shared) {
|
||||
self.after_change_style(context, new_values)
|
||||
@ -467,57 +477,149 @@ trait PrivateMatchMethods: TElement {
|
||||
fn process_animations(
|
||||
&self,
|
||||
context: &mut StyleContext<Self>,
|
||||
old_values: &mut Option<Arc<ComputedValues>>,
|
||||
old_styles: &mut ElementStyles,
|
||||
new_resolved_styles: &mut ResolvedElementStyles,
|
||||
_restyle_hint: RestyleHint,
|
||||
_important_rules_changed: bool,
|
||||
) {
|
||||
if !self.process_animations_for_style(
|
||||
use crate::animation::AnimationSetKey;
|
||||
use crate::dom::TDocument;
|
||||
|
||||
let style_changed = self.process_animations_for_style(
|
||||
context,
|
||||
old_values,
|
||||
&mut old_styles.primary,
|
||||
new_resolved_styles.primary_style_mut(),
|
||||
) {
|
||||
/* pseudo_element = */ None,
|
||||
);
|
||||
|
||||
// If we have modified animation or transitions, we recascade style for this node.
|
||||
if style_changed {
|
||||
let mut rule_node = new_resolved_styles.primary_style().rules().clone();
|
||||
let declarations = context.shared.animations.get_all_declarations(
|
||||
&AnimationSetKey::new_for_non_pseudo(self.as_node().opaque()),
|
||||
context.shared.current_time_for_animations,
|
||||
self.as_node().owner_doc().shared_lock(),
|
||||
);
|
||||
Self::replace_single_rule_node(
|
||||
&context.shared,
|
||||
CascadeLevel::Transitions,
|
||||
declarations.transitions.as_ref().map(|a| a.borrow_arc()),
|
||||
&mut rule_node,
|
||||
);
|
||||
Self::replace_single_rule_node(
|
||||
&context.shared,
|
||||
CascadeLevel::Animations,
|
||||
declarations.animations.as_ref().map(|a| a.borrow_arc()),
|
||||
&mut rule_node,
|
||||
);
|
||||
|
||||
if rule_node != *new_resolved_styles.primary_style().rules() {
|
||||
let inputs = CascadeInputs {
|
||||
rules: Some(rule_node),
|
||||
visited_rules: new_resolved_styles.primary_style().visited_rules().cloned(),
|
||||
};
|
||||
|
||||
new_resolved_styles.primary.style = StyleResolverForElement::new(
|
||||
*self,
|
||||
context,
|
||||
RuleInclusion::All,
|
||||
PseudoElementResolution::IfApplicable,
|
||||
)
|
||||
.cascade_style_and_visited_with_default_parents(inputs);
|
||||
}
|
||||
}
|
||||
|
||||
self.process_animations_for_pseudo(
|
||||
context,
|
||||
old_styles,
|
||||
new_resolved_styles,
|
||||
PseudoElement::Before,
|
||||
);
|
||||
self.process_animations_for_pseudo(
|
||||
context,
|
||||
old_styles,
|
||||
new_resolved_styles,
|
||||
PseudoElement::After,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
fn process_animations_for_pseudo(
|
||||
&self,
|
||||
context: &mut StyleContext<Self>,
|
||||
old_styles: &mut ElementStyles,
|
||||
new_resolved_styles: &mut ResolvedElementStyles,
|
||||
pseudo_element: PseudoElement,
|
||||
) {
|
||||
use crate::animation::AnimationSetKey;
|
||||
use crate::dom::TDocument;
|
||||
|
||||
let key = AnimationSetKey::new_for_pseudo(self.as_node().opaque(), pseudo_element.clone());
|
||||
let mut style = match new_resolved_styles.pseudos.get(&pseudo_element) {
|
||||
Some(style) => Arc::clone(style),
|
||||
None => {
|
||||
context
|
||||
.shared
|
||||
.animations
|
||||
.cancel_all_animations_for_key(&key);
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
let mut old_style = old_styles.pseudos.get(&pseudo_element).cloned();
|
||||
self.process_animations_for_style(
|
||||
context,
|
||||
&mut old_style,
|
||||
&mut style,
|
||||
Some(pseudo_element.clone()),
|
||||
);
|
||||
|
||||
let declarations = context.shared.animations.get_all_declarations(
|
||||
&key,
|
||||
context.shared.current_time_for_animations,
|
||||
self.as_node().owner_doc().shared_lock(),
|
||||
);
|
||||
if declarations.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have modified animation or transitions, we recascade style for this node.
|
||||
let mut rule_node = new_resolved_styles.primary_style().rules().clone();
|
||||
let mut rule_node = style.rules().clone();
|
||||
Self::replace_single_rule_node(
|
||||
context,
|
||||
&context.shared,
|
||||
CascadeLevel::Transitions,
|
||||
self.transition_rule(&context.shared)
|
||||
.as_ref()
|
||||
.map(|a| a.borrow_arc()),
|
||||
declarations.transitions.as_ref().map(|a| a.borrow_arc()),
|
||||
&mut rule_node,
|
||||
);
|
||||
Self::replace_single_rule_node(
|
||||
context,
|
||||
&context.shared,
|
||||
CascadeLevel::Animations,
|
||||
self.animation_rule(&context.shared)
|
||||
.as_ref()
|
||||
.map(|a| a.borrow_arc()),
|
||||
declarations.animations.as_ref().map(|a| a.borrow_arc()),
|
||||
&mut rule_node,
|
||||
);
|
||||
|
||||
// If these animations haven't modified the rule now, we can just exit early.
|
||||
if rule_node == *new_resolved_styles.primary_style().rules() {
|
||||
if rule_node == *style.rules() {
|
||||
return;
|
||||
}
|
||||
|
||||
let inputs = CascadeInputs {
|
||||
rules: Some(rule_node),
|
||||
visited_rules: new_resolved_styles.primary_style().visited_rules().cloned(),
|
||||
visited_rules: style.visited_rules().cloned(),
|
||||
};
|
||||
|
||||
let style = StyleResolverForElement::new(
|
||||
let new_style = StyleResolverForElement::new(
|
||||
*self,
|
||||
context,
|
||||
RuleInclusion::All,
|
||||
PseudoElementResolution::IfApplicable,
|
||||
)
|
||||
.cascade_style_and_visited_with_default_parents(inputs);
|
||||
.cascade_style_and_visited_for_pseudo_with_default_parents(
|
||||
inputs,
|
||||
&pseudo_element,
|
||||
&new_resolved_styles.primary,
|
||||
);
|
||||
|
||||
new_resolved_styles.primary.style = style;
|
||||
new_resolved_styles
|
||||
.pseudos
|
||||
.set(&pseudo_element, new_style.0);
|
||||
}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
@ -526,17 +628,24 @@ trait PrivateMatchMethods: TElement {
|
||||
context: &mut StyleContext<Self>,
|
||||
old_values: &mut Option<Arc<ComputedValues>>,
|
||||
new_values: &mut Arc<ComputedValues>,
|
||||
pseudo_element: Option<PseudoElement>,
|
||||
) -> bool {
|
||||
use crate::animation::{AnimationSetKey, AnimationState};
|
||||
|
||||
// We need to call this before accessing the `ElementAnimationSet` from the
|
||||
// map because this call will do a RwLock::read().
|
||||
let needs_animations_update =
|
||||
self.needs_animations_update(context, old_values.as_ref().map(|s| &**s), new_values);
|
||||
let needs_animations_update = self.needs_animations_update(
|
||||
context,
|
||||
old_values.as_ref().map(|s| &**s),
|
||||
new_values,
|
||||
pseudo_element,
|
||||
);
|
||||
|
||||
let might_need_transitions_update = self.might_need_transitions_update(
|
||||
context,
|
||||
old_values.as_ref().map(|s| &**s),
|
||||
new_values,
|
||||
pseudo_element,
|
||||
);
|
||||
|
||||
let mut after_change_style = None;
|
||||
@ -544,7 +653,7 @@ trait PrivateMatchMethods: TElement {
|
||||
after_change_style = self.after_change_style(context, new_values);
|
||||
}
|
||||
|
||||
let key = AnimationSetKey(self.as_node().opaque());
|
||||
let key = AnimationSetKey::new(self.as_node().opaque(), pseudo_element);
|
||||
let shared_context = context.shared;
|
||||
let mut animation_set = shared_context
|
||||
.animations
|
||||
@ -764,7 +873,7 @@ pub trait MatchMethods: TElement {
|
||||
|
||||
self.process_animations(
|
||||
context,
|
||||
&mut data.styles.primary,
|
||||
&mut data.styles,
|
||||
&mut new_styles,
|
||||
data.hint,
|
||||
important_rules_changed,
|
||||
|
@ -29,7 +29,7 @@ use style_traits::{ParseError, StyleParseErrorKind};
|
||||
/// A pseudo-element, both public and private.
|
||||
///
|
||||
/// NB: If you add to this list, be sure to update `each_simple_pseudo_element` too.
|
||||
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, ToShmem)]
|
||||
#[allow(missing_docs)]
|
||||
#[repr(usize)]
|
||||
pub enum PseudoElement {
|
||||
|
@ -118,6 +118,17 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_parent_style_for_pseudo<'a>(
|
||||
primary_style: &'a PrimaryStyle,
|
||||
layout_parent_style: Option<&'a ComputedValues>,
|
||||
) -> Option<&'a ComputedValues> {
|
||||
if primary_style.style().is_display_contents() {
|
||||
layout_parent_style
|
||||
} else {
|
||||
Some(primary_style.style())
|
||||
}
|
||||
}
|
||||
|
||||
fn eager_pseudo_is_definitely_not_generated(
|
||||
pseudo: &PseudoElement,
|
||||
style: &ComputedValues,
|
||||
@ -246,11 +257,8 @@ where
|
||||
let mut pseudo_styles = EagerPseudoStyles::default();
|
||||
|
||||
if !self.element.is_pseudo_element() {
|
||||
let layout_parent_style_for_pseudo = if primary_style.style().is_display_contents() {
|
||||
layout_parent_style
|
||||
} else {
|
||||
Some(primary_style.style())
|
||||
};
|
||||
let layout_parent_style_for_pseudo =
|
||||
layout_parent_style_for_pseudo(&primary_style, layout_parent_style);
|
||||
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
||||
let pseudo_style = self.resolve_pseudo_style(
|
||||
&pseudo,
|
||||
@ -298,6 +306,26 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
/// Cascade a set of rules for pseudo element, using the default parent for inheritance.
|
||||
pub(crate) fn cascade_style_and_visited_for_pseudo_with_default_parents(
|
||||
&mut self,
|
||||
inputs: CascadeInputs,
|
||||
pseudo: &PseudoElement,
|
||||
primary_style: &PrimaryStyle,
|
||||
) -> ResolvedStyle {
|
||||
with_default_parent_styles(self.element, |_, layout_parent_style| {
|
||||
let layout_parent_style_for_pseudo =
|
||||
layout_parent_style_for_pseudo(primary_style, layout_parent_style);
|
||||
|
||||
self.cascade_style_and_visited(
|
||||
inputs,
|
||||
Some(primary_style.style()),
|
||||
layout_parent_style_for_pseudo,
|
||||
Some(pseudo),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn cascade_style_and_visited(
|
||||
&mut self,
|
||||
inputs: CascadeInputs,
|
||||
|
Loading…
Reference in New Issue
Block a user