mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +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
|
@ -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
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ use style::data::ElementData;
|
||||||
use style::dom::{LayoutIterator, NodeInfo, TElement, TNode};
|
use style::dom::{LayoutIterator, NodeInfo, TElement, TNode};
|
||||||
use style::dom::OpaqueNode;
|
use style::dom::OpaqueNode;
|
||||||
use style::font_metrics::ServoMetricsProvider;
|
use style::font_metrics::ServoMetricsProvider;
|
||||||
use style::properties::{CascadeFlags, ComputedValues};
|
use style::properties::ComputedValues;
|
||||||
use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl};
|
use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl};
|
||||||
use style::stylist::RuleInclusion;
|
use style::stylist::RuleInclusion;
|
||||||
use webrender_api::ClipId;
|
use webrender_api::ClipId;
|
||||||
|
@ -393,7 +393,6 @@ pub trait ThreadSafeLayoutElement
|
||||||
&context.guards,
|
&context.guards,
|
||||||
&style_pseudo,
|
&style_pseudo,
|
||||||
Some(data.styles.primary()),
|
Some(data.styles.primary()),
|
||||||
CascadeFlags::empty(),
|
|
||||||
&ServoMetricsProvider,
|
&ServoMetricsProvider,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -680,7 +680,7 @@ pub trait TElement
|
||||||
/// Whether we should skip any root- or item-based display property
|
/// Whether we should skip any root- or item-based display property
|
||||||
/// blockification on this element. (This function exists so that Gecko
|
/// blockification on this element. (This function exists so that Gecko
|
||||||
/// native anonymous content can opt out of this style fixup.)
|
/// 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
|
/// Sets selector flags, which indicate what kinds of selectors may have
|
||||||
/// matched on this element and therefore what kind of work may need to
|
/// matched on this element and therefore what kind of work may need to
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use cssparser::{ToCss, serialize_identifier};
|
use cssparser::{ToCss, serialize_identifier};
|
||||||
use gecko_bindings::structs::{self, CSSPseudoElementType};
|
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 properties::longhands::display::computed_value::T as Display;
|
||||||
use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
|
use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -51,6 +51,15 @@ impl PseudoElement {
|
||||||
PseudoElementCascadeType::Lazy
|
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
|
/// Whether the pseudo-element should inherit from the default computed
|
||||||
/// values instead of from the parent element.
|
/// values instead of from the parent element.
|
||||||
///
|
///
|
||||||
|
@ -128,7 +137,7 @@ impl PseudoElement {
|
||||||
/// Whether this pseudo-element skips flex/grid container display-based
|
/// Whether this pseudo-element skips flex/grid container display-based
|
||||||
/// fixup.
|
/// fixup.
|
||||||
#[inline]
|
#[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
|
(self.flags() & structs::CSS_PSEUDO_ELEMENT_IS_FLEX_OR_GRID_ITEM) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1285,15 +1285,11 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn skip_root_and_item_based_display_fixup(&self) -> bool {
|
fn skip_item_display_fixup(&self) -> bool {
|
||||||
if !self.is_native_anonymous() {
|
debug_assert!(
|
||||||
return false;
|
self.implemented_pseudo_element().is_none(),
|
||||||
}
|
"Just don't call me if I'm a pseudo, you should know the answer already"
|
||||||
|
);
|
||||||
if let Some(p) = self.implemented_pseudo_element() {
|
|
||||||
return p.skip_item_based_display_fixup();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.is_root_of_native_anonymous_subtree()
|
self.is_root_of_native_anonymous_subtree()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3148,30 +3148,8 @@ bitflags! {
|
||||||
/// present, non-inherited styles are reset to their initial values.
|
/// present, non-inherited styles are reset to their initial values.
|
||||||
const INHERIT_ALL = 1;
|
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.
|
/// Whether to only cascade properties that are visited dependent.
|
||||||
const VISITED_DEPENDENT_ONLY = 1 << 2;
|
const VISITED_DEPENDENT_ONLY = 1 << 1;
|
||||||
|
|
||||||
/// 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3287,7 +3265,7 @@ pub fn apply_declarations<'a, E, F, I>(
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
rule_cache: Option<<&RuleCache>,
|
rule_cache: Option<<&RuleCache>,
|
||||||
rule_cache_conditions: &mut RuleCacheConditions,
|
rule_cache_conditions: &mut RuleCacheConditions,
|
||||||
_element: Option<E>,
|
element: Option<E>,
|
||||||
) -> Arc<ComputedValues>
|
) -> Arc<ComputedValues>
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
|
@ -3326,7 +3304,7 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut context = computed::Context {
|
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
|
// 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
|
// animation's usage of `apply_declarations` make this tricky. See bug
|
||||||
// 1375525.
|
// 1375525.
|
||||||
|
@ -3610,8 +3588,11 @@ where
|
||||||
|
|
||||||
builder.clear_modified_reset();
|
builder.clear_modified_reset();
|
||||||
|
|
||||||
StyleAdjuster::new(&mut builder)
|
StyleAdjuster::new(&mut builder).adjust(
|
||||||
.adjust(layout_parent_style, flags);
|
layout_parent_style,
|
||||||
|
element,
|
||||||
|
flags,
|
||||||
|
);
|
||||||
|
|
||||||
if builder.modified_reset() || !apply_reset {
|
if builder.modified_reset() || !apply_reset {
|
||||||
// If we adjusted any reset structs, we can't cache this ComputedValues.
|
// If we adjusted any reset structs, we can't cache this ComputedValues.
|
||||||
|
|
|
@ -14,8 +14,7 @@ use element_state::{DocumentState, ElementState};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use invalidation::element::document_state::InvalidationMatchingData;
|
use invalidation::element::document_state::InvalidationMatchingData;
|
||||||
use invalidation::element::element_wrapper::ElementSnapshot;
|
use invalidation::element::element_wrapper::ElementSnapshot;
|
||||||
use properties::ComputedValues;
|
use properties::{CascadeFlags, ComputedValues, PropertyFlags};
|
||||||
use properties::PropertyFlags;
|
|
||||||
use properties::longhands::display::computed_value::T as Display;
|
use properties::longhands::display::computed_value::T as Display;
|
||||||
use selector_parser::{AttrValue as SelectorAttrValue, PseudoElementCascadeType, SelectorParser};
|
use selector_parser::{AttrValue as SelectorAttrValue, PseudoElementCascadeType, SelectorParser};
|
||||||
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
|
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
|
||||||
|
@ -174,10 +173,10 @@ impl PseudoElement {
|
||||||
self.is_precomputed()
|
self.is_precomputed()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this pseudo-element skips flex/grid container
|
/// Whether this pseudo-element skips flex/grid container display-based
|
||||||
/// display-based fixup.
|
/// fixup.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn skip_item_based_display_fixup(&self) -> bool {
|
pub fn skip_item_display_fixup(&self) -> bool {
|
||||||
!self.is_before_or_after()
|
!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
|
/// Covert non-canonical pseudo-element to canonical one, and keep a
|
||||||
/// canonical one as it is.
|
/// canonical one as it is.
|
||||||
pub fn canonical(&self) -> PseudoElement {
|
pub fn canonical(&self) -> PseudoElement {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
//! a computed style needs in order for it to adhere to the CSS spec.
|
//! a computed style needs in order for it to adhere to the CSS spec.
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
|
use dom::TElement;
|
||||||
use properties::{self, CascadeFlags, ComputedValues, StyleBuilder};
|
use properties::{self, CascadeFlags, ComputedValues, StyleBuilder};
|
||||||
use properties::longhands::display::computed_value::T as Display;
|
use properties::longhands::display::computed_value::T as Display;
|
||||||
use properties::longhands::float::computed_value::T as Float;
|
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.
|
/// 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>
|
/// <https://drafts.csswg.org/css2/visuren.html#dis-pos-flo>
|
||||||
fn blockify_if_necessary(
|
fn blockify_if_necessary<E>(
|
||||||
&mut self,
|
&mut self,
|
||||||
layout_parent_style: &ComputedValues,
|
layout_parent_style: &ComputedValues,
|
||||||
flags: CascadeFlags,
|
element: Option<E>,
|
||||||
) {
|
)
|
||||||
|
where
|
||||||
|
E: TElement,
|
||||||
|
{
|
||||||
let mut blockify = false;
|
let mut blockify = false;
|
||||||
macro_rules! blockify_if {
|
macro_rules! blockify_if {
|
||||||
($if_what:expr) => {
|
($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) {
|
let is_root = self.style.pseudo.is_none() && element.map_or(false, |e| e.is_root());
|
||||||
blockify_if!(flags.contains(CascadeFlags::IS_ROOT_ELEMENT));
|
blockify_if!(is_root);
|
||||||
|
if !self.skip_item_display_fixup(element) {
|
||||||
blockify_if!(layout_parent_style.get_box().clone_display().is_item_container());
|
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 display = self.style.get_box().clone_display();
|
||||||
let blockified_display =
|
let blockified_display = display.equivalent_block_display(is_root);
|
||||||
display.equivalent_block_display(flags.contains(CascadeFlags::IS_ROOT_ELEMENT));
|
|
||||||
if display != blockified_display {
|
if display != blockified_display {
|
||||||
self.style.mutate_box().set_adjusted_display(
|
self.style.mutate_box().set_adjusted_display(
|
||||||
blockified_display,
|
blockified_display,
|
||||||
|
@ -477,12 +495,14 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
||||||
/// * suppress border and padding for ruby level containers,
|
/// * suppress border and padding for ruby level containers,
|
||||||
/// * correct unicode-bidi.
|
/// * correct unicode-bidi.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
fn adjust_for_ruby(
|
fn adjust_for_ruby<E>(
|
||||||
&mut self,
|
&mut self,
|
||||||
layout_parent_style: &ComputedValues,
|
layout_parent_style: &ComputedValues,
|
||||||
flags: CascadeFlags,
|
element: Option<E>,
|
||||||
) {
|
)
|
||||||
use properties::CascadeFlags;
|
where
|
||||||
|
E: TElement,
|
||||||
|
{
|
||||||
use properties::computed_value_flags::ComputedValueFlags;
|
use properties::computed_value_flags::ComputedValueFlags;
|
||||||
use properties::longhands::unicode_bidi::computed_value::T as UnicodeBidi;
|
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) {
|
if self.should_suppress_linebreak(layout_parent_style) {
|
||||||
self.style.flags.insert(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
|
self.style.flags.insert(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
|
||||||
// Inlinify the display type if allowed.
|
// 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();
|
let inline_display = self_display.inlinify();
|
||||||
if self_display != inline_display {
|
if self_display != inline_display {
|
||||||
self.style.mutate_box().set_adjusted_display(inline_display, false);
|
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
|
/// FIXME(emilio): This isn't technically a style adjustment thingie, could
|
||||||
/// it move somewhere else?
|
/// it move somewhere else?
|
||||||
fn adjust_for_visited(&mut self, flags: CascadeFlags) {
|
fn adjust_for_visited<E>(&mut self, element: Option<E>)
|
||||||
use properties::CascadeFlags;
|
where
|
||||||
|
E: TElement,
|
||||||
|
{
|
||||||
use properties::computed_value_flags::ComputedValueFlags;
|
use properties::computed_value_flags::ComputedValueFlags;
|
||||||
|
|
||||||
if !self.style.has_visited_style() {
|
if !self.style.has_visited_style() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let relevant_link_visited = if flags.contains(CascadeFlags::IS_LINK) {
|
let is_link_element =
|
||||||
flags.contains(CascadeFlags::IS_VISITED_LINK)
|
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 {
|
} else {
|
||||||
self.style.inherited_flags().contains(ComputedValueFlags::IS_RELEVANT_LINK_VISITED)
|
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
|
/// When comparing to Gecko, this is similar to the work done by
|
||||||
/// `nsStyleContext::ApplyStyleFixups`, plus some parts of
|
/// `nsStyleContext::ApplyStyleFixups`, plus some parts of
|
||||||
/// `nsStyleSet::GetContext`.
|
/// `nsStyleSet::GetContext`.
|
||||||
pub fn adjust(
|
pub fn adjust<E>(
|
||||||
&mut self,
|
&mut self,
|
||||||
layout_parent_style: &ComputedValues,
|
layout_parent_style: &ComputedValues,
|
||||||
|
element: Option<E>,
|
||||||
flags: CascadeFlags,
|
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
|
// Don't adjust visited styles, visited-dependent properties aren't
|
||||||
// affected by these adjustments and it'd be just wasted work anyway.
|
// affected by these adjustments and it'd be just wasted work anyway.
|
||||||
//
|
//
|
||||||
|
@ -600,14 +650,14 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.adjust_for_visited(flags);
|
self.adjust_for_visited(element);
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
{
|
{
|
||||||
self.adjust_for_prohibited_display_contents();
|
self.adjust_for_prohibited_display_contents();
|
||||||
self.adjust_for_fieldset_content(layout_parent_style);
|
self.adjust_for_fieldset_content(layout_parent_style);
|
||||||
}
|
}
|
||||||
self.adjust_for_top_layer();
|
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_position();
|
||||||
self.adjust_for_overflow();
|
self.adjust_for_overflow();
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
@ -627,7 +677,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
||||||
self.adjust_for_text_decoration_lines(layout_parent_style);
|
self.adjust_for_text_decoration_lines(layout_parent_style);
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
{
|
{
|
||||||
self.adjust_for_ruby(layout_parent_style, flags);
|
self.adjust_for_ruby(layout_parent_style, element);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,9 +9,8 @@ use context::{CascadeInputs, ElementCascadeInputs, StyleContext};
|
||||||
use data::{ElementStyles, EagerPseudoStyles};
|
use data::{ElementStyles, EagerPseudoStyles};
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
use log::LogLevel::Trace;
|
use log::LogLevel::Trace;
|
||||||
use matching::{CascadeVisitedMode, MatchMethods};
|
use matching::MatchMethods;
|
||||||
use properties::{AnimationRules, CascadeFlags, ComputedValues};
|
use properties::{AnimationRules, ComputedValues};
|
||||||
use properties::cascade;
|
|
||||||
use properties::longhands::display::computed_value::T as Display;
|
use properties::longhands::display::computed_value::T as Display;
|
||||||
use rule_tree::StrongRuleNode;
|
use rule_tree::StrongRuleNode;
|
||||||
use selector_parser::{PseudoElement, SelectorImpl};
|
use selector_parser::{PseudoElement, SelectorImpl};
|
||||||
|
@ -161,7 +160,8 @@ where
|
||||||
parent_style.map_or(false, |s| s.visited_style().is_some());
|
parent_style.map_or(false, |s| s.visited_style().is_some());
|
||||||
|
|
||||||
let visited_rules =
|
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 =
|
let visited_matching_results =
|
||||||
self.match_primary(VisitedHandlingMode::RelevantLinkVisited);
|
self.match_primary(VisitedHandlingMode::RelevantLinkVisited);
|
||||||
Some(visited_matching_results.rule_node)
|
Some(visited_matching_results.rule_node)
|
||||||
|
@ -291,29 +291,37 @@ where
|
||||||
layout_parent_style: Option<&ComputedValues>,
|
layout_parent_style: Option<&ComputedValues>,
|
||||||
pseudo: Option<&PseudoElement>,
|
pseudo: Option<&PseudoElement>,
|
||||||
) -> ResolvedStyle {
|
) -> ResolvedStyle {
|
||||||
let mut style_if_visited = None;
|
debug_assert!(
|
||||||
if parent_style.map_or(false, |s| s.visited_style().is_some()) ||
|
self.element.implemented_pseudo_element().is_none() || pseudo.is_none(),
|
||||||
inputs.visited_rules.is_some() {
|
"Pseudo-elements can't have other pseudos!"
|
||||||
style_if_visited = Some(self.cascade_style(
|
);
|
||||||
inputs.visited_rules.as_ref().or(inputs.rules.as_ref()),
|
debug_assert!(pseudo.map_or(true, |p| p.is_eager()));
|
||||||
/* style_if_visited = */ None,
|
|
||||||
parent_style,
|
|
||||||
layout_parent_style,
|
|
||||||
CascadeVisitedMode::Visited,
|
|
||||||
pseudo,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
ResolvedStyle(
|
let implemented_pseudo = self.element.implemented_pseudo_element();
|
||||||
self.cascade_style(
|
let pseudo = pseudo.or(implemented_pseudo.as_ref());
|
||||||
inputs.rules.as_ref(),
|
|
||||||
style_if_visited,
|
let mut conditions = Default::default();
|
||||||
parent_style,
|
let values = self.context.shared.stylist.cascade_style_and_visited(
|
||||||
layout_parent_style,
|
Some(self.element),
|
||||||
CascadeVisitedMode::Unvisited,
|
pseudo,
|
||||||
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.
|
/// Cascade the element and pseudo-element styles with the default parents.
|
||||||
|
@ -469,7 +477,7 @@ where
|
||||||
) -> Option<StrongRuleNode> {
|
) -> Option<StrongRuleNode> {
|
||||||
debug!("Match pseudo {:?} for {:?}, visited: {:?}",
|
debug!("Match pseudo {:?} for {:?}, visited: {:?}",
|
||||||
self.element, pseudo_element, visited_handling);
|
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(),
|
debug_assert!(self.element.implemented_pseudo_element().is_none(),
|
||||||
"Element pseudos can't have any other pseudo.");
|
"Element pseudos can't have any other pseudo.");
|
||||||
|
|
||||||
|
@ -524,87 +532,4 @@ where
|
||||||
|
|
||||||
Some(rule_node)
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ use malloc_size_of::MallocUnconditionalShallowSizeOf;
|
||||||
use media_queries::Device;
|
use media_queries::Device;
|
||||||
use properties::{self, CascadeFlags, ComputedValues};
|
use properties::{self, CascadeFlags, ComputedValues};
|
||||||
use properties::{AnimationRules, PropertyDeclarationBlock};
|
use properties::{AnimationRules, PropertyDeclarationBlock};
|
||||||
|
use rule_cache::{RuleCache, RuleCacheConditions};
|
||||||
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
|
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
|
||||||
use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry};
|
use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry};
|
||||||
use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement};
|
use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement};
|
||||||
|
@ -650,7 +651,6 @@ impl Stylist {
|
||||||
guards: &StylesheetGuards,
|
guards: &StylesheetGuards,
|
||||||
pseudo: &PseudoElement,
|
pseudo: &PseudoElement,
|
||||||
parent: Option<&ComputedValues>,
|
parent: Option<&ComputedValues>,
|
||||||
cascade_flags: CascadeFlags,
|
|
||||||
font_metrics: &FontMetricsProvider,
|
font_metrics: &FontMetricsProvider,
|
||||||
) -> Arc<ComputedValues>
|
) -> Arc<ComputedValues>
|
||||||
where
|
where
|
||||||
|
@ -668,7 +668,6 @@ impl Stylist {
|
||||||
guards,
|
guards,
|
||||||
pseudo,
|
pseudo,
|
||||||
parent,
|
parent,
|
||||||
cascade_flags,
|
|
||||||
font_metrics,
|
font_metrics,
|
||||||
rule_node
|
rule_node
|
||||||
)
|
)
|
||||||
|
@ -684,25 +683,23 @@ impl Stylist {
|
||||||
guards: &StylesheetGuards,
|
guards: &StylesheetGuards,
|
||||||
pseudo: &PseudoElement,
|
pseudo: &PseudoElement,
|
||||||
parent: Option<&ComputedValues>,
|
parent: Option<&ComputedValues>,
|
||||||
cascade_flags: CascadeFlags,
|
|
||||||
font_metrics: &FontMetricsProvider,
|
font_metrics: &FontMetricsProvider,
|
||||||
rule_node: StrongRuleNode
|
rules: StrongRuleNode
|
||||||
) -> Arc<ComputedValues>
|
) -> Arc<ComputedValues>
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
{
|
{
|
||||||
self.compute_pseudo_element_style_with_inputs::<E>(
|
self.compute_pseudo_element_style_with_inputs::<E>(
|
||||||
&CascadeInputs {
|
CascadeInputs {
|
||||||
rules: Some(rule_node),
|
rules: Some(rules),
|
||||||
visited_rules: None,
|
visited_rules: None,
|
||||||
},
|
},
|
||||||
pseudo,
|
pseudo,
|
||||||
guards,
|
guards,
|
||||||
parent,
|
parent,
|
||||||
font_metrics,
|
font_metrics,
|
||||||
cascade_flags,
|
|
||||||
None,
|
None,
|
||||||
).unwrap()
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the rule node for given precomputed pseudo-element.
|
/// Returns the rule node for given precomputed pseudo-element.
|
||||||
|
@ -757,44 +754,10 @@ impl Stylist {
|
||||||
E: TElement,
|
E: TElement,
|
||||||
{
|
{
|
||||||
use font_metrics::ServoMetricsProvider;
|
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>(
|
self.precomputed_values_for_pseudo::<E>(
|
||||||
guards,
|
guards,
|
||||||
&pseudo,
|
&pseudo,
|
||||||
Some(parent_style),
|
Some(parent_style),
|
||||||
cascade_flags,
|
|
||||||
&ServoMetricsProvider,
|
&ServoMetricsProvider,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -828,17 +791,16 @@ impl Stylist {
|
||||||
is_probe,
|
is_probe,
|
||||||
rule_inclusion,
|
rule_inclusion,
|
||||||
matching_fn
|
matching_fn
|
||||||
);
|
)?;
|
||||||
|
|
||||||
self.compute_pseudo_element_style_with_inputs(
|
Some(self.compute_pseudo_element_style_with_inputs(
|
||||||
&cascade_inputs,
|
cascade_inputs,
|
||||||
pseudo,
|
pseudo,
|
||||||
guards,
|
guards,
|
||||||
Some(parent_style),
|
Some(parent_style),
|
||||||
font_metrics,
|
font_metrics,
|
||||||
CascadeFlags::empty(),
|
|
||||||
Some(element),
|
Some(element),
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes a pseudo-element style lazily using the given CascadeInputs.
|
/// Computes a pseudo-element style lazily using the given CascadeInputs.
|
||||||
|
@ -847,23 +809,16 @@ impl Stylist {
|
||||||
/// their style with a new parent style.
|
/// their style with a new parent style.
|
||||||
pub fn compute_pseudo_element_style_with_inputs<E>(
|
pub fn compute_pseudo_element_style_with_inputs<E>(
|
||||||
&self,
|
&self,
|
||||||
inputs: &CascadeInputs,
|
inputs: CascadeInputs,
|
||||||
pseudo: &PseudoElement,
|
pseudo: &PseudoElement,
|
||||||
guards: &StylesheetGuards,
|
guards: &StylesheetGuards,
|
||||||
parent_style: Option<&ComputedValues>,
|
parent_style: Option<&ComputedValues>,
|
||||||
font_metrics: &FontMetricsProvider,
|
font_metrics: &FontMetricsProvider,
|
||||||
cascade_flags: CascadeFlags,
|
|
||||||
element: Option<E>,
|
element: Option<E>,
|
||||||
) -> Option<Arc<ComputedValues>>
|
) -> Arc<ComputedValues>
|
||||||
where
|
where
|
||||||
E: TElement,
|
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
|
// FIXME(emilio): The lack of layout_parent_style here could be
|
||||||
// worrying, but we're probably dropping the display fixup for
|
// worrying, but we're probably dropping the display fixup for
|
||||||
// pseudos other than before and after, so it's probably ok.
|
// 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
|
// <fieldset style="display: contents">. That is, the computed value of
|
||||||
// display for the fieldset is "contents", even though it's not the used
|
// 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.
|
// value, so we don't need to adjust in a different way anyway.
|
||||||
Some(self.compute_style_with_inputs(
|
self.cascade_style_and_visited(
|
||||||
inputs,
|
element,
|
||||||
Some(pseudo),
|
Some(pseudo),
|
||||||
|
inputs,
|
||||||
guards,
|
guards,
|
||||||
parent_style,
|
parent_style,
|
||||||
parent_style,
|
parent_style,
|
||||||
parent_style,
|
parent_style,
|
||||||
font_metrics,
|
font_metrics,
|
||||||
cascade_flags,
|
/* rule_cache = */ None,
|
||||||
element,
|
&mut RuleCacheConditions::default(),
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes a style using the given CascadeInputs. This can be used to
|
/// 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
|
/// is_link should be true if we're computing style for a link; that affects
|
||||||
/// how :visited handling is done.
|
/// how :visited handling is done.
|
||||||
pub fn compute_style_with_inputs<E>(
|
pub fn cascade_style_and_visited<E>(
|
||||||
&self,
|
&self,
|
||||||
inputs: &CascadeInputs,
|
element: Option<E>,
|
||||||
pseudo: Option<&PseudoElement>,
|
pseudo: Option<&PseudoElement>,
|
||||||
|
inputs: CascadeInputs,
|
||||||
guards: &StylesheetGuards,
|
guards: &StylesheetGuards,
|
||||||
parent_style: Option<&ComputedValues>,
|
parent_style: Option<&ComputedValues>,
|
||||||
parent_style_ignoring_first_line: Option<&ComputedValues>,
|
parent_style_ignoring_first_line: Option<&ComputedValues>,
|
||||||
layout_parent_style: Option<&ComputedValues>,
|
layout_parent_style: Option<&ComputedValues>,
|
||||||
font_metrics: &FontMetricsProvider,
|
font_metrics: &FontMetricsProvider,
|
||||||
cascade_flags: CascadeFlags,
|
rule_cache: Option<&RuleCache>,
|
||||||
element: Option<E>,
|
rule_cache_conditions: &mut RuleCacheConditions,
|
||||||
) -> Arc<ComputedValues>
|
) -> Arc<ComputedValues>
|
||||||
where
|
where
|
||||||
E: TElement,
|
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
|
// We need to compute visited values if we have visited rules or if our
|
||||||
// parent has visited values.
|
// parent has visited values.
|
||||||
let mut visited_values = None;
|
let mut visited_values = None;
|
||||||
if inputs.visited_rules.is_some() ||
|
if inputs.visited_rules.is_some() ||
|
||||||
parent_style.and_then(|s| s.visited_style()).is_some()
|
parent_style.and_then(|s| s.visited_style()).is_some()
|
||||||
{
|
{
|
||||||
// At this point inputs may have visited rules, or rules, or both,
|
// At this point inputs may have visited rules, or rules.
|
||||||
// or neither (e.g. if it's a text style it may have neither). So
|
|
||||||
// we have to be a bit careful here.
|
|
||||||
let rule_node = match inputs.visited_rules.as_ref() {
|
let rule_node = match inputs.visited_rules.as_ref() {
|
||||||
Some(rules) => rules,
|
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;
|
||||||
let inherited_style_ignoring_first_line;
|
let inherited_style_ignoring_first_line;
|
||||||
let layout_parent_style_for_visited;
|
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.
|
// We just want to use our parent style as our parent.
|
||||||
inherited_style = parent_style;
|
inherited_style = parent_style;
|
||||||
inherited_style_ignoring_first_line = parent_style_ignoring_first_line;
|
inherited_style_ignoring_first_line = parent_style_ignoring_first_line;
|
||||||
|
@ -969,24 +930,22 @@ impl Stylist {
|
||||||
font_metrics,
|
font_metrics,
|
||||||
cascade_flags | CascadeFlags::VISITED_DEPENDENT_ONLY,
|
cascade_flags | CascadeFlags::VISITED_DEPENDENT_ONLY,
|
||||||
self.quirks_mode,
|
self.quirks_mode,
|
||||||
/* rule_cache = */ None,
|
rule_cache,
|
||||||
&mut Default::default(),
|
rule_cache_conditions,
|
||||||
element,
|
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
|
// Read the comment on `precomputed_values_for_pseudo` to see why it's
|
||||||
// difficult to assert that display: contents nodes never arrive here
|
// difficult to assert that display: contents nodes never arrive here
|
||||||
// (tl;dr: It doesn't apply for replaced elements and such, but the
|
// (tl;dr: It doesn't apply for replaced elements and such, but the
|
||||||
// computed value is still "contents").
|
// computed value is still "contents").
|
||||||
|
//
|
||||||
|
// FIXME(emilio): We should assert that it holds if pseudo.is_none()!
|
||||||
properties::cascade::<E>(
|
properties::cascade::<E>(
|
||||||
&self.device,
|
&self.device,
|
||||||
pseudo,
|
pseudo,
|
||||||
rules,
|
inputs.rules.as_ref().unwrap_or(self.rule_tree.root()),
|
||||||
guards,
|
guards,
|
||||||
parent_style,
|
parent_style,
|
||||||
parent_style_ignoring_first_line,
|
parent_style_ignoring_first_line,
|
||||||
|
@ -995,9 +954,9 @@ impl Stylist {
|
||||||
font_metrics,
|
font_metrics,
|
||||||
cascade_flags,
|
cascade_flags,
|
||||||
self.quirks_mode,
|
self.quirks_mode,
|
||||||
/* rule_cache = */ None,
|
rule_cache,
|
||||||
&mut Default::default(),
|
rule_cache_conditions,
|
||||||
None,
|
element,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1014,7 +973,7 @@ impl Stylist {
|
||||||
is_probe: bool,
|
is_probe: bool,
|
||||||
rule_inclusion: RuleInclusion,
|
rule_inclusion: RuleInclusion,
|
||||||
matching_fn: Option<&Fn(&PseudoElement) -> bool>,
|
matching_fn: Option<&Fn(&PseudoElement) -> bool>,
|
||||||
) -> CascadeInputs
|
) -> Option<CascadeInputs>
|
||||||
where
|
where
|
||||||
E: TElement
|
E: TElement
|
||||||
{
|
{
|
||||||
|
@ -1051,7 +1010,6 @@ impl Stylist {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut inputs = CascadeInputs::default();
|
|
||||||
let mut declarations = ApplicableDeclarationList::new();
|
let mut declarations = ApplicableDeclarationList::new();
|
||||||
let mut matching_context = MatchingContext::new(
|
let mut matching_context = MatchingContext::new(
|
||||||
MatchingMode::ForStatelessPseudoElement,
|
MatchingMode::ForStatelessPseudoElement,
|
||||||
|
@ -1074,19 +1032,14 @@ impl Stylist {
|
||||||
&mut set_selector_flags
|
&mut set_selector_flags
|
||||||
);
|
);
|
||||||
|
|
||||||
if !declarations.is_empty() {
|
if declarations.is_empty() && is_probe {
|
||||||
let rule_node =
|
return None;
|
||||||
self.rule_tree.compute_rule_node(&mut declarations, guards);
|
|
||||||
debug_assert!(rule_node != *self.rule_tree.root());
|
|
||||||
inputs.rules = Some(rule_node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_probe && inputs.rules.is_none() {
|
let rules =
|
||||||
// When probing, don't compute visited styles if we have no
|
self.rule_tree.compute_rule_node(&mut declarations, guards);
|
||||||
// unvisited styles.
|
|
||||||
return inputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let mut visited_rules = None;
|
||||||
if parent_style.visited_style().is_some() {
|
if parent_style.visited_style().is_some() {
|
||||||
let mut declarations = ApplicableDeclarationList::new();
|
let mut declarations = ApplicableDeclarationList::new();
|
||||||
let mut matching_context =
|
let mut matching_context =
|
||||||
|
@ -1114,14 +1067,15 @@ impl Stylist {
|
||||||
let rule_node =
|
let rule_node =
|
||||||
self.rule_tree.insert_ordered_rules_with_important(
|
self.rule_tree.insert_ordered_rules_with_important(
|
||||||
declarations.drain().map(|a| a.order_and_level()),
|
declarations.drain().map(|a| a.order_and_level()),
|
||||||
guards);
|
guards,
|
||||||
|
);
|
||||||
if rule_node != *self.rule_tree.root() {
|
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
|
/// Set a given device, which may change the styles that apply to the
|
||||||
|
@ -1596,7 +1550,7 @@ impl Stylist {
|
||||||
self.quirks_mode,
|
self.quirks_mode,
|
||||||
/* rule_cache = */ None,
|
/* rule_cache = */ None,
|
||||||
&mut Default::default(),
|
&mut Default::default(),
|
||||||
None,
|
/* element = */ None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use cssparser::{ParseErrorKind, Parser, ParserInput};
|
||||||
use cssparser::ToCss as ParserToCss;
|
use cssparser::ToCss as ParserToCss;
|
||||||
use env_logger::LogBuilder;
|
use env_logger::LogBuilder;
|
||||||
use malloc_size_of::MallocSizeOfOps;
|
use malloc_size_of::MallocSizeOfOps;
|
||||||
use selectors::{Element, NthIndexCache};
|
use selectors::NthIndexCache;
|
||||||
use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
|
use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
|
||||||
use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
|
use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -122,7 +122,7 @@ use style::gecko_properties;
|
||||||
use style::invalidation::element::restyle_hints;
|
use style::invalidation::element::restyle_hints;
|
||||||
use style::media_queries::{Device, MediaList, parse_media_query_list};
|
use style::media_queries::{Device, MediaList, parse_media_query_list};
|
||||||
use style::parser::{Parse, ParserContext, self};
|
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::{LonghandId, LonghandIdSet, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
|
||||||
use style::properties::{PropertyDeclarationId, ShorthandId};
|
use style::properties::{PropertyDeclarationId, ShorthandId};
|
||||||
use style::properties::{SourcePropertyDeclaration, StyleBuilder};
|
use style::properties::{SourcePropertyDeclaration, StyleBuilder};
|
||||||
|
@ -2039,12 +2039,10 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null:
|
||||||
page_decls,
|
page_decls,
|
||||||
);
|
);
|
||||||
|
|
||||||
let cascade_flags = CascadeFlags::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP;
|
|
||||||
data.stylist.precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
|
data.stylist.precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
|
||||||
&guards,
|
&guards,
|
||||||
&pseudo,
|
&pseudo,
|
||||||
parent_style_or_null.map(|x| &*x),
|
parent_style_or_null.map(|x| &*x),
|
||||||
cascade_flags,
|
|
||||||
&metrics,
|
&metrics,
|
||||||
rule_node
|
rule_node
|
||||||
).into()
|
).into()
|
||||||
|
@ -2220,7 +2218,7 @@ fn get_pseudo_style(
|
||||||
PseudoElementCascadeType::Eager => {
|
PseudoElementCascadeType::Eager => {
|
||||||
match *pseudo {
|
match *pseudo {
|
||||||
PseudoElement::FirstLetter => {
|
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
|
// inherited_styles can be None when doing lazy resolution
|
||||||
// (e.g. for computed style) or when probing. In that case
|
// (e.g. for computed style) or when probing. In that case
|
||||||
// we just inherit from our element, which is what Gecko
|
// 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 metrics = get_metrics_provider_for_product();
|
||||||
let inputs = CascadeInputs::new_from_style(pseudo_styles);
|
let inputs = CascadeInputs::new_from_style(pseudo_styles);
|
||||||
doc_data.stylist.compute_pseudo_element_style_with_inputs(
|
doc_data.stylist.compute_pseudo_element_style_with_inputs(
|
||||||
&inputs,
|
inputs,
|
||||||
pseudo,
|
pseudo,
|
||||||
&guards,
|
&guards,
|
||||||
Some(inherited_styles),
|
Some(inherited_styles),
|
||||||
&metrics,
|
&metrics,
|
||||||
CascadeFlags::empty(),
|
|
||||||
Some(element),
|
Some(element),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -3633,29 +3630,17 @@ pub extern "C" fn Servo_ReparentStyle(
|
||||||
let pseudo = style_to_reparent.pseudo();
|
let pseudo = style_to_reparent.pseudo();
|
||||||
let element = element.map(GeckoElement);
|
let element = element.map(GeckoElement);
|
||||||
|
|
||||||
let mut cascade_flags = CascadeFlags::empty();
|
doc_data.stylist.cascade_style_and_visited(
|
||||||
if style_to_reparent.is_anon_box() {
|
element,
|
||||||
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,
|
|
||||||
pseudo.as_ref(),
|
pseudo.as_ref(),
|
||||||
|
inputs,
|
||||||
&StylesheetGuards::same(&guard),
|
&StylesheetGuards::same(&guard),
|
||||||
Some(parent_style),
|
Some(parent_style),
|
||||||
Some(parent_style_ignoring_first_line),
|
Some(parent_style_ignoring_first_line),
|
||||||
Some(layout_parent_style),
|
Some(layout_parent_style),
|
||||||
&metrics,
|
&metrics,
|
||||||
cascade_flags,
|
/* rule_cache = */ None,
|
||||||
element,
|
&mut RuleCacheConditions::default(),
|
||||||
).into()
|
).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue