Bug 1374233 - Part 4: Add NonNegativeLengthOr{Auto|Normal|Number}. draft
authorBoris Chiou <boris.chiou@gmail.com>
Thu, 20 Jul 2017 16:27:35 +0800
changeset 614995 88d1a5c41b977f7e0b99b53f72b9ae1e9be517d3
parent 614994 0f88e920e67170831229b6f4da8b80b65294a4dc
child 614996 2d07c4faed1715015d4a1cd94812f3ee4d96d22c
push id70205
push userbmo:boris.chiou@gmail.com
push dateTue, 25 Jul 2017 08:53:17 +0000
bugs1374233
milestone56.0a1
Bug 1374233 - Part 4: Add NonNegativeLengthOr{Auto|Normal|Number}. Add NonNegativeLength, which could be computed to NonNegativeAu. So we can declare Either<NonNegativeLength, X>, X=Auto, Normal, or Number. NonNegativeLengthOrAuto is for column-width. NonNegativeLengthOrNormal is for column-gap. NonNegativeLengthOrNumber is for -moz-tab-size. MozReview-Commit-ID: AfU8XpA1um0
servo/components/style/gecko/values.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/helpers/animated_properties.mako.rs
servo/components/style/properties/longhand/column.mako.rs
servo/components/style/properties/longhand/inherited_text.mako.rs
servo/components/style/values/computed/length.rs
servo/components/style/values/specified/length.rs
--- a/servo/components/style/gecko/values.rs
+++ b/servo/components/style/gecko/values.rs
@@ -12,17 +12,17 @@ use cssparser::RGBA;
 use gecko_bindings::structs::{CounterStylePtr, nsStyleCoord};
 use gecko_bindings::structs::{StyleGridTrackBreadth, StyleShapeRadius};
 use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
 use media_queries::Device;
 use nsstring::{nsACString, nsCString};
 use std::cmp::max;
 use values::{Auto, Either, ExtremumLength, None_, Normal};
 use values::computed::{Angle, LengthOrPercentage, LengthOrPercentageOrAuto};
-use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
+use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage, NonNegativeAu};
 use values::computed::{MaxLength, MozLength, Percentage};
 use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
 use values::generics::CounterStyleOrNone;
 use values::generics::basic_shape::ShapeRadius;
 use values::generics::gecko::ScrollSnapPoint;
 use values::generics::grid::{TrackBreadth, TrackKeyword};
 
 /// A trait that defines an interface to convert from and to `nsStyleCoord`s.
@@ -129,16 +129,26 @@ impl GeckoStyleCoordConvertible for Au {
     fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
         match coord.as_value() {
             CoordDataValue::Coord(coord) => Some(Au(coord)),
             _ => None,
         }
     }
 }
 
