servo: Merge #17338 - Derive ToCss for computed LengthOrPercentage types (from servo:derive-all-the-things); r=emilio,waffles
authorAnthony Ramine <n.oxyde@gmail.com>
Thu, 15 Jun 2017 13:37:04 -0700
changeset 364228 5e2be621f53200eca0693d43fa10c31901240123
parent 364227 dc1837d384484985e9d486a1dc454e3d7c37e118
child 364229 d9824cf47dc84c956db9b299e2ea5d8a5e853d70
push id32036
push userarchaeopteryx@coole-files.de
push dateFri, 16 Jun 2017 07:47:22 +0000
treeherdermozilla-central@64a2ba65f0d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio, waffles
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #17338 - Derive ToCss for computed LengthOrPercentage types (from servo:derive-all-the-things); r=emilio,waffles Source-Repo: https://github.com/servo/servo Source-Revision: 0142d193a3fde057718612028d9c1676e046b816
servo/components/layout/block.rs
servo/components/layout/display_list_builder.rs
servo/components/layout/flex.rs
servo/components/layout/floats.rs
servo/components/layout/fragment.rs
servo/components/layout/model.rs
servo/components/layout/table.rs
servo/components/layout/table_row.rs
servo/components/style/gecko/conversions.rs
servo/components/style/gecko/values.rs
servo/components/style/gecko_bindings/sugar/ns_css_value.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/helpers/animated_properties.mako.rs
servo/components/style/values/computed/length.rs
servo/components/style/values/computed/position.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/transform.rs
servo/tests/unit/style/animated_properties.rs
servo/tests/unit/style/attr.rs
--- a/servo/components/layout/block.rs
+++ b/servo/components/layout/block.rs
@@ -317,39 +317,39 @@ impl CandidateBSizeIterator {
         // Per CSS 2.1 ยง 10.7, (assuming an horizontal writing mode,)
         // percentages in `min-height` and `max-height` refer to the height of
         // the containing block.
         // If that is not determined yet by the time we need to resolve
         // `min-height` and `max-height`, percentage values are ignored.
 
         let block_size = match (fragment.style.content_block_size(), block_container_block_size) {
             (LengthOrPercentageOrAuto::Percentage(percent), Some(block_container_block_size)) => {
-                MaybeAuto::Specified(block_container_block_size.scale_by(percent))
+                MaybeAuto::Specified(block_container_block_size.scale_by(percent.0))
             }
             (LengthOrPercentageOrAuto::Calc(calc), _) => {
                 MaybeAuto::from_option(calc.to_used_value(block_container_block_size))
             }
             (LengthOrPercentageOrAuto::Percentage(_), None) |
             (LengthOrPercentageOrAuto::Auto, _) => MaybeAuto::Auto,
             (LengthOrPercentageOrAuto::Length(length), _) => MaybeAuto::Specified(length),
         };
         let max_block_size = match (fragment.style.max_block_size(), block_container_block_size) {
             (LengthOrPercentageOrNone::Percentage(percent), Some(block_container_block_size)) => {
-                Some(block_container_block_size.scale_by(percent))
+                Some(block_container_block_size.scale_by(percent.0))
             }
             (LengthOrPercentageOrNone::Calc(calc), _) => {
                 calc.to_used_value(block_container_block_size)
             }
             (LengthOrPercentageOrNone::Percentage(_), None) |
             (LengthOrPercentageOrNone::None, _) => None,
             (LengthOrPercentageOrNone::Length(length), _) => Some(length),
         };
         let min_block_size = match (fragment.style.min_block_size(), block_container_block_size) {
             (LengthOrPercentage::Percentage(percent), Some(block_container_block_size)) => {
-                block_container_block_size.scale_by(percent)
+                block_container_block_size.scale_by(percent.0)
             }
             (LengthOrPercentage::Calc(calc), _) => {
                 calc.to_used_value(block_container_block_size).unwrap_or(Au(0))
             }
             (LengthOrPercentage::Percentage(_), None) => Au(0),
             (LengthOrPercentage::Length(length), _) => length,
         };
 
@@ -1173,17 +1173,17 @@ impl BlockFlow {
         let content_block_size = self.fragment.style().content_block_size();
 
         match (content_block_size, containing_block_size) {
             (LengthOrPercentageOrAuto::Calc(calc), _) => {
                 calc.to_used_value(containing_block_size)
             }
             (LengthOrPercentageOrAuto::Length(length), _) => Some(length),
             (LengthOrPercentageOrAuto::Percentage(percent), Some(container_size)) => {
-                Some(container_size.scale_by(percent))
+                Some(container_size.scale_by(percent.0))
             }
             (LengthOrPercentageOrAuto::Percentage(_), None) |
             (LengthOrPercentageOrAuto::Auto, None) => {
                 None
             }
             (LengthOrPercentageOrAuto::Auto, Some(container_size)) => {
                 let (block_start, block_end) = {
                     let position = self.fragment.style().logical_position();
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -60,16 +60,17 @@ use style::values::{Either, RGBA};
 use style::values::computed::{Gradient, GradientItem, LengthOrPercentage};
 use style::values::computed::{LengthOrPercentageOrAuto, NumberOrPercentage, Position, Shadow};
 use style::values::computed::image::{EndingShape, LineDirection};
 use style::values::generics::background::BackgroundSize;
 use style::values::generics::image::{Circle, Ellipse, EndingShape as GenericEndingShape};
 use style::values::generics::image::{GradientItem as GenericGradientItem, GradientKind};
 use style::values::generics::image::{Image, ShapeExtent};
 use style::values::generics::image::PaintWorklet;
+use style::values::specified::length::Percentage;
 use style::values::specified::position::{X, Y};
 use style_traits::CSSPixel;
 use style_traits::cursor::Cursor;
 use table_cell::CollapsedBordersForCell;
 use webrender_helpers::{ToMixBlendMode, ToTransformStyle};
 use webrender_traits::{ColorF, ClipId, GradientStop, RepeatMode, ScrollPolicy, TransformStyle};
 
 trait ResolvePercentage {
@@ -648,24 +649,24 @@ fn convert_gradient_stops(gradient_items
     // Run the algorithm from
     // https://drafts.csswg.org/css-images-3/#color-stop-syntax
 
     // Step 1:
     // If the first color stop does not have a position, set its position to 0%.
     {
         let first = stop_items.first_mut().unwrap();
         if first.position.is_none() {
-            first.position = Some(LengthOrPercentage::Percentage(0.0));
+            first.position = Some(LengthOrPercentage::Percentage(Percentage(0.0)));
         }
     }
     // If the last color stop does not have a position, set its position to 100%.
     {
         let last = stop_items.last_mut().unwrap();
         if last.position.is_none() {
-            last.position = Some(LengthOrPercentage::Percentage(1.0));
+            last.position = Some(LengthOrPercentage::Percentage(Percentage(1.0)));
         }
     }
 
     // Step 2: Move any stops placed before earlier stops to the
     // same position as the preceding stop.
     let mut last_stop_position = stop_items.first().unwrap().position.unwrap();
     for stop in stop_items.iter_mut().skip(1) {
         if let Some(pos) = stop.position {
@@ -2866,17 +2867,17 @@ struct StopRun {
     end_offset: f32,
     start_index: usize,
     stop_count: usize,
 }
 
 fn position_to_offset(position: LengthOrPercentage, total_length: Au) -> f32 {
     match position {
         LengthOrPercentage::Length(Au(length)) => length as f32 / total_length.0 as f32,
-        LengthOrPercentage::Percentage(percentage) => percentage as f32,
+        LengthOrPercentage::Percentage(percentage) => percentage.0 as f32,
         LengthOrPercentage::Calc(calc) => {
             calc.to_used_value(Some(total_length)).unwrap().0 as f32 / total_length.0 as f32
         },
     }
 }
 
 /// Adjusts `content_rect` as necessary for the given spread, and blur so that the resulting
 /// bounding rect contains all of a shadow's ink.
--- a/servo/components/layout/flex.rs
+++ b/servo/components/layout/flex.rs
@@ -41,17 +41,17 @@ impl AxisSize {
     /// Generate a new available cross or main axis size from the specified size of the container,
     /// containing block size, min constraint, and max constraint
     pub fn new(size: LengthOrPercentageOrAuto, content_size: Option<Au>, min: LengthOrPercentage,
                max: LengthOrPercentageOrNone) -> AxisSize {
         match size {
             LengthOrPercentageOrAuto::Length(length) => AxisSize::Definite(length),
             LengthOrPercentageOrAuto::Percentage(percent) => {
                 match content_size {
-                    Some(size) => AxisSize::Definite(size.scale_by(percent)),
+                    Some(size) => AxisSize::Definite(size.scale_by(percent.0)),
                     None => AxisSize::Infinite
                 }
             }
             LengthOrPercentageOrAuto::Calc(calc) => {
                 match calc.to_used_value(content_size) {
                     Some(length) => AxisSize::Definite(length),
                     None => AxisSize::Infinite,
                 }
@@ -69,17 +69,17 @@ impl AxisSize {
 /// is definite after flex size resolving.
 fn from_flex_basis(flex_basis: LengthOrPercentageOrAutoOrContent,
                    main_length: LengthOrPercentageOrAuto,
                    containing_length: Option<Au>) -> MaybeAuto {
     match (flex_basis, containing_length) {
         (LengthOrPercentageOrAutoOrContent::Length(length), _) =>
             MaybeAuto::Specified(length),
         (LengthOrPercentageOrAutoOrContent::Percentage(percent), Some(size)) =>
-            MaybeAuto::Specified(size.scale_by(percent)),
+            MaybeAuto::Specified(size.scale_by(percent.0)),
         (LengthOrPercentageOrAutoOrContent::Percentage(_), None) =>
             MaybeAuto::Auto,
         (LengthOrPercentageOrAutoOrContent::Calc(calc), _) =>
             MaybeAuto::from_option(calc.to_used_value(containing_length)),
         (LengthOrPercentageOrAutoOrContent::Content, _) =>
             MaybeAuto::Auto,
         (LengthOrPercentageOrAutoOrContent::Auto, Some(size)) =>
             MaybeAuto::from_style(main_length, size),
--- a/servo/components/layout/floats.rs
+++ b/servo/components/layout/floats.rs
@@ -500,17 +500,17 @@ impl SpeculatedFloatPlacement {
         if float_inline_size == Au(0) {
             if flow.is_block_like() {
                 // Hack: If the size of the float is a percentage, then there's no way we can guess
                 // at its size now. So just pick an arbitrary nonzero value (in this case, 1px) so
                 // that the layout traversal logic will know that objects later in the document
                 // might flow around this float.
                 if let LengthOrPercentageOrAuto::Percentage(percentage) =
                         flow.as_block().fragment.style.content_inline_size() {
-                    if percentage > 0.0 {
+                    if percentage.0 > 0.0 {
                         float_inline_size = Au::from_px(1)
                     }
                 }
             }
         }
 
         match base_flow.flags.float_kind() {
             float::T::none => {}
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -2229,17 +2229,17 @@ impl Fragment {
                             content_inline_metrics.space_below_baseline
                     }
                 }
                 vertical_align::T::LengthOrPercentage(LengthOrPercentage::Length(length)) => {
                     offset -= length
                 }
                 vertical_align::T::LengthOrPercentage(LengthOrPercentage::Percentage(
                         percentage)) => {
-                    offset -= minimum_line_metrics.space_needed().scale_by(percentage)
+                    offset -= minimum_line_metrics.space_needed().scale_by(percentage.0)
                 }
                 vertical_align::T::LengthOrPercentage(LengthOrPercentage::Calc(formula)) => {
                     offset -= formula.to_used_value(Some(minimum_line_metrics.space_needed())).unwrap()
                 }
             }
         }
         offset
     }
--- a/servo/components/layout/model.rs
+++ b/servo/components/layout/model.rs
@@ -139,27 +139,27 @@ impl MarginCollapseInfo {
                                                   -> (CollapsibleMargins, Au) {
         let state = match self.state {
             MarginCollapseState::AccumulatingCollapsibleTopMargin => {
                 may_collapse_through = may_collapse_through &&
                     match fragment.style().content_block_size() {
                         LengthOrPercentageOrAuto::Auto => true,
                         LengthOrPercentageOrAuto::Length(Au(v)) => v == 0,
                         LengthOrPercentageOrAuto::Percentage(v) => {
-                            v == 0. || containing_block_size.is_none()
+                            v.0 == 0. || containing_block_size.is_none()
                         }
                         LengthOrPercentageOrAuto::Calc(_) => false,
                     };
 
                 if may_collapse_through {
                     match fragment.style().min_block_size() {
                         LengthOrPercentage::Length(Au(0)) => {
                             FinalMarginState::MarginsCollapseThrough
                         },
-                        LengthOrPercentage::Percentage(v) if v == 0. => {
+                        LengthOrPercentage::Percentage(v) if v.0 == 0. => {
                             FinalMarginState::MarginsCollapseThrough
                         },
                         _ => {
                             // If the fragment has non-zero min-block-size, margins may not
                             // collapse through it.
                             FinalMarginState::BottomMarginCollapses
                         }
                     }
@@ -403,17 +403,17 @@ pub enum MaybeAuto {
 
 impl MaybeAuto {
     #[inline]
     pub fn from_style(length: LengthOrPercentageOrAuto, containing_length: Au)
                       -> MaybeAuto {
         match length {
             LengthOrPercentageOrAuto::Auto => MaybeAuto::Auto,
             LengthOrPercentageOrAuto::Percentage(percent) => {
-                MaybeAuto::Specified(containing_length.scale_by(percent))
+                MaybeAuto::Specified(containing_length.scale_by(percent.0))
             }
             LengthOrPercentageOrAuto::Calc(calc) => {
                 MaybeAuto::from_option(calc.to_used_value(Some(containing_length)))
             }
             LengthOrPercentageOrAuto::Length(length) => MaybeAuto::Specified(length)
         }
     }
 
--- a/servo/components/layout/table.rs
+++ b/servo/components/layout/table.rs
@@ -248,17 +248,17 @@ impl Flow for TableFlow {
                         LengthOrPercentageOrAuto::Calc(_) |
                         LengthOrPercentageOrAuto::Percentage(_) => Au(0),
                         LengthOrPercentageOrAuto::Length(length) => length,
                     },
                     percentage: match *specified_inline_size {
                         LengthOrPercentageOrAuto::Auto |
                         LengthOrPercentageOrAuto::Calc(_) |
                         LengthOrPercentageOrAuto::Length(_) => 0.0,
-                        LengthOrPercentageOrAuto::Percentage(percentage) => percentage,
+                        LengthOrPercentageOrAuto::Percentage(percentage) => percentage.0,
                     },
                     preferred: Au(0),
                     constrained: false,
                 })
             }
         }
 
         self.collapsed_inline_direction_border_widths_for_table = Vec::new();
--- a/servo/components/layout/table_row.rs
+++ b/servo/components/layout/table_row.rs
@@ -305,17 +305,17 @@ impl Flow for TableRowFlow {
                             child_base.intrinsic_inline_sizes.minimum_inline_size
                         }
                         LengthOrPercentageOrAuto::Length(length) => length,
                     },
                     percentage: match child_specified_inline_size {
                         LengthOrPercentageOrAuto::Auto |
                         LengthOrPercentageOrAuto::Calc(_) |
                         LengthOrPercentageOrAuto::Length(_) => 0.0,
-                        LengthOrPercentageOrAuto::Percentage(percentage) => percentage,
+                        LengthOrPercentageOrAuto::Percentage(percentage) => percentage.0,
                     },
                     preferred: child_base.intrinsic_inline_sizes.preferred_inline_size,
                     constrained: match child_specified_inline_size {
                         LengthOrPercentageOrAuto::Length(_) => true,
                         LengthOrPercentageOrAuto::Auto |
                         LengthOrPercentageOrAuto::Calc(_) |
                         LengthOrPercentageOrAuto::Percentage(_) => false,
                     },
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -14,32 +14,33 @@ use gecko_bindings::bindings::{Gecko_Cre
 use gecko_bindings::bindings::{Gecko_InitializeImageCropRect, Gecko_SetImageElement};
 use gecko_bindings::structs::{nsCSSUnit, nsStyleCoord_CalcValue, nsStyleImage};
 use gecko_bindings::structs::{nsresult, SheetType};
 use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut};
 use stylesheets::{Origin, RulesMutateError};
 use values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image};
 use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
 use values::generics::image::{CompatMode, Image as GenericImage, GradientItem};
+use values::specified::length::Percentage;
 
 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,
-            mPercent: other.percentage.unwrap_or(0.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(other.mPercent)
+            Some(Percentage(other.mPercent))
         } else {
             None
         };
         Self::new(Au(other.mLength), percentage)
     }
 }
 
 impl From<LengthOrPercentage> for nsStyleCoord_CalcValue {
@@ -50,17 +51,17 @@ impl From<LengthOrPercentage> for nsStyl
                     mLength: au.0,
                     mPercent: 0.0,
                     mHasPercent: false,
                 }
             },
             LengthOrPercentage::Percentage(pc) => {
                 nsStyleCoord_CalcValue {
                     mLength: 0,
-                    mPercent: pc,
+                    mPercent: pc.0,
                     mHasPercent: true,
                 }
             },
             LengthOrPercentage::Calc(calc) => calc.into(),
         }
     }
 }
 
@@ -73,31 +74,31 @@ impl LengthOrPercentageOrAuto {
                     mLength: au.0,
                     mPercent: 0.0,
                     mHasPercent: false,
                 })
             },
             LengthOrPercentageOrAuto::Percentage(pc) => {
                 Some(nsStyleCoord_CalcValue {
                     mLength: 0,
-                    mPercent: pc,
+                    mPercent: pc.0,
                     mHasPercent: true,
                 })
             },
             LengthOrPercentageOrAuto::Calc(calc) => Some(calc.into()),
             LengthOrPercentageOrAuto::Auto => None,
         }
     }
 }
 
 impl From<nsStyleCoord_CalcValue> for LengthOrPercentage {
     fn from(other: nsStyleCoord_CalcValue) -> LengthOrPercentage {
         match (other.mHasPercent, other.mLength) {
             (false, _) => LengthOrPercentage::Length(Au(other.mLength)),
-            (true, 0) => LengthOrPercentage::Percentage(other.mPercent),
+            (true, 0) => LengthOrPercentage::Percentage(Percentage(other.mPercent)),
             _ => LengthOrPercentage::Calc(other.into()),
         }
     }
 }
 
 impl From<Angle> for CoordDataValue {
     fn from(reference: Angle) -> Self {
         match reference {
--- a/servo/components/style/gecko/values.rs
+++ b/servo/components/style/gecko/values.rs
@@ -100,26 +100,26 @@ impl GeckoStyleCoordConvertible for Numb
         }
     }
 }
 
 impl GeckoStyleCoordConvertible for LengthOrPercentage {
     fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
         let value = match *self {
             LengthOrPercentage::Length(au) => CoordDataValue::Coord(au.0),
-            LengthOrPercentage::Percentage(p) => CoordDataValue::Percent(p),
+            LengthOrPercentage::Percentage(p) => CoordDataValue::Percent(p.0),
             LengthOrPercentage::Calc(calc) => CoordDataValue::Calc(calc.into()),
         };
         coord.set_value(value);
     }
 
     fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
         match coord.as_value() {
             CoordDataValue::Coord(coord) => Some(LengthOrPercentage::Length(Au(coord))),
-            CoordDataValue::Percent(p) => Some(LengthOrPercentage::Percentage(p)),
+            CoordDataValue::Percent(p) => Some(LengthOrPercentage::Percentage(Percentage(p))),
             CoordDataValue::Calc(calc) => Some(LengthOrPercentage::Calc(calc.into())),
             _ => None,
         }
     }
 }
 
 impl GeckoStyleCoordConvertible for Au {
     fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
@@ -133,49 +133,49 @@ impl GeckoStyleCoordConvertible for Au {
         }
     }
 }
 
 impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto {
     fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
         let value = match *self {
             LengthOrPercentageOrAuto::Length(au) => CoordDataValue::Coord(au.0),
-            LengthOrPercentageOrAuto::Percentage(p) => CoordDataValue::Percent(p),
+            LengthOrPercentageOrAuto::Percentage(p) => CoordDataValue::Percent(p.0),
             LengthOrPercentageOrAuto::Auto => CoordDataValue::Auto,
             LengthOrPercentageOrAuto::Calc(calc) => CoordDataValue::Calc(calc.into()),
         };
         coord.set_value(value);
     }
 
     fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
         match coord.as_value() {
             CoordDataValue::Coord(coord) => Some(LengthOrPercentageOrAuto::Length(Au(coord))),
-            CoordDataValue::Percent(p) => Some(LengthOrPercentageOrAuto::Percentage(p)),
+            CoordDataValue::Percent(p) => Some(LengthOrPercentageOrAuto::Percentage(Percentage(p))),
             CoordDataValue::Auto => Some(LengthOrPercentageOrAuto::Auto),
             CoordDataValue::Calc(calc) => Some(LengthOrPercentageOrAuto::Calc(calc.into())),
             _ => None,
         }
     }
 }
 
 impl GeckoStyleCoordConvertible for LengthOrPercentageOrNone {
     fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
         let value = match *self {
             LengthOrPercentageOrNone::Length(au) => CoordDataValue::Coord(au.0),
-            LengthOrPercentageOrNone::Percentage(p) => CoordDataValue::Percent(p),
+            LengthOrPercentageOrNone::Percentage(p) => CoordDataValue::Percent(p.0),
             LengthOrPercentageOrNone::None => CoordDataValue::None,
             LengthOrPercentageOrNone::Calc(calc) => CoordDataValue::Calc(calc.into()),
         };
         coord.set_value(value);
     }
 
     fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
         match coord.as_value() {
             CoordDataValue::Coord(coord) => Some(LengthOrPercentageOrNone::Length(Au(coord))),
-            CoordDataValue::Percent(p) => Some(LengthOrPercentageOrNone::Percentage(p)),
+            CoordDataValue::Percent(p) => Some(LengthOrPercentageOrNone::Percentage(Percentage(p))),
             CoordDataValue::None => Some(LengthOrPercentageOrNone::None),
             CoordDataValue::Calc(calc) => Some(LengthOrPercentageOrNone::Calc(calc.into())),
             _ => None,
         }
     }
 }
 
 impl<L: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for TrackBreadth<L> {
--- a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
@@ -10,16 +10,17 @@ use gecko_bindings::structs;
 use gecko_bindings::structs::{nsCSSValue, nsCSSUnit};
 use gecko_bindings::structs::{nsCSSValue_Array, nsCSSValueList, nscolor};
 use gecko_string_cache::Atom;
 use std::marker::PhantomData;
 use std::mem;
 use std::ops::{Index, IndexMut};
 use std::slice;
 use values::computed::{Angle, LengthOrPercentage};
+use values::specified::length::Percentage;
 use values::specified::url::SpecifiedUrl;
 
 impl nsCSSValue {
     /// Create a CSSValue with null unit, useful to be used as a return value.
     #[inline]
     pub fn null() -> Self {
         unsafe { mem::zeroed() }
     }
@@ -74,32 +75,32 @@ impl nsCSSValue {
 
     /// Sets LengthOrPercentage value to this nsCSSValue.
     pub unsafe fn set_lop(&mut self, lop: LengthOrPercentage) {
         match lop {
             LengthOrPercentage::Length(au) => {
                 bindings::Gecko_CSSValue_SetAbsoluteLength(self, au.0)
             }
             LengthOrPercentage::Percentage(pc) => {
-                bindings::Gecko_CSSValue_SetPercentage(self, pc)
+                bindings::Gecko_CSSValue_SetPercentage(self, pc.0)
             }
             LengthOrPercentage::Calc(calc) => {
                 bindings::Gecko_CSSValue_SetCalc(self, calc.into())
             }
         }
     }
 
     /// Returns LengthOrPercentage value.
     pub unsafe fn get_lop(&self) -> LengthOrPercentage {
         match self.mUnit {
             nsCSSUnit::eCSSUnit_Pixel => {
                 LengthOrPercentage::Length(Au(bindings::Gecko_CSSValue_GetAbsoluteLength(self)))
             },
             nsCSSUnit::eCSSUnit_Percent => {
-                LengthOrPercentage::Percentage(bindings::Gecko_CSSValue_GetPercentage(self))
+                LengthOrPercentage::Percentage(Percentage(bindings::Gecko_CSSValue_GetPercentage(self)))
             },
             nsCSSUnit::eCSSUnit_Calc => {
                 LengthOrPercentage::Calc(bindings::Gecko_CSSValue_GetCalc(self).into())
             },
             x => panic!("The unit should not be {:?}", x),
         }
     }
 
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -60,16 +60,17 @@ use properties::{Importance, LonghandId}
 use properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyDeclarationId};
 use std::fmt::{self, Debug};
 use std::mem::{forget, transmute, zeroed};
 use std::ptr;
 use stylearc::Arc;
 use std::cmp;
 use values::{Auto, CustomIdent, Either, KeyframesName};
 use values::computed::{Shadow, ToComputedValue};
+use values::specified::length::Percentage;
 use computed_values::border_style;
 
 pub mod style_structs {
     % for style_struct in data.style_structs:
     pub use super::${style_struct.gecko_struct_name} as ${style_struct.name};
     % endfor
 }
 
@@ -4040,17 +4041,17 @@ clip-path
 
         let mut vec = SmallVec::new();
         for gecko in self.gecko.mStrokeDasharray.iter() {
             match gecko.as_value() {
                 CoordDataValue::Factor(number) => vec.push(Either::First(number)),
                 CoordDataValue::Coord(coord) =>
                     vec.push(Either::Second(LengthOrPercentage::Length(Au(coord)))),
                 CoordDataValue::Percent(p) =>
-                    vec.push(Either::Second(LengthOrPercentage::Percentage(p))),
+                    vec.push(Either::Second(LengthOrPercentage::Percentage(Percentage(p)))),
                 CoordDataValue::Calc(calc) =>
                     vec.push(Either::Second(LengthOrPercentage::Calc(calc.into()))),
                 _ => unreachable!(),
             }
         }
         longhands::stroke_dasharray::computed_value::T(vec)
     }
 
@@ -4063,17 +4064,17 @@ clip-path
 
     ${impl_coord_copy('stroke_dashoffset', 'mStrokeDashoffset')}
 
     pub fn clone_stroke_dashoffset(&self) -> longhands::stroke_dashoffset::computed_value::T {
         use values::computed::LengthOrPercentage;
         match self.gecko.mStrokeDashoffset.as_value() {
             CoordDataValue::Factor(number) => Either::First(number),
             CoordDataValue::Coord(coord) => Either::Second(LengthOrPercentage::Length(Au(coord))),
-            CoordDataValue::Percent(p) => Either::Second(LengthOrPercentage::Percentage(p)),
+            CoordDataValue::Percent(p) => Either::Second(LengthOrPercentage::Percentage(Percentage(p))),
             CoordDataValue::Calc(calc) => Either::Second(LengthOrPercentage::Calc(calc.into())),
             _ => unreachable!(),
         }
     }
 
     pub fn set_stroke_width(&mut self, v: longhands::stroke_width::computed_value::T) {
         match v {
             Either::First(number) => self.gecko.mStrokeWidth.set_value(CoordDataValue::Factor(number)),
@@ -4083,17 +4084,17 @@ clip-path
 
     ${impl_coord_copy('stroke_width', 'mStrokeWidth')}
 
     pub fn clone_stroke_width(&self) -> longhands::stroke_width::computed_value::T {
         use values::computed::LengthOrPercentage;
         match self.gecko.mStrokeWidth.as_value() {
             CoordDataValue::Factor(number) => Either::First(number),
             CoordDataValue::Coord(coord) => Either::Second(LengthOrPercentage::Length(Au(coord))),
-            CoordDataValue::Percent(p) => Either::Second(LengthOrPercentage::Percentage(p)),
+            CoordDataValue::Percent(p) => Either::Second(LengthOrPercentage::Percentage(Percentage(p))),
             CoordDataValue::Calc(calc) => Either::Second(LengthOrPercentage::Calc(calc.into())),
             _ => unreachable!(),
         }
     }
 
     #[allow(non_snake_case)]
     pub fn set__moz_context_properties<I>(&mut self, v: I)
         where I: IntoIterator<Item = longhands::_moz_context_properties::computed_value::single_value::T>,
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -36,16 +36,17 @@ use super::ComputedValues;
 use values::{Auto, CSSFloat, CustomIdent, Either};
 use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
 use values::computed::{BorderCornerRadius, ClipRect};
 use values::computed::{CalcLengthOrPercentage, Color, Context, ComputedValueAsSpecified};
 use values::computed::{LengthOrPercentage, MaxLength, MozLength, Shadow, ToComputedValue};
 use values::generics::{SVGPaint, SVGPaintKind};
 use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
 use values::generics::position as generic_position;
+use values::specified::length::Percentage;
 
 
 /// A longhand property whose animation type is not "none".
 ///
 /// NOTE: This includes the 'display' property since it is animatable from SMIL even though it is
 /// not animatable from CSS animations or Web Animations. CSS transitions also does not allow
 /// animating 'display', but for CSS transitions we have the separate TransitionProperty type.
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -936,16 +937,32 @@ impl Animatable for Angle {
     #[inline]
     fn add_weighted(&self, other: &Angle, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         self.radians()
             .add_weighted(&other.radians(), self_portion, other_portion)
             .map(Angle::from_radians)
     }
 }
 
+/// https://drafts.csswg.org/css-transitions/#animtype-percentage
+impl Animatable for Percentage {
+    #[inline]
+    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+        Ok(Percentage((self.0 as f64 * self_portion + other.0 as f64 * other_portion) as f32))
+    }
+
+    #[inline]
+    fn get_zero_value(&self) -> Option<Self> { Some(Percentage(0.)) }
+
+    #[inline]
+    fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
+        Ok((self.0 as f64 - other.0 as f64).abs())
+    }
+}
+
 /// https://drafts.csswg.org/css-transitions/#animtype-visibility
 impl Animatable for Visibility {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         match (*self, *other) {
             (Visibility::visible, _) => {
                 Ok(if self_portion > 0.0 { *self } else { *other })
             },
@@ -1145,17 +1162,17 @@ impl Animatable for LengthOrPercentage {
         match (*self, *other) {
             (LengthOrPercentage::Length(ref this),
              LengthOrPercentage::Length(ref other)) => {
                 let diff = (this.0 - other.0) as f64;
                 Ok(diff * diff)
             },
             (LengthOrPercentage::Percentage(ref this),
              LengthOrPercentage::Percentage(ref other)) => {
-                let diff = (this - other) as f64;
+                let diff = this.0 as f64 - other.0 as f64;
                 Ok(diff * diff)
             },
             (this, other) => {
                 let this: CalcLengthOrPercentage = From::from(this);
                 let other: CalcLengthOrPercentage = From::from(other);
                 let length_diff = (this.unclamped_length().0 - other.unclamped_length().0) as f64;
                 let percentage_diff = (this.percentage() - other.percentage()) as f64;
                 Ok(length_diff * length_diff + percentage_diff * percentage_diff)
@@ -1230,17 +1247,17 @@ impl Animatable for LengthOrPercentageOr
         match (*self, *other) {
             (LengthOrPercentageOrAuto::Length(ref this),
              LengthOrPercentageOrAuto::Length(ref other)) => {
                 let diff = (this.0 - other.0) as f64;
                 Ok(diff * diff)
             },
             (LengthOrPercentageOrAuto::Percentage(ref this),
              LengthOrPercentageOrAuto::Percentage(ref other)) => {
-                let diff = (this - other) as f64;
+                let diff = this.0 as f64 - other.0 as f64;
                 Ok(diff * diff)
             },
             (this, other) => {
                 let this: Option<CalcLengthOrPercentage> = From::from(this);
                 let other: Option<CalcLengthOrPercentage> = From::from(other);
                 if let (Some(this), Some(other)) = (this, other) {
                     let length_diff = (this.unclamped_length().0 - other.unclamped_length().0) as f64;
                     let percentage_diff = (this.percentage() - other.percentage()) as f64;
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -6,17 +6,18 @@
 
 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 super::{Number, ToComputedValue, Context};
 use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
-use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength, ViewportPercentageLength};
+use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength};
+use values::specified::length::{Percentage, ViewportPercentageLength};
 
 pub use super::image::Image;
 pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
 
 impl ToComputedValue for specified::NoCalcLength {
     type ComputedValue = Au;
 
     #[inline]
@@ -60,30 +61,30 @@ impl ToComputedValue for specified::Leng
 }
 
 #[derive(Clone, PartialEq, Copy, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
 pub struct CalcLengthOrPercentage {
     pub clamping_mode: AllowedLengthType,
     length: Au,
-    pub percentage: Option<CSSFloat>,
+    pub percentage: Option<Percentage>,
 }
 
 impl CalcLengthOrPercentage {
     /// Returns a new `CalcLengthOrPercentage`.
     #[inline]
-    pub fn new(length: Au, percentage: Option<CSSFloat>) -> Self {
+    pub fn new(length: Au, percentage: Option<Percentage>) -> Self {
         Self::with_clamping_mode(length, percentage, AllowedLengthType::All)
     }
 
     /// Returns a new `CalcLengthOrPercentage` with a specific clamping mode.
     #[inline]
     pub fn with_clamping_mode(length: Au,
-                              percentage: Option<CSSFloat>,
+                              percentage: Option<Percentage>,
                               clamping_mode: AllowedLengthType)
                               -> Self {
         Self {
             clamping_mode: clamping_mode,
             length: length,
             percentage: percentage,
         }
     }
@@ -101,25 +102,25 @@ impl CalcLengthOrPercentage {
     #[inline]
     pub fn unclamped_length(&self) -> Au {
         self.length
     }
 
     #[inline]
     #[allow(missing_docs)]
     pub fn percentage(&self) -> CSSFloat {
-        self.percentage.unwrap_or(0.)
+        self.percentage.map_or(0., |p| p.0)
     }
 
     /// 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> {
         match (container_len, self.percentage) {
             (Some(len), Some(percent)) => {
-                Some(self.clamping_mode.clamp(self.length + len.scale_by(percent)))
+                Some(self.clamping_mode.clamp(self.length + len.scale_by(percent.0)))
             },
             (_, None) => Some(self.length()),
             _ => None,
         }
     }
 }
 
 impl From<LengthOrPercentage> for CalcLengthOrPercentage {
@@ -174,18 +175,18 @@ impl From<LengthOrPercentageOrNone> for 
             }
         }
     }
 }
 
 impl ToCss for CalcLengthOrPercentage {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         match (self.length, self.percentage) {
-            (l, Some(p)) if l == Au(0) => write!(dest, "{}%", p * 100.),
-            (l, Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p * 100.),
+            (l, Some(p)) if l == Au(0) => p.to_css(dest),
+            (l, Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p.0 * 100.),
             (l, None) => write!(dest, "{}px", Au::to_px(l)),
         }
     }
 }
 
 impl ToComputedValue for specified::CalcLengthOrPercentage {
     type ComputedValue = CalcLengthOrPercentage;
 
@@ -227,22 +228,22 @@ impl ToComputedValue for specified::Calc
             clamping_mode: computed.clamping_mode,
             absolute: Some(computed.length),
             percentage: computed.percentage,
             ..Default::default()
         }
     }
 }
 
-#[derive(PartialEq, Clone, Copy)]
+#[allow(missing_docs)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[allow(missing_docs)]
+#[derive(Clone, Copy, PartialEq, ToCss)]
 pub enum LengthOrPercentage {
     Length(Au),
-    Percentage(CSSFloat),
+    Percentage(Percentage),
     Calc(CalcLengthOrPercentage),
 }
 
 impl From<Au> for LengthOrPercentage {
     #[inline]
     fn from(length: Au) -> Self {
         LengthOrPercentage::Length(length)
     }
@@ -264,147 +265,136 @@ impl LengthOrPercentage {
     /// Returns true if the computed value is absolute 0 or 0%.
     ///
     /// (Returns false for calc() values, even if ones that may resolve to zero.)
     #[inline]
     pub fn is_definitely_zero(&self) -> bool {
         use self::LengthOrPercentage::*;
         match *self {
             Length(Au(0)) => true,
-            Percentage(p) => p == 0.0,
+            Percentage(p) => p.0 == 0.0,
             Length(_) | Calc(_) => false
         }
     }
 
     #[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).unwrap()),
+            Percentage(p) => (Au(0), NotNaN::new(p.0).unwrap()),
             Calc(c) => (c.unclamped_length(), 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),
+            LengthOrPercentage::Percentage(p) => containing_length.scale_by(p.0),
             LengthOrPercentage::Calc(ref calc) => {
                 calc.to_used_value(Some(containing_length)).unwrap()
             },
         }
     }
 }
 
 impl fmt::Debug for LengthOrPercentage {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             LengthOrPercentage::Length(length) => write!(f, "{:?}", length),
-            LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
+            LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage.0 * 100.),
             LengthOrPercentage::Calc(calc) => write!(f, "{:?}", calc),
         }
     }
 }
 
 impl ToComputedValue for specified::LengthOrPercentage {
     type ComputedValue = LengthOrPercentage;
 
     fn to_computed_value(&self, context: &Context) -> LengthOrPercentage {
         match *self {
             specified::LengthOrPercentage::Length(ref value) => {
                 LengthOrPercentage::Length(value.to_computed_value(context))
             }
             specified::LengthOrPercentage::Percentage(value) => {
-                LengthOrPercentage::Percentage(value.0)
+                LengthOrPercentage::Percentage(value)
             }
             specified::LengthOrPercentage::Calc(ref calc) => {
                 LengthOrPercentage::Calc(calc.to_computed_value(context))
             }
         }
     }
 
     fn from_computed_value(computed: &LengthOrPercentage) -> Self {
         match *computed {
             LengthOrPercentage::Length(value) => {
                 specified::LengthOrPercentage::Length(
                     ToComputedValue::from_computed_value(&value)
                 )
             }
             LengthOrPercentage::Percentage(value) => {
-                specified::LengthOrPercentage::Percentage(specified::Percentage(value))
+                specified::LengthOrPercentage::Percentage(value)
             }
             LengthOrPercentage::Calc(ref calc) => {
                 specified::LengthOrPercentage::Calc(
                     Box::new(ToComputedValue::from_computed_value(calc))
                 )
             }
         }
     }
 }
 
