mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
style: Use CascadeFlags for what they're for.
Now that we have an Element around on cascade, we can stop using the cascade flags mechanism to pass various element-related state, like "is this element the root", or "should it use the item-based display fixup". That fixes handwaviness in the handling of those flags from style reparenting, and code duplication to handle tricky stuff like :visited. There are a number of other changes that are worth noticing: * skip_root_and_item_based_display_fixup is renamed to skip_item_display_fixup: TElement::is_root() already implies being the document element, which by definition is not native anonymous and not a pseudo-element. Thus, you never get fixed-up if your NAC or a pseudo, which is what the code tried to avoid, so the only fixup with a point is the item one, which is necessary. * The pseudo-element probing code was refactored to return early a Option::<CascadeInputs>::None, which is nicer than what it was doing. * The visited_links_enabled check has moved to selector-matching time. The rest of the checks aren't based on whether the element is a link, or are properly guarded by parent_style.visited_style().is_some() or visited_rules.is_some(). Thus you can transitively infer that no element will end up with a :visited style, not even from style reparenting. Anyway, the underlying reason why I want the element in StyleAdjuster is because we're going to implement an adjustment in there depending on the tag of the element (converting display: contents to display: none depending on the tag), so computing that information eagerly, including a hash lookup, wouldn't be nice.
This commit is contained in:
parent
104f5c2553
commit
cd04664fb9
11 changed files with 233 additions and 298 deletions
|
@ -22,6 +22,7 @@ use malloc_size_of::MallocUnconditionalShallowSizeOf;
|
|||
use media_queries::Device;
|
||||
use properties::{self, CascadeFlags, ComputedValues};
|
||||
use properties::{AnimationRules, PropertyDeclarationBlock};
|
||||
use rule_cache::{RuleCache, RuleCacheConditions};
|
||||
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
|
||||
use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry};
|
||||
use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement};
|
||||
|
@ -650,7 +651,6 @@ impl Stylist {
|
|||
guards: &StylesheetGuards,
|
||||
pseudo: &PseudoElement,
|
||||
parent: Option<&ComputedValues>,
|
||||
cascade_flags: CascadeFlags,
|
||||
font_metrics: &FontMetricsProvider,
|
||||
) -> Arc<ComputedValues>
|
||||
where
|
||||
|
@ -668,7 +668,6 @@ impl Stylist {
|
|||
guards,
|
||||
pseudo,
|
||||
parent,
|
||||
cascade_flags,
|
||||
font_metrics,
|
||||
rule_node
|
||||
)
|
||||
|
@ -684,25 +683,23 @@ impl Stylist {
|
|||
guards: &StylesheetGuards,
|
||||
pseudo: &PseudoElement,
|
||||
parent: Option<&ComputedValues>,
|
||||
cascade_flags: CascadeFlags,
|
||||
font_metrics: &FontMetricsProvider,
|
||||
rule_node: StrongRuleNode
|
||||
rules: StrongRuleNode
|
||||
) -> Arc<ComputedValues>
|
||||
where
|
||||
E: TElement,
|
||||
{
|
||||
self.compute_pseudo_element_style_with_inputs::<E>(
|
||||
&CascadeInputs {
|
||||
rules: Some(rule_node),
|
||||
CascadeInputs {
|
||||
rules: Some(rules),
|
||||
visited_rules: None,
|
||||
},
|
||||
pseudo,
|
||||
guards,
|
||||
parent,
|
||||
font_metrics,
|
||||
cascade_flags,
|
||||
None,
|
||||
).unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the rule node for given precomputed pseudo-element.
|
||||
|
@ -757,44 +754,10 @@ impl Stylist {
|
|||
E: TElement,
|
||||
{
|
||||
use font_metrics::ServoMetricsProvider;
|
||||
|
||||
// For most (but not all) pseudo-elements, we inherit all values from the parent.
|
||||
let inherit_all = match *pseudo {
|
||||
// Anonymous table flows shouldn't inherit their parents properties in order
|
||||
// to avoid doubling up styles such as transformations.
|
||||
PseudoElement::ServoAnonymousTableCell |
|
||||
PseudoElement::ServoAnonymousTableRow |
|
||||
PseudoElement::ServoText |
|
||||
PseudoElement::ServoInputText => false,
|
||||
PseudoElement::ServoAnonymousBlock |
|
||||
|
||||
// For tables, we do want style to inherit, because TableWrapper is responsible
|
||||
// for handling clipping and scrolling, while Table is responsible for creating
|
||||
// stacking contexts. StackingContextCollectionFlags makes sure this is processed
|
||||
// properly.
|
||||
PseudoElement::ServoAnonymousTable |
|
||||
PseudoElement::ServoAnonymousTableWrapper |
|
||||
|
||||
PseudoElement::ServoTableWrapper |
|
||||
PseudoElement::ServoInlineBlockWrapper |
|
||||
PseudoElement::ServoInlineAbsolute => true,
|
||||
PseudoElement::Before |
|
||||
PseudoElement::After |
|
||||
PseudoElement::Selection |
|
||||
PseudoElement::DetailsSummary |
|
||||
PseudoElement::DetailsContent => {
|
||||
unreachable!("That pseudo doesn't represent an anonymous box!")
|
||||
}
|
||||
};
|
||||
let mut cascade_flags = CascadeFlags::empty();
|
||||
if inherit_all {
|
||||
cascade_flags.insert(CascadeFlags::INHERIT_ALL);
|
||||
}
|
||||
self.precomputed_values_for_pseudo::<E>(
|
||||
guards,
|
||||
&pseudo,
|
||||
Some(parent_style),
|
||||
cascade_flags,
|
||||
&ServoMetricsProvider,
|
||||
)
|
||||
}
|
||||
|
@ -828,17 +791,16 @@ impl Stylist {
|
|||
is_probe,
|
||||
rule_inclusion,
|
||||
matching_fn
|
||||
);
|
||||
)?;
|
||||
|
||||
self.compute_pseudo_element_style_with_inputs(
|
||||
&cascade_inputs,
|
||||
Some(self.compute_pseudo_element_style_with_inputs(
|
||||
cascade_inputs,
|
||||
pseudo,
|
||||
guards,
|
||||
Some(parent_style),
|
||||
font_metrics,
|
||||
CascadeFlags::empty(),
|
||||
Some(element),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
/// Computes a pseudo-element style lazily using the given CascadeInputs.
|
||||
|
@ -847,23 +809,16 @@ impl Stylist {
|
|||
/// their style with a new parent style.
|
||||
pub fn compute_pseudo_element_style_with_inputs<E>(
|
||||
&self,
|
||||
inputs: &CascadeInputs,
|
||||
inputs: CascadeInputs,
|
||||
pseudo: &PseudoElement,
|
||||
guards: &StylesheetGuards,
|
||||
parent_style: Option<&ComputedValues>,
|
||||
font_metrics: &FontMetricsProvider,
|
||||
cascade_flags: CascadeFlags,
|
||||
element: Option<E>,
|
||||
) -> Option<Arc<ComputedValues>>
|
||||
) -> Arc<ComputedValues>
|
||||
where
|
||||
E: TElement,
|
||||
{
|
||||
// We may have only visited rules in cases when we are actually
|
||||
// resolving, not probing, pseudo-element style.
|
||||
if inputs.rules.is_none() && inputs.visited_rules.is_none() {
|
||||
return None
|
||||
}
|
||||
|
||||
// FIXME(emilio): The lack of layout_parent_style here could be
|
||||
// worrying, but we're probably dropping the display fixup for
|
||||
// pseudos other than before and after, so it's probably ok.
|
||||
|
@ -876,17 +831,18 @@ impl Stylist {
|
|||
// <fieldset style="display: contents">. That is, the computed value of
|
||||
// display for the fieldset is "contents", even though it's not the used
|
||||
// value, so we don't need to adjust in a different way anyway.
|
||||
Some(self.compute_style_with_inputs(
|
||||
inputs,
|
||||
self.cascade_style_and_visited(
|
||||
element,
|
||||
Some(pseudo),
|
||||
inputs,
|
||||
guards,
|
||||
parent_style,
|
||||
parent_style,
|
||||
parent_style,
|
||||
font_metrics,
|
||||
cascade_flags,
|
||||
element,
|
||||
))
|
||||
/* rule_cache = */ None,
|
||||
&mut RuleCacheConditions::default(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Computes a style using the given CascadeInputs. This can be used to
|
||||
|
@ -904,38 +860,43 @@ impl Stylist {
|
|||
///
|
||||
/// is_link should be true if we're computing style for a link; that affects
|
||||
/// how :visited handling is done.
|
||||
pub fn compute_style_with_inputs<E>(
|
||||
pub fn cascade_style_and_visited<E>(
|
||||
&self,
|
||||
inputs: &CascadeInputs,
|
||||
element: Option<E>,
|
||||
pseudo: Option<&PseudoElement>,
|
||||
inputs: CascadeInputs,
|
||||
guards: &StylesheetGuards,
|
||||
parent_style: Option<&ComputedValues>,
|
||||
parent_style_ignoring_first_line: Option<&ComputedValues>,
|
||||
layout_parent_style: Option<&ComputedValues>,
|
||||
font_metrics: &FontMetricsProvider,
|
||||
cascade_flags: CascadeFlags,
|
||||
element: Option<E>,
|
||||
rule_cache: Option<&RuleCache>,
|
||||
rule_cache_conditions: &mut RuleCacheConditions,
|
||||
) -> Arc<ComputedValues>
|
||||
where
|
||||
E: TElement,
|
||||
{
|
||||
debug_assert!(pseudo.is_some() || element.is_some(), "Huh?");
|
||||
|
||||
let cascade_flags =
|
||||
pseudo.map_or(CascadeFlags::empty(), |p| p.cascade_flags());
|
||||
|
||||
// We need to compute visited values if we have visited rules or if our
|
||||
// parent has visited values.
|
||||
let mut visited_values = None;
|
||||
if inputs.visited_rules.is_some() ||
|
||||
parent_style.and_then(|s| s.visited_style()).is_some()
|
||||
{
|
||||
// At this point inputs may have visited rules, or rules, or both,
|
||||
// or neither (e.g. if it's a text style it may have neither). So
|
||||
// we have to be a bit careful here.
|
||||
// At this point inputs may have visited rules, or rules.
|
||||
let rule_node = match inputs.visited_rules.as_ref() {
|
||||
Some(rules) => rules,
|
||||
None => inputs.rules.as_ref().unwrap_or(self.rule_tree().root()),
|
||||
None => inputs.rules.as_ref().unwrap_or(self.rule_tree.root()),
|
||||
};
|
||||
|
||||
let inherited_style;
|
||||
let inherited_style_ignoring_first_line;
|
||||
let layout_parent_style_for_visited;
|
||||
if cascade_flags.contains(CascadeFlags::IS_LINK) {
|
||||
if pseudo.is_none() && element.unwrap().is_link() {
|
||||
// We just want to use our parent style as our parent.
|
||||
inherited_style = parent_style;
|
||||
inherited_style_ignoring_first_line = parent_style_ignoring_first_line;
|
||||
|
@ -969,24 +930,22 @@ impl Stylist {
|
|||
font_metrics,
|
||||
cascade_flags | CascadeFlags::VISITED_DEPENDENT_ONLY,
|
||||
self.quirks_mode,
|
||||
/* rule_cache = */ None,
|
||||
&mut Default::default(),
|
||||
rule_cache,
|
||||
rule_cache_conditions,
|
||||
element,
|
||||
));
|
||||
}
|
||||
|
||||
// We may not have non-visited rules, if we only had visited ones. In
|
||||
// that case we want to use the root rulenode for our non-visited rules.
|
||||
let rules = inputs.rules.as_ref().unwrap_or(self.rule_tree.root());
|
||||
|
||||
// Read the comment on `precomputed_values_for_pseudo` to see why it's
|
||||
// difficult to assert that display: contents nodes never arrive here
|
||||
// (tl;dr: It doesn't apply for replaced elements and such, but the
|
||||
// computed value is still "contents").
|
||||
//
|
||||
// FIXME(emilio): We should assert that it holds if pseudo.is_none()!
|
||||
properties::cascade::<E>(
|
||||
&self.device,
|
||||
pseudo,
|
||||
rules,
|
||||
inputs.rules.as_ref().unwrap_or(self.rule_tree.root()),
|
||||
guards,
|
||||
parent_style,
|
||||
parent_style_ignoring_first_line,
|
||||
|
@ -995,9 +954,9 @@ impl Stylist {
|
|||
font_metrics,
|
||||
cascade_flags,
|
||||
self.quirks_mode,
|
||||
/* rule_cache = */ None,
|
||||
&mut Default::default(),
|
||||
None,
|
||||
rule_cache,
|
||||
rule_cache_conditions,
|
||||
element,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1014,7 +973,7 @@ impl Stylist {
|
|||
is_probe: bool,
|
||||
rule_inclusion: RuleInclusion,
|
||||
matching_fn: Option<&Fn(&PseudoElement) -> bool>,
|
||||
) -> CascadeInputs
|
||||
) -> Option<CascadeInputs>
|
||||
where
|
||||
E: TElement
|
||||
{
|
||||
|
@ -1051,7 +1010,6 @@ impl Stylist {
|
|||
}
|
||||
};
|
||||
|
||||
let mut inputs = CascadeInputs::default();
|
||||
let mut declarations = ApplicableDeclarationList::new();
|
||||
let mut matching_context = MatchingContext::new(
|
||||
MatchingMode::ForStatelessPseudoElement,
|
||||
|
@ -1074,19 +1032,14 @@ impl Stylist {
|
|||
&mut set_selector_flags
|
||||
);
|
||||
|
||||
if !declarations.is_empty() {
|
||||
let rule_node =
|
||||
self.rule_tree.compute_rule_node(&mut declarations, guards);
|
||||
debug_assert!(rule_node != *self.rule_tree.root());
|
||||
inputs.rules = Some(rule_node);
|
||||
if declarations.is_empty() && is_probe {
|
||||
return None;
|
||||
}
|
||||
|
||||
if is_probe && inputs.rules.is_none() {
|
||||
// When probing, don't compute visited styles if we have no
|
||||
// unvisited styles.
|
||||
return inputs;
|
||||
}
|
||||
let rules =
|
||||
self.rule_tree.compute_rule_node(&mut declarations, guards);
|
||||
|
||||
let mut visited_rules = None;
|
||||
if parent_style.visited_style().is_some() {
|
||||
let mut declarations = ApplicableDeclarationList::new();
|
||||
let mut matching_context =
|
||||
|
@ -1114,14 +1067,15 @@ impl Stylist {
|
|||
let rule_node =
|
||||
self.rule_tree.insert_ordered_rules_with_important(
|
||||
declarations.drain().map(|a| a.order_and_level()),
|
||||
guards);
|
||||
guards,
|
||||
);
|
||||
if rule_node != *self.rule_tree.root() {
|
||||
inputs.visited_rules = Some(rule_node);
|
||||
visited_rules = Some(rule_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inputs
|
||||
Some(CascadeInputs { rules: Some(rules), visited_rules })
|
||||
}
|
||||
|
||||
/// Set a given device, which may change the styles that apply to the
|
||||
|
@ -1596,7 +1550,7 @@ impl Stylist {
|
|||
self.quirks_mode,
|
||||
/* rule_cache = */ None,
|
||||
&mut Default::default(),
|
||||
None,
|
||||
/* element = */ None,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue