mirror of
https://github.com/servo/servo.git
synced 2025-08-15 02:15:33 +01:00
style: Rewrite restyling to split between resolving styles and handling changes.
MozReview-Commit-ID: 4BzjbLbFebF
This commit is contained in:
parent
0ad2d39c30
commit
c6d5dbbb01
8 changed files with 485 additions and 1500 deletions
|
@ -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,7 +131,7 @@ where
|
|||
}
|
||||
|
||||
let style = self.cascade_style(
|
||||
&primary_results.rule_node,
|
||||
Some(&primary_results.rule_node),
|
||||
visited_style,
|
||||
parent_style,
|
||||
layout_parent_style,
|
||||
|
@ -113,7 +139,7 @@ where
|
|||
/* 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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue