servo: Merge #20124 - Replace LengthOrNone by a specific type for the perspective property (from servo:perspective); r=emilio
authorAnthony Ramine <n.oxyde@gmail.com>
Mon, 26 Feb 2018 16:35:32 -0500
changeset 760290 62d9bbdd6feeaec0153ed7ab65a14c77b7dcd032
parent 760289 bf5c890bbac17c2e21c0984ba3a5ab6a28cd4211
child 760291 109cd0a34ffea65f7540dbd6d7feb9c6ca39ec55
push id100603
push userjcristau@mozilla.com
push dateTue, 27 Feb 2018 11:10:29 +0000
reviewersemilio
milestone60.0a1
servo: Merge #20124 - Replace LengthOrNone by a specific type for the perspective property (from servo:perspective); r=emilio Source-Repo: https://github.com/servo/servo Source-Revision: 6df0dc5b2710a6ba856de7c064a6631a8d63efc5
servo/components/layout/fragment.rs
servo/components/style/gecko/values.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/longhand/box.mako.rs
servo/components/style/properties/longhand/inherited_text.mako.rs
servo/components/style/values/computed/box.rs
servo/components/style/values/computed/length.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/generics/box.rs
servo/components/style/values/specified/box.rs
servo/components/style/values/specified/length.rs
servo/components/style/values/specified/mod.rs
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -54,20 +54,19 @@ use style::computed_values::text_decorat
 use style::computed_values::transform_style::T as TransformStyle;
 use style::computed_values::white_space::T as WhiteSpace;
 use style::computed_values::word_break::T as WordBreak;
 use style::logical_geometry::{Direction, LogicalMargin, LogicalRect, LogicalSize, WritingMode};
 use style::properties::ComputedValues;
 use style::selector_parser::RestyleDamage;
 use style::servo::restyle_damage::ServoRestyleDamage;
 use style::str::char_is_whitespace;
-use style::values::{self, Either};
 use style::values::computed::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
 use style::values::computed::counters::ContentItem;
-use style::values::generics::box_::VerticalAlign;
+use style::values::generics::box_::{Perspective, VerticalAlign};
 use style::values::generics::transform;
 use text;
 use text::TextRunScanner;
 use webrender_api::{self, LayoutTransform};
 use wrapper::ThreadSafeLayoutNodeHelpers;
 
 // From gfxFontConstants.h in Firefox.
 static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
