Bug 1396692 - Part 3: Make computed::CalcLengthOrPercentage return pixel value as default. draft
authorBoris Chiou <boris.chiou@gmail.com>
Wed, 06 Sep 2017 11:33:59 +0800
changeset 659758 df49e877e3a01145eaddd586dae436eb443d8276
parent 659757 e79d01326057d00ffd606a440820ee8e599fbb28
child 659759 9ad4f2a26cf76b2dc4f82162e838d27138706cce
push id78218
push userbmo:boris.chiou@gmail.com
push dateWed, 06 Sep 2017 09:51:28 +0000
bugs1396692
milestone57.0a1
Bug 1396692 - Part 3: Make computed::CalcLengthOrPercentage return pixel value as default. Now, computed::CalcLengthOrPercentage uses CSSFloat as its internal length type, so let's return pixel value as the default unit. For some properties, we don't care about the extremely small values (e.g. calc(0.001px)), so add some helper methods to return the length with app unit. For transform, we want to keep the precision for small value, so we can create a correct transform matrix without any rounding issue. Therefore, add to_px() for computed::CalcLengthOrPercentage which returns the used value with pixel unit. MozReview-Commit-ID: LRHPgq6WoIZ
servo/components/layout/fragment.rs
servo/components/style/gecko/conversions.rs
servo/components/style/properties/helpers/animated_properties.mako.rs
servo/components/style/values/computed/length.rs
servo/components/style/values/computed/transform.rs
servo/components/style/values/specified/calc.rs
servo/components/style/values/specified/length.rs
servo/components/style/values/specified/position.rs
servo/components/style/values/specified/text.rs
servo/components/style_traits/values.rs
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -1515,17 +1515,17 @@ impl Fragment {
                         self.border_padding.block_end += border.block_end;
                         let (result_inline, _) = self.calculate_replaced_sizes(None, None);
                         result_inline
                     }
                     LengthOrPercentageOrAuto::Length(length) => length,
                     LengthOrPercentageOrAuto::Calc(calc) => {
                         // TODO(nox): This is probably wrong, because it accounts neither for
                         // clamping (not sure if necessary here) nor percentage.
-                        calc.unclamped_length()
+                        calc.unclamped_length_as_au()
                     },
                 };
 
                 let size_constraint = self.size_constraint(None, Direction::Inline);
                 inline_size = size_constraint.clamp(inline_size);
 
                 result.union_block(&IntrinsicISizes {
                     minimum_inline_size: inline_size,
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -24,31 +24,31 @@ use values::generics::grid::TrackSize;
 use values::generics::image::{CompatMode, Image as GenericImage, GradientItem};
 use values::generics::rect::Rect;
 use values::specified::url::SpecifiedUrl;
 
 impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
     fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
         let has_percentage = other.percentage.is_some();
         nsStyleCoord_CalcValue {
-            mLength: other.unclamped_length().0,
+            mLength: other.unclamped_length_as_au().0,
             mPercent: other.percentage.map_or(0., |p| p.0),
             mHasPercent: has_percentage,
         }
     }
 }
 
 impl From<nsStyleCoord_CalcValue> for CalcLengthOrPercentage {
     fn from(other: nsStyleCoord_CalcValue) -> CalcLengthOrPercentage {
         let percentage = if other.mHasPercent {
             Some(Percentage(other.mPercent))
         } else {
             None
         };
-        Self::new(Au(other.mLength), percentage)
+        Self::new(Au(other.mLength).to_f32_px(), percentage)
     }
 }
 
 impl From<LengthOrPercentage> for nsStyleCoord_CalcValue {
     fn from(other: LengthOrPercentage) -> nsStyleCoord_CalcValue {
         match other {
             LengthOrPercentage::Length(au) => {
                 nsStyleCoord_CalcValue {
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -2138,17 +2138,17 @@ impl ComputeSquaredDistance for Transfor
                 // compute the distance for the percentage-percentage case, but Gecko uses the
                 // same formula, so it's fine for now.
                 // Note: We use pixel value to compute the distance for translate, so we have to
                 // convert Au into px.
                 let extract_pixel_length = |lop: &LengthOrPercentage| {
                     match *lop {
                         LengthOrPercentage::Length(au) => au.to_f64_px(),
                         LengthOrPercentage::Percentage(_) => 0.,
-                        LengthOrPercentage::Calc(calc) => calc.length().to_f64_px(),
+                        LengthOrPercentage::Calc(calc) => calc.length() as f64,
                     }
                 };
 
                 let fx = extract_pixel_length(&fx);
                 let fy = extract_pixel_length(&fy);
                 let tx = extract_pixel_length(&tx);
                 let ty = extract_pixel_length(&ty);
 
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! `<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 style_traits::values::specified::AllowedLengthType;
+use style_traits::values::specified::AllowedNumericType;
 use super::{Number, ToComputedValue, Context, Percentage};
 use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
 use values::animated::{Animate, Procedure, ToAnimatedZero};
 use values::computed::{NonNegativeAu, NonNegativeNumber};
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
 use values::generics::NonNegative;
 use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength};
 use values::specified::length::ViewportPercentageLength;
@@ -49,146 +49,165 @@ impl ToComputedValue for specified::NoCa
 
 impl ToComputedValue for specified::Length {
     type ComputedValue = Au;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> Au {
         match *self {
             specified::Length::NoCalc(l) => l.to_computed_value(context),
-            specified::Length::Calc(ref calc) => calc.to_computed_value(context).length(),
+            specified::Length::Calc(ref calc) => calc.to_computed_value(context).length_as_au(),
         }
     }
 
     #[inline]
     fn from_computed_value(computed: &Au) -> Self {
         specified::Length::NoCalc(specified::NoCalcLength::from_computed_value(computed))
     }
 }
 
 #[allow(missing_docs)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[derive(Clone, Copy, Debug, PartialEq, ToAnimatedZero)]
 pub struct CalcLengthOrPercentage {
     #[animation(constant)]
-    pub clamping_mode: AllowedLengthType,
+    pub clamping_mode: AllowedNumericType,
     length: CSSFloat,
     pub percentage: Option<Percentage>,
 }
 
 impl ComputeSquaredDistance for CalcLengthOrPercentage {
     #[inline]
     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
         // FIXME(nox): This looks incorrect to me, to add a distance between lengths
         // with a distance between percentages.
         Ok(
-            self.unclamped_length().to_f64_px().compute_squared_distance(
-                &other.unclamped_length().to_f64_px())? +
+            self.unclamped_length().compute_squared_distance(&other.unclamped_length())? +
             self.percentage().compute_squared_distance(&other.percentage())?,
         )
     }
 }
 
 impl CalcLengthOrPercentage {
     /// Returns a new `CalcLengthOrPercentage`.
     #[inline]
-    pub fn new(length: Au, percentage: Option<Percentage>) -> Self {
-        Self::with_clamping_mode(length, percentage, AllowedLengthType::All)
+    pub fn new(length: CSSFloat, percentage: Option<Percentage>) -> Self {
+        Self::with_clamping_mode(length, percentage, AllowedNumericType::All)
     }
 
     /// Returns a new `CalcLengthOrPercentage` with a specific clamping mode.
     #[inline]
-    pub fn with_clamping_mode(length: Au,
+    pub fn with_clamping_mode(length: CSSFloat,
                               percentage: Option<Percentage>,
-                              clamping_mode: AllowedLengthType)
+                              clamping_mode: AllowedNumericType)
                               -> Self {
         Self {
             clamping_mode: clamping_mode,
-            length: length.to_f32_px(),
+            length: length,
             percentage: percentage,
         }
     }
 
     /// Returns this `calc()` as a `<length>`.
     ///
     /// Panics in debug mode if a percentage is present in the expression.
     #[inline]
-    pub fn length(&self) -> Au {
+    pub fn length(&self) -> CSSFloat {
         debug_assert!(self.percentage.is_none());
-        self.clamping_mode.clamp(Au::from_f32_px(self.length))
+        self.clamping_mode.clamp(self.length)
+    }
+
+    /// Returns this `calc()` as a `<length>`.
+    ///
+    /// Panics in debug mode if a percentage is present in the expression.
+    #[inline]
+    pub fn length_as_au(&self) -> Au {
+        Au::from_f32_px(self.length())
     }
 
     /// Returns the `<length>` component of this `calc()`, unclamped.
     #[inline]
-    pub fn unclamped_length(&self) -> Au {
+    pub fn unclamped_length(&self) -> CSSFloat {
+        self.length
+    }
+
+    /// Returns the `<length>` component of this `calc()`, unclamped, as app_unit.
+    #[inline]
+    pub fn unclamped_length_as_au(&self) -> Au {
         Au::from_f32_px(self.length)
     }
 
     #[inline]
     #[allow(missing_docs)]
     pub fn percentage(&self) -> CSSFloat {
         self.percentage.map_or(0., |p| p.0)
     }
 
+    /// Like to_px(), but return Option<Au>.
+    #[inline]
+    pub fn to_used_value(&self, container_len: Option<Au>) -> Option<Au> {
+        self.to_px(container_len).map(Au::from_f32_px)
+    }
+
     /// If there are special rules for computing percentages in a value (e.g. the height property),
     /// they apply whenever a calc() expression contains percentages.
-    pub fn to_used_value(&self, container_len: Option<Au>) -> Option<Au> {
+    pub fn to_px(&self, container_len: Option<Au>) -> Option<CSSFloat> {
         match (container_len, self.percentage) {
             (Some(len), Some(percent)) => {
-                Some(self.clamping_mode.clamp(Au::from_f32_px(self.length) + len.scale_by(percent.0)))
+                Some(self.clamping_mode.clamp(self.length + len.to_f32_px() * percent.0))
             },
             (_, None) => Some(self.length()),
             _ => None,
         }
     }
 }
 
 impl From<LengthOrPercentage> for CalcLengthOrPercentage {
     fn from(len: LengthOrPercentage) -> CalcLengthOrPercentage {
         match len {
             LengthOrPercentage::Percentage(this) => {
-                CalcLengthOrPercentage::new(Au(0), Some(this))
+                CalcLengthOrPercentage::new(0., Some(this))
             }
             LengthOrPercentage::Length(this) => {
-                CalcLengthOrPercentage::new(this, None)
+                CalcLengthOrPercentage::new(this.to_f32_px(), None)
             }
             LengthOrPercentage::Calc(this) => {
                 this
             }
         }
     }
 }
 
 impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> {
     fn from(len: LengthOrPercentageOrAuto) -> Option<CalcLengthOrPercentage> {
         match len {
             LengthOrPercentageOrAuto::Percentage(this) => {
-                Some(CalcLengthOrPercentage::new(Au(0), Some(this)))
+                Some(CalcLengthOrPercentage::new(0., Some(this)))
             }
             LengthOrPercentageOrAuto::Length(this) => {
-                Some(CalcLengthOrPercentage::new(this, None))
+                Some(CalcLengthOrPercentage::new(this.to_f32_px(), None))
             }
             LengthOrPercentageOrAuto::Calc(this) => {
                 Some(this)
             }
             LengthOrPercentageOrAuto::Auto => {
                 None
             }
         }
     }
 }
 
 impl From<LengthOrPercentageOrNone> for Option<CalcLengthOrPercentage> {
     fn from(len: LengthOrPercentageOrNone) -> Option<CalcLengthOrPercentage> {
         match len {
             LengthOrPercentageOrNone::Percentage(this) => {
-                Some(CalcLengthOrPercentage::new(Au(0), Some(this)))
+                Some(CalcLengthOrPercentage::new(0., Some(this)))
             }
             LengthOrPercentageOrNone::Length(this) => {
-                Some(CalcLengthOrPercentage::new(this, None))
+                Some(CalcLengthOrPercentage::new(this.to_f32_px(), None))
             }
             LengthOrPercentageOrNone::Calc(this) => {
                 Some(this)
             }
             LengthOrPercentageOrNone::None => {
                 None
             }
         }
@@ -358,31 +377,45 @@ impl LengthOrPercentage {
     }
 
     #[allow(missing_docs)]
     pub fn to_hash_key(&self) -> (Au, NotNaN<f32>) {
         use self::LengthOrPercentage::*;
         match *self {
             Length(l) => (l, NotNaN::new(0.0).unwrap()),
             Percentage(p) => (Au(0), NotNaN::new(p.0).unwrap()),
-            Calc(c) => (c.unclamped_length(), NotNaN::new(c.percentage()).unwrap()),
+            Calc(c) => (c.unclamped_length_as_au(),
+                        NotNaN::new(c.percentage()).unwrap()),
         }
     }
 
     /// Returns the used value.
     pub fn to_used_value(&self, containing_length: Au) -> Au {
         match *self {
             LengthOrPercentage::Length(length) => length,
             LengthOrPercentage::Percentage(p) => containing_length.scale_by(p.0),
             LengthOrPercentage::Calc(ref calc) => {
                 calc.to_used_value(Some(containing_length)).unwrap()
             },
         }
     }
 
+    /// Returns the used value as pixel value. This is especially useful for transform.
+    pub fn to_px(&self, containing_length: Au) -> CSSFloat {
+        use std::f32;
+        let result = match *self {
+            LengthOrPercentage::Length(length) => length.to_f32_px(),
+            LengthOrPercentage::Percentage(p) => containing_length.to_f32_px() * p.0,
+            LengthOrPercentage::Calc(ref calc) => {
+                calc.to_px(Some(containing_length)).unwrap()
+            },
+        };
+        result.min(f32::MAX).max(f32::MIN)
+    }
+
     /// Returns the clamped non-negative values.
     #[inline]
     pub fn clamp_to_non_negative(self) -> Self {
         match self {
             LengthOrPercentage::Length(length) => {
                 LengthOrPercentage::Length(Au(::std::cmp::max(length.0, 0)))
             },
             LengthOrPercentage::Percentage(percentage) => {
--- a/servo/components/style/values/computed/transform.rs
+++ b/servo/components/style/values/computed/transform.rs
@@ -69,17 +69,17 @@ impl TransformList {
             Some(list) => list,
             None => return None,
         };
 
         let extract_pixel_length = |lop: &LengthOrPercentage| {
             match *lop {
                 LengthOrPercentage::Length(au) => au.to_f32_px(),
                 LengthOrPercentage::Percentage(_) => 0.,
-                LengthOrPercentage::Calc(calc) => calc.length().to_f32_px(),
+                LengthOrPercentage::Calc(calc) => calc.length(),
             }
         };
 
         for operation in list {
             let matrix = match *operation {
                 ComputedOperation::Rotate(ax, ay, az, theta) => {
                     let theta = Angle::from_radians(2.0f32 * f32::consts::PI - theta.radians());
                     let (ax, ay, az, theta) =
@@ -90,18 +90,18 @@ impl TransformList {
                     Self::create_perspective_matrix(d)
                 }
                 ComputedOperation::Scale(sx, sy, sz) => {
                     Transform3D::create_scale(sx, sy, sz)
                 }
                 ComputedOperation::Translate(tx, ty, tz) => {
                     let (tx, ty) = match reference_box {
                         Some(relative_border_box) => {
-                            (tx.to_used_value(relative_border_box.size.width).to_f32_px(),
-                             ty.to_used_value(relative_border_box.size.height).to_f32_px())
+                            (tx.to_px(relative_border_box.size.width),
+                             ty.to_px(relative_border_box.size.height))
                         },
                         None => {
                             // If we don't have reference box, we cannot resolve the used value,
                             // so only retrieve the length part. This will be used for computing
                             // distance without any layout info.
                             (extract_pixel_length(&tx), extract_pixel_length(&ty))
                         }
                     };
@@ -115,17 +115,17 @@ impl TransformList {
                     // `-moz-transform` is not implemented in Servo yet.
                     unreachable!()
                 }
                 ComputedOperation::Skew(theta_x, theta_y) => {
                     Transform3D::create_skew(theta_x.into(), theta_y.into())
                 }
                 ComputedOperation::InterpolateMatrix { .. } |
                 ComputedOperation::AccumulateMatrix { .. } => {
-                    // TODO: Convert InterpolateMatrix/AccmulateMatrix into a valid Transform3D by
+                    // TODO: Convert InterpolateMatrix/AccumulateMatrix into a valid Transform3D by
                     // the reference box and do interpolation on these two Transform3D matrices.
                     // Both Gecko and Servo don't support this for computing distance, and Servo
                     // doesn't support animations on InterpolateMatrix/AccumulateMatrix, so
                     // return None.
                     return None;
                 }
             };
 
--- a/servo/components/style/values/specified/calc.rs
+++ b/servo/components/style/values/specified/calc.rs
@@ -6,17 +6,17 @@
 //!
 //! [calc]: https://drafts.csswg.org/css-values/#calc-notation
 
 use cssparser::{Parser, Token, BasicParseError};
 use parser::ParserContext;
 use std::ascii::AsciiExt;
 use std::fmt;
 use style_traits::{ToCss, ParseError, StyleParseError};
-use style_traits::values::specified::AllowedLengthType;
+use style_traits::values::specified::AllowedNumericType;
 use values::{CSSInteger, CSSFloat};
 use values::computed;
 use values::specified::{Angle, Time};
 use values::specified::length::{AbsoluteLength, FontRelativeLength, NoCalcLength};
 use values::specified::length::ViewportPercentageLength;
 
 /// A node inside a `Calc` expression's AST.
 #[derive(Clone, Debug)]
@@ -62,17 +62,17 @@ pub enum CalcUnit {
     Time,
 }
 
 /// A struct to hold a simplified `<length>` or `<percentage>` expression.
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
 pub struct CalcLengthOrPercentage {
-    pub clamping_mode: AllowedLengthType,
+    pub clamping_mode: AllowedNumericType,
     pub absolute: Option<AbsoluteLength>,
     pub vw: Option<CSSFloat>,
     pub vh: Option<CSSFloat>,
     pub vmin: Option<CSSFloat>,
     pub vmax: Option<CSSFloat>,
     pub em: Option<CSSFloat>,
     pub ex: Option<CSSFloat>,
     pub ch: Option<CSSFloat>,
@@ -291,17 +291,17 @@ impl CalcNode {
             }
         }
 
         Ok(root)
     }
 
     /// Tries to simplify this expression into a `<length>` or `<percentage`>
     /// value.
-    fn to_length_or_percentage(&self, clamping_mode: AllowedLengthType)
+    fn to_length_or_percentage(&self, clamping_mode: AllowedNumericType)
                                -> Result<CalcLengthOrPercentage, ()> {
         let mut ret = CalcLengthOrPercentage {
             clamping_mode: clamping_mode,
             .. Default::default()
         };
         self.add_length_or_percentage_to(&mut ret, 1.0)?;
         Ok(ret)
     }
@@ -565,17 +565,17 @@ impl CalcNode {
             .map(|n| n as CSSInteger)
             .map_err(|()| StyleParseError::UnspecifiedError.into())
     }
 
     /// Convenience parsing function for `<length> | <percentage>`.
     pub fn parse_length_or_percentage<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
-        clamping_mode: AllowedLengthType
+        clamping_mode: AllowedNumericType
     ) -> Result<CalcLengthOrPercentage, ParseError<'i>> {
         Self::parse(context, input, CalcUnit::LengthOrPercentage)?
             .to_length_or_percentage(clamping_mode)
             .map_err(|()| StyleParseError::UnspecifiedError.into())
     }
 
     /// Convenience parsing function for percentages.
     pub fn parse_percentage<'i, 't>(
@@ -586,17 +586,17 @@ impl CalcNode {
             .to_percentage()
             .map_err(|()| StyleParseError::UnspecifiedError.into())
     }
 
     /// Convenience parsing function for `<length>`.
     pub fn parse_length<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
-        clamping_mode: AllowedLengthType
+        clamping_mode: AllowedNumericType
     ) -> Result<CalcLengthOrPercentage, ParseError<'i>> {
         Self::parse(context, input, CalcUnit::Length)?
             .to_length_or_percentage(clamping_mode)
             .map_err(|()| StyleParseError::UnspecifiedError.into())
     }
 
     /// Convenience parsing function for `<number>`.
     pub fn parse_number<'i, 't>(
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -715,17 +715,18 @@ impl Length {
                     }
                     return Ok(Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(value))))
                 },
                 Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {}
                 ref token => return Err(BasicParseError::UnexpectedToken(token.clone()).into())
             }
         }
         input.parse_nested_block(|input| {
-            CalcNode::parse_length(context, input, num_context).map(|calc| Length::Calc(Box::new(calc)))
+            CalcNode::parse_length(context, input, num_context.into()).map(
+                |calc| Length::Calc(Box::new(calc)))
         })
     }
 
     /// Parse a non-negative length
     #[inline]
     pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                       -> Result<Length, ParseError<'i>> {
         Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
@@ -916,17 +917,17 @@ impl LengthOrPercentage {
                     }
                 }
                 Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {}
                 _ => return Err(BasicParseError::UnexpectedToken(token.clone()).into())
             }
         }
 
         let calc = input.parse_nested_block(|i| {
-            CalcNode::parse_length_or_percentage(context, i, num_context)
+            CalcNode::parse_length_or_percentage(context, i, num_context.into())
         })?;
         Ok(LengthOrPercentage::Calc(Box::new(calc)))
     }
 
     /// Parse a non-negative length.
     #[inline]
     pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                       -> Result<LengthOrPercentage, ParseError<'i>> {
@@ -1061,17 +1062,17 @@ impl LengthOrPercentageOrAuto {
                     return Ok(LengthOrPercentageOrAuto::Auto)
                 }
                 Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {}
                 _ => return Err(BasicParseError::UnexpectedToken(token.clone()).into())
             }
         }
 
         let calc = input.parse_nested_block(|i| {
-            CalcNode::parse_length_or_percentage(context, i, num_context)
+            CalcNode::parse_length_or_percentage(context, i, num_context.into())
         })?;
         Ok(LengthOrPercentageOrAuto::Calc(Box::new(calc)))
     }
 
     /// Parse a non-negative length, percentage, or auto.
     #[inline]
     pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                       -> Result<LengthOrPercentageOrAuto, ParseError<'i>> {
@@ -1164,17 +1165,17 @@ impl LengthOrPercentageOrNone {
                 Token::Ident(ref value) if value.eq_ignore_ascii_case("none") => {
                     return Ok(LengthOrPercentageOrNone::None)
                 }
                 _ => return Err(BasicParseError::UnexpectedToken(token.clone()).into())
             }
         }
 
         let calc = input.parse_nested_block(|i| {
-            CalcNode::parse_length_or_percentage(context, i, num_context)
+            CalcNode::parse_length_or_percentage(context, i, num_context.into())
         })?;
         Ok(LengthOrPercentageOrNone::Calc(Box::new(calc)))
     }
 
     /// Parse a non-negative LengthOrPercentageOrNone.
     #[inline]
     pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                       -> Result<Self, ParseError<'i>> {
--- a/servo/components/style/values/specified/position.rs
+++ b/servo/components/style/values/specified/position.rs
@@ -198,17 +198,17 @@ impl<S: Side> ToComputedValue for Positi
             PositionComponent::Side(ref keyword, None) => {
                 let p = Percentage(if keyword.is_start() { 0. } else { 1. });
                 ComputedLengthOrPercentage::Percentage(p)
             },
             PositionComponent::Side(ref keyword, Some(ref length)) if !keyword.is_start() => {
                 match length.to_computed_value(context) {
                     ComputedLengthOrPercentage::Length(length) => {
                         ComputedLengthOrPercentage::Calc(
-                            CalcLengthOrPercentage::new(-length, Some(Percentage::hundred())))
+                            CalcLengthOrPercentage::new(-length.to_f32_px(), Some(Percentage::hundred())))
                     },
                     ComputedLengthOrPercentage::Percentage(p) => {
                         ComputedLengthOrPercentage::Percentage(Percentage(1.0 - p.0))
                     },
                     ComputedLengthOrPercentage::Calc(calc) => {
                         let p = Percentage(1. - calc.percentage.map_or(0., |p| p.0));
                         ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage::new(-calc.unclamped_length(), Some(p)))
                     },
--- a/servo/components/style/values/specified/text.rs
+++ b/servo/components/style/values/specified/text.rs
@@ -79,16 +79,17 @@ impl Parse for LineHeight {
     }
 }
 
 impl ToComputedValue for LineHeight {
     type ComputedValue = ComputedLineHeight;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+        use app_units::Au;
         use values::specified::length::FontBaseSize;
         match *self {
             GenericLineHeight::Normal => {
                 GenericLineHeight::Normal
             },
             #[cfg(feature = "gecko")]
             GenericLineHeight::MozBlockHeight => {
                 GenericLineHeight::MozBlockHeight
@@ -116,20 +117,20 @@ impl ToComputedValue for LineHeight {
                         let font_relative_length =
                             FontRelativeLength::Em(computed_calc.percentage())
                                 .to_computed_value(
                                     context,
                                     FontBaseSize::CurrentStyle,
                                 );
 
                         let absolute_length = computed_calc.unclamped_length();
-                        computed_calc
-                            .clamping_mode
-                            .clamp(absolute_length + font_relative_length)
-                            .into()
+                        Au::from_f32_px(
+                            computed_calc
+                                .clamping_mode
+                                .clamp(absolute_length + font_relative_length.to_f32_px())).into()
                     }
                 };
                 GenericLineHeight::Length(result)
             }
         }
     }
 
     #[inline]
--- a/servo/components/style_traits/values.rs
+++ b/servo/components/style_traits/values.rs
@@ -501,16 +501,23 @@ pub mod specified {
         /// Allow all kind of numeric values.
         All,
         /// Allow only non-negative numeric values.
         NonNegative,
         /// Allow only numeric values greater or equal to 1.0.
         AtLeastOne,
     }
 
+    impl Default for AllowedNumericType {
+        #[inline]
+        fn default() -> Self {
+            AllowedNumericType::All
+        }
+    }
+
     impl AllowedNumericType {
         /// Whether the value fits the rules of this numeric type.
         #[inline]
         pub fn is_ok(&self, parsing_mode: ParsingMode, val: f32) -> bool {
             if parsing_mode.allows_all_numeric_values() {
                 return true;
             }
             match *self {
@@ -525,16 +532,26 @@ pub mod specified {
         pub fn clamp(&self, val: f32) -> f32 {
             match *self {
                 AllowedNumericType::NonNegative if val < 0. => 0.,
                 AllowedNumericType::AtLeastOne if val < 1. => 1.,
                 _ => val,
             }
         }
     }
+
+    impl From<AllowedLengthType> for AllowedNumericType {
+        #[inline]
+        fn from(t: AllowedLengthType) -> Self {
+            match t {
+                AllowedLengthType::All => AllowedNumericType::All,
+                AllowedLengthType::NonNegative => AllowedNumericType::NonNegative,
+            }
+        }
+    }
 }
 
 
 /// Wrap CSS types for serialization with `write!` or `format!` macros.
 /// Used by ToCss of SpecifiedOperation.
 pub struct Css<T>(pub T);
 
 impl<T: ToCss> fmt::Display for Css<T> {