Bug 1360508: Adjust text-combine properly. r?jryans draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 28 Apr 2017 13:10:00 +0200
changeset 570139 5bba8f3e5eb05918f5a471ee16fd4670feb6e6a6
parent 570136 f6d02271397beec583ce2379ab0d608a15541b26
child 570170 1d61bb9fa88a0cb3c4c3e7fc5db6ec86ea9c5286
push id56402
push userbmo:emilio+bugs@crisal.io
push dateFri, 28 Apr 2017 11:17:52 +0000
reviewersjryans
bugs1360508
milestone55.0a1
Bug 1360508: Adjust text-combine properly. r?jryans Text style is always resolved via ServoStyleSet::ResolveStyleForText, either from the frame constructor initially, or from ServoRestyleManager::ProcessPostTraversalForText. So text-only adjustments should go there instead. Since that doesn't call into cascade(), all the code that passes `pseudo` there is dead code we can remove. MozReview-Commit-ID: jpbBYpLlUL
layout/style/ServoBindingList.h
layout/style/ServoStyleSet.cpp
servo/components/style/animation.rs
servo/components/style/matching.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/style_adjuster.rs
servo/components/style/stylist.rs
servo/ports/geckolib/glue.rs
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -327,17 +327,18 @@ SERVO_BINDING_FUNC(Servo_CSSSupports, bo
 // Computed style data
 SERVO_BINDING_FUNC(Servo_ComputedValues_GetForAnonymousBox,
                    ServoComputedValuesStrong,
                    ServoComputedValuesBorrowedOrNull parent_style_or_null,
                    nsIAtom* pseudoTag, bool skip_display_fixup,
                    RawServoStyleSetBorrowed set)
 SERVO_BINDING_FUNC(Servo_ComputedValues_Inherit, ServoComputedValuesStrong,
                    RawServoStyleSetBorrowed set,
-                   ServoComputedValuesBorrowedOrNull parent_style)
+                   ServoComputedValuesBorrowedOrNull parent_style,
+                   bool for_text)
 
 // Initialize Servo components. Should be called exactly once at startup.
 SERVO_BINDING_FUNC(Servo_Initialize, void,
                    RawGeckoURLExtraData* dummy_url_data)
 // Shut down Servo components. Should be called exactly once at shutdown.
 SERVO_BINDING_FUNC(Servo_Shutdown, void)
 
 // Gets the snapshot for the element. This will return null if the element
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -361,30 +361,34 @@ ServoStyleSet::ResolveStyleForText(nsICo
 
   // Gecko expects text node style contexts to be like elements that match no
   // rules: inherit the inherit structs, reset the reset structs. This is cheap
   // enough to do on the main thread, which means that the parallel style system
   // can avoid worrying about text nodes.
   const ServoComputedValues* parentComputedValues =
     aParentContext->StyleSource().AsServoComputedValues();
   RefPtr<ServoComputedValues> computedValues =
-    Servo_ComputedValues_Inherit(mRawSet.get(), parentComputedValues).Consume();
+    Servo_ComputedValues_Inherit(mRawSet.get(),
+                                 parentComputedValues,
+                                 /* for_text = */ true).Consume();
 
   return GetContext(computedValues.forget(), aParentContext,
                     nsCSSAnonBoxes::mozText,
                     CSSPseudoElementType::InheritingAnonBox,
                     nullptr);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveStyleForFirstLetterContinuation(nsStyleContext* aParentContext)
 {
   const ServoComputedValues* parent = aParentContext->StyleSource().AsServoComputedValues();
   RefPtr<ServoComputedValues> computedValues =
-    Servo_ComputedValues_Inherit(mRawSet.get(), parent).Consume();
+    Servo_ComputedValues_Inherit(mRawSet.get(),
+                                 parent,
+                                 /* for_text = */ false).Consume();
   MOZ_ASSERT(computedValues);
 
   return GetContext(computedValues.forget(), aParentContext,
                     nsCSSAnonBoxes::firstLetterContinuation,
                     CSSPseudoElementType::InheritingAnonBox,
                     nullptr);
 }
 
@@ -394,17 +398,19 @@ ServoStyleSet::ResolveStyleForPlaceholde
   RefPtr<nsStyleContext>& cache =
     mNonInheritingStyleContexts[nsCSSAnonBoxes::NonInheriting::oofPlaceholder];
   if (cache) {
     RefPtr<nsStyleContext> retval = cache;
     return retval.forget();
   }
 
   RefPtr<ServoComputedValues> computedValues =
-    Servo_ComputedValues_Inherit(mRawSet.get(), nullptr).Consume();
+    Servo_ComputedValues_Inherit(mRawSet.get(),
+                                 nullptr,
+                                 /* for_text = */ false).Consume();
   MOZ_ASSERT(computedValues);
 
   RefPtr<nsStyleContext> retval =
     GetContext(computedValues.forget(), nullptr,
                nsCSSAnonBoxes::oofPlaceholder,
                CSSPseudoElementType::NonInheritingAnonBox,
                nullptr);
   cache = retval;
--- a/servo/components/style/animation.rs
+++ b/servo/components/style/animation.rs
@@ -456,17 +456,16 @@ fn compute_style_for_animation_step(cont
 
             let iter = || {
                 guard.declarations().iter().rev().map(|&(ref decl, _importance)| decl)
             };
 
             let computed =
                 properties::apply_declarations(&context.stylist.device,
                                                /* is_root = */ false,
-                                               /* pseudo = */ None,
                                                iter,
                                                previous_style,
                                                previous_style,
                                                /* cascade_info = */ None,
                                                &*context.error_reporter,
                                                font_metrics_provider,
                                                CascadeFlags::empty(),
                                                context.quirks_mode);
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -405,18 +405,17 @@ trait PrivateMatchMethods: TElement {
         }
     }
 
     fn cascade_with_rules(&self,
                           shared_context: &SharedStyleContext,
                           font_metrics_provider: &FontMetricsProvider,
                           rule_node: &StrongRuleNode,
                           primary_style: &ComputedStyle,
-                          inherit_mode: InheritMode,
-                          pseudo: Option<&PseudoElement>)
+                          inherit_mode: InheritMode)
                           -> Arc<ComputedValues> {
         let mut cascade_info = CascadeInfo::new();
         let mut cascade_flags = CascadeFlags::empty();
         if self.skip_root_and_item_based_display_fixup() {
             cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP)
         }
 
         // Grab the inherited values.