@@ -2472,17 +2471,17 @@ impl Fragment {
                   Size2D::new(stacking_relative_border_box.size.width - border_padding.horizontal(),
                               stacking_relative_border_box.size.height - border_padding.vertical()))
     }
 
     /// Returns true if this fragment has a filter, transform, or perspective property set.
     pub fn has_filter_transform_or_perspective(&self) -> bool {
            !self.style().get_box().transform.0.is_empty() ||
            !self.style().get_effects().filter.0.is_empty() ||
-           self.style().get_box().perspective != Either::Second(values::None_)
+           self.style().get_box().perspective != Perspective::None
     }
 
     /// Returns true if this fragment establishes a new stacking context and false otherwise.
     pub fn establishes_stacking_context(&self) -> bool {
         // Text fragments shouldn't create stacking contexts.
         match self.specific {
             SpecificFragmentInfo::TruncatedFragment(_) |
             SpecificFragmentInfo::ScannedText(_) |
@@ -2894,17 +2893,17 @@ impl Fragment {
             -transform_origin_z);
 
         Some(pre_transform.pre_mul(&transform).pre_mul(&post_transform))
     }
 
     /// Returns the 4D matrix representing this fragment's perspective.
     pub fn perspective_matrix(&self, stacking_relative_border_box: &Rect<Au>) -> Option<LayoutTransform> {
         match self.style().get_box().perspective {
-            Either::First(length) => {
+            Perspective::Length(length) => {
                 let perspective_origin = self.style().get_box().perspective_origin;
                 let perspective_origin =
                     Point2D::new(
                         perspective_origin.horizontal
                             .to_used_value(stacking_relative_border_box.size.width),
                         perspective_origin.vertical
                             .to_used_value(stacking_relative_border_box.size.height)
                     ).to_layout();
@@ -2918,17 +2917,17 @@ impl Fragment {
                     -perspective_origin.y,
                     0.0);
 
                 let perspective_matrix = LayoutTransform::from_untyped(
                     &transform::create_perspective_matrix(length.px()));
 
                 Some(pre_transform.pre_mul(&perspective_matrix).pre_mul(&post_transform))
             }
-            Either::Second(values::None_) => {
+            Perspective::None => {
                 None
             }
         }
     }
 }
 
 impl fmt::Debug for Fragment {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
--- a/servo/components/style/gecko/values.rs
+++ b/servo/components/style/gecko/values.rs
@@ -19,16 +19,17 @@ use std::cmp::max;
 use values::{Auto, Either, None_, Normal};
 use values::computed::{Angle, ExtremumLength, Length, LengthOrPercentage, LengthOrPercentageOrAuto};
 use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
 use values::computed::{MaxLength, MozLength, Percentage};
 use values::computed::{NonNegativeLength, NonNegativeLengthOrPercentage, NonNegativeNumber};
 use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
 use values::generics::{CounterStyleOrNone, NonNegative};
 use values::generics::basic_shape::ShapeRadius;
+use values::generics::box_::Perspective;
 use values::generics::gecko::ScrollSnapPoint;
 use values::generics::grid::{TrackBreadth, TrackKeyword};
 
 /// A trait that defines an interface to convert from and to `nsStyleCoord`s.
 pub trait GeckoStyleCoordConvertible : Sized {
     /// Convert this to a `nsStyleCoord`.
     fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T);
     /// Given a `nsStyleCoord`, try to get a value of this type..
@@ -417,16 +418,37 @@ impl GeckoStyleCoordConvertible for Scro
                 nsStyleUnit::eStyleUnit_None => ScrollSnapPoint::None,
                 _  => ScrollSnapPoint::Repeat(LengthOrPercentage::from_gecko_style_coord(coord)
                             .expect("coord could not convert to LengthOrPercentage")),
             }
         )
     }
 }
 
