Bug 1355427 - Part 1: stylo: Support computing font-size against an arbitrary base size; r?heycam draft
authorManish Goregaokar <manishearth@gmail.com>
Thu, 13 Apr 2017 13:25:01 +0800
changeset 565620 0e63cf0184929f0b52da55a2c26b202fc253668a
parent 565531 20dff607fb88ee69135a280bbb7f32df75a86237
child 565621 153d8e4dc47952434c33cf0087a0727b970ca4f9
push id54926
push userbmo:manishearth@gmail.com
push dateThu, 20 Apr 2017 05:09:50 +0000
reviewersheycam
bugs1355427
milestone55.0a1
Bug 1355427 - Part 1: stylo: Support computing font-size against an arbitrary base size; r?heycam MozReview-Commit-ID: 4jWcugvXR65
servo/components/style/properties/longhand/font.mako.rs
servo/components/style/values/computed/length.rs
servo/components/style/values/specified/length.rs
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -413,16 +413,17 @@
 <%helpers:longhand name="font-size" need_clone="True" animation_type="normal"
                    spec="https://drafts.csswg.org/css-fonts/#propdef-font-size">
     use app_units::Au;
     use std::fmt;
     use style_traits::ToCss;
     use values::{FONT_MEDIUM_PX, HasViewportPercentage};
     use values::specified::{FontRelativeLength, LengthOrPercentage, Length};
     use values::specified::{NoCalcLength, Percentage};
+    use values::specified::length::FontBaseSize;
 
     impl ToCss for SpecifiedValue {
         fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             match *self {
                 SpecifiedValue::Length(ref lop) => lop.to_css(dest),
                 SpecifiedValue::Keyword(kw, _) => kw.to_css(dest),
                 SpecifiedValue::Smaller => dest.write_str("smaller"),
                 SpecifiedValue::Larger => dest.write_str("larger"),
@@ -622,67 +623,73 @@
                 } else if let LengthOrPercentage::Length(ref nocalc) = *lop {
                     if let NoCalcLength::FontRelative(FontRelativeLength::Em(em)) = *nocalc {
                         return Some(em)
                     }
                 }
             }
             None
         }
+
+        /// Compute it against a given base font size
+        pub fn to_computed_value_against(&self, context: &Context, base_size: FontBaseSize) -> Au {
+            use values::specified::length::FontRelativeLength;
+            match *self {
+                SpecifiedValue::Length(LengthOrPercentage::Length(
+                        NoCalcLength::FontRelative(value))) => {
+                    value.to_computed_value(context, base_size)
+                }
+                SpecifiedValue::Length(LengthOrPercentage::Length(
+                        NoCalcLength::ServoCharacterWidth(value))) => {
+                    value.to_computed_value(base_size.resolve(context))
+                }
+                SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => {
+                    l.to_computed_value(context)
+                }
+                SpecifiedValue::Length(LengthOrPercentage::Percentage(Percentage(value))) => {
+                    base_size.resolve(context).scale_by(value)
+                }
+                SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => {
+                    let calc = calc.to_computed_value(context);
+                    calc.length() +base_size.resolve(context)
+                                           .scale_by(calc.percentage())
+                }
+                SpecifiedValue::Keyword(ref key, fraction) => {
+                    key.to_computed_value(context).scale_by(fraction)
+                }
+                SpecifiedValue::Smaller => {
+                    FontRelativeLength::Em(0.85)
+                        .to_computed_value(context, base_size)
+                }
+                SpecifiedValue::Larger => {
+                    FontRelativeLength::Em(1.2)
+                        .to_computed_value(context, base_size)
+                }
+            }
+        }
     }
 
     #[inline]
     #[allow(missing_docs)]
     pub fn get_initial_value() -> computed_value::T {
         Au::from_px(FONT_MEDIUM_PX)
     }
 
     #[inline]
     pub fn get_initial_specified_value() -> SpecifiedValue {
         SpecifiedValue::Keyword(Medium, 1.)
     }
 