-impl ToCss for LengthOrPercentage {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-        match *self {
-            LengthOrPercentage::Length(length) => length.to_css(dest),
-            LengthOrPercentage::Percentage(percentage)
-            => write!(dest, "{}%", percentage * 100.),
-            LengthOrPercentage::Calc(calc) => calc.to_css(dest),
-        }
-    }
-}
-
-#[derive(PartialEq, Clone, Copy)]
+#[allow(missing_docs)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[allow(missing_docs)]
+#[derive(Clone, Copy, PartialEq, ToCss)]
 pub enum LengthOrPercentageOrAuto {
     Length(Au),
-    Percentage(CSSFloat),
+    Percentage(Percentage),
     Auto,
     Calc(CalcLengthOrPercentage),
 }
 
 impl LengthOrPercentageOrAuto {
     /// Returns true if the computed value is absolute 0 or 0%.
     ///
     /// (Returns false for calc() values, even if ones that may resolve to zero.)
     #[inline]
     pub fn is_definitely_zero(&self) -> bool {
         use self::LengthOrPercentageOrAuto::*;
         match *self {
             Length(Au(0)) => true,
-            Percentage(p) => p == 0.0,
+            Percentage(p) => p.0 == 0.0,
             Length(_) | Calc(_) | Auto => false
         }
     }
 }
 
 impl fmt::Debug for LengthOrPercentageOrAuto {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             LengthOrPercentageOrAuto::Length(length) => write!(f, "{:?}", length),
-            LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
+            LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage.0 * 100.),
             LengthOrPercentageOrAuto::Auto => write!(f, "auto"),
             LengthOrPercentageOrAuto::Calc(calc) => write!(f, "{:?}", calc),
         }
     }
 }
 
 impl ToComputedValue for specified::LengthOrPercentageOrAuto {
     type ComputedValue = LengthOrPercentageOrAuto;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrAuto {
         match *self {
             specified::LengthOrPercentageOrAuto::Length(ref value) => {
                 LengthOrPercentageOrAuto::Length(value.to_computed_value(context))
             }
             specified::LengthOrPercentageOrAuto::Percentage(value) => {
-                LengthOrPercentageOrAuto::Percentage(value.0)
+                LengthOrPercentageOrAuto::Percentage(value)
             }
             specified::LengthOrPercentageOrAuto::Auto => {
                 LengthOrPercentageOrAuto::Auto
             }
             specified::LengthOrPercentageOrAuto::Calc(ref calc) => {
                 LengthOrPercentageOrAuto::Calc(calc.to_computed_value(context))
             }
         }
@@ -415,55 +405,43 @@ impl ToComputedValue for specified::Leng
         match *computed {
             LengthOrPercentageOrAuto::Auto => specified::LengthOrPercentageOrAuto::Auto,
             LengthOrPercentageOrAuto::Length(value) => {
                 specified::LengthOrPercentageOrAuto::Length(
                     ToComputedValue::from_computed_value(&value)
                 )
             }
             LengthOrPercentageOrAuto::Percentage(value) => {
-                specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(value))
+                specified::LengthOrPercentageOrAuto::Percentage(value)
             }
             LengthOrPercentageOrAuto::Calc(calc) => {
                 specified::LengthOrPercentageOrAuto::Calc(
                     Box::new(ToComputedValue::from_computed_value(&calc))
                 )
             }
         }
     }
 }
 