+impl<L> GeckoStyleCoordConvertible for Perspective<L>
+where
+    L: GeckoStyleCoordConvertible,
+{
+    fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
+        match *self {
+            Perspective::None => coord.set_value(CoordDataValue::None),
+            Perspective::Length(ref l) => l.to_gecko_style_coord(coord),
+        };
+    }
+
+    fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
+        use gecko_bindings::structs::root::nsStyleUnit;
+
+        if coord.unit() == nsStyleUnit::eStyleUnit_None {
+            return Some(Perspective::None);
+        }
+        Some(Perspective::Length(L::from_gecko_style_coord(coord)?))
+    }
+}
+
 /// Convert a given RGBA value to `nscolor`.
 pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 {
     ((rgba.alpha as u32) << 24) |
     ((rgba.blue as u32) << 16) |
     ((rgba.green as u32) << 8) |
     (rgba.red as u32)
 }
 
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -1442,38 +1442,38 @@ impl Clone for ${style_struct.gecko_stru
 <%def name="impl_trait(style_struct_name, skip_longhands='')">
 <%
     style_struct = next(x for x in data.style_structs if x.name == style_struct_name)
     longhands = [x for x in style_struct.longhands
                 if not (skip_longhands == "*" or x.name in skip_longhands.split())]
 
     # Types used with predefined_type()-defined properties that we can auto-generate.
     predefined_types = {
+        "Color": impl_color,
+        "GreaterThanOrEqualToOneNumber": impl_simple,
+        "Integer": impl_simple,
         "length::LengthOrAuto": impl_style_coord,
         "length::LengthOrNormal": impl_style_coord,
         "length::NonNegativeLengthOrAuto": impl_style_coord,
         "length::NonNegativeLengthOrNormal": impl_style_coord,
-        "GreaterThanOrEqualToOneNumber": impl_simple,
         "Length": impl_absolute_length,
-        "Position": impl_position,
+        "LengthOrNormal": impl_style_coord,
         "LengthOrPercentage": impl_style_coord,
         "LengthOrPercentageOrAuto": impl_style_coord,
         "LengthOrPercentageOrNone": impl_style_coord,
-        "LengthOrNone": impl_style_coord,
-        "LengthOrNormal": impl_style_coord,
         "MaxLength": impl_style_coord,
         "MozLength": impl_style_coord,
         "MozScriptMinSize": impl_absolute_length,
         "MozScriptSizeMultiplier": impl_simple,
         "NonNegativeLengthOrPercentage": impl_style_coord,
         "NonNegativeNumber": impl_simple,
         "Number": impl_simple,
-        "Integer": impl_simple,
         "Opacity": impl_simple,
-        "Color": impl_color,
+        "Perspective": impl_style_coord,
+        "Position": impl_position,
         "RGBAColor": impl_rgba_color,
         "SVGLength": impl_svg_length,
         "SVGOpacity": impl_svg_opacity,
         "SVGPaint": impl_svg_paint,
         "SVGWidth": impl_svg_length,
         "Transform": impl_transform,
         "TransformOrigin": impl_transform_origin,
         "UrlOrNone": impl_css_url,
@@ -4790,32 +4790,32 @@ fn static_assert() {
     ${impl_non_negative_length('_webkit_text_stroke_width',
                                'mWebkitTextStrokeWidth')}
 
     #[allow(non_snake_case)]
     pub fn set__moz_tab_size(&mut self, v: longhands::_moz_tab_size::computed_value::T) {
         use values::Either;
 
         match v {
-            Either::Second(non_negative_number) => {
+            Either::First(non_negative_number) => {
                 self.gecko.mTabSize.set_value(CoordDataValue::Factor(non_negative_number.0));
             }
-            Either::First(non_negative_length) => {
+            Either::Second(non_negative_length) => {
                 self.gecko.mTabSize.set(non_negative_length);
             }
         }
     }
 
     #[allow(non_snake_case)]
     pub fn clone__moz_tab_size(&self) -> longhands::_moz_tab_size::computed_value::T {
         use values::Either;
 
         match self.gecko.mTabSize.as_value() {
-            CoordDataValue::Coord(coord) => Either::First(Au(coord).into()),
-            CoordDataValue::Factor(number) => Either::Second(From::from(number)),
+            CoordDataValue::Coord(coord) => Either::Second(Au(coord).into()),
+            CoordDataValue::Factor(number) => Either::First(From::from(number)),
             _ => unreachable!(),
         }
     }
 
     <%call expr="impl_coord_copy('_moz_tab_size', 'mTabSize')"></%call>
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="Text"
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -502,27 +502,27 @@
 // makes the UA rules easier to write.
 ${helpers.single_keyword("resize",
                          "none both horizontal vertical",
                          products="gecko",
                          spec="https://drafts.csswg.org/css-ui/#propdef-resize",
                          flags="APPLIES_TO_PLACEHOLDER",
                          animation_value_type="discrete")}
 
-
-${helpers.predefined_type("perspective",
-                          "LengthOrNone",
-                          "Either::Second(None_)",
-                          "parse_non_negative_length",
-                          gecko_ffi_name="mChildPerspective",
-                          spec="https://drafts.csswg.org/css-transforms/#perspective",
-                          extra_prefixes="moz webkit",
-                          flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
-                          animation_value_type="ComputedValue",
-                          servo_restyle_damage = "reflow_out_of_flow")}
+${helpers.predefined_type(
+    "perspective",
+    "Perspective",
+    "computed::Perspective::none()",
+    gecko_ffi_name="mChildPerspective",
+    spec="https://drafts.csswg.org/css-transforms/#perspective",
+    extra_prefixes="moz webkit",
+    flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
+    animation_value_type="AnimatedPerspective",
+    servo_restyle_damage = "reflow_out_of_flow",
+)}
 
 ${helpers.predefined_type("perspective-origin",
                           "position::Position",
                           "computed::position::Position::center()",
                           boxed=True,
                           extra_prefixes="moz webkit",
                           spec="https://drafts.csswg.org/css-transforms-2/#perspective-origin-property",
                           animation_value_type="ComputedValue",
--- a/servo/components/style/properties/longhand/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_text.mako.rs
@@ -483,17 +483,17 @@
     products="gecko",
     animation_value_type="AnimatedColor",
     ignored_when_colors_disabled=True,
     spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color",
 )}
 
 ${helpers.predefined_type(
     "-moz-tab-size", "length::NonNegativeLengthOrNumber",
-    "::values::Either::Second(From::from(8.0))",
+    "::values::Either::First(From::from(8.0))",
     products="gecko", animation_value_type="::values::computed::length::NonNegativeLengthOrNumber",
     spec="https://drafts.csswg.org/css-text-3/#tab-size-property")}
 
 
 // CSS Compatibility
 // https://compat.spec.whatwg.org
 ${helpers.predefined_type(
     "-webkit-text-fill-color",
--- a/servo/components/style/values/computed/box.rs
+++ b/servo/components/style/values/computed/box.rs
@@ -1,17 +1,18 @@
 /* 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/. */
 
 //! Computed types for box properties.
 
 use values::computed::Number;
-use values::computed::length::LengthOrPercentage;
+use values::computed::length::{LengthOrPercentage, NonNegativeLength};
 use values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount;
+use values::generics::box_::Perspective as GenericPerspective;
 use values::generics::box_::VerticalAlign as GenericVerticalAlign;
 
 pub use values::specified::box_::{AnimationName, Display, OverflowClipBox, Contain};
 pub use values::specified::box_::{OverscrollBehavior, ScrollSnapType, TouchAction, WillChange};
 
 /// A computed value for the `vertical-align` property.
 pub type VerticalAlign = GenericVerticalAlign<LengthOrPercentage>;
 
@@ -20,8 +21,11 @@ pub type AnimationIterationCount = Gener
 
 impl AnimationIterationCount {
     /// Returns the value `1.0`.
     #[inline]
     pub fn one() -> Self {
         GenericAnimationIterationCount::Number(1.0)
     }
 }
+
+/// A computed value for the `perspective` property.
+pub type Perspective = GenericPerspective<NonNegativeLength>;
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -8,17 +8,17 @@ use app_units::Au;
 use logical_geometry::WritingMode;
 use ordered_float::NotNaN;
 use properties::LonghandId;
 use std::fmt::{self, Write};
 use std::ops::{Add, Neg};
 use style_traits::{CssWriter, ToCss};
 use style_traits::values::specified::AllowedNumericType;
 use super::{Number, ToComputedValue, Context, Percentage};
-use values::{Auto, CSSFloat, Either, None_, Normal, specified};
+use values::{Auto, CSSFloat, Either, Normal, specified};
 use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
 use values::computed::NonNegativeNumber;
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
 use values::generics::NonNegative;
 use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength};
 use values::specified::length::ViewportPercentageLength;
 
 pub use super::image::Image;
@@ -787,19 +787,16 @@ impl From<Au> for CSSPixelLength {
     fn from(len: Au) -> Self {
         CSSPixelLength::new(len.to_f32_px())
     }
 }
 
 /// An alias of computed `<length>` value.
 pub type Length = CSSPixelLength;
 
-/// 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>;
 
 /// Either a computed `<length>` or a `<number>` value.
 pub type LengthOrNumber = Either<Length, Number>;
 
 impl LengthOrNumber {
     /// Returns `0`.
@@ -897,17 +894,17 @@ impl From<NonNegativeLength> for Au {
 
 /// Either a computed NonNegativeLength or the `auto` keyword.
 pub type NonNegativeLengthOrAuto = Either<NonNegativeLength, Auto>;
 
 /// Either a computed NonNegativeLength or the `normal` keyword.
 pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;
 
 /// Either a computed NonNegativeLength or a NonNegativeNumber value.
-pub type NonNegativeLengthOrNumber = Either<NonNegativeLength, NonNegativeNumber>;
+pub type NonNegativeLengthOrNumber = Either<NonNegativeNumber, NonNegativeLength>;
 
 /// A type for possible values for min- and max- flavors of width, height,
 /// block-size, and inline-size.
 #[allow(missing_docs)]
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)]
 pub enum ExtremumLength {
     MozMaxContent,
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -42,31 +42,32 @@ pub use self::align::{AlignSelf, Justify
 pub use self::angle::Angle;
 pub use self::background::{BackgroundSize, BackgroundRepeat};
 pub use self::border::{BorderImageRepeat, BorderImageSlice, BorderImageWidth, BorderImageSideWidth};
 pub use self::border::{BorderRadius, BorderCornerRadius, BorderSpacing};
 pub use self::font::{FontSize, FontSizeAdjust, FontSynthesis, FontWeight, FontVariantAlternates};
 pub use self::font::{FontFamily, FontLanguageOverride, FontVariationSettings, FontVariantEastAsian};
 pub use self::font::{FontVariantLigatures, FontVariantNumeric, FontFeatureSettings};
 pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XTextZoom, XLang};
-pub use self::box_::{AnimationIterationCount, AnimationName, Display, OverscrollBehavior, Contain};
-pub use self::box_::{OverflowClipBox, ScrollSnapType, TouchAction, VerticalAlign, WillChange};
+pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display};
+pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective};
+pub use self::box_::{ScrollSnapType, TouchAction, VerticalAlign, WillChange};
 pub use self::color::{Color, ColorPropertyValue, RGBAColor};
 pub use self::column::ColumnCount;
 pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset};
 pub use self::effects::{BoxShadow, Filter, SimpleShadow};
 pub use self::flex::FlexBasis;
 pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect};
 pub use self::inherited_box::{Orientation, ImageOrientation};
 #[cfg(feature = "gecko")]
 pub use self::gecko::ScrollSnapPoint;
 pub use self::rect::LengthOrNumberRect;
 pub use super::{Auto, Either, None_};
 pub use super::specified::{BorderStyle, TextDecorationLine};
-pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNone, LengthOrNumber, LengthOrPercentage};
+pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage};
 pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength};
 pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength, NonNegativeLengthOrPercentage};
 pub use self::list::{ListStyleImage, Quotes};
 #[cfg(feature = "gecko")]
 pub use self::list::ListStyleType;
 pub use self::outline::OutlineStyle;
 pub use self::percentage::Percentage;
 pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex};