+impl GeckoStyleCoordConvertible for NonNegativeAu {
+    fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
+        self.0.to_gecko_style_coord(coord);
+    }
+
+    fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
+        Au::from_gecko_style_coord(coord).map(NonNegativeAu)
+    }
+}
+
 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.0),
             LengthOrPercentageOrAuto::Auto => CoordDataValue::Auto,
             LengthOrPercentageOrAuto::Calc(calc) => CoordDataValue::Calc(calc.into()),
         };
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -905,16 +905,18 @@ impl Clone for ${style_struct.gecko_stru
     force_stub = [];
     # These have unusual representations in gecko.
     force_stub += ["list-style-type"]
 
     # Types used with predefined_type()-defined properties that we can auto-generate.
     predefined_types = {
         "length::LengthOrAuto": impl_style_coord,
         "length::LengthOrNormal": impl_style_coord,
+        "length::NonNegativeLengthOrAuto": impl_style_coord,
+        "length::NonNegativeLengthOrNormal": impl_style_coord,
         "GreaterThanOrEqualToOneNumber": impl_simple_wrapper,
         "Length": impl_absolute_length,
         "Position": impl_position,
         "LengthOrPercentage": impl_style_coord,
         "LengthOrPercentageOrAuto": impl_style_coord,
         "LengthOrPercentageOrNone": impl_style_coord,
         "LengthOrNone": impl_style_coord,
         "LengthOrNormal": impl_style_coord,
@@ -4196,32 +4198,33 @@ fn static_assert() {
                                              'mWebkitTextStrokeWidth',
                                              need_clone=True)"></%call>
 
     #[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(number) => {
-                self.gecko.mTabSize.set_value(CoordDataValue::Factor(number));
+            Either::Second(non_negative_number) => {
+                self.gecko.mTabSize.set_value(CoordDataValue::Factor(non_negative_number.0));
             }
-            Either::First(au) => {
-                self.gecko.mTabSize.set(au);
+            Either::First(non_negative_au) => {
+                self.gecko.mTabSize.set(non_negative_au.0);
             }
         }
     }
 
     #[allow(non_snake_case)]
     pub fn clone__moz_tab_size(&self) -> longhands::_moz_tab_size::computed_value::T {
         use values::Either;
+        use values::computed::NonNegativeNumber;
 
         match self.gecko.mTabSize.as_value() {
-            CoordDataValue::Coord(coord) => Either::First(Au(coord)),
-            CoordDataValue::Factor(number) => Either::Second(number),
+            CoordDataValue::Coord(coord) => Either::First(NonNegativeAu(Au(coord))),
+            CoordDataValue::Factor(number) => Either::Second(NonNegativeNumber(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/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -40,16 +40,18 @@ use values::animated::effects::BoxShadow
 use values::animated::effects::Filter as AnimatedFilter;
 use values::animated::effects::FilterList as AnimatedFilterList;
 use values::animated::effects::TextShadowList as AnimatedTextShadowList;
 use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
 use values::computed::{BorderCornerRadius, ClipRect};
 use values::computed::{CalcLengthOrPercentage, Color, Context, ComputedValueAsSpecified};
 use values::computed::{LengthOrPercentage, MaxLength, MozLength, Percentage, ToComputedValue};
 use values::computed::{GreaterThanOrEqualToOneNumber, NonNegativeAu, NonNegativeNumber};
+use values::computed::length::{NonNegativeLengthOrAuto, NonNegativeLengthOrNormal};
+use values::computed::length::NonNegativeLengthOrNumber;
 use values::generics::{SVGPaint, SVGPaintKind};
 use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
 use values::generics::effects::Filter;
 use values::generics::position as generic_position;
 
 /// A trait used to implement various procedures used during animation.
 pub trait Animatable: Sized {
     /// Performs a weighted sum of this value and |other|. This is used for
--- a/servo/components/style/properties/longhand/column.mako.rs
+++ b/servo/components/style/properties/longhand/column.mako.rs
@@ -2,43 +2,41 @@
  * 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/. */
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 <% data.new_style_struct("Column", inherited=False) %>
 
 ${helpers.predefined_type("column-width",
-                          "length::LengthOrAuto",
+                          "length::NonNegativeLengthOrAuto",
                           "Either::Second(Auto)",
                           initial_specified_value="Either::Second(Auto)",
-                          parse_method="parse_non_negative_length",
                           extra_prefixes="moz",
-                          animation_value_type="ComputedValue",
+                          animation_value_type="NonNegativeLengthOrAuto",
                           experimental=True,
                           spec="https://drafts.csswg.org/css-multicol/#propdef-column-width")}
 
 
 ${helpers.predefined_type("column-count",
                           "IntegerOrAuto",
                           "Either::Second(Auto)",
                           parse_method="parse_positive",
                           initial_specified_value="Either::Second(Auto)",
                           experimental="True",
                           animation_value_type="ComputedValue",
                           extra_prefixes="moz",
                           spec="https://drafts.csswg.org/css-multicol/#propdef-column-count")}
 
 ${helpers.predefined_type("column-gap",
-                          "length::LengthOrNormal",
+                          "length::NonNegativeLengthOrNormal",
                           "Either::Second(Normal)",
-                          parse_method='parse_non_negative_length',
                           extra_prefixes="moz",
                           experimental=True,
-                          animation_value_type="ComputedValue",
+                          animation_value_type="NonNegativeLengthOrNormal",
                           spec="https://drafts.csswg.org/css-multicol/#propdef-column-gap")}
 
 ${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz",
                          products="gecko", animation_value_type="discrete",
                          spec="https://drafts.csswg.org/css-multicol/#propdef-column-fill")}
 
 ${helpers.predefined_type("column-rule-width",
                           "BorderSideWidth",
--- a/servo/components/style/properties/longhand/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_text.mako.rs
@@ -709,20 +709,19 @@
                           "computed_value::T::currentcolor()",
                           initial_specified_value="specified::Color::currentcolor()",
                           products="gecko", animation_value_type="IntermediateColor",
                           need_clone=True, ignored_when_colors_disabled=True,
                           spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color")}
 
 
 ${helpers.predefined_type(
-    "-moz-tab-size", "LengthOrNumber",
-    "::values::Either::Second(8.0)",
-    "parse_non_negative",
-    products="gecko", animation_value_type="ComputedValue",
+    "-moz-tab-size", "length::NonNegativeLengthOrNumber",
+    "::values::Either::Second(::values::computed::NonNegativeNumber(8.0))",
+    products="gecko", animation_value_type="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", "Color",
     "computed_value::T::currentcolor()",
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -6,16 +6,17 @@
 
 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::computed::{NonNegativeAu, NonNegativeNumber};
 use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength};
 use values::specified::length::ViewportPercentageLength;
 
 pub use super::image::Image;
 pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
 
 /// A computed `<percentage>` value.
 ///
@@ -96,16 +97,30 @@ impl ToComputedValue for specified::Leng
     }
 
     #[inline]
     fn from_computed_value(computed: &Au) -> Self {
         specified::Length::NoCalc(specified::NoCalcLength::from_computed_value(computed))
     }
 }
 
+impl ToComputedValue for specified::length::NonNegativeLength {
+    type ComputedValue = NonNegativeLength;
+
+    #[inline]
+    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+        NonNegativeAu(self.0.to_computed_value(context))
+    }
+
+    #[inline]
+    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+        specified::length::NonNegativeLength(ToComputedValue::from_computed_value(&computed.0))
+    }
+}
+
 #[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<Percentage>,
 }
@@ -555,16 +570,28 @@ impl LengthOrNumber {
     pub fn zero() -> Self {
         Either::Second(0.)
     }
 }
 
 /// Either a computed `<length>` or the `normal` keyword.
 pub type LengthOrNormal = Either<Length, Normal>;
 
+/// A wrapper of Length, whose value must be >= 0.
+pub type NonNegativeLength = NonNegativeAu;
+
+/// 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>;
+
 /// A value suitable for a `min-width`, `min-height`, `width` or `height` property.
 /// See specified/values/length.rs for more details.
 #[allow(missing_docs)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[derive(Clone, Copy, Debug, PartialEq, ToCss)]
 pub enum MozLength {
     LengthOrPercentageOrAuto(LengthOrPercentageOrAuto),
     ExtremumLength(ExtremumLength),
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -17,16 +17,17 @@ use std::ops::Mul;
 use style_traits::{HasViewportPercentage, ToCss, ParseError, StyleParseError};
 use style_traits::values::specified::{AllowedLengthType, AllowedNumericType};
 use stylesheets::CssRuleType;
 use super::{AllowQuirks, Number, ToComputedValue};
 use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, None_, Normal};
 use values::ExtremumLength;
 use values::computed::{self, Context};
 use values::specified::calc::CalcNode;
+use values::specified::NonNegativeNumber;
 
 pub use values::specified::calc::CalcLengthOrPercentage;
 pub use super::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
 pub use super::image::{GradientKind, Image};
 
 /// Number of app units per pixel
 pub const AU_PER_PX: CSSFloat = 60.;
 /// Number of app units per inch
@@ -695,16 +696,41 @@ impl<T: Parse> Either<Length, 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, AllowedLengthType::NonNegative, AllowQuirks::No).map(Either::First)
     }
 }
 
+/// A wrapper of Length, whose value must be >= 0.
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
+pub struct NonNegativeLength(pub Length);
+
+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, AllowedLengthType::NonNegative, AllowQuirks::No)
+            .map(NonNegativeLength).map(Either::First)
+    }
+}
+
+/// 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>;
+
 /// A percentage value.
 #[derive(Clone, Copy, Debug, Default, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub struct Percentage {
     /// The percentage value as a float.
     ///
     /// [0 .. 100%] maps to [0.0 .. 1.0]
     value: CSSFloat,