-impl ToCss for LengthOrPercentageOrAuto {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-        match *self {
-            LengthOrPercentageOrAuto::Length(length) => length.to_css(dest),
-            LengthOrPercentageOrAuto::Percentage(percentage)
-            => write!(dest, "{}%", percentage * 100.),
-            LengthOrPercentageOrAuto::Auto => dest.write_str("auto"),
-            LengthOrPercentageOrAuto::Calc(calc) => calc.to_css(dest),
-        }
-    }
-}
-
-#[derive(PartialEq, Clone, Copy)]
+#[allow(missing_docs)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[allow(missing_docs)]
+#[derive(Clone, Copy, PartialEq, ToCss)]
 pub enum LengthOrPercentageOrAutoOrContent {
     Length(Au),
-    Percentage(CSSFloat),
+    Percentage(Percentage),
     Calc(CalcLengthOrPercentage),
     Auto,
     Content
 }
 
 impl fmt::Debug for LengthOrPercentageOrAutoOrContent {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             LengthOrPercentageOrAutoOrContent::Length(length) => write!(f, "{:?}", length),
-            LengthOrPercentageOrAutoOrContent::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
+            LengthOrPercentageOrAutoOrContent::Percentage(percentage) => write!(f, "{}%", percentage.0 * 100.),
             LengthOrPercentageOrAutoOrContent::Calc(calc) => write!(f, "{:?}", calc),
             LengthOrPercentageOrAutoOrContent::Auto => write!(f, "auto"),
             LengthOrPercentageOrAutoOrContent::Content => write!(f, "content")
         }
     }
 }
 
 impl ToComputedValue for specified::LengthOrPercentageOrAutoOrContent {
@@ -471,17 +449,17 @@ impl ToComputedValue for specified::Leng
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrAutoOrContent {
         match *self {
             specified::LengthOrPercentageOrAutoOrContent::Length(ref value) => {
                 LengthOrPercentageOrAutoOrContent::Length(value.to_computed_value(context))
             },
             specified::LengthOrPercentageOrAutoOrContent::Percentage(value) => {
-                LengthOrPercentageOrAutoOrContent::Percentage(value.0)
+                LengthOrPercentageOrAutoOrContent::Percentage(value)
             },
             specified::LengthOrPercentageOrAutoOrContent::Calc(ref calc) => {
                 LengthOrPercentageOrAutoOrContent::Calc(calc.to_computed_value(context))
             },
             specified::LengthOrPercentageOrAutoOrContent::Auto => {
                 LengthOrPercentageOrAutoOrContent::Auto
             },
             specified::LengthOrPercentageOrAutoOrContent::Content => {
@@ -501,84 +479,71 @@ impl ToComputedValue for specified::Leng
                 specified::LengthOrPercentageOrAutoOrContent::Content
             }
             LengthOrPercentageOrAutoOrContent::Length(value) => {
                 specified::LengthOrPercentageOrAutoOrContent::Length(
                     ToComputedValue::from_computed_value(&value)
                 )
             }
             LengthOrPercentageOrAutoOrContent::Percentage(value) => {
-                specified::LengthOrPercentageOrAutoOrContent::Percentage(specified::Percentage(value))
+                specified::LengthOrPercentageOrAutoOrContent::Percentage(value)
             }
             LengthOrPercentageOrAutoOrContent::Calc(calc) => {
                 specified::LengthOrPercentageOrAutoOrContent::Calc(
                     Box::new(ToComputedValue::from_computed_value(&calc))
                 )
             }
         }
     }
 }
 