--- a/servo/components/style/values/generics/box.rs
+++ b/servo/components/style/values/generics/box.rs
@@ -50,8 +50,26 @@ impl<L> ToAnimatedZero for VerticalAlign
 /// https://drafts.csswg.org/css-animations/#animation-iteration-count
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
 pub enum AnimationIterationCount<Number> {
     /// A `<number>` value.
     Number(Number),
     /// The `infinite` keyword.
     Infinite,
 }
+
+/// A generic value for the `perspective` property.
+#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf)]
+#[derive(PartialEq, ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)]
+pub enum Perspective<NonNegativeLength> {
+    /// A non-negative length.
+    Length(NonNegativeLength),
+    /// The keyword `none`.
+    None,
+}
+
+impl<L> Perspective<L> {
+    /// Returns `none`.
+    #[inline]
+    pub fn none() -> Self {
+        Perspective::None
+    }
+}
--- a/servo/components/style/values/specified/box.rs
+++ b/servo/components/style/values/specified/box.rs
@@ -8,19 +8,20 @@ use Atom;
 use cssparser::Parser;
 use parser::{Parse, ParserContext};
 use selectors::parser::SelectorParseErrorKind;
 use std::fmt::{self, Write};
 use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
 use values::CustomIdent;
 use values::KeyframesName;
 use values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount;