@@ -471,50 +470,47 @@ trait PrivateMatchMethods: TElement {
                 layout_parent_el.as_ref().unwrap().as_node().can_be_fragmented();
             unsafe { self.as_node().set_can_be_fragmented(can_be_fragmented); }
         }
 
         // Invoke the cascade algorithm.
         let values =
             Arc::new(cascade(&shared_context.stylist.device,
                              rule_node,
-                             pseudo,
                              &shared_context.guards,
                              style_to_inherit_from,
                              layout_parent_style,
                              Some(&mut cascade_info),
                              &*shared_context.error_reporter,
                              font_metrics_provider,
                              cascade_flags,
                              shared_context.quirks_mode));
 
         cascade_info.finish(&self.as_node());
         values
     }
 
     fn cascade_internal(&self,
                         context: &StyleContext<Self>,
                         primary_style: &ComputedStyle,
-                        pseudo: Option<&PseudoElement>,
                         eager_pseudo_style: Option<&ComputedStyle>)
                         -> Arc<ComputedValues> {
         // Grab the rule node.
         let rule_node = &eager_pseudo_style.unwrap_or(primary_style).rules;
         let inherit_mode = if eager_pseudo_style.is_some() {
             InheritMode::FromPrimaryStyle
         } else {
             InheritMode::FromParentElement
         };
 
         self.cascade_with_rules(context.shared,
                                 &context.thread_local.font_metrics_provider,
                                 rule_node,
                                 primary_style,
-                                inherit_mode,
-                                pseudo)
+                                inherit_mode)
     }
 
     /// Computes values and damage for the primary or pseudo style of an element,
     /// setting them on the ElementData.
     fn cascade_primary_or_pseudo(&self,
                                  context: &mut StyleContext<Self>,
                                  data: &mut ElementData,
                                  pseudo: Option<&PseudoElement>) {
@@ -556,26 +552,24 @@ trait PrivateMatchMethods: TElement {
 
                     let parent_data = parent.borrow_data().unwrap();
                     let pseudo_style =
                         parent_data.styles().pseudos.get(pseudo).unwrap();
                     pseudo_style.values().clone()
                 } else {
                     self.cascade_internal(context,
                                           primary_style,
-                                          None,
                                           None)
                 }
             }
             None => {
                 // Else it's an eager pseudo or a normal element, do the cascade
                 // work.
                 self.cascade_internal(context,
                                       primary_style,
-                                      pseudo,
                                       pseudo_style.as_ref().map(|s| &**s))
             }
         };
 
         // NB: Animations for pseudo-elements in Gecko are handled while
         // traversing the pseudo-elements themselves.
         if pseudo.is_none() &&
            !context.shared.traversal_flags.for_animation_only() {
@@ -607,34 +601,32 @@ trait PrivateMatchMethods: TElement {
         relevant_style.values = Some(new_values);
     }
 
     /// get_after_change_style removes the transition rules from the ComputedValues.
     /// If there is no transition rule in the ComputedValues, it returns None.
     #[cfg(feature = "gecko")]
     fn get_after_change_style(&self,
                               context: &mut StyleContext<Self>,
-                              primary_style: &ComputedStyle,
-                              pseudo: Option<&PseudoElement>)
+                              primary_style: &ComputedStyle)
                               -> Option<Arc<ComputedValues>> {
         let rule_node = &primary_style.rules;
         let without_transition_rules =
             context.shared.stylist.rule_tree.remove_transition_rule_if_applicable(rule_node);
         if without_transition_rules == *rule_node {
             // We don't have transition rule in this case, so return None to let the caller
             // use the original ComputedValues.
             return None;
         }
 
         Some(self.cascade_with_rules(context.shared,
                                      &context.thread_local.font_metrics_provider,
                                      &without_transition_rules,
                                      primary_style,
-                                     InheritMode::FromParentElement,
-                                     pseudo))
+                                     InheritMode::FromParentElement))
     }
 
     #[cfg(feature = "gecko")]
     fn needs_animations_update(&self,
                                old_values: Option<&Arc<ComputedValues>>,
                                new_values: &ComputedValues)
                                -> bool {
         let new_box_style = new_values.get_box();
@@ -669,17 +661,17 @@ trait PrivateMatchMethods: TElement {
         let mut tasks = UpdateAnimationsTasks::empty();
         if self.needs_animations_update(old_values.as_ref(), new_values) {
             tasks.insert(CSS_ANIMATIONS);
         }
 
         let before_change_style = if self.might_need_transitions_update(old_values.as_ref().map(|s| &**s),
                                                                         new_values) {
             let after_change_style = if self.has_css_transitions() {
-                self.get_after_change_style(context, primary_style, None)
+                self.get_after_change_style(context, primary_style)
             } else {
                 None
             };
 
             // In order to avoid creating a SequentialTask for transitions which
             // may not be updated, we check it per property to make sure Gecko
             // side will really update transition.
             let needs_transitions_update = {
@@ -1430,32 +1422,30 @@ pub trait MatchMethods : TElement {
         }
     }
 
     /// Returns computed values without animation and transition rules.
     fn get_base_style(&self,
                       shared_context: &SharedStyleContext,
                       font_metrics_provider: &FontMetricsProvider,
                       primary_style: &ComputedStyle,
-                      pseudo: Option<&PseudoElement>,
                       pseudo_style: Option<&ComputedStyle>)
                       -> Arc<ComputedValues> {
         let relevant_style = pseudo_style.unwrap_or(primary_style);
         let rule_node = &relevant_style.rules;
         let without_animation_rules =
             shared_context.stylist.rule_tree.remove_animation_rules(rule_node);
         if without_animation_rules == *rule_node {
             // Note that unwrapping here is fine, because the style is
             // only incomplete during the styling process.
             return relevant_style.values.as_ref().unwrap().clone();
         }
 
         self.cascade_with_rules(shared_context,
                                 font_metrics_provider,
                                 &without_animation_rules,
                                 primary_style,
-                                InheritMode::FromParentElement,
-                                pseudo)
+                                InheritMode::FromParentElement)
     }
 
 }
 
 impl<E: TElement> MatchMethods for E {}
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -97,31 +97,33 @@ pub struct ComputedValues {
     /// When this is Some, we compute font sizes by computing the keyword against
     /// the generic font, and then multiplying it by the ratio.
     pub font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
     /// The cached system font. See longhand/font.mako.rs
     pub cached_system_font: Option<longhands::system_font::ComputedSystemFont>,
 }
 
 impl ComputedValues {
-    pub fn inherit_from(parent: &Self, default: &Self) -> Arc<Self> {
-        Arc::new(ComputedValues {
+    /// Inherits style from the parent element, accounting for the default
+    /// computed values that need to be provided as well.
+    pub fn inherit_from(parent: &Self, default: &Self) -> Self {
+        ComputedValues {
             custom_properties: parent.custom_properties.clone(),
             writing_mode: parent.writing_mode,
             root_font_size: parent.root_font_size,
             font_size_keyword: parent.font_size_keyword,
             cached_system_font: None,
             % for style_struct in data.style_structs:
             % if style_struct.inherited:
             ${style_struct.ident}: parent.${style_struct.ident}.clone(),
             % else:
             ${style_struct.ident}: default.${style_struct.ident}.clone(),
             % endif
             % endfor
-        })
+        }
     }
 
     pub fn new(custom_properties: Option<Arc<ComputedValuesMap>>,
            writing_mode: WritingMode,
            root_font_size: Au,
            font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
             % for style_struct in data.style_structs:
            ${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -25,17 +25,16 @@ use context::QuirksMode;
 use font_metrics::FontMetricsProvider;
 #[cfg(feature = "gecko")] use gecko_bindings::bindings;
 #[cfg(feature = "gecko")] use gecko_bindings::structs::{self, nsCSSPropertyID};
 #[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
 use logical_geometry::WritingMode;
 use media_queries::Device;
 use parser::{LengthParsingMode, Parse, ParserContext};
 use properties::animated_properties::TransitionProperty;
-use selector_parser::PseudoElement;
 #[cfg(feature = "servo")] use servo_config::prefs::PREFS;
 use shared_lock::StylesheetGuards;
 use style_traits::ToCss;
 use stylesheets::{CssRuleType, Origin, UrlExtraData};
 #[cfg(feature = "servo")] use values::Either;
 use values::{HasViewportPercentage, computed};
 use cascade_info::CascadeInfo;
 use rule_tree::StrongRuleNode;
@@ -2109,17 +2108,16 @@ bitflags! {
 ///
 ///   * `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,
                rule_node: &StrongRuleNode,
-               pseudo: Option<<&PseudoElement>,
                guards: &StylesheetGuards,
                parent_style: Option<<&ComputedValues>,
                layout_parent_style: Option<<&ComputedValues>,
                cascade_info: Option<<&mut CascadeInfo>,
                error_reporter: &ParseErrorReporter,
                font_metrics_provider: &FontMetricsProvider,
                flags: CascadeFlags,
                quirks_mode: QuirksMode)
@@ -2156,33 +2154,31 @@ pub fn cascade(device: &Device,
                     } else {
                         None
                     }
                 })
         })
     };
     apply_declarations(device,
                        is_root_element,
-                       pseudo,
                        iter_declarations,
                        inherited_style,
                        layout_parent_style,
                        cascade_info,
                        error_reporter,
                        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,
                                     is_root_element: bool,
-                                    pseudo: Option<<&PseudoElement>,
                                     iter_declarations: F,
                                     inherited_style: &ComputedValues,
                                     layout_parent_style: &ComputedValues,
                                     mut cascade_info: Option<<&mut CascadeInfo>,
                                     error_reporter: &ParseErrorReporter,
                                     font_metrics_provider: &FontMetricsProvider,
                                     flags: CascadeFlags,
                                     quirks_mode: QuirksMode)