-impl ToCss for LengthOrPercentageOrAutoOrContent {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-        match *self {
-            LengthOrPercentageOrAutoOrContent::Length(length) => length.to_css(dest),
-            LengthOrPercentageOrAutoOrContent::Percentage(percentage)
-            => write!(dest, "{}%", percentage * 100.),
-            LengthOrPercentageOrAutoOrContent::Calc(calc) => calc.to_css(dest),
-            LengthOrPercentageOrAutoOrContent::Auto => dest.write_str("auto"),
-            LengthOrPercentageOrAutoOrContent::Content => dest.write_str("content")
-        }
-    }
-}
-
-#[derive(PartialEq, Clone, Copy)]
+#[allow(missing_docs)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[allow(missing_docs)]
+#[derive(Clone, Copy, PartialEq, ToCss)]
 pub enum LengthOrPercentageOrNone {
     Length(Au),
-    Percentage(CSSFloat),
+    Percentage(Percentage),
     Calc(CalcLengthOrPercentage),
     None,
 }
 
 impl LengthOrPercentageOrNone {
     /// Returns the used value.
     pub fn to_used_value(&self, containing_length: Au) -> Option<Au> {
         match *self {
             LengthOrPercentageOrNone::None => None,
             LengthOrPercentageOrNone::Length(length) => Some(length),
-            LengthOrPercentageOrNone::Percentage(percent) => Some(containing_length.scale_by(percent)),
+            LengthOrPercentageOrNone::Percentage(percent) => Some(containing_length.scale_by(percent.0)),
             LengthOrPercentageOrNone::Calc(ref calc) => calc.to_used_value(Some(containing_length)),
         }
     }
 }
 
 impl fmt::Debug for LengthOrPercentageOrNone {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             LengthOrPercentageOrNone::Length(length) => write!(f, "{:?}", length),
-            LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
+            LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage.0 * 100.),
             LengthOrPercentageOrNone::Calc(calc) => write!(f, "{:?}", calc),
             LengthOrPercentageOrNone::None => write!(f, "none"),
         }
     }
 }
 
 impl ToComputedValue for specified::LengthOrPercentageOrNone {
     type ComputedValue = LengthOrPercentageOrNone;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrNone {
         match *self {
             specified::LengthOrPercentageOrNone::Length(ref value) => {
                 LengthOrPercentageOrNone::Length(value.to_computed_value(context))
             }
             specified::LengthOrPercentageOrNone::Percentage(value) => {
-                LengthOrPercentageOrNone::Percentage(value.0)
+                LengthOrPercentageOrNone::Percentage(value)
             }
             specified::LengthOrPercentageOrNone::Calc(ref calc) => {
                 LengthOrPercentageOrNone::Calc(calc.to_computed_value(context))
             }
             specified::LengthOrPercentageOrNone::None => {
                 LengthOrPercentageOrNone::None
             }
         }
@@ -589,39 +554,27 @@ impl ToComputedValue for specified::Leng
         match *computed {
             LengthOrPercentageOrNone::None => specified::LengthOrPercentageOrNone::None,
             LengthOrPercentageOrNone::Length(value) => {
                 specified::LengthOrPercentageOrNone::Length(
                     ToComputedValue::from_computed_value(&value)
                 )
             }
             LengthOrPercentageOrNone::Percentage(value) => {
-                specified::LengthOrPercentageOrNone::Percentage(specified::Percentage(value))
+                specified::LengthOrPercentageOrNone::Percentage(value)
             }
             LengthOrPercentageOrNone::Calc(calc) => {
                 specified::LengthOrPercentageOrNone::Calc(
                     Box::new(ToComputedValue::from_computed_value(&calc))
                 )
             }
         }
     }
 }
 
