Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style: Split style resolution and dynamic change computation. #17688

Merged
merged 11 commits into from Jul 12, 2017

style: Rewrite restyling to split between resolving styles and handli…

…ng changes.

MozReview-Commit-ID: 4BzjbLbFebF
  • Loading branch information
emilio committed Jul 12, 2017
commit c6d5dbbb01eeb41865f0f070d9c72a0b7589ad09

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -2576,11 +2576,11 @@ pub fn cascade(device: &Device,
flags: CascadeFlags,
quirks_mode: QuirksMode)
-> ComputedValues {
debug_assert_eq!(parent_style.is_some(), layout_parent_style.is_some());
debug_assert!(layout_parent_style.is_none() || parent_style.is_some());
let (inherited_style, layout_parent_style) = match parent_style {
Some(parent_style) => {
(parent_style,
layout_parent_style.unwrap())
layout_parent_style.unwrap_or(parent_style))
},
None => {
(device.default_computed_values(),
@@ -75,7 +75,7 @@ use dom::{TElement, SendElement};
use matching::{ChildCascadeRequirement, MatchMethods};
use properties::ComputedValues;
use selector_parser::RestyleDamage;
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode, StyleRelations};
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
use smallvec::SmallVec;
use std::mem;
use std::ops::Deref;
@@ -494,11 +494,8 @@ impl<E: TElement> StyleSharingCandidateCache<E> {
pub fn insert_if_possible(&mut self,
element: &E,
style: &ComputedValues,
relations: StyleRelations,
mut validation_data: ValidationData,
validation_data: ValidationData,
dom_depth: usize) {
use selectors::matching::AFFECTED_BY_PRESENTATIONAL_HINTS;

let parent = match element.traversal_parent() {
Some(element) => element,
None => {
@@ -525,13 +522,6 @@ impl<E: TElement> StyleSharingCandidateCache<E> {
return;
}

// Take advantage of the information we've learned during
// selector-matching.
if !relations.intersects(AFFECTED_BY_PRESENTATIONAL_HINTS) {
debug_assert!(validation_data.pres_hints.as_ref().map_or(true, |v| v.is_empty()));
validation_data.pres_hints = Some(SmallVec::new());
}

debug!("Inserting into cache: {:?} with parent {:?}", element, parent);

if self.dom_depth != dom_depth {
@@ -6,7 +6,7 @@

use applicable_declarations::ApplicableDeclarationList;
use cascade_info::CascadeInfo;
use context::StyleContext;
use context::{CascadeInputs, ElementCascadeInputs, StyleContext};
use data::{ElementStyles, EagerPseudoStyles};
use dom::TElement;
use log::LogLevel::Trace;
@@ -42,11 +42,37 @@ struct MatchingResults {
pub struct PrimaryStyle {
/// The style per se.
pub style: Arc<ComputedValues>,
}

/// Whether a relevant link was found while computing this style.
///
/// FIXME(emilio): Slightly out of place?
pub relevant_link_found: bool,
fn with_default_parent_styles<E, F, R>(element: E, f: F) -> R
where
E: TElement,
F: FnOnce(Option<&ComputedValues>, Option<&ComputedValues>) -> R,
{
let parent_el = element.inheritance_parent();
let parent_data = parent_el.as_ref().and_then(|e| e.borrow_data());
let parent_style = parent_data.as_ref().map(|d| {
// Sometimes Gecko eagerly styles things without processing
// pending restyles first. In general we'd like to avoid this,
// but there can be good reasons (for example, needing to
// construct a frame for some small piece of newly-added
// content in order to do something specific with that frame,
// but not wanting to flush all of layout).
debug_assert!(cfg!(feature = "gecko") ||
parent_el.unwrap().has_current_styles(d));
d.styles.primary()
});

let mut layout_parent_el = parent_el.clone();
let layout_parent_data;
let mut layout_parent_style = parent_style;
if parent_style.map_or(false, |s| s.is_display_contents()) {
layout_parent_el = Some(layout_parent_el.unwrap().layout_parent());
layout_parent_data = layout_parent_el.as_ref().unwrap().borrow_data().unwrap();
layout_parent_style = Some(layout_parent_data.styles.primary());
}

f(parent_style.map(|s| &**s), layout_parent_style.map(|s| &**s))
}

impl<'a, 'ctx, 'le, E> StyleResolverForElement<'a, 'ctx, 'le, E>
@@ -95,7 +121,7 @@ where

if should_compute_visited_style {
visited_style = Some(self.cascade_style(
visited_rules.as_ref().unwrap_or(&primary_results.rule_node),
visited_rules.as_ref(),
/* style_if_visited = */ None,
parent_style,
layout_parent_style,
@@ -105,15 +131,15 @@ where
}

let style = self.cascade_style(
&primary_results.rule_node,
Some(&primary_results.rule_node),
visited_style,
parent_style,
layout_parent_style,
CascadeVisitedMode::Unvisited,
/* pseudo = */ None,
);

PrimaryStyle { style, relevant_link_found, }
PrimaryStyle { style, }
}


@@ -137,7 +163,7 @@ where
}
}

{
if self.element.implemented_pseudo_element().is_none() {
let layout_parent_style_for_pseudo =
if primary_style.style.is_display_contents() {
layout_parent_style
@@ -163,6 +189,115 @@ where
}
}

/// Resolve an element's styles with the default inheritance parent/layout
/// parents.
pub fn resolve_style_with_default_parents(&mut self) -> ElementStyles {
with_default_parent_styles(self.element, |parent_style, layout_parent_style| {
self.resolve_style(parent_style, layout_parent_style)
})
}

/// Cascade a set of rules, using the default parent for inheritance.
pub fn cascade_style_and_visited_with_default_parents(
&mut self,
inputs: CascadeInputs,
) -> Arc<ComputedValues> {
with_default_parent_styles(self.element, |parent_style, layout_parent_style| {
self.cascade_style_and_visited(
inputs,
parent_style,
layout_parent_style,
/* pseudo = */ None
)
})
}

fn cascade_style_and_visited(
&mut self,
inputs: CascadeInputs,
parent_style: Option<&ComputedValues>,
layout_parent_style: Option<&ComputedValues>,
pseudo: Option<&PseudoElement>,
) -> Arc<ComputedValues> {
let mut style_if_visited = None;
if parent_style.map_or(false, |s| s.get_visited_style().is_some()) ||
inputs.visited_rules.is_some() {
style_if_visited = Some(self.cascade_style(
inputs.visited_rules.as_ref(),
/* style_if_visited = */ None,
parent_style,
layout_parent_style,
CascadeVisitedMode::Visited,
pseudo,
));
}
self.cascade_style(
inputs.rules.as_ref(),
style_if_visited,
parent_style,
layout_parent_style,
CascadeVisitedMode::Unvisited,
pseudo,
)
}

/// Cascade the element and pseudo-element styles with the default parents.
pub fn cascade_styles_with_default_parents(
&mut self,
inputs: ElementCascadeInputs,
) -> ElementStyles {
use properties::longhands::display::computed_value::T as display;
with_default_parent_styles(self.element, move |parent_style, layout_parent_style| {
let primary_style = PrimaryStyle {
style: self.cascade_style_and_visited(
inputs.primary,
parent_style,
layout_parent_style,
/* pseudo = */ None,
),
};

let mut pseudo_styles = EagerPseudoStyles::default();
let pseudo_array = inputs.pseudos.into_array();
if pseudo_array.is_none() ||
primary_style.style.get_box().clone_display() == display::none {
return ElementStyles {
primary: Some(primary_style.style),
pseudos: pseudo_styles,
}
}

{
let layout_parent_style_for_pseudo =
if primary_style.style.is_display_contents() {
layout_parent_style
} else {
Some(&*primary_style.style)
};

for (i, mut inputs) in pseudo_array.unwrap().iter_mut().enumerate() {
if let Some(inputs) = inputs.take() {
let pseudo = PseudoElement::from_eager_index(i);
pseudo_styles.set(
&pseudo,
self.cascade_style_and_visited(
inputs,
Some(&*primary_style.style),
layout_parent_style_for_pseudo,
Some(&pseudo),
)
)
}
}
}

ElementStyles {
primary: Some(primary_style.style),
pseudos: pseudo_styles,
}
})
}

fn resolve_pseudo_style(
&mut self,
pseudo: &PseudoElement,
@@ -179,33 +314,23 @@ where
None => return None,
};

let mut visited_style = None;
if originating_element_style.relevant_link_found {
let visited_rules = self.match_pseudo(
let mut visited_rules = None;
if originating_element_style.style.get_visited_style().is_some() {
visited_rules = self.match_pseudo(
&originating_element_style.style,
pseudo,
VisitedHandlingMode::RelevantLinkVisited,
);

if let Some(ref rules) = visited_rules {
visited_style = Some(self.cascade_style(
rules,
/* style_if_visited = */ None,
Some(&originating_element_style.style),
layout_parent_style,
CascadeVisitedMode::Visited,
Some(pseudo),
));
}
}

Some(self.cascade_style(
&rules,
visited_style,
Some(self.cascade_style_and_visited(
CascadeInputs {
rules: Some(rules),
visited_rules
},
Some(&originating_element_style.style),
layout_parent_style,
CascadeVisitedMode::Unvisited,
Some(pseudo)
Some(pseudo),
))
}

@@ -335,9 +460,9 @@ where

fn cascade_style(
&mut self,
rules: &StrongRuleNode,
rules: Option<&StrongRuleNode>,
style_if_visited: Option<Arc<ComputedValues>>,
parent_style: Option<&ComputedValues>,
mut parent_style: Option<&ComputedValues>,
layout_parent_style: Option<&ComputedValues>,
cascade_visited: CascadeVisitedMode,
pseudo: Option<&PseudoElement>,
@@ -349,6 +474,9 @@ where
cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP);
}
if cascade_visited.visited_dependent_only() {
parent_style = parent_style.map(|s| {
s.get_visited_style().map(|s| &**s).unwrap_or(s)
});
cascade_flags.insert(VISITED_DEPENDENT_ONLY);
}
if self.element.is_native_anonymous() || pseudo.is_some() {
@@ -360,13 +488,12 @@ where
let values =
Arc::new(cascade(
self.context.shared.stylist.device(),
rules,
rules.unwrap_or(self.context.shared.stylist.rule_tree().root()),
&self.context.shared.guards,
parent_style,
layout_parent_style,
style_if_visited,
Some(&mut cascade_info),
&*self.context.shared.error_reporter,
&self.context.thread_local.font_metrics_provider,
cascade_flags,
self.context.shared.quirks_mode
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.