aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout_thread/dom_wrapper.rs2
-rw-r--r--components/script_layout_interface/wrapper_traits.rs3
-rw-r--r--components/style/dom.rs2
-rw-r--r--components/style/gecko/pseudo_element.rs13
-rw-r--r--components/style/gecko/wrapper.rs14
-rw-r--r--components/style/properties/properties.mako.rs35
-rw-r--r--components/style/servo/selector_parser.rs46
-rw-r--r--components/style/style_adjuster.rs92
-rw-r--r--components/style/style_resolver.rs145
-rw-r--r--components/style/stylist.rs146
-rw-r--r--ports/geckolib/glue.rs33
11 files changed, 233 insertions, 298 deletions
diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs
index f900854d1c4..0110704edad 100644
--- a/components/layout_thread/dom_wrapper.rs
+++ b/components/layout_thread/dom_wrapper.rs
@@ -455,7 +455,7 @@ impl<'le> TElement for ServoLayoutElement<'le> {
}
}
- fn skip_root_and_item_based_display_fixup(&self) -> bool {
+ fn skip_item_display_fixup(&self) -> bool {
false
}
diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs
index ffdc9aa95ed..0b04d4256a6 100644
--- a/components/script_layout_interface/wrapper_traits.rs
+++ b/components/script_layout_interface/wrapper_traits.rs
@@ -22,7 +22,7 @@ use style::data::ElementData;
use style::dom::{LayoutIterator, NodeInfo, TElement, TNode};
use style::dom::OpaqueNode;
use style::font_metrics::ServoMetricsProvider;
-use style::properties::{CascadeFlags, ComputedValues};
+use style::properties::ComputedValues;
use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl};
use style::stylist::RuleInclusion;
use webrender_api::ClipId;
@@ -393,7 +393,6 @@ pub trait ThreadSafeLayoutElement
&context.guards,
&style_pseudo,
Some(data.styles.primary()),
- CascadeFlags::empty(),
&ServoMetricsProvider,
)
}
diff --git a/components/style/dom.rs b/components/style/dom.rs
index bfa0b6078ac..88cd7a82829 100644
--- a/components/style/dom.rs
+++ b/components/style/dom.rs
@@ -680,7 +680,7 @@ pub trait TElement
/// Whether we should skip any root- or item-based display property
/// blockification on this element. (This function exists so that Gecko
/// native anonymous content can opt out of this style fixup.)
- fn skip_root_and_item_based_display_fixup(&self) -> bool;
+ fn skip_item_display_fixup(&self) -> bool;
/// Sets selector flags, which indicate what kinds of selectors may have
/// matched on this element and therefore what kind of work may need to
diff --git a/components/style/gecko/pseudo_element.rs b/components/style/gecko/pseudo_element.rs
index 852498ab9ec..ab38bdff798 100644
--- a/components/style/gecko/pseudo_element.rs
+++ b/components/style/gecko/pseudo_element.rs
@@ -10,7 +10,7 @@
use cssparser::{ToCss, serialize_identifier};
use gecko_bindings::structs::{self, CSSPseudoElementType};
-use properties::{ComputedValues, PropertyFlags};
+use properties::{CascadeFlags, ComputedValues, PropertyFlags};
use properties::longhands::display::computed_value::T as Display;
use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
use std::fmt;
@@ -51,6 +51,15 @@ impl PseudoElement {
PseudoElementCascadeType::Lazy
}
+ /// The CascadeFlags needed to cascade this pseudo-element.
+ ///
+ /// This is only needed to support the broken INHERIT_ALL pseudo mode for
+ /// Servo.
+ #[inline]
+ pub fn cascade_flags(&self) -> CascadeFlags {
+ CascadeFlags::empty()
+ }
+
/// Whether the pseudo-element should inherit from the default computed
/// values instead of from the parent element.
///
@@ -128,7 +137,7 @@ impl PseudoElement {
/// Whether this pseudo-element skips flex/grid container display-based
/// fixup.
#[inline]
- pub fn skip_item_based_display_fixup(&self) -> bool {
+ pub fn skip_item_display_fixup(&self) -> bool {
(self.flags() & structs::CSS_PSEUDO_ELEMENT_IS_FLEX_OR_GRID_ITEM) == 0
}
diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs
index de4855c4ed4..92aedc3b5d7 100644
--- a/components/style/gecko/wrapper.rs
+++ b/components/style/gecko/wrapper.rs
@@ -1285,15 +1285,11 @@ impl<'le> TElement for GeckoElement<'le> {
}
#[inline]
- fn skip_root_and_item_based_display_fixup(&self) -> bool {
- if !self.is_native_anonymous() {
- return false;
- }
-
- if let Some(p) = self.implemented_pseudo_element() {
- return p.skip_item_based_display_fixup();
- }
-
+ fn skip_item_display_fixup(&self) -> bool {
+ debug_assert!(
+ self.implemented_pseudo_element().is_none(),
+ "Just don't call me if I'm a pseudo, you should know the answer already"
+ );
self.is_root_of_native_anonymous_subtree()
}
diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs
index 8e551312044..e87f6758b3c 100644
--- a/components/style/properties/properties.mako.rs
+++ b/components/style/properties/properties.mako.rs
@@ -3148,30 +3148,8 @@ bitflags! {
/// present, non-inherited styles are reset to their initial values.
const INHERIT_ALL = 1;
- /// Whether to skip any display style fixup for root element, flex/grid
- /// item, and ruby descendants.
- const SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP = 1 << 1;
-
/// Whether to only cascade properties that are visited dependent.
- const VISITED_DEPENDENT_ONLY = 1 << 2;
-
- /// Whether the given element we're styling is the document element,
- /// that is, matches :root.
- ///
- /// Not set for native anonymous content since some NAC form their own
- /// root, but share the device.
- ///
- /// This affects some style adjustments, like blockification, and means
- /// that it may affect global state, like the Device's root font-size.
- const IS_ROOT_ELEMENT = 1 << 3;
-
- /// Whether we're computing the style of a link, either visited or
- /// unvisited.
- const IS_LINK = 1 << 4;
-
- /// Whether we're computing the style of a link element that happens to
- /// be visited.
- const IS_VISITED_LINK = 1 << 5;
+ const VISITED_DEPENDENT_ONLY = 1 << 1;
}
}
@@ -3287,7 +3265,7 @@ pub fn apply_declarations<'a, E, F, I>(
quirks_mode: QuirksMode,
rule_cache: Option<<&RuleCache>,
rule_cache_conditions: &mut RuleCacheConditions,
- _element: Option<E>,
+ element: Option<E>,
) -> Arc<ComputedValues>
where
E: TElement,
@@ -3326,7 +3304,7 @@ where
};
let mut context = computed::Context {
- is_root_element: flags.contains(CascadeFlags::IS_ROOT_ELEMENT),
+ is_root_element: pseudo.is_none() && element.map_or(false, |e| e.is_root()),
// We'd really like to own the rules here to avoid refcount traffic, but
// animation's usage of `apply_declarations` make this tricky. See bug
// 1375525.
@@ -3610,8 +3588,11 @@ where
builder.clear_modified_reset();
- StyleAdjuster::new(&mut builder)
- .adjust(layout_parent_style, flags);
+ StyleAdjuster::new(&mut builder).adjust(
+ layout_parent_style,
+ element,
+ flags,
+ );
if builder.modified_reset() || !apply_reset {
// If we adjusted any reset structs, we can't cache this ComputedValues.
diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs
index bc6cc31cf7d..04c164e290d 100644
--- a/components/style/servo/selector_parser.rs
+++ b/components/style/servo/selector_parser.rs
@@ -14,8 +14,7 @@ use element_state::{DocumentState, ElementState};
use fnv::FnvHashMap;
use invalidation::element::document_state::InvalidationMatchingData;
use invalidation::element::element_wrapper::ElementSnapshot;
-use properties::ComputedValues;
-use properties::PropertyFlags;
+use properties::{CascadeFlags, ComputedValues, PropertyFlags};
use properties::longhands::display::computed_value::T as Display;
use selector_parser::{AttrValue as SelectorAttrValue, PseudoElementCascadeType, SelectorParser};
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
@@ -174,10 +173,10 @@ impl PseudoElement {
self.is_precomputed()
}
- /// Whether this pseudo-element skips flex/grid container
- /// display-based fixup.
+ /// Whether this pseudo-element skips flex/grid container display-based
+ /// fixup.
#[inline]
- pub fn skip_item_based_display_fixup(&self) -> bool {
+ pub fn skip_item_display_fixup(&self) -> bool {
!self.is_before_or_after()
}
@@ -213,6 +212,43 @@ impl PseudoElement {
}
}
+ /// For most (but not all) anon-boxes, we inherit all values from the
+ /// parent, this is the hook in the style system to allow this.
+ ///
+ /// FIXME(emilio): It's likely that this is broken in a variety of
+ /// situations, and what it really wants is just inherit some reset
+ /// properties... Also, I guess it just could do all: inherit on the
+ /// stylesheet, though chances are that'd be kinda slow if we don't cache
+ /// them...
+ pub fn cascade_flags(&self) -> CascadeFlags {
+ match *self {
+ PseudoElement::After |
+ PseudoElement::Before |
+ PseudoElement::Selection |
+ PseudoElement::DetailsContent |
+ PseudoElement::DetailsSummary => CascadeFlags::empty(),
+ // 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 => CascadeFlags::empty(),
+
+ // 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::ServoAnonymousBlock |
+ PseudoElement::ServoInlineBlockWrapper |
+ PseudoElement::ServoInlineAbsolute => CascadeFlags::INHERIT_ALL,
+ }
+ }
+
/// Covert non-canonical pseudo-element to canonical one, and keep a
/// canonical one as it is.
pub fn canonical(&self) -> PseudoElement {
diff --git a/components/style/style_adjuster.rs b/components/style/style_adjuster.rs
index 052d80dbe22..7f805bb3f5c 100644
--- a/components/style/style_adjuster.rs
+++ b/components/style/style_adjuster.rs
@@ -6,6 +6,7 @@
//! a computed style needs in order for it to adhere to the CSS spec.
use app_units::Au;
+use dom::TElement;
use properties::{self, CascadeFlags, ComputedValues, StyleBuilder};
use properties::longhands::display::computed_value::T as Display;
use properties::longhands::float::computed_value::T as Float;
@@ -50,13 +51,30 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
}
+ /// Whether we should skip any item-based display property blockification on
+ /// this element.
+ fn skip_item_display_fixup<E>(&self, element: Option<E>) -> bool
+ where
+ E: TElement,
+ {
+ if let Some(pseudo) = self.style.pseudo {
+ return pseudo.skip_item_display_fixup();
+ }
+
+ element.map_or(false, |e| e.skip_item_display_fixup())
+ }
+
+
/// Apply the blockification rules based on the table in CSS 2.2 section 9.7.
/// <https://drafts.csswg.org/css2/visuren.html#dis-pos-flo>
- fn blockify_if_necessary(
+ fn blockify_if_necessary<E>(
&mut self,
layout_parent_style: &ComputedValues,
- flags: CascadeFlags,
- ) {
+ element: Option<E>,
+ )
+ where
+ E: TElement,
+ {
let mut blockify = false;
macro_rules! blockify_if {
($if_what:expr) => {
@@ -66,8 +84,9 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
}
- if !flags.contains(CascadeFlags::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP) {
- blockify_if!(flags.contains(CascadeFlags::IS_ROOT_ELEMENT));
+ let is_root = self.style.pseudo.is_none() && element.map_or(false, |e| e.is_root());
+ blockify_if!(is_root);
+ if !self.skip_item_display_fixup(element) {
blockify_if!(layout_parent_style.get_box().clone_display().is_item_container());
}
@@ -81,8 +100,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
let display = self.style.get_box().clone_display();
- let blockified_display =
- display.equivalent_block_display(flags.contains(CascadeFlags::IS_ROOT_ELEMENT));
+ let blockified_display = display.equivalent_block_display(is_root);
if display != blockified_display {
self.style.mutate_box().set_adjusted_display(
blockified_display,
@@ -477,12 +495,14 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
/// * suppress border and padding for ruby level containers,
/// * correct unicode-bidi.
#[cfg(feature = "gecko")]
- fn adjust_for_ruby(
+ fn adjust_for_ruby<E>(
&mut self,
layout_parent_style: &ComputedValues,
- flags: CascadeFlags,
- ) {
- use properties::CascadeFlags;
+ element: Option<E>,
+ )
+ where
+ E: TElement,
+ {
use properties::computed_value_flags::ComputedValueFlags;
use properties::longhands::unicode_bidi::computed_value::T as UnicodeBidi;
@@ -491,7 +511,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
if self.should_suppress_linebreak(layout_parent_style) {
self.style.flags.insert(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
// Inlinify the display type if allowed.
- if !flags.contains(CascadeFlags::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP) {
+ if !self.skip_item_display_fixup(element) {
let inline_display = self_display.inlinify();
if self_display != inline_display {
self.style.mutate_box().set_adjusted_display(inline_display, false);
@@ -531,16 +551,22 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
///
/// FIXME(emilio): This isn't technically a style adjustment thingie, could
/// it move somewhere else?
- fn adjust_for_visited(&mut self, flags: CascadeFlags) {
- use properties::CascadeFlags;
+ fn adjust_for_visited<E>(&mut self, element: Option<E>)
+ where
+ E: TElement,
+ {
use properties::computed_value_flags::ComputedValueFlags;
if !self.style.has_visited_style() {
return;
}
- let relevant_link_visited = if flags.contains(CascadeFlags::IS_LINK) {
- flags.contains(CascadeFlags::IS_VISITED_LINK)
+ let is_link_element =
+ self.style.pseudo.is_none() &&
+ element.map_or(false, |e| e.is_link());
+
+ let relevant_link_visited = if is_link_element {
+ element.unwrap().is_visited_link()
} else {
self.style.inherited_flags().contains(ComputedValueFlags::IS_RELEVANT_LINK_VISITED)
};
@@ -586,11 +612,35 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
/// When comparing to Gecko, this is similar to the work done by
/// `nsStyleContext::ApplyStyleFixups`, plus some parts of
/// `nsStyleSet::GetContext`.
- pub fn adjust(
+ pub fn adjust<E>(
&mut self,
layout_parent_style: &ComputedValues,
+ element: Option<E>,
flags: CascadeFlags,
- ) {
+ )
+ where
+ E: TElement,
+ {
+ if cfg!(debug_assertions) {
+ if element.and_then(|e| e.implemented_pseudo_element()).is_some() {
+ // It'd be nice to assert `self.style.pseudo == Some(&pseudo)`,
+ // but we do resolve ::-moz-list pseudos on ::before / ::after
+ // content, sigh.
+ debug_assert!(
+ self.style.pseudo.is_some(),
+ "Someone really messed up"
+ );
+ }
+ }
+ // FIXME(emilio): The apply_declarations callsite in Servo's
+ // animation, and the font stuff for Gecko
+ // (Stylist::compute_for_declarations) should pass an element to
+ // cascade(), then we can make this assertion hold everywhere.
+ // debug_assert!(
+ // element.is_some() || self.style.pseudo.is_some(),
+ // "Should always have an element around for non-pseudo styles"
+ // );
+
// Don't adjust visited styles, visited-dependent properties aren't
// affected by these adjustments and it'd be just wasted work anyway.
//
@@ -600,14 +650,14 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
return;
}
- self.adjust_for_visited(flags);
+ self.adjust_for_visited(element);
#[cfg(feature = "gecko")]
{
self.adjust_for_prohibited_display_contents();
self.adjust_for_fieldset_content(layout_parent_style);
}
self.adjust_for_top_layer();
- self.blockify_if_necessary(layout_parent_style, flags);
+ self.blockify_if_necessary(layout_parent_style, element);
self.adjust_for_position();
self.adjust_for_overflow();
#[cfg(feature = "gecko")]
@@ -627,7 +677,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
self.adjust_for_text_decoration_lines(layout_parent_style);
#[cfg(feature = "gecko")]
{
- self.adjust_for_ruby(layout_parent_style, flags);
+ self.adjust_for_ruby(layout_parent_style, element);
}
#[cfg(feature = "servo")]
{
diff --git a/components/style/style_resolver.rs b/components/style/style_resolver.rs
index 2a30aa1659b..b07dfb487b9 100644
--- a/components/style/style_resolver.rs
+++ b/components/style/style_resolver.rs
@@ -9,9 +9,8 @@ use context::{CascadeInputs, ElementCascadeInputs, StyleContext};
use data::{ElementStyles, EagerPseudoStyles};
use dom::TElement;
use log::LogLevel::Trace;
-use matching::{CascadeVisitedMode, MatchMethods};
-use properties::{AnimationRules, CascadeFlags, ComputedValues};
-use properties::cascade;
+use matching::MatchMethods;
+use properties::{AnimationRules, ComputedValues};
use properties::longhands::display::computed_value::T as Display;
use rule_tree::StrongRuleNode;
use selector_parser::{PseudoElement, SelectorImpl};
@@ -161,7 +160,8 @@ where
parent_style.map_or(false, |s| s.visited_style().is_some());
let visited_rules =
- if inside_link || self.element.is_link() {
+ if self.context.shared.visited_styles_enabled &&
+ (inside_link || self.element.is_link()) {
let visited_matching_results =
self.match_primary(VisitedHandlingMode::RelevantLinkVisited);
Some(visited_matching_results.rule_node)
@@ -291,29 +291,37 @@ where
layout_parent_style: Option<&ComputedValues>,
pseudo: Option<&PseudoElement>,
) -> ResolvedStyle {
- let mut style_if_visited = None;
- if parent_style.map_or(false, |s| s.visited_style().is_some()) ||
- inputs.visited_rules.is_some() {
- style_if_visited = Some(self.cascade_style(
- inputs.visited_rules.as_ref().or(inputs.rules.as_ref()),
- /* style_if_visited = */ None,
- parent_style,
- layout_parent_style,
- CascadeVisitedMode::Visited,
- pseudo,
- ));
- }
+ debug_assert!(
+ self.element.implemented_pseudo_element().is_none() || pseudo.is_none(),
+ "Pseudo-elements can't have other pseudos!"
+ );
+ debug_assert!(pseudo.map_or(true, |p| p.is_eager()));
- ResolvedStyle(
- self.cascade_style(
- inputs.rules.as_ref(),
- style_if_visited,
- parent_style,
- layout_parent_style,
- CascadeVisitedMode::Unvisited,
- pseudo,
- )
- )
+ let implemented_pseudo = self.element.implemented_pseudo_element();
+ let pseudo = pseudo.or(implemented_pseudo.as_ref());
+
+ let mut conditions = Default::default();
+ let values = self.context.shared.stylist.cascade_style_and_visited(
+ Some(self.element),
+ pseudo,
+ inputs,
+ &self.context.shared.guards,
+ parent_style,
+ parent_style,
+ layout_parent_style,
+ &self.context.thread_local.font_metrics_provider,
+ Some(&self.context.thread_local.rule_cache),
+ &mut conditions,
+ );
+
+ self.context.thread_local.rule_cache.insert_if_possible(
+ &self.context.shared.guards,
+ &values,
+ pseudo,
+ &conditions
+ );
+
+ ResolvedStyle(values)
}
/// Cascade the element and pseudo-element styles with the default parents.
@@ -469,7 +477,7 @@ where
) -> Option<StrongRuleNode> {
debug!("Match pseudo {:?} for {:?}, visited: {:?}",
self.element, pseudo_element, visited_handling);
- debug_assert!(pseudo_element.is_eager() || pseudo_element.is_lazy());
+ debug_assert!(pseudo_element.is_eager());
debug_assert!(self.element.implemented_pseudo_element().is_none(),
"Element pseudos can't have any other pseudo.");
@@ -524,87 +532,4 @@ where
Some(rule_node)
}
-
- fn cascade_style(
- &mut self,
- rules: Option<&StrongRuleNode>,
- style_if_visited: Option<Arc<ComputedValues>>,
- mut parent_style: Option<&ComputedValues>,
- layout_parent_style: Option<&ComputedValues>,
- cascade_visited: CascadeVisitedMode,
- pseudo: Option<&PseudoElement>,
- ) -> Arc<ComputedValues> {
- debug_assert!(
- self.element.implemented_pseudo_element().is_none() || pseudo.is_none(),
- "Pseudo-elements can't have other pseudos!"
- );
- debug_assert!(pseudo.map_or(true, |p| p.is_eager()));
-
- let mut cascade_flags = CascadeFlags::empty();
-
- if self.element.skip_root_and_item_based_display_fixup() ||
- pseudo.map_or(false, |p| p.skip_item_based_display_fixup()) {
- cascade_flags.insert(CascadeFlags::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP);
- }
-
- if pseudo.is_none() && self.element.is_link() {
- cascade_flags.insert(CascadeFlags::IS_LINK);
- if self.element.is_visited_link() &&
- self.context.shared.visited_styles_enabled {
- cascade_flags.insert(CascadeFlags::IS_VISITED_LINK);
- }
- }
-
- if cascade_visited.visited_dependent_only() {
- // If this element is a link, we want its visited style to inherit
- // from the regular style of its parent, because only the
- // visitedness of the relevant link should influence style.
- if pseudo.is_some() || !self.element.is_link() {
- parent_style = parent_style.map(|s| {
- s.visited_style().unwrap_or(s)
- });
- }
- cascade_flags.insert(CascadeFlags::VISITED_DEPENDENT_ONLY);
- }
- if !self.element.is_native_anonymous() &&
- pseudo.is_none() &&
- self.element.is_root()
- {
- cascade_flags.insert(CascadeFlags::IS_ROOT_ELEMENT);
- }
-
- let implemented_pseudo = self.element.implemented_pseudo_element();
- let pseudo = pseudo.or(implemented_pseudo.as_ref());
-
- let mut conditions = Default::default();
- let values =
- cascade(
- self.context.shared.stylist.device(),
- pseudo,
- rules.unwrap_or(self.context.shared.stylist.rule_tree().root()),
- &self.context.shared.guards,
- parent_style,
- parent_style,
- layout_parent_style,
- style_if_visited,
- &self.context.thread_local.font_metrics_provider,
- cascade_flags,
- self.context.shared.quirks_mode(),
- Some(&self.context.thread_local.rule_cache),
- &mut conditions,
- Some(self.element),
- );
-
- self.context
- .thread_local
- .rule_cache
- .insert_if_possible(
- &self.context.shared.guards,
- &values,
- pseudo,
- &conditions
- );
-
- values
- }
}
diff --git a/components/style/stylist.rs b/components/style/stylist.rs
index d43f7ed6740..6ed2b36ac89 100644
--- a/components/style/stylist.rs
+++ b/components/style/stylist.rs
@@ -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,
)
}
diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs
index fdaa9ab09a4..4a93d43a83a 100644
--- a/ports/geckolib/glue.rs
+++ b/ports/geckolib/glue.rs
@@ -6,7 +6,7 @@ use cssparser::{ParseErrorKind, Parser, ParserInput};
use cssparser::ToCss as ParserToCss;
use env_logger::LogBuilder;
use malloc_size_of::MallocSizeOfOps;
-use selectors::{Element, NthIndexCache};
+use selectors::NthIndexCache;
use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
use smallvec::SmallVec;
@@ -122,7 +122,7 @@ use style::gecko_properties;
use style::invalidation::element::restyle_hints;
use style::media_queries::{Device, MediaList, parse_media_query_list};
use style::parser::{Parse, ParserContext, self};
-use style::properties::{CascadeFlags, ComputedValues, DeclarationSource, Importance};
+use style::properties::{ComputedValues, DeclarationSource, Importance};
use style::properties::{LonghandId, LonghandIdSet, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
use style::properties::{PropertyDeclarationId, ShorthandId};
use style::properties::{SourcePropertyDeclaration, StyleBuilder};
@@ -2039,12 +2039,10 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null:
page_decls,
);
- let cascade_flags = CascadeFlags::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP;
data.stylist.precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
&guards,
&pseudo,
parent_style_or_null.map(|x| &*x),
- cascade_flags,
&metrics,
rule_node
).into()
@@ -2220,7 +2218,7 @@ fn get_pseudo_style(
PseudoElementCascadeType::Eager => {
match *pseudo {
PseudoElement::FirstLetter => {
- styles.pseudos.get(&pseudo).and_then(|pseudo_styles| {
+ styles.pseudos.get(&pseudo).map(|pseudo_styles| {
// inherited_styles can be None when doing lazy resolution
// (e.g. for computed style) or when probing. In that case
// we just inherit from our element, which is what Gecko
@@ -2232,12 +2230,11 @@ fn get_pseudo_style(
let metrics = get_metrics_provider_for_product();
let inputs = CascadeInputs::new_from_style(pseudo_styles);
doc_data.stylist.compute_pseudo_element_style_with_inputs(
- &inputs,
+ inputs,
pseudo,
&guards,
Some(inherited_styles),
&metrics,
- CascadeFlags::empty(),
Some(element),
)
})
@@ -3633,29 +3630,17 @@ pub extern "C" fn Servo_ReparentStyle(
let pseudo = style_to_reparent.pseudo();
let element = element.map(GeckoElement);
- let mut cascade_flags = CascadeFlags::empty();
- if style_to_reparent.is_anon_box() {
- cascade_flags.insert(CascadeFlags::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP);
- }
- if let Some(element) = element {
- if element.is_link() {
- cascade_flags.insert(CascadeFlags::IS_LINK);
- if element.is_visited_link() && doc_data.visited_styles_enabled() {
- cascade_flags.insert(CascadeFlags::IS_VISITED_LINK);
- }
- };
- }
-
- doc_data.stylist.compute_style_with_inputs(
- &inputs,
+ doc_data.stylist.cascade_style_and_visited(
+ element,
pseudo.as_ref(),
+ inputs,
&StylesheetGuards::same(&guard),
Some(parent_style),
Some(parent_style_ignoring_first_line),
Some(layout_parent_style),
&metrics,
- cascade_flags,
- element,
+ /* rule_cache = */ None,
+ &mut RuleCacheConditions::default(),
).into()
}