-impl ToCss for LengthOrPercentageOrNone {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-        match *self {
-            LengthOrPercentageOrNone::Length(length) => length.to_css(dest),
-            LengthOrPercentageOrNone::Percentage(percentage) =>
-                write!(dest, "{}%", percentage * 100.),
-            LengthOrPercentageOrNone::Calc(calc) => calc.to_css(dest),
-            LengthOrPercentageOrNone::None => dest.write_str("none"),
-        }
-    }
-}
-
 /// A computed `<length>` value.
 pub type Length = Au;
 
 /// Either a computed `<length>` or the `none` keyword.
 pub type LengthOrNone = Either<Length, None_>;
 
 /// Either a computed `<length>` or the `auto` keyword.
 pub type LengthOrAuto = Either<Length, Auto>;
--- a/servo/components/style/values/computed/position.rs
+++ b/servo/components/style/values/computed/position.rs
@@ -6,31 +6,35 @@
 //! [`position`][position] values.
 //!
 //! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
 
 use std::fmt;
 use style_traits::ToCss;
 use values::computed::LengthOrPercentage;
 use values::generics::position::Position as GenericPosition;
+use values::specified::length::Percentage;
 
 /// The computed value of a CSS `<position>`
 pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>;
 
 /// The computed value of a CSS horizontal position.
 pub type HorizontalPosition = LengthOrPercentage;
 
 /// The computed value of a CSS vertical position.
 pub type VerticalPosition = LengthOrPercentage;
 
 impl Position {
     /// `50% 50%`
     #[inline]
     pub fn center() -> Self {
-        Self::new(LengthOrPercentage::Percentage(0.5), LengthOrPercentage::Percentage(0.5))
+        Self::new(
+            LengthOrPercentage::Percentage(Percentage(0.5)),
+            LengthOrPercentage::Percentage(Percentage(0.5)),
+        )
     }
 
     /// `0% 0%`
     #[inline]
     pub fn zero() -> Self {
         Self::new(LengthOrPercentage::zero(), LengthOrPercentage::zero())
     }
 }
