Record pseudo-element in computed::Context. r?emilio draft
authorXidorn Quan <me@upsuper.org>
Thu, 13 Jul 2017 11:45:09 +1000
changeset 607976 4eb4a8ca42f1bcb0ca756866a0303c8b8830ba4a
parent 607269 3c8c1d7d2a657ac6d2e648320472b65592c3a59d
child 607977 0955419fdd1bebca141283819327eed67f4b52e0
child 607979 e9ab8b28f02f0d1673c939d91594f6d6639fb226
push id68149
push userxquan@mozilla.com
push dateThu, 13 Jul 2017 02:03:11 +0000
reviewersemilio
milestone56.0a1
Record pseudo-element in computed::Context. r?emilio MozReview-Commit-ID: 30h8xzYUqSy
servo/components/style/animation.rs
servo/components/style/gecko/media_queries.rs
servo/components/style/matching.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/servo/media_queries.rs
servo/components/style/stylesheets/viewport_rule.rs
servo/components/style/stylist.rs
servo/components/style/values/computed/mod.rs
servo/ports/geckolib/glue.rs
servo/tests/unit/style/parsing/mod.rs
--- 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,
     };