+use values::generics::box_::Perspective as GenericPerspective;
 use values::generics::box_::VerticalAlign as GenericVerticalAlign;
 use values::specified::{AllowQuirks, Number};
-use values::specified::length::LengthOrPercentage;
+use values::specified::length::{LengthOrPercentage, NonNegativeLength};
 
 #[allow(missing_docs)]
 #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)]
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
 /// Defines an element’s display type, which consists of
 /// the two basic qualities of how an element generates boxes
 /// <https://drafts.csswg.org/css-display/#propdef-display>
 pub enum Display {
@@ -583,8 +584,23 @@ impl Parse for Contain {
 
         if !result.is_empty() {
             Ok(result)
         } else {
             Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
         }
     }
 }
+
+/// A specified value for the `perspective` property.
+pub type Perspective = GenericPerspective<NonNegativeLength>;
+
+impl Parse for Perspective {
+    fn parse<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>
+    ) -> Result<Self, ParseError<'i>> {
+        if input.try(|i| i.expect_ident_matching("none")).is_ok() {
+            return Ok(GenericPerspective::None);
+        }
+        Ok(GenericPerspective::Length(NonNegativeLength::parse(context, input)?))
+    }
+}
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -12,17 +12,17 @@ use euclid::Size2D;
 use font_metrics::FontMetricsQueryResult;
 use parser::{Parse, ParserContext};
 use std::cmp;
 #[allow(unused_imports)] use std::ascii::AsciiExt;
 use std::ops::{Add, Mul};
 use style_traits::{ParseError, StyleParseErrorKind};
 use style_traits::values::specified::AllowedNumericType;
 use super::{AllowQuirks, Number, ToComputedValue, Percentage};