--- a/servo/components/style/values/computed/transform.rs
+++ b/servo/components/style/values/computed/transform.rs
@@ -3,31 +3,32 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Computed types for CSS values that are related to transformations.
 
 use properties::animated_properties::Animatable;
 use values::computed::{Length, LengthOrPercentage, Number};
 use values::generics::transform::TimingFunction as GenericTimingFunction;
 use values::generics::transform::TransformOrigin as GenericTransformOrigin;
+use values::specified::length::Percentage;
 
 /// The computed value of a CSS `<transform-origin>`
 pub type TransformOrigin = GenericTransformOrigin<LengthOrPercentage, LengthOrPercentage, Length>;
 
 /// A computed timing function.
 pub type TimingFunction = GenericTimingFunction<u32, Number>;
 
 impl TransformOrigin {
     /// Returns the initial computed value for `transform-origin`.
     #[inline]
     pub fn initial_value() -> Self {
         Self::new(
-            LengthOrPercentage::Percentage(0.5),
-            LengthOrPercentage::Percentage(0.5),
-            Length::from_px(0)
+            LengthOrPercentage::Percentage(Percentage(0.5)),
+            LengthOrPercentage::Percentage(Percentage(0.5)),
+            Length::from_px(0),
         )
     }
 }
 
 impl Animatable for TransformOrigin {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         Ok(Self::new(
--- a/servo/components/style/values/specified/calc.rs
+++ b/servo/components/style/values/specified/calc.rs
@@ -10,17 +10,18 @@ use app_units::Au;
 use cssparser::{Parser, Token, BasicParseError};
 use parser::ParserContext;
 use std::ascii::AsciiExt;
 use std::fmt;
 use style_traits::{HasViewportPercentage, ToCss, ParseError, StyleParseError};
 use style_traits::values::specified::AllowedLengthType;
 use values::{CSSInteger, CSSFloat};
 use values::specified::{Angle, Time};
-use values::specified::length::{FontRelativeLength, NoCalcLength, ViewportPercentageLength};
+use values::specified::length::{FontRelativeLength, NoCalcLength};
+use values::specified::length::{Percentage, ViewportPercentageLength};
 
 /// A node inside a `Calc` expression's AST.
 #[derive(Clone, Debug)]
 pub enum CalcNode {
     /// `<length>`
     Length(NoCalcLength),
     /// `<angle>`
     Angle(Angle),
@@ -69,17 +70,17 @@ pub struct CalcLengthOrPercentage {
     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>,
     pub rem: Option<CSSFloat>,
-    pub percentage: Option<CSSFloat>,
+    pub percentage: Option<Percentage>,
     #[cfg(feature = "gecko")]
     pub mozmm: Option<CSSFloat>,
 }
 
 impl HasViewportPercentage for CalcLengthOrPercentage {
     fn has_viewport_percentage(&self) -> bool {
         self.vw.is_some() || self.vh.is_some() ||
         self.vmin.is_some() || self.vmax.is_some()
@@ -123,17 +124,17 @@ impl ToCss for CalcLengthOrPercentage {
 
         if let Some(val) = self.absolute {
             first_value_check!();
             try!(val.to_css(dest));
         }
 
         if let Some(val) = self.percentage {
             first_value_check!();
-            try!(write!(dest, "{}%", val * 100.));
+            val.to_css(dest)?;
         }
 
         write!(dest, ")")
     }
 }
 
 impl CalcNode {
     /// Tries to parse a single element in the expression, that is, a
@@ -293,17 +294,19 @@ impl CalcNode {
     fn add_length_or_percentage_to(
         &self,
         ret: &mut CalcLengthOrPercentage,
         factor: CSSFloat)
         -> Result<(), ()>
     {
         match *self {
             CalcNode::Percentage(pct) => {
-                ret.percentage = Some(ret.percentage.unwrap_or(0.) + pct * factor)
+                ret.percentage = Some(Percentage(
+                    ret.percentage.map_or(0., |p| p.0) + pct * factor,
+                ));
             }
             CalcNode::Length(ref l) => {
                 match *l {
                     NoCalcLength::Absolute(abs) => {
                         ret.absolute = Some(
                             ret.absolute.unwrap_or(Au(0)) +
                             Au::from(abs).scale_by(factor)
                         );
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -696,17 +696,17 @@ impl<T: Parse> Either<Length, T> {
 /// without requiring also a `<length>`. If such a property existed, we'd need
 /// to add special handling for `calc()` and percentages in here in the same way
 /// as for `Angle` and `Time`, but the lack of this this is otherwise
 /// undistinguishable (we handle it correctly from `CalcLengthOrPercentage`).
 ///
 /// As of today, only `-moz-image-rect` supports percentages without length.
 /// This is not a regression, and that's a non-standard extension anyway, so I'm
 /// not implementing it for now.
-#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
+#[derive(Clone, Copy, Debug, Default, HasViewportPercentage, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub struct Percentage(pub CSSFloat);
 
 impl ToCss for Percentage {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result
         where W: fmt::Write,
     {
         write!(dest, "{}%", self.0 * 100.)
--- a/servo/components/style/values/specified/position.rs
+++ b/servo/components/style/values/specified/position.rs
@@ -219,32 +219,32 @@ impl<S: ToCss> ToCss for PositionCompone
 }
 
 impl<S: Side> ToComputedValue for PositionComponent<S> {
     type ComputedValue = ComputedLengthOrPercentage;
 
     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
         match *self {
             PositionComponent::Center => {
-                ComputedLengthOrPercentage::Percentage(0.5)
+                ComputedLengthOrPercentage::Percentage(Percentage(0.5))
             },
             PositionComponent::Side(ref keyword, None) => {
-                let p = if keyword.is_start() { 0. } else { 1. };
+                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(1.0)))
+                        ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage::new(-length, Some(Percentage(1.0))))
                     },
                     ComputedLengthOrPercentage::Percentage(p) => {
-                        ComputedLengthOrPercentage::Percentage(1.0 - p)
+                        ComputedLengthOrPercentage::Percentage(Percentage(1.0 - p.0))
                     },
                     ComputedLengthOrPercentage::Calc(calc) => {
-                        let p = 1. - calc.percentage.unwrap_or(0.);
+                        let p = Percentage(1. - calc.percentage.map_or(0., |p| p.0));
                         ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage::new(-calc.unclamped_length(), Some(p)))
                     },
                 }
             },
             PositionComponent::Side(_, Some(ref length)) |
             PositionComponent::Length(ref length) => {
                 length.to_computed_value(context)
             },
--- a/servo/components/style/values/specified/transform.rs
+++ b/servo/components/style/values/specified/transform.rs
@@ -9,17 +9,17 @@ use euclid::Point2D;
 use parser::{Parse, ParserContext};
 use selectors::parser::SelectorParseError;
 use style_traits::{ParseError, StyleParseError};
 use values::computed::{LengthOrPercentage as ComputedLengthOrPercentage, Context, ToComputedValue};
 use values::computed::transform::TimingFunction as ComputedTimingFunction;
 use values::generics::transform::{StepPosition, TimingFunction as GenericTimingFunction};
 use values::generics::transform::{TimingKeyword, TransformOrigin as GenericTransformOrigin};
 use values::specified::{Integer, Number};
-use values::specified::length::{Length, LengthOrPercentage};
+use values::specified::length::{Length, LengthOrPercentage, Percentage};
 use values::specified::position::{Side, X, Y};
 
 /// The specified value of a CSS `<transform-origin>`
 pub type TransformOrigin = GenericTransformOrigin<OriginComponent<X>, OriginComponent<Y>, Length>;
 
 /// The specified value of a component of a CSS `<transform-origin>`.
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
@@ -102,23 +102,23 @@ impl<S> Parse for OriginComponent<S>
 impl<S> ToComputedValue for OriginComponent<S>
     where S: Side,
 {
     type ComputedValue = ComputedLengthOrPercentage;
 
     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
         match *self {
             OriginComponent::Center => {
-                ComputedLengthOrPercentage::Percentage(0.5)
+                ComputedLengthOrPercentage::Percentage(Percentage(0.5))
             },
             OriginComponent::Length(ref length) => {
                 length.to_computed_value(context)
             },
             OriginComponent::Side(ref keyword) => {
-                let p = if keyword.is_start() { 0. } else { 1. };
+                let p = Percentage(if keyword.is_start() { 0. } else { 1. });
                 ComputedLengthOrPercentage::Percentage(p)
             },
         }
     }
 
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
         OriginComponent::Length(ToComputedValue::from_computed_value(computed))
     }
--- a/servo/tests/unit/style/animated_properties.rs
+++ b/servo/tests/unit/style/animated_properties.rs
@@ -2,16 +2,17 @@
  * 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/. */
 
 use app_units::Au;
 use cssparser::RGBA;
 use style::properties::animated_properties::{Animatable, IntermediateRGBA};
 use style::properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
 use style::properties::longhands::transform::computed_value::T as TransformList;
+use style::values::specified::length::Percentage;
 
 fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA {
     let from: IntermediateRGBA = from.into();
     let to: IntermediateRGBA = to.into();
     from.interpolate(&to, progress).unwrap().into()
 }
 
 // Color
@@ -73,35 +74,35 @@ fn test_transform_interpolation_on_trans
                                       LengthOrPercentage::Length(Au(0)),
                                       Au(75))]));
     assert_eq!(from.interpolate(&to, 0.5).unwrap(),
                TransformList(Some(vec![
                    TransformOperation::Translate(LengthOrPercentage::Length(Au(50)),
                                                  LengthOrPercentage::Length(Au(50)),
                                                  Au(50))])));
 
-    let from = TransformList(Some(vec![
-        TransformOperation::Translate(LengthOrPercentage::Percentage(0.5),
-                                      LengthOrPercentage::Percentage(1.0),
-                                      Au(25))]));
+    let from = TransformList(Some(vec![TransformOperation::Translate(
+        LengthOrPercentage::Percentage(Percentage(0.5)),
+        LengthOrPercentage::Percentage(Percentage(1.0)),
+        Au(25),
+    )]));
     let to = TransformList(Some(vec![
         TransformOperation::Translate(LengthOrPercentage::Length(Au(100)),
                                       LengthOrPercentage::Length(Au(50)),
                                       Au(75))]));
-    assert_eq!(from.interpolate(&to, 0.5).unwrap(),
-               TransformList(Some(vec![
-                   TransformOperation::Translate(LengthOrPercentage::Calc(
-                                                     // calc(50px + 25%)
-                                                     CalcLengthOrPercentage::new(Au(50),
-                                                                                 Some(0.25))),
-                                                 LengthOrPercentage::Calc(
-                                                     // calc(25px + 50%)
-                                                     CalcLengthOrPercentage::new(Au(25),
-                                                                                 Some(0.5))),
-                                                 Au(50))])));
+    assert_eq!(
+        from.interpolate(&to, 0.5).unwrap(),
+        TransformList(Some(vec![TransformOperation::Translate(
+            // calc(50px + 25%)
+            LengthOrPercentage::Calc(CalcLengthOrPercentage::new(Au(50), Some(Percentage(0.25)))),
+            // calc(25px + 50%)
+            LengthOrPercentage::Calc(CalcLengthOrPercentage::new(Au(25), Some(Percentage(0.5)))),
+            Au(50),
+        )]))
+    );
 }
 
 #[test]
 fn test_transform_interpolation_on_scale() {
     let from = TransformList(Some(vec![TransformOperation::Scale(1.0, 2.0, 1.0)]));
     let to = TransformList(Some(vec![TransformOperation::Scale(2.0, 4.0, 2.0)]));
     assert_eq!(from.interpolate(&to, 0.5).unwrap(),
                TransformList(Some(vec![TransformOperation::Scale(1.5, 3.0, 1.5)])));
@@ -138,15 +139,17 @@ fn test_transform_interpolation_on_misma
     use style::values::computed::{Angle, LengthOrPercentage, Percentage};
 
     let from = TransformList(Some(vec![TransformOperation::Rotate(0.0, 0.0, 1.0,
                                                                   Angle::from_radians(100.0))]));
     let to = TransformList(Some(vec![
         TransformOperation::Translate(LengthOrPercentage::Length(Au(100)),
                                       LengthOrPercentage::Length(Au(0)),
                                       Au(0))]));
-    assert_eq!(from.interpolate(&to, 0.5).unwrap(),
-               TransformList(Some(vec![TransformOperation::InterpolateMatrix {
-                   from_list: from.clone(),
-                   to_list: to.clone(),
-                   progress: Percentage(0.5)
-               }])));
+    assert_eq!(
+        from.interpolate(&to, 0.5).unwrap(),
+        TransformList(Some(vec![TransformOperation::InterpolateMatrix {
+            from_list: from.clone(),
+            to_list: to.clone(),
+            progress: Percentage(0.5),
+        }]))
+    );
 }
--- a/servo/tests/unit/style/attr.rs
+++ b/servo/tests/unit/style/attr.rs
@@ -1,19 +1,20 @@
 /* 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/. */
 
 use app_units::Au;
 use style::attr::{AttrValue, LengthOrPercentageOrAuto, parse_length};
 use style::values::computed::CalcLengthOrPercentage;
+use style::values::specified::length::Percentage;
 
 #[test]
 fn test_length_calc() {
-    let calc = CalcLengthOrPercentage::new(Au(10), Some(0.2));
+    let calc = CalcLengthOrPercentage::new(Au(10), Some(Percentage(0.2)));
     assert_eq!(calc.to_used_value(Some(Au(10))), Some(Au(12)));
     assert_eq!(calc.to_used_value(Some(Au(0))), Some(Au(10)));
     assert_eq!(calc.to_used_value(None), None);
 
     let calc = CalcLengthOrPercentage::new(Au(10), None);
     assert_eq!(calc.to_used_value(Some(Au(0))), Some(Au(10)));
     assert_eq!(calc.to_used_value(None), Some(Au(10)));
 }