Record pseudo-element in computed::Context. r?emilio
draft
Record pseudo-element in computed::Context. r?emilio
MozReview-Commit-ID: 30h8xzYUqSy
--- a/servo/components/style/animation.rs
+++ b/servo/components/style/animation.rs
@@ -497,16 +497,17 @@ fn compute_style_for_animation_step(cont
guard.declarations().iter().rev()
.map(|&(ref decl, _importance)| (decl, CascadeLevel::Animations))
};
// This currently ignores visited styles, which seems acceptable,
// as existing browsers don't appear to animate visited styles.
let computed =
properties::apply_declarations(context.stylist.device(),
+ None,
previous_style.rules(),
iter,
previous_style,
previous_style,
/* cascade_info = */ None,
/* visited_style = */ None,
font_metrics_provider,
CascadeFlags::empty(),
--- a/servo/components/style/gecko/media_queries.rs
+++ b/servo/components/style/gecko/media_queries.rs
@@ -627,16 +627,17 @@ impl Expression {
let provider = get_metrics_provider_for_product();
// http://dev.w3.org/csswg/mediaqueries3/#units
// em units are relative to the initial font-size.
let context = computed::Context {
is_root_element: false,
device: device,
+ pseudo: None,
inherited_style: default_values,
layout_parent_style: default_values,
style: StyleBuilder::for_derived_style(default_values),
font_metrics_provider: &provider,
cached_system_font: None,
in_media_query: true,
// TODO: pass the correct value here.
quirks_mode: quirks_mode,
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -387,19 +387,25 @@ trait PrivateMatchMethods: TElement {
// TODO(emilio): This is servo-only, move somewhere else?
if let Some(ref p) = layout_parent_style {
let can_be_fragmented =
p.is_multicol() ||
layout_parent_el.as_ref().unwrap().as_node().can_be_fragmented();
unsafe { self.as_node().set_can_be_fragmented(can_be_fragmented); }
}
+ // XXX Strictly speaking, we can be cascading an eager pseudo-element
+ // here, but currently we don't have any special handling for them,
+ // so it is probably fine for now. We may want to pass it properly at
+ // some point.
+ let pseudo = None;
// Invoke the cascade algorithm.
let values =
Arc::new(cascade(shared_context.stylist.device(),
+ pseudo,
rule_node,
&shared_context.guards,
style_to_inherit_from,
layout_parent_style,
visited_values_to_insert,
Some(&mut cascade_info),
font_metrics_provider,
cascade_flags,
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -40,16 +40,17 @@ use shared_lock::StylesheetGuards;
use style_traits::{PARSING_MODE_DEFAULT, HasViewportPercentage, ToCss, ParseError};
use style_traits::{PropertyDeclarationParseError, StyleParseError};
use stylesheets::{CssRuleType, MallocSizeOf, MallocSizeOfFn, Origin, UrlExtraData};
#[cfg(feature = "servo")] use values::Either;
use values::generics::text::LineHeight;
use values::computed;
use cascade_info::CascadeInfo;
use rule_tree::{CascadeLevel, StrongRuleNode};
+use selector_parser::PseudoElement;
use self::computed_value_flags::ComputedValueFlags;
use style_adjuster::StyleAdjuster;
#[cfg(feature = "servo")] use values::specified::BorderStyle;
pub use self::declaration_block::*;
#[cfg(feature = "gecko")]
#[macro_export]
@@ -2561,16 +2562,17 @@ bitflags! {
/// matched.
///
/// * `parent_style`: The parent style, if applicable; if `None`, this is the root node.
///
/// Returns the computed values.
/// * `flags`: Various flags.
///
pub fn cascade(device: &Device,
+ pseudo: Option<<&PseudoElement>,
rule_node: &StrongRuleNode,
guards: &StylesheetGuards,
parent_style: Option<<&ComputedValues>,
layout_parent_style: Option<<&ComputedValues>,
visited_style: Option<Arc<ComputedValues>>,
cascade_info: Option<<&mut CascadeInfo>,
font_metrics_provider: &FontMetricsProvider,
flags: CascadeFlags,
@@ -2608,31 +2610,33 @@ pub fn cascade(device: &Device,
Some((declaration, cascade_level))
} else {
None
}
})
})
};
apply_declarations(device,
+ pseudo,
rule_node,
iter_declarations,
inherited_style,
layout_parent_style,
visited_style,
cascade_info,
font_metrics_provider,
flags,
quirks_mode)
}
/// NOTE: This function expects the declaration with more priority to appear
/// first.
#[allow(unused_mut)] // conditionally compiled code for "position"
pub fn apply_declarations<'a, F, I>(device: &Device,
+ pseudo: Option<<&PseudoElement>,
rules: &StrongRuleNode,
iter_declarations: F,
inherited_style: &ComputedValues,
layout_parent_style: &ComputedValues,
visited_style: Option<Arc<ComputedValues>>,
mut cascade_info: Option<<&mut CascadeInfo>,
font_metrics_provider: &FontMetricsProvider,
flags: CascadeFlags,
@@ -2661,16 +2665,17 @@ pub fn apply_declarations<'a, F, I>(devi
inherited_style
} else {
default_style
};
let mut context = computed::Context {
is_root_element: flags.contains(IS_ROOT_ELEMENT),
device: device,
+ pseudo: pseudo,
inherited_style: inherited_style,
layout_parent_style: layout_parent_style,
// 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.
style: StyleBuilder::new(
inherited_style,
reset_style,
--- a/servo/components/style/servo/media_queries.rs
+++ b/servo/components/style/servo/media_queries.rs
@@ -225,16 +225,17 @@ pub enum Range<T> {
impl Range<specified::Length> {
fn to_computed_range(&self, device: &Device, quirks_mode: QuirksMode) -> Range<Au> {
let default_values = device.default_computed_values();
// http://dev.w3.org/csswg/mediaqueries3/#units
// em units are relative to the initial font-size.
let context = computed::Context {
is_root_element: false,
device: device,
+ pseudo: None,
inherited_style: default_values,
layout_parent_style: default_values,
style: StyleBuilder::for_derived_style(default_values),
// Servo doesn't support font metrics
// A real provider will be needed here once we do; since
// ch units can exist in media queries.
font_metrics_provider: &ServoMetricsProvider,
in_media_query: true,
--- a/servo/components/style/stylesheets/viewport_rule.rs
+++ b/servo/components/style/stylesheets/viewport_rule.rs
@@ -701,16 +701,17 @@ impl MaybeNew for ViewportConstraints {
let provider = get_metrics_provider_for_product();
let default_values = device.default_computed_values();
// TODO(emilio): Stop cloning `ComputedValues` around!
let context = Context {
is_root_element: false,
device: device,
+ pseudo: None,
inherited_style: default_values,
layout_parent_style: default_values,
style: StyleBuilder::for_derived_style(default_values),
font_metrics_provider: &provider,
cached_system_font: None,
in_media_query: false,
quirks_mode: quirks_mode,
};
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -627,16 +627,17 @@ impl Stylist {
// value, so we don't need to adjust in a different way anyway.
//
// In practice, I don't think any anonymous content can be a direct
// descendant of a display: contents element where display: contents is
// the actual used value, and the computed value of it would need
// blockification.
let computed =
properties::cascade(&self.device,
+ Some(pseudo),
&rule_node,
guards,
parent.map(|p| &**p),
parent.map(|p| &**p),
None,
None,
font_metrics,
cascade_flags,
@@ -697,27 +698,29 @@ impl Stylist {
is_probe: bool,
font_metrics: &FontMetricsProvider)
-> Option<Arc<ComputedValues>>
where E: TElement,
{
let cascade_inputs =
self.lazy_pseudo_rules(guards, element, pseudo, is_probe, rule_inclusion);
self.compute_pseudo_element_style_with_inputs(&cascade_inputs,
+ pseudo,
guards,
parent_style,
font_metrics)
}
/// Computes a pseudo-element style lazily using the given CascadeInputs.
/// This can be used for truly lazy pseudo-elements or to avoid redoing
/// selector matching for eager pseudo-elements when we need to recompute
/// their style with a new parent style.
pub fn compute_pseudo_element_style_with_inputs(&self,
inputs: &CascadeInputs,
+ pseudo: &PseudoElement,
guards: &StylesheetGuards,
parent_style: &Arc<ComputedValues>,
font_metrics: &FontMetricsProvider)
-> Option<Arc<ComputedValues>>
{
// We may have only visited rules in cases when we are actually
// resolving, not probing, pseudo-element style.
if !inputs.has_rules() && !inputs.has_visited_rules() {
@@ -735,16 +738,17 @@ impl Stylist {
None => inputs.rules()
};
// We want to use the visited bits (if any) from our parent style as
// our parent.
let mode = CascadeVisitedMode::Visited;
let inherited_style = mode.values(parent_style);
let computed =
properties::cascade(&self.device,
+ Some(pseudo),
rule_node,
guards,
Some(inherited_style),
Some(inherited_style),
None,
None,
font_metrics,
CascadeFlags::empty(),
@@ -766,16 +770,17 @@ impl Stylist {
};
// 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").
let computed =
properties::cascade(&self.device,
+ Some(pseudo),
rules,
guards,
Some(parent_style),
Some(parent_style),
visited_values,
None,
font_metrics,
CascadeFlags::empty(),
@@ -1352,16 +1357,17 @@ impl Stylist {
let rule_node =
self.rule_tree.insert_ordered_rules(v.into_iter().map(|a| a.order_and_level()));
// This currently ignores visited styles. It appears to be used for
// font styles in <canvas> via Servo_StyleSet_ResolveForDeclarations.
// It is unclear if visited styles are meaningful for this case.
let metrics = get_metrics_provider_for_product();
Arc::new(properties::cascade(&self.device,
+ None,
&rule_node,
guards,
Some(parent_style),
Some(parent_style),
None,
None,
&metrics,
CascadeFlags::empty(),
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -7,16 +7,17 @@
use Atom;
use context::QuirksMode;
use euclid::Size2D;
use font_metrics::FontMetricsProvider;
use media_queries::Device;
#[cfg(feature = "gecko")]
use properties;
use properties::{ComputedValues, StyleBuilder};
+use selector_parser::PseudoElement;
use std::f32;
use std::f32::consts::PI;
use std::fmt;
use style_traits::ToCss;
use super::{CSSFloat, CSSInteger, RGBA};
use super::generics::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
use super::generics::grid::TrackList as GenericTrackList;
@@ -65,16 +66,23 @@ pub mod transform;
/// itself and be transformed to a computed value.
pub struct Context<'a> {
/// Whether the current element is the root element.
pub is_root_element: bool,
/// The Device holds the viewport and other external state.
pub device: &'a Device,
+ /// The pseudo element we are computing style for.
+ ///
+ /// It is only guaranteed to be set for lazy pseudo-element and
+ /// anonymous boxes. Eager ones may not have this field set. This
+ /// can change in the future if necessary.
+ pub pseudo: Option<&'a PseudoElement>,
+
/// The style we're inheriting from.
pub inherited_style: &'a ComputedValues,
/// The style of the layout parent node. This will almost always be
/// `inherited_style`, except when `display: contents` is at play, in which
/// case it's the style of the last ancestor with a `display` value that
/// isn't `contents`.
pub layout_parent_style: &'a ComputedValues,
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -1605,16 +1605,17 @@ fn get_pseudo_style(
let inherited_styles =
inherited_styles.unwrap_or(styles.primary());
let guards = StylesheetGuards::same(guard);
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,
+ &pseudo,
&guards,
inherited_styles,
&metrics)
})
},
_ => {
debug_assert!(inherited_styles.is_none() ||
ptr::eq(&**inherited_styles.unwrap(),
@@ -2821,16 +2822,17 @@ fn create_context<'a>(per_doc_data: &'a
style: &'a ComputedValues,
parent_style: &'a Option<&Arc<ComputedValues>>)
-> Context<'a> {
let default_values = per_doc_data.default_computed_values();
Context {
is_root_element: false,
device: per_doc_data.stylist.device(),
+ pseudo: None,
inherited_style: parent_style.unwrap_or(default_values),
layout_parent_style: parent_style.unwrap_or(default_values),
style: StyleBuilder::for_derived_style(&style),
font_metrics_provider: font_metrics_provider,
cached_system_font: None,
in_media_query: false,
quirks_mode: per_doc_data.stylist.quirks_mode(),
}
--- a/servo/tests/unit/style/parsing/mod.rs
+++ b/servo/tests/unit/style/parsing/mod.rs
@@ -50,16 +50,17 @@ fn assert_computed_serialization<C, F, T
{
let viewport_size = TypedSize2D::new(0., 0.);
let initial_style = ComputedValues::initial_values();
let device = Device::new(MediaType::Screen, viewport_size);
let context = Context {
is_root_element: true,
device: &device,
+ pseudo: None,
inherited_style: initial_style,
layout_parent_style: initial_style,
style: StyleBuilder::for_derived_style(&initial_style),
cached_system_font: None,
font_metrics_provider: &ServoMetricsProvider,
in_media_query: false,
quirks_mode: QuirksMode::NoQuirks,
};