-use values::{Auto, CSSFloat, Either, None_, Normal};
+use values::{Auto, CSSFloat, Either, Normal};
 use values::computed::{self, CSSPixelLength, Context, ExtremumLength};
 use values::generics::NonNegative;
 use values::specified::NonNegativeNumber;
 use values::specified::calc::CalcNode;
 
 pub use values::specified::calc::CalcLengthOrPercentage;
 pub use super::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
 pub use super::image::{GradientKind, Image};
@@ -635,56 +635,43 @@ impl Length {
     pub fn parse_quirky<'i, 't>(context: &ParserContext,
                                 input: &mut Parser<'i, 't>,
                                 allow_quirks: AllowQuirks)
                                 -> Result<Self, ParseError<'i>> {
         Self::parse_internal(context, input, AllowedNumericType::All, allow_quirks)
     }
 }
 
-impl<T: Parse> Either<Length, T> {
-    /// Parse a non-negative length
+/// A wrapper of Length, whose value must be >= 0.
+pub type NonNegativeLength = NonNegative<Length>;
+
+impl Parse for NonNegativeLength {
     #[inline]
-    pub fn parse_non_negative_length<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-                                             -> Result<Self, ParseError<'i>> {
-        if let Ok(v) = input.try(|input| T::parse(context, input)) {
-            return Ok(Either::Second(v));
-        }
-        Length::parse_internal(context, input, AllowedNumericType::NonNegative, AllowQuirks::No).map(Either::First)
+    fn parse<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Self, ParseError<'i>> {
+        Ok(NonNegative(Length::parse_non_negative(context, input)?))
     }
 }
 
-/// A wrapper of Length, whose value must be >= 0.
-pub type NonNegativeLength = NonNegative<Length>;
-
 impl From<NoCalcLength> for NonNegativeLength {
     #[inline]
     fn from(len: NoCalcLength) -> Self {
         NonNegative::<Length>(Length::NoCalc(len))
     }
 }
 
 impl From<Length> for NonNegativeLength {
     #[inline]
     fn from(len: Length) -> Self {
         NonNegative::<Length>(len)
     }
 }
 