+
     impl ToComputedValue for SpecifiedValue {
         type ComputedValue = computed_value::T;
 
         #[inline]
         fn to_computed_value(&self, context: &Context) -> computed_value::T {
-            use values::specified::length::FontRelativeLength;
-            match *self {
-                SpecifiedValue::Length(LengthOrPercentage::Length(
-                        NoCalcLength::FontRelative(value))) => {
-                    value.to_computed_value(context, /* use inherited */ true)
-                }
-                SpecifiedValue::Length(LengthOrPercentage::Length(
-                        NoCalcLength::ServoCharacterWidth(value))) => {
-                    value.to_computed_value(context.inherited_style().get_font().clone_font_size())
-                }
-                SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => {
-                    l.to_computed_value(context)
-                }
-                SpecifiedValue::Length(LengthOrPercentage::Percentage(Percentage(value))) => {
-                    context.inherited_style().get_font().clone_font_size().scale_by(value)
-                }
-                SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => {
-                    let calc = calc.to_computed_value(context);
-                    calc.length() + context.inherited_style().get_font().clone_font_size()
-                                           .scale_by(calc.percentage())
-                }
-                SpecifiedValue::Keyword(ref key, fraction) => {
-                    key.to_computed_value(context).scale_by(fraction)
-                }
-                SpecifiedValue::Smaller => {
-                    FontRelativeLength::Em(0.85).to_computed_value(context,
-                                                                   /* use_inherited */ true)
-                }
-                SpecifiedValue::Larger => {
-                    FontRelativeLength::Em(1.2).to_computed_value(context,
-                                                                   /* use_inherited */ true)
-                }
-            }
+            self.to_computed_value_against(context, FontBaseSize::InheritedStyle)
         }
 
         #[inline]
         fn from_computed_value(computed: &computed_value::T) -> Self {
                 SpecifiedValue::Length(LengthOrPercentage::Length(
                         ToComputedValue::from_computed_value(computed)
                 ))
         }
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -5,32 +5,32 @@
 //! `<length>` computed values, and related ones.
 
 use app_units::{Au, AU_PER_PX};
 use ordered_float::NotNaN;
 use std::fmt;
 use style_traits::ToCss;
 use super::{Number, ToComputedValue, Context};
 use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
-use values::specified::length::{AbsoluteLength, FontRelativeLength, ViewportPercentageLength};
+use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength, ViewportPercentageLength};
 
 pub use super::image::{EndingShape as GradientShape, Gradient, GradientKind, Image};
 pub use super::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
 pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
 
 impl ToComputedValue for specified::NoCalcLength {
     type ComputedValue = Au;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> Au {
         match *self {
             specified::NoCalcLength::Absolute(length) =>
                 length.to_computed_value(context),
             specified::NoCalcLength::FontRelative(length) =>
-                length.to_computed_value(context, /* use inherited */ false),
+                length.to_computed_value(context, /* base_size */ FontBaseSize::CurrentStyle),
             specified::NoCalcLength::ViewportPercentage(length) =>
                 length.to_computed_value(context.viewport_size()),
             specified::NoCalcLength::ServoCharacterWidth(length) =>
                 length.to_computed_value(context.style().get_font().clone_font_size())
         }
     }
 
     #[inline]
@@ -134,16 +134,17 @@ impl ToCss for CalcLengthOrPercentage {
         }
     }
 }
 
 impl ToComputedValue for specified::CalcLengthOrPercentage {
     type ComputedValue = CalcLengthOrPercentage;
 
     fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage {
+
         let mut length = Au(0);
 
         if let Some(absolute) = self.absolute {
             length += absolute;
         }
 
         for val in &[self.vw.map(ViewportPercentageLength::Vw),
                      self.vh.map(ViewportPercentageLength::Vh),
@@ -154,17 +155,17 @@ impl ToComputedValue for specified::Calc
             }
         }
 
         for val in &[self.ch.map(FontRelativeLength::Ch),
                      self.em.map(FontRelativeLength::Em),
                      self.ex.map(FontRelativeLength::Ex),
                      self.rem.map(FontRelativeLength::Rem)] {
             if let Some(val) = *val {
-                length += val.to_computed_value(context, /* use inherited */ false);
+                length += val.to_computed_value(context, /* base_size */ FontBaseSize::CurrentStyle);
             }
         }
 
         CalcLengthOrPercentage {
             length: length,
             percentage: self.percentage,
         }
     }
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -71,33 +71,50 @@ impl ToCss for FontRelativeLength {
             FontRelativeLength::Em(length) => write!(dest, "{}em", length),
             FontRelativeLength::Ex(length) => write!(dest, "{}ex", length),
             FontRelativeLength::Ch(length) => write!(dest, "{}ch", length),
             FontRelativeLength::Rem(length) => write!(dest, "{}rem", length)
         }
     }
 }
 
+/// A source to resolve font-relative units against
+pub enum FontBaseSize {
+    /// Use the font-size of the current element
+    CurrentStyle,
+    /// Use the inherited font-size
+    InheritedStyle,
+    /// Use a custom base size
+    Custom(Au),
+}
+
+impl FontBaseSize {
+    /// Calculate the actual size for a given context
+    pub fn resolve(&self, context: &Context) -> Au {
+        match *self {
+            FontBaseSize::Custom(size) => size,
+            FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size(),
+            FontBaseSize::InheritedStyle => context.inherited_style().get_font().clone_font_size(),
+        }
+    }
+}
+
 impl FontRelativeLength {
-    /// Computes the font-relative length. We use the use_inherited flag to
-    /// special-case the computation of font-size.
-    pub fn to_computed_value(&self, context: &Context, use_inherited: bool) -> Au {
+    /// Computes the font-relative length. We use the inherited_size
+    /// flag to pass a different size for computing font-size and unconstrained font-size
+    pub fn to_computed_value(&self, context: &Context, base_size: FontBaseSize) -> Au {
         fn query_font_metrics(context: &Context, reference_font_size: Au) -> FontMetricsQueryResult {
             context.font_metrics_provider.query(context.style().get_font(),
                                                 reference_font_size,
                                                 context.style().writing_mode,
                                                 context.in_media_query,
                                                 context.device)
         }
 
-        let reference_font_size = if use_inherited {
-            context.inherited_style().get_font().clone_font_size()
-        } else {
-            context.style().get_font().clone_font_size()
-        };
+        let reference_font_size = base_size.resolve(context);
 
         let root_font_size = context.style().root_font_size;
         match *self {
             FontRelativeLength::Em(length) => reference_font_size.scale_by(length),
             FontRelativeLength::Ex(length) => {
                 match query_font_metrics(context, reference_font_size) {
                     FontMetricsQueryResult::Available(metrics) => metrics.x_height.scale_by(length),
                     // https://drafts.csswg.org/css-values/#ex