@@ -2381,17 +2377,17 @@ pub fn apply_declarations<'a, F, I>(devi
                                                  &mut cascade_info,
                                                  error_reporter);
             }
         % endif
     % endfor
 
     let mut style = context.style;
 
-    StyleAdjuster::new(&mut style, is_root_element, pseudo)
+    StyleAdjuster::new(&mut style, is_root_element)
         .adjust(context.layout_parent_style,
                 flags.contains(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP));
 
     % if product == "gecko":
         // FIXME(emilio): This is effectively creating a new nsStyleBackground
         // and nsStyleSVG per element. We should only do this when necessary
         // using the `seen` bitfield!
         style.mutate_background().fill_arrays();
--- a/servo/components/style/style_adjuster.rs
+++ b/servo/components/style/style_adjuster.rs
@@ -1,38 +1,37 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! A struct to encapsulate all the style fixups a computed style needs in order
 //! for it to adhere to the CSS spec.
 
 use app_units::Au;
+use computed_values::text_combine_upright::T as text_combine_upright;
+use computed_values::writing_mode::T as writing_mode;
 use properties::{self, ComputedValues};
 use properties::longhands::display::computed_value::T as display;
 use properties::longhands::float::computed_value::T as float;
 use properties::longhands::overflow_x::computed_value::T as overflow;
 use properties::longhands::position::computed_value::T as position;
-use selector_parser::PseudoElement;
+
 
 /// An unsized struct that implements all the adjustment methods.
-#[allow(dead_code)] // `pseudo` field is currently unused by Servo
 pub struct StyleAdjuster<'a> {
     style: &'a mut ComputedValues,
     is_root_element: bool,
-    pseudo: Option<&'a PseudoElement>,
 }
 
 impl<'a> StyleAdjuster<'a> {
     /// Trivially constructs a new StyleAdjuster.
-    pub fn new(style: &'a mut ComputedValues, is_root_element: bool, pseudo: Option<&'a PseudoElement>) -> Self {
+    pub fn new(style: &'a mut ComputedValues, is_root_element: bool) -> Self {
         StyleAdjuster {
             style: style,
             is_root_element: is_root_element,
-            pseudo: pseudo,
         }
     }
 
     /// https://fullscreen.spec.whatwg.org/#new-stacking-layer
     ///
     ///    Any position value other than 'absolute' and 'fixed' are
     ///    computed to 'absolute' if the element is in a top layer.
     ///
@@ -85,33 +84,40 @@ impl<'a> StyleAdjuster<'a> {
         let blockified_display =
             display.equivalent_block_display(self.is_root_element);
         if display != blockified_display {
             self.style.mutate_box().set_adjusted_display(blockified_display,
                                                          is_item_or_root);
         }
     }
 
-    /// Change writing mode of text frame for text-combine-upright.
-    /// It is safe to look at the parent's style because we are looking at
-    /// inherited properties, and ::-moz-text never matches any rules.
-    #[cfg(feature = "gecko")]
-    fn adjust_for_text_combine_upright(&mut self,
-                                       layout_parent_style: &ComputedValues) {
-        if let Some(p) = self.pseudo {
-            if *p.as_atom() == atom!(":-moz-text") {
-                use computed_values::text_combine_upright::T as text_combine_upright;
-                use computed_values::writing_mode::T as writing_mode;
-                let parent_writing_mode = layout_parent_style.get_inheritedbox().clone_writing_mode();
-                let parent_text_combine_upright = layout_parent_style.get_inheritedtext().clone_text_combine_upright();
-                if parent_writing_mode != writing_mode::horizontal_tb &&
-                   parent_text_combine_upright == text_combine_upright::all {
-                    self.style.mutate_inheritedbox().set_writing_mode(writing_mode::horizontal_tb);
-                }
-            }
+    /// Adjust the style for text style.
+    ///
+    /// The adjustments here are a subset of the adjustments generally, because
+    /// text only inherits properties.
+    pub fn adjust_for_text(&mut self) {
+        self.adjust_for_text_combine_upright();
+    }
+
+    /// Change writing mode of the text frame for text-combine-upright.
+    ///
+    /// It is safe to look at our own style because we are looking at inherited
+    /// properties, and text is just plain inheritance.
+    ///
+    /// TODO(emilio): we should (Gecko too) revise these adjustments in presence
+    /// of display: contents.
+    fn adjust_for_text_combine_upright(&mut self) {
+        let writing_mode =
+            self.style.get_inheritedbox().clone_writing_mode();
+        let text_combine_upright =
+            self.style.get_inheritedtext().clone_text_combine_upright();
+
+        if writing_mode != writing_mode::horizontal_tb &&
+           text_combine_upright == text_combine_upright::all {
+            self.style.mutate_inheritedbox().set_writing_mode(writing_mode::horizontal_tb);
         }
     }
 
     /// https://drafts.csswg.org/css-writing-modes-3/#block-flow:
     ///
     ///    If a box has a different writing-mode value than its containing
     ///    block:
     ///
@@ -243,25 +249,24 @@ impl<'a> StyleAdjuster<'a> {
         if overflow_x != original_overflow_x ||
            overflow_y != original_overflow_y {
             let mut box_style = self.style.mutate_box();
             box_style.set_overflow_x(overflow_x);
             box_style.set_overflow_y(overflow_y);
         }
     }
 
-    /// Adjusts the style to account for various fixups that don't fit naturally into the cascade.
-    /// When comparing to Gecko, this is similar to the work done by `nsStyleContext::ApplyStyleFixups`.
+    /// Adjusts the style to account for various fixups that don't fit naturally
+    /// into the cascade.
+    ///
+    /// When comparing to Gecko, this is similar to the work done by
+    /// `nsStyleContext::ApplyStyleFixups`.
     pub fn adjust(mut self,
                   layout_parent_style: &ComputedValues,
                   skip_root_and_element_display_fixup: bool) {
-        #[cfg(feature = "gecko")]
-        {
-            self.adjust_for_text_combine_upright(layout_parent_style);
-        }
         self.adjust_for_top_layer();
         self.blockify_if_necessary(layout_parent_style,
                                    skip_root_and_element_display_fixup);
         self.adjust_for_position();
         self.adjust_for_overflow();
         #[cfg(feature = "gecko")]
         {
             self.adjust_for_contain();
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -413,17 +413,16 @@ impl Stylist {
         //
         // 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,
                                 &rule_node,
-                                Some(pseudo),
                                 guards,
                                 parent.map(|p| &**p),
                                 parent.map(|p| &**p),
                                 None,
                                 &RustLogReporter,
                                 font_metrics,
                                 cascade_flags,
                                 self.quirks_mode);
@@ -538,17 +537,16 @@ 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,
                                 &rule_node,
-                                Some(pseudo),
                                 guards,
                                 Some(&**parent),
                                 Some(&**parent),
                                 None,
                                 &RustLogReporter,
                                 font_metrics,
                                 CascadeFlags::empty(),
                                 self.quirks_mode);
@@ -884,17 +882,16 @@ impl Stylist {
                                                           CascadeLevel::StyleAttributeNormal)
         ];
         let rule_node =
             self.rule_tree.insert_ordered_rules(v.into_iter().map(|a| (a.source, a.level)));
 
         let metrics = get_metrics_provider_for_product();
         Arc::new(properties::cascade(&self.device,
                                      &rule_node,
-                                     None,
                                      guards,
                                      Some(parent_style),
                                      Some(parent_style),
                                      None,
                                      &RustLogReporter,
                                      &metrics,
                                      CascadeFlags::empty(),
                                      self.quirks_mode))
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -77,16 +77,17 @@ use style::properties::SKIP_ROOT_AND_ITE
 use style::properties::animated_properties::{AnimationValue, ComputeDistance, Interpolate, TransitionProperty};
 use style::properties::parse_one_declaration;
 use style::restyle_hints::{self, RestyleHint};
 use style::rule_tree::StyleSource;
 use style::selector_parser::PseudoElementCascadeType;
 use style::sequential;
 use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked};
 use style::string_cache::Atom;
+use style::style_adjuster::StyleAdjuster;
 use style::stylesheets::{CssRule, CssRules, CssRuleType, CssRulesHelpers};
 use style::stylesheets::{ImportRule, MediaRule, NamespaceRule, Origin};
 use style::stylesheets::{PageRule, Stylesheet, StyleRule};
 use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
 use style::supports::parse_condition_or_declaration;
 use style::thread_state;
 use style::timer::Timer;
 use style::traversal::{ANIMATION_ONLY, FOR_RECONSTRUCT, UNSTYLED_CHILDREN_ONLY};
@@ -461,17 +462,17 @@ pub extern "C" fn Servo_StyleSet_GetBase
             let style = pseudos.get(p);
             debug_assert!(style.is_some());
             style
         }
         None => None,
     };
 
     let provider = get_metrics_provider_for_product();
-    element.get_base_style(shared_context, &provider, &styles.primary, pseudo.as_ref(), pseudo_style)
+    element.get_base_style(shared_context, &provider, &styles.primary, pseudo_style)
            .into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue(computed_values: ServoComputedValuesBorrowed,
                                                              property_id: nsCSSPropertyID)
                                                              -> RawServoAnimationValueStrong
 {
@@ -961,25 +962,36 @@ fn get_pseudo_style(guard: &SharedRwLock
                      .map(|s| s.values().clone())
         },
     }
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_Inherit(
   raw_data: RawServoStyleSetBorrowed,
-  parent_style: ServoComputedValuesBorrowedOrNull)
+  parent_style: ServoComputedValuesBorrowedOrNull,
+  for_text: bool)
      -> ServoComputedValuesStrong {
     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
     let maybe_arc = ComputedValues::arc_from_borrowed(&parent_style);
     let style = if let Some(reference) = maybe_arc.as_ref() {
-        ComputedValues::inherit_from(reference, &data.default_computed_values())
+        let mut style =
+            ComputedValues::inherit_from(reference,
+                                         &data.default_computed_values());
+        if for_text {
+            StyleAdjuster::new(&mut style, /* is_root = */ false)
+                .adjust_for_text();
+        }
+
+        Arc::new(style)
     } else {
+        debug_assert!(!for_text);
         data.default_computed_values().clone()
     };
+
     style.into_strong()
 }
 
 /// See the comment in `Device` to see why it's ok to pass an owned reference to
 /// the pres context (hint: the context outlives the StyleSet, that holds the
 /// device alive).
 #[no_mangle]
 pub extern "C" fn Servo_StyleSet_Init(pres_context: RawGeckoPresContextOwned)