-impl<T: Parse> Parse for Either<NonNegativeLength, T> {
-    #[inline]
-    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
-        if let Ok(v) = input.try(|input| T::parse(context, input)) {
-            return Ok(Either::Second(v));
-        }
-        Length::parse_internal(context, input, AllowedNumericType::NonNegative, AllowQuirks::No)
-            .map(NonNegative::<Length>).map(Either::First)
-    }
-}
-
 impl NonNegativeLength {
     /// Returns a `zero` length.
     #[inline]
     pub fn zero() -> Self {
         Length::zero().into()
     }
 
     /// Get an absolute length from a px value.
@@ -696,17 +683,20 @@ impl NonNegativeLength {
 
 /// Either a NonNegativeLength or the `normal` keyword.
 pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;
 
 /// Either a NonNegativeLength or the `auto` keyword.
 pub type NonNegativeLengthOrAuto = Either<NonNegativeLength, Auto>;
 
 /// Either a NonNegativeLength or a NonNegativeNumber value.
-pub type NonNegativeLengthOrNumber = Either<NonNegativeLength, NonNegativeNumber>;
+///
+/// The order is important, because `0` must be parsed as the number `0` and not
+/// the length `0px`.
+pub type NonNegativeLengthOrNumber = Either<NonNegativeNumber, NonNegativeLength>;
 
 /// A length or a percentage value.
 #[allow(missing_docs)]
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
 pub enum LengthOrPercentage {
     Length(NoCalcLength),
     Percentage(computed::Percentage),
     Calc(Box<CalcLengthOrPercentage>),
@@ -1067,19 +1057,16 @@ impl NonNegativeLengthOrPercentage {
         input: &mut Parser<'i, 't>,
         allow_quirks: AllowQuirks,
     ) -> Result<Self, ParseError<'i>> {
         LengthOrPercentage::parse_non_negative_quirky(context, input, allow_quirks)
             .map(NonNegative::<LengthOrPercentage>)
     }
 }
 
-/// Either a `<length>` or the `none` keyword.
-pub type LengthOrNone = Either<Length, None_>;
-
 /// Either a `<length>` or the `normal` keyword.
 pub type LengthOrNormal = Either<Length, Normal>;
 
 /// Either a `<length>` or the `auto` keyword.
 pub type LengthOrAuto = Either<Length, Auto>;
 
 /// Either a `<length>` or a `<number>`.
 pub type LengthOrNumber = Either<Length, Number>;
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -34,29 +34,30 @@ pub use self::align::{AlignSelf, Justify
 pub use self::background::{BackgroundRepeat, BackgroundSize};
 pub use self::border::{BorderCornerRadius, BorderImageSlice, BorderImageWidth};
 pub use self::border::{BorderImageRepeat, BorderImageSideWidth, BorderRadius, BorderSideWidth, BorderSpacing};
 pub use self::column::ColumnCount;
 pub use self::font::{FontSize, FontSizeAdjust, FontSynthesis, FontWeight, FontVariantAlternates};
 pub use self::font::{FontFamily, FontLanguageOverride, FontVariationSettings, FontVariantEastAsian};
 pub use self::font::{FontVariantLigatures, FontVariantNumeric, FontFeatureSettings};
 pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XTextZoom, XLang};
-pub use self::box_::{AnimationIterationCount, AnimationName, Display, OverscrollBehavior, Contain};
-pub use self::box_::{OverflowClipBox, ScrollSnapType, TouchAction, VerticalAlign, WillChange};
+pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display};
+pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective};
+pub use self::box_::{ScrollSnapType, TouchAction, VerticalAlign, WillChange};
 pub use self::color::{Color, ColorPropertyValue, RGBAColor};
 pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset};
 pub use self::effects::{BoxShadow, Filter, SimpleShadow};
 pub use self::flex::FlexBasis;
 #[cfg(feature = "gecko")]
 pub use self::gecko::ScrollSnapPoint;
 pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
 pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect};
 pub use self::inherited_box::ImageOrientation;
 pub use self::length::{AbsoluteLength, CalcLengthOrPercentage, CharacterWidth};
-pub use self::length::{FontRelativeLength, Length, LengthOrNone, LengthOrNumber};
+pub use self::length::{FontRelativeLength, Length, LengthOrNumber};
 pub use self::length::{LengthOrPercentage, LengthOrPercentageOrAuto};
 pub use self::length::{LengthOrPercentageOrNone, MaxLength, MozLength};
 pub use self::length::{NoCalcLength, ViewportPercentageLength};
 pub use self::length::NonNegativeLengthOrPercentage;
 pub use self::list::{ListStyleImage, Quotes};
 #[cfg(feature = "gecko")]
 pub use self::list::ListStyleType;
 pub use self::outline::OutlineStyle;