mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Auto merge of #16289 - bholley:primary_before_pseudos, r=emilio
Cascade the primary style before matching pseudos https://bugzilla.mozilla.org/show_bug.cgi?id=1353960 <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16289) <!-- Reviewable:end -->
This commit is contained in:
commit
3beaa8d2e9
5 changed files with 187 additions and 191 deletions
|
@ -80,7 +80,7 @@ pub struct EagerPseudoStyles(Option<Box<[Option<ComputedStyle>]>>);
|
||||||
impl EagerPseudoStyles {
|
impl EagerPseudoStyles {
|
||||||
/// Returns whether there are any pseudo styles.
|
/// Returns whether there are any pseudo styles.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.0.is_some()
|
self.0.is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the style for a given eager pseudo, if it exists.
|
/// Returns a reference to the style for a given eager pseudo, if it exists.
|
||||||
|
|
|
@ -15,7 +15,7 @@ use cascade_info::CascadeInfo;
|
||||||
use context::{SequentialTask, SharedStyleContext, StyleContext};
|
use context::{SequentialTask, SharedStyleContext, StyleContext};
|
||||||
use data::{ComputedStyle, ElementData, ElementStyles, RestyleData};
|
use data::{ComputedStyle, ElementData, ElementStyles, RestyleData};
|
||||||
use dom::{AnimationRules, SendElement, TElement, TNode};
|
use dom::{AnimationRules, SendElement, TElement, TNode};
|
||||||
use properties::{CascadeFlags, ComputedValues, SHAREABLE, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade};
|
use properties::{CascadeFlags, ComputedValues, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade};
|
||||||
use properties::longhands::display::computed_value as display;
|
use properties::longhands::display::computed_value as display;
|
||||||
use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_CSS_ANIMATIONS, RestyleHint};
|
use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_CSS_ANIMATIONS, RestyleHint};
|
||||||
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode};
|
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode};
|
||||||
|
@ -58,24 +58,6 @@ fn create_common_style_affecting_attributes_from_element<E: TElement>(element: &
|
||||||
flags
|
flags
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The results returned from running selector matching on an element.
|
|
||||||
pub struct MatchResults {
|
|
||||||
/// A set of style relations (different hints about what rules matched or
|
|
||||||
/// could have matched). This is necessary if the style will be shared.
|
|
||||||
/// If None, the style will not be shared.
|
|
||||||
pub primary_relations: Option<StyleRelations>,
|
|
||||||
/// Whether the rule nodes changed during selector matching.
|
|
||||||
pub rule_nodes_changed: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MatchResults {
|
|
||||||
/// Returns true if the primary rule node is shareable with other nodes.
|
|
||||||
pub fn primary_is_shareable(&self) -> bool {
|
|
||||||
self.primary_relations.as_ref()
|
|
||||||
.map_or(false, relations_are_shareable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Information regarding a style sharing candidate.
|
/// Information regarding a style sharing candidate.
|
||||||
///
|
///
|
||||||
/// Note that this information is stored in TLS and cleared after the traversal,
|
/// Note that this information is stored in TLS and cleared after the traversal,
|
||||||
|
@ -430,15 +412,6 @@ pub enum StyleSharingResult {
|
||||||
StyleWasShared(usize),
|
StyleWasShared(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Callers need to pass several boolean flags to cascade_primary_or_pseudo.
|
|
||||||
/// We encapsulate them in this struct to avoid mixing them up.
|
|
||||||
///
|
|
||||||
/// FIXME(pcwalton): Unify with `CascadeFlags`, perhaps?
|
|
||||||
struct CascadeBooleans {
|
|
||||||
shareable: bool,
|
|
||||||
animate: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
trait PrivateMatchMethods: TElement {
|
trait PrivateMatchMethods: TElement {
|
||||||
/// Returns the closest parent element that doesn't have a display: contents
|
/// Returns the closest parent element that doesn't have a display: contents
|
||||||
/// style (and thus generates a box).
|
/// style (and thus generates a box).
|
||||||
|
@ -543,13 +516,9 @@ trait PrivateMatchMethods: TElement {
|
||||||
fn cascade_internal(&self,
|
fn cascade_internal(&self,
|
||||||
context: &StyleContext<Self>,
|
context: &StyleContext<Self>,
|
||||||
primary_style: &ComputedStyle,
|
primary_style: &ComputedStyle,
|
||||||
pseudo_style: &Option<(&PseudoElement, &mut ComputedStyle)>,
|
pseudo_style: &Option<(&PseudoElement, &mut ComputedStyle)>)
|
||||||
booleans: &CascadeBooleans)
|
|
||||||
-> Arc<ComputedValues> {
|
-> Arc<ComputedValues> {
|
||||||
let mut cascade_flags = CascadeFlags::empty();
|
let mut cascade_flags = CascadeFlags::empty();
|
||||||
if booleans.shareable {
|
|
||||||
cascade_flags.insert(SHAREABLE)
|
|
||||||
}
|
|
||||||
if self.skip_root_and_item_based_display_fixup() {
|
if self.skip_root_and_item_based_display_fixup() {
|
||||||
cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP)
|
cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP)
|
||||||
}
|
}
|
||||||
|
@ -566,7 +535,7 @@ trait PrivateMatchMethods: TElement {
|
||||||
data: &mut ElementData,
|
data: &mut ElementData,
|
||||||
pseudo: Option<&PseudoElement>,
|
pseudo: Option<&PseudoElement>,
|
||||||
possibly_expired_animations: &mut Vec<PropertyAnimation>,
|
possibly_expired_animations: &mut Vec<PropertyAnimation>,
|
||||||
booleans: CascadeBooleans) {
|
animate: bool) {
|
||||||
// Collect some values.
|
// Collect some values.
|
||||||
let (mut styles, restyle) = data.styles_and_restyle_mut();
|
let (mut styles, restyle) = data.styles_and_restyle_mut();
|
||||||
let mut primary_style = &mut styles.primary;
|
let mut primary_style = &mut styles.primary;
|
||||||
|
@ -577,10 +546,10 @@ trait PrivateMatchMethods: TElement {
|
||||||
|
|
||||||
// Compute the new values.
|
// Compute the new values.
|
||||||
let mut new_values = self.cascade_internal(context, primary_style,
|
let mut new_values = self.cascade_internal(context, primary_style,
|
||||||
&pseudo_style, &booleans);
|
&pseudo_style);
|
||||||
|
|
||||||
// Handle animations.
|
// Handle animations.
|
||||||
if booleans.animate {
|
if animate {
|
||||||
self.process_animations(context,
|
self.process_animations(context,
|
||||||
&mut old_values,
|
&mut old_values,
|
||||||
&mut new_values,
|
&mut new_values,
|
||||||
|
@ -806,13 +775,71 @@ fn compute_rule_node<E: TElement>(rule_tree: &RuleTree,
|
||||||
|
|
||||||
impl<E: TElement> PrivateMatchMethods for E {}
|
impl<E: TElement> PrivateMatchMethods for E {}
|
||||||
|
|
||||||
|
/// Controls whether the style sharing cache is used.
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
pub enum StyleSharingBehavior {
|
||||||
|
/// Style sharing allowed.
|
||||||
|
Allow,
|
||||||
|
/// Style sharing disallowed.
|
||||||
|
Disallow,
|
||||||
|
}
|
||||||
|
|
||||||
/// The public API that elements expose for selector matching.
|
/// The public API that elements expose for selector matching.
|
||||||
pub trait MatchMethods : TElement {
|
pub trait MatchMethods : TElement {
|
||||||
/// Runs selector matching to (re)compute rule nodes for this element.
|
/// Performs selector matching and property cascading on an element and its eager pseudos.
|
||||||
fn match_element(&self,
|
fn match_and_cascade(&self,
|
||||||
|
context: &mut StyleContext<Self>,
|
||||||
|
data: &mut ElementData,
|
||||||
|
sharing: StyleSharingBehavior)
|
||||||
|
{
|
||||||
|
// Perform selector matching for the primary style.
|
||||||
|
let mut primary_relations = StyleRelations::empty();
|
||||||
|
let _rule_node_changed = self.match_primary(context, data, &mut primary_relations);
|
||||||
|
|
||||||
|
// Cascade properties and compute primary values.
|
||||||
|
let mut expired = vec![];
|
||||||
|
self.cascade_primary(context, data, &mut expired);
|
||||||
|
|
||||||
|
// Match and cascade eager pseudo-elements.
|
||||||
|
if !data.styles().is_display_none() {
|
||||||
|
let _pseudo_rule_nodes_changed =
|
||||||
|
self.match_pseudos(context, data);
|
||||||
|
self.cascade_pseudos(context, data, &mut expired);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have any pseudo elements, indicate so in the primary StyleRelations.
|
||||||
|
if !data.styles().pseudos.is_empty() {
|
||||||
|
primary_relations |= AFFECTED_BY_PSEUDO_ELEMENTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the style is shareable, add it to the LRU cache.
|
||||||
|
if sharing == StyleSharingBehavior::Allow && relations_are_shareable(&primary_relations) {
|
||||||
|
context.thread_local
|
||||||
|
.style_sharing_candidate_cache
|
||||||
|
.insert_if_possible(self,
|
||||||
|
data.styles().primary.values(),
|
||||||
|
primary_relations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs the cascade, without matching.
|
||||||
|
fn cascade_primary_and_pseudos(&self,
|
||||||
|
context: &mut StyleContext<Self>,
|
||||||
|
mut data: &mut ElementData)
|
||||||
|
{
|
||||||
|
let mut possibly_expired_animations = vec![];
|
||||||
|
self.cascade_primary(context, &mut data, &mut possibly_expired_animations);
|
||||||
|
self.cascade_pseudos(context, &mut data, &mut possibly_expired_animations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs selector matching to (re)compute the primary rule node for this element.
|
||||||
|
///
|
||||||
|
/// Returns whether the primary rule node changed.
|
||||||
|
fn match_primary(&self,
|
||||||
context: &mut StyleContext<Self>,
|
context: &mut StyleContext<Self>,
|
||||||
data: &mut ElementData)
|
data: &mut ElementData,
|
||||||
-> MatchResults
|
relations: &mut StyleRelations)
|
||||||
|
-> bool
|
||||||
{
|
{
|
||||||
let mut applicable_declarations =
|
let mut applicable_declarations =
|
||||||
Vec::<ApplicableDeclarationBlock>::with_capacity(16);
|
Vec::<ApplicableDeclarationBlock>::with_capacity(16);
|
||||||
|
@ -821,74 +848,25 @@ pub trait MatchMethods : TElement {
|
||||||
let style_attribute = self.style_attribute();
|
let style_attribute = self.style_attribute();
|
||||||
let animation_rules = self.get_animation_rules(None);
|
let animation_rules = self.get_animation_rules(None);
|
||||||
let mut rule_nodes_changed = false;
|
let mut rule_nodes_changed = false;
|
||||||
|
let bloom = context.thread_local.bloom_filter.filter();
|
||||||
|
|
||||||
// TODO(emilio): This is somewhat inefficient, because of a variety of
|
|
||||||
// reasons:
|
|
||||||
//
|
|
||||||
// * It doesn't coalesce flags.
|
|
||||||
// * It doesn't look at flags already sent in a task for the main
|
|
||||||
// thread to process.
|
|
||||||
// * It doesn't take advantage of us knowing that the traversal is
|
|
||||||
// sequential.
|
|
||||||
//
|
|
||||||
// I suspect (need to measure!) that we don't use to set flags on
|
|
||||||
// a lot of different elements, but we could end up posting the same
|
|
||||||
// flag over and over with this approach.
|
|
||||||
//
|
|
||||||
// If the number of elements is low, perhaps a small cache with the
|
|
||||||
// flags already sent would be appropriate.
|
|
||||||
//
|
|
||||||
// The sequential task business for this is kind of sad :(.
|
|
||||||
//
|
|
||||||
// Anyway, let's do the obvious thing for now.
|
|
||||||
let tasks = &mut context.thread_local.tasks;
|
let tasks = &mut context.thread_local.tasks;
|
||||||
let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| {
|
let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| {
|
||||||
// Apply the selector flags.
|
self.apply_selector_flags(tasks, element, flags);
|
||||||
let self_flags = flags.for_self();
|
|
||||||
if !self_flags.is_empty() {
|
|
||||||
if element == self {
|
|
||||||
unsafe { element.set_selector_flags(self_flags); }
|
|
||||||
} else {
|
|
||||||
if !element.has_selector_flags(self_flags) {
|
|
||||||
let task =
|
|
||||||
SequentialTask::set_selector_flags(element.clone(),
|
|
||||||
self_flags);
|
|
||||||
tasks.push(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let parent_flags = flags.for_parent();
|
|
||||||
if !parent_flags.is_empty() {
|
|
||||||
if let Some(p) = element.parent_element() {
|
|
||||||
// Avoid the overhead of the SequentialTask if the flags are
|
|
||||||
// already set.
|
|
||||||
if !p.has_selector_flags(parent_flags) {
|
|
||||||
let task = SequentialTask::set_selector_flags(p, parent_flags);
|
|
||||||
tasks.push(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Borrow the stuff we need here so the borrow checker doesn't get mad
|
|
||||||
// at us later in the closure.
|
|
||||||
let guards = &context.shared.guards;
|
|
||||||
let rule_tree = &context.shared.stylist.rule_tree;
|
|
||||||
let bloom_filter = context.thread_local.bloom_filter.filter();
|
|
||||||
|
|
||||||
// Compute the primary rule node.
|
// Compute the primary rule node.
|
||||||
let mut primary_relations =
|
*relations = stylist.push_applicable_declarations(self,
|
||||||
stylist.push_applicable_declarations(self,
|
Some(bloom),
|
||||||
Some(bloom_filter),
|
style_attribute,
|
||||||
style_attribute,
|
animation_rules,
|
||||||
animation_rules,
|
None,
|
||||||
None,
|
&context.shared.guards,
|
||||||
guards,
|
&mut applicable_declarations,
|
||||||
&mut applicable_declarations,
|
&mut set_selector_flags);
|
||||||
&mut set_selector_flags);
|
|
||||||
|
|
||||||
let primary_rule_node =
|
let primary_rule_node =
|
||||||
compute_rule_node::<Self>(rule_tree, &mut applicable_declarations);
|
compute_rule_node::<Self>(&stylist.rule_tree, &mut applicable_declarations);
|
||||||
if !data.has_styles() {
|
if !data.has_styles() {
|
||||||
data.set_styles(ElementStyles::new(ComputedStyle::new_partial(primary_rule_node)));
|
data.set_styles(ElementStyles::new(ComputedStyle::new_partial(primary_rule_node)));
|
||||||
rule_nodes_changed = true;
|
rule_nodes_changed = true;
|
||||||
|
@ -897,6 +875,35 @@ pub trait MatchMethods : TElement {
|
||||||
rule_nodes_changed = true;
|
rule_nodes_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule_nodes_changed
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs selector matching to (re)compute eager pseudo-element rule nodes for this
|
||||||
|
/// element.
|
||||||
|
///
|
||||||
|
/// Returns whether any of the pseudo rule nodes changed (including, but not
|
||||||
|
/// limited to, cases where we match different pseudos altogether).
|
||||||
|
fn match_pseudos(&self,
|
||||||
|
context: &mut StyleContext<Self>,
|
||||||
|
data: &mut ElementData)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
|
let mut applicable_declarations =
|
||||||
|
Vec::<ApplicableDeclarationBlock>::with_capacity(16);
|
||||||
|
let mut rule_nodes_changed = false;
|
||||||
|
|
||||||
|
let tasks = &mut context.thread_local.tasks;
|
||||||
|
let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| {
|
||||||
|
self.apply_selector_flags(tasks, 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;
|
||||||
|
let guards = &context.shared.guards;
|
||||||
|
let rule_tree = &stylist.rule_tree;
|
||||||
|
let bloom_filter = context.thread_local.bloom_filter.filter();
|
||||||
|
|
||||||
// Compute rule nodes for eagerly-cascaded pseudo-elements.
|
// Compute rule nodes for eagerly-cascaded pseudo-elements.
|
||||||
let mut matches_different_pseudos = false;
|
let mut matches_different_pseudos = false;
|
||||||
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
||||||
|
@ -938,14 +945,59 @@ pub trait MatchMethods : TElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have any pseudo elements, indicate so in the primary StyleRelations.
|
rule_nodes_changed
|
||||||
if data.styles().pseudos.is_empty() {
|
}
|
||||||
primary_relations |= AFFECTED_BY_PSEUDO_ELEMENTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
MatchResults {
|
/// Applies selector flags to an element, deferring mutations of the parent
|
||||||
primary_relations: Some(primary_relations),
|
/// until after the traversal.
|
||||||
rule_nodes_changed: rule_nodes_changed,
|
///
|
||||||
|
/// TODO(emilio): This is somewhat inefficient, because of a variety of
|
||||||
|
/// reasons:
|
||||||
|
///
|
||||||
|
/// * It doesn't coalesce flags.
|
||||||
|
/// * It doesn't look at flags already sent in a task for the main
|
||||||
|
/// thread to process.
|
||||||
|
/// * It doesn't take advantage of us knowing that the traversal is
|
||||||
|
/// sequential.
|
||||||
|
///
|
||||||
|
/// I suspect (need to measure!) that we don't use to set flags on
|
||||||
|
/// a lot of different elements, but we could end up posting the same
|
||||||
|
/// flag over and over with this approach.
|
||||||
|
///
|
||||||
|
/// If the number of elements is low, perhaps a small cache with the
|
||||||
|
/// flags already sent would be appropriate.
|
||||||
|
///
|
||||||
|
/// The sequential task business for this is kind of sad :(.
|
||||||
|
///
|
||||||
|
/// Anyway, let's do the obvious thing for now.
|
||||||
|
fn apply_selector_flags(&self,
|
||||||
|
tasks: &mut Vec<SequentialTask<Self>>,
|
||||||
|
element: &Self,
|
||||||
|
flags: ElementSelectorFlags) {
|
||||||
|
// Apply the selector flags.
|
||||||
|
let self_flags = flags.for_self();
|
||||||
|
if !self_flags.is_empty() {
|
||||||
|
if element == self {
|
||||||
|
unsafe { element.set_selector_flags(self_flags); }
|
||||||
|
} else {
|
||||||
|
if !element.has_selector_flags(self_flags) {
|
||||||
|
let task =
|
||||||
|
SequentialTask::set_selector_flags(element.clone(),
|
||||||
|
self_flags);
|
||||||
|
tasks.push(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let parent_flags = flags.for_parent();
|
||||||
|
if !parent_flags.is_empty() {
|
||||||
|
if let Some(p) = element.parent_element() {
|
||||||
|
// Avoid the overhead of the SequentialTask if the flags are
|
||||||
|
// already set.
|
||||||
|
if !p.has_selector_flags(parent_flags) {
|
||||||
|
let task = SequentialTask::set_selector_flags(p, parent_flags);
|
||||||
|
tasks.push(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1163,51 +1215,33 @@ pub trait MatchMethods : TElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the CSS cascade and compute values for the element, potentially
|
/// Performs the cascade for the element's primary style.
|
||||||
/// starting any new transitions or animations.
|
fn cascade_primary(&self,
|
||||||
fn cascade_element(&self,
|
|
||||||
context: &mut StyleContext<Self>,
|
context: &mut StyleContext<Self>,
|
||||||
mut data: &mut AtomicRefMut<ElementData>,
|
mut data: &mut ElementData,
|
||||||
primary_is_shareable: bool)
|
possibly_expired_animations: &mut Vec<PropertyAnimation>)
|
||||||
{
|
{
|
||||||
let mut possibly_expired_animations = vec![];
|
self.cascade_primary_or_pseudo(context, &mut data, None,
|
||||||
|
possibly_expired_animations, /* animate = */ true);
|
||||||
|
}
|
||||||
|
|
||||||
// Cascade the primary style.
|
/// Performs the cascade for the element's eager pseudos.
|
||||||
self.cascade_primary_or_pseudo(context, data, None,
|
fn cascade_pseudos(&self,
|
||||||
&mut possibly_expired_animations,
|
context: &mut StyleContext<Self>,
|
||||||
CascadeBooleans {
|
mut data: &mut ElementData,
|
||||||
shareable: primary_is_shareable,
|
possibly_expired_animations: &mut Vec<PropertyAnimation>)
|
||||||
animate: true,
|
{
|
||||||
});
|
|
||||||
|
|
||||||
// Check whether the primary style is display:none.
|
|
||||||
let display_none = data.styles().primary.values().get_box().clone_display() ==
|
|
||||||
display::T::none;
|
|
||||||
|
|
||||||
// Cascade each pseudo-element.
|
|
||||||
//
|
|
||||||
// Note that we've already set up the map of matching pseudo-elements
|
// Note that we've already set up the map of matching pseudo-elements
|
||||||
// in match_element (and handled the damage implications of changing
|
// in match_pseudos (and handled the damage implications of changing
|
||||||
// which pseudos match), so now we can just iterate what we have. This
|
// which pseudos match), so now we can just iterate what we have. This
|
||||||
// does mean collecting owned pseudos, so that the borrow checker will
|
// does mean collecting owned pseudos, so that the borrow checker will
|
||||||
// let us pass the mutable |data| to the inner cascade function.
|
// let us pass the mutable |data| to the cascade function.
|
||||||
let matched_pseudos = data.styles().pseudos.keys();
|
let matched_pseudos = data.styles().pseudos.keys();
|
||||||
for pseudo in matched_pseudos {
|
for pseudo in matched_pseudos {
|
||||||
// If the new primary style is display:none, we don't need pseudo
|
|
||||||
// styles, but we still need to clear any stale values.
|
|
||||||
if display_none {
|
|
||||||
data.styles_mut().pseudos.get_mut(&pseudo).unwrap().values = None;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only ::before and ::after are animatable.
|
// Only ::before and ::after are animatable.
|
||||||
let animate = pseudo.is_before_or_after();
|
let animate = pseudo.is_before_or_after();
|
||||||
self.cascade_primary_or_pseudo(context, data, Some(&pseudo),
|
self.cascade_primary_or_pseudo(context, data, Some(&pseudo),
|
||||||
&mut possibly_expired_animations,
|
possibly_expired_animations, animate);
|
||||||
CascadeBooleans {
|
|
||||||
shareable: false,
|
|
||||||
animate: animate,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,6 @@ pub struct ComputedValues {
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
custom_properties: Option<Arc<ComputedValuesMap>>,
|
custom_properties: Option<Arc<ComputedValuesMap>>,
|
||||||
shareable: bool,
|
|
||||||
pub writing_mode: WritingMode,
|
pub writing_mode: WritingMode,
|
||||||
pub root_font_size: Au,
|
pub root_font_size: Au,
|
||||||
pub font_size_keyword: Option<longhands::font_size::KeywordSize>,
|
pub font_size_keyword: Option<longhands::font_size::KeywordSize>,
|
||||||
|
@ -87,7 +86,6 @@ impl ComputedValues {
|
||||||
pub fn inherit_from(parent: &Self, default: &Self) -> Arc<Self> {
|
pub fn inherit_from(parent: &Self, default: &Self) -> Arc<Self> {
|
||||||
Arc::new(ComputedValues {
|
Arc::new(ComputedValues {
|
||||||
custom_properties: parent.custom_properties.clone(),
|
custom_properties: parent.custom_properties.clone(),
|
||||||
shareable: parent.shareable,
|
|
||||||
writing_mode: parent.writing_mode,
|
writing_mode: parent.writing_mode,
|
||||||
root_font_size: parent.root_font_size,
|
root_font_size: parent.root_font_size,
|
||||||
font_size_keyword: parent.font_size_keyword,
|
font_size_keyword: parent.font_size_keyword,
|
||||||
|
@ -102,7 +100,6 @@ impl ComputedValues {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(custom_properties: Option<Arc<ComputedValuesMap>>,
|
pub fn new(custom_properties: Option<Arc<ComputedValuesMap>>,
|
||||||
shareable: bool,
|
|
||||||
writing_mode: WritingMode,
|
writing_mode: WritingMode,
|
||||||
root_font_size: Au,
|
root_font_size: Au,
|
||||||
font_size_keyword: Option<longhands::font_size::KeywordSize>,
|
font_size_keyword: Option<longhands::font_size::KeywordSize>,
|
||||||
|
@ -112,7 +109,6 @@ impl ComputedValues {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
ComputedValues {
|
ComputedValues {
|
||||||
custom_properties: custom_properties,
|
custom_properties: custom_properties,
|
||||||
shareable: shareable,
|
|
||||||
writing_mode: writing_mode,
|
writing_mode: writing_mode,
|
||||||
root_font_size: root_font_size,
|
root_font_size: root_font_size,
|
||||||
font_size_keyword: font_size_keyword,
|
font_size_keyword: font_size_keyword,
|
||||||
|
@ -125,7 +121,6 @@ impl ComputedValues {
|
||||||
pub fn default_values(pres_context: RawGeckoPresContextBorrowed) -> Arc<Self> {
|
pub fn default_values(pres_context: RawGeckoPresContextBorrowed) -> Arc<Self> {
|
||||||
Arc::new(ComputedValues {
|
Arc::new(ComputedValues {
|
||||||
custom_properties: None,
|
custom_properties: None,
|
||||||
shareable: true,
|
|
||||||
writing_mode: WritingMode::empty(), // FIXME(bz): This seems dubious
|
writing_mode: WritingMode::empty(), // FIXME(bz): This seems dubious
|
||||||
root_font_size: longhands::font_size::get_initial_value(), // FIXME(bz): Also seems dubious?
|
root_font_size: longhands::font_size::get_initial_value(), // FIXME(bz): Also seems dubious?
|
||||||
font_size_keyword: Some(Default::default()),
|
font_size_keyword: Some(Default::default()),
|
||||||
|
|
|
@ -1542,7 +1542,6 @@ pub struct ComputedValues {
|
||||||
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
||||||
% endfor
|
% endfor
|
||||||
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||||
shareable: bool,
|
|
||||||
/// The writing mode of this computed values struct.
|
/// The writing mode of this computed values struct.
|
||||||
pub writing_mode: WritingMode,
|
pub writing_mode: WritingMode,
|
||||||
/// The root element's computed font size.
|
/// The root element's computed font size.
|
||||||
|
@ -1555,7 +1554,6 @@ pub struct ComputedValues {
|
||||||
impl ComputedValues {
|
impl ComputedValues {
|
||||||
/// Construct a `ComputedValues` instance.
|
/// Construct a `ComputedValues` instance.
|
||||||
pub fn new(custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
pub fn new(custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||||
shareable: bool,
|
|
||||||
writing_mode: WritingMode,
|
writing_mode: WritingMode,
|
||||||
root_font_size: Au,
|
root_font_size: Au,
|
||||||
font_size_keyword: Option<longhands::font_size::KeywordSize>,
|
font_size_keyword: Option<longhands::font_size::KeywordSize>,
|
||||||
|
@ -1565,7 +1563,6 @@ impl ComputedValues {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
ComputedValues {
|
ComputedValues {
|
||||||
custom_properties: custom_properties,
|
custom_properties: custom_properties,
|
||||||
shareable: shareable,
|
|
||||||
writing_mode: writing_mode,
|
writing_mode: writing_mode,
|
||||||
root_font_size: root_font_size,
|
root_font_size: root_font_size,
|
||||||
font_size_keyword: font_size_keyword,
|
font_size_keyword: font_size_keyword,
|
||||||
|
@ -1889,7 +1886,6 @@ mod lazy_static_module {
|
||||||
}),
|
}),
|
||||||
% endfor
|
% endfor
|
||||||
custom_properties: None,
|
custom_properties: None,
|
||||||
shareable: true,
|
|
||||||
writing_mode: WritingMode::empty(),
|
writing_mode: WritingMode::empty(),
|
||||||
root_font_size: longhands::font_size::get_initial_value(),
|
root_font_size: longhands::font_size::get_initial_value(),
|
||||||
font_size_keyword: Some(Default::default()),
|
font_size_keyword: Some(Default::default()),
|
||||||
|
@ -1918,15 +1914,12 @@ static CASCADE_PROPERTY: [CascadePropertyFn; ${len(data.longhands)}] = [
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// A set of flags to tweak the behavior of the `cascade` function.
|
/// A set of flags to tweak the behavior of the `cascade` function.
|
||||||
pub flags CascadeFlags: u8 {
|
pub flags CascadeFlags: u8 {
|
||||||
/// Whether the `ComputedValues` structure to be constructed should be
|
|
||||||
/// considered shareable.
|
|
||||||
const SHAREABLE = 0x01,
|
|
||||||
/// Whether to inherit all styles from the parent. If this flag is not
|
/// Whether to inherit all styles from the parent. If this flag is not
|
||||||
/// present, non-inherited styles are reset to their initial values.
|
/// present, non-inherited styles are reset to their initial values.
|
||||||
const INHERIT_ALL = 0x02,
|
const INHERIT_ALL = 0x01,
|
||||||
/// Whether to skip any root element and flex/grid item display style
|
/// Whether to skip any root element and flex/grid item display style
|
||||||
/// fixup.
|
/// fixup.
|
||||||
const SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP = 0x04,
|
const SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP = 0x02,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2033,7 +2026,6 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
|
||||||
|
|
||||||
let starting_style = if !flags.contains(INHERIT_ALL) {
|
let starting_style = if !flags.contains(INHERIT_ALL) {
|
||||||
ComputedValues::new(custom_properties,
|
ComputedValues::new(custom_properties,
|
||||||
flags.contains(SHAREABLE),
|
|
||||||
WritingMode::empty(),
|
WritingMode::empty(),
|
||||||
inherited_style.root_font_size,
|
inherited_style.root_font_size,
|
||||||
inherited_style.font_size_keyword,
|
inherited_style.font_size_keyword,
|
||||||
|
@ -2047,7 +2039,6 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
ComputedValues::new(custom_properties,
|
ComputedValues::new(custom_properties,
|
||||||
flags.contains(SHAREABLE),
|
|
||||||
WritingMode::empty(),
|
WritingMode::empty(),
|
||||||
inherited_style.root_font_size,
|
inherited_style.root_font_size,
|
||||||
inherited_style.font_size_keyword,
|
inherited_style.font_size_keyword,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use atomic_refcell::{AtomicRefCell, AtomicRefMut};
|
||||||
use context::{SharedStyleContext, StyleContext, ThreadLocalStyleContext};
|
use context::{SharedStyleContext, StyleContext, ThreadLocalStyleContext};
|
||||||
use data::{ElementData, ElementStyles, StoredRestyleHint};
|
use data::{ElementData, ElementStyles, StoredRestyleHint};
|
||||||
use dom::{DirtyDescendants, NodeInfo, TElement, TNode};
|
use dom::{DirtyDescendants, NodeInfo, TElement, TNode};
|
||||||
use matching::{MatchMethods, MatchResults};
|
use matching::{MatchMethods, StyleSharingBehavior};
|
||||||
use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_SELF};
|
use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_SELF};
|
||||||
use selector_parser::RestyleDamage;
|
use selector_parser::RestyleDamage;
|
||||||
use servo_config::opts;
|
use servo_config::opts;
|
||||||
|
@ -395,9 +395,7 @@ fn resolve_style_internal<E, F>(context: &mut StyleContext<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute our style.
|
// Compute our style.
|
||||||
let match_results = element.match_element(context, &mut data);
|
element.match_and_cascade(context, &mut data, StyleSharingBehavior::Disallow);
|
||||||
element.cascade_element(context, &mut data,
|
|
||||||
match_results.primary_is_shareable());
|
|
||||||
|
|
||||||
// Conservatively mark us as having dirty descendants, since there might
|
// Conservatively mark us as having dirty descendants, since there might
|
||||||
// be other unstyled siblings we miss when walking straight up the parent
|
// be other unstyled siblings we miss when walking straight up the parent
|
||||||
|
@ -587,7 +585,7 @@ fn compute_style<E, D>(_traversal: &D,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let match_results = match kind {
|
match kind {
|
||||||
MatchAndCascade => {
|
MatchAndCascade => {
|
||||||
// Ensure the bloom filter is up to date.
|
// Ensure the bloom filter is up to date.
|
||||||
let dom_depth =
|
let dom_depth =
|
||||||
|
@ -602,42 +600,20 @@ fn compute_style<E, D>(_traversal: &D,
|
||||||
traversal_data.current_dom_depth = Some(dom_depth);
|
traversal_data.current_dom_depth = Some(dom_depth);
|
||||||
|
|
||||||
context.thread_local.bloom_filter.assert_complete(element);
|
context.thread_local.bloom_filter.assert_complete(element);
|
||||||
|
|
||||||
|
|
||||||
// Perform CSS selector matching.
|
|
||||||
context.thread_local.statistics.elements_matched += 1;
|
context.thread_local.statistics.elements_matched += 1;
|
||||||
element.match_element(context, &mut data)
|
|
||||||
|
// Perform the matching and cascading.
|
||||||
|
element.match_and_cascade(context, &mut data, StyleSharingBehavior::Allow);
|
||||||
}
|
}
|
||||||
CascadeWithReplacements(hint) => {
|
CascadeWithReplacements(hint) => {
|
||||||
let rule_nodes_changed =
|
let _rule_nodes_changed =
|
||||||
element.cascade_with_replacements(hint, context, &mut data);
|
element.cascade_with_replacements(hint, context, &mut data);
|
||||||
MatchResults {
|
element.cascade_primary_and_pseudos(context, &mut data);
|
||||||
primary_relations: None,
|
|
||||||
rule_nodes_changed: rule_nodes_changed,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
CascadeOnly => {
|
CascadeOnly => {
|
||||||
MatchResults {
|
element.cascade_primary_and_pseudos(context, &mut data);
|
||||||
primary_relations: None,
|
|
||||||
rule_nodes_changed: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cascade properties and compute values.
|
|
||||||
let shareable = match_results.primary_is_shareable();
|
|
||||||
unsafe {
|
|
||||||
element.cascade_element(context, &mut data, shareable);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the style is shareable, add it to the LRU cache.
|
|
||||||
if shareable {
|
|
||||||
context.thread_local
|
|
||||||
.style_sharing_candidate_cache
|
|
||||||
.insert_if_possible(&element,
|
|
||||||
data.styles().primary.values(),
|
|
||||||
match_results.primary_relations.unwrap());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn preprocess_children<E, D>(traversal: &D,
|
fn preprocess_children<E, D>(traversal: &D,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue