diff --git a/components/style/gecko/values.rs b/components/style/gecko/values.rs index e2ae1f538f1..194627e84b2 100644 --- a/components/style/gecko/values.rs +++ b/components/style/gecko/values.rs @@ -19,6 +19,7 @@ use values::{Auto, Either, ExtremumLength, None_, Normal}; use values::computed::{Angle, LengthOrPercentage, LengthOrPercentageOrAuto}; use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage, NonNegativeAu}; use values::computed::{MaxLength, MozLength, Percentage}; +use values::computed::NonNegativeLengthOrPercentage; use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius; use values::generics::{CounterStyleOrNone, NonNegative}; use values::generics::basic_shape::ShapeRadius; @@ -121,6 +122,16 @@ impl GeckoStyleCoordConvertible for LengthOrPercentage { } } +impl GeckoStyleCoordConvertible for NonNegativeLengthOrPercentage { + fn to_gecko_style_coord(&self, coord: &mut T) { + self.0.to_gecko_style_coord(coord); + } + + fn from_gecko_style_coord(coord: &T) -> Option { + LengthOrPercentage::from_gecko_style_coord(coord).map(NonNegative::) + } +} + impl GeckoStyleCoordConvertible for Au { fn to_gecko_style_coord(&self, coord: &mut T) { coord.set_value(CoordDataValue::Coord(self.0)); diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 45fa2401863..69c6b467301 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1101,6 +1101,7 @@ impl Clone for ${style_struct.gecko_struct_name} { "LengthOrNormal": impl_style_coord, "MaxLength": impl_style_coord, "MozLength": impl_style_coord, + "NonNegativeLengthOrPercentage": impl_style_coord, "NonNegativeNumber": impl_simple, "Number": impl_simple, "Integer": impl_simple, diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 9dcd1ff8417..972fab39ac6 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -46,6 +46,7 @@ use values::computed::{CalcLengthOrPercentage, Color, Context, ComputedValueAsSp use values::computed::{LengthOrPercentage, MaxLength, MozLength, Percentage, ToComputedValue}; use values::computed::{NonNegativeAu, NonNegativeNumber, PositiveIntegerOrAuto}; use values::computed::length::{NonNegativeLengthOrAuto, NonNegativeLengthOrNormal}; +use values::computed::length::NonNegativeLengthOrPercentage; use values::generics::{GreaterThanOrEqualToOne, NonNegative}; use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; use values::generics::effects::Filter; diff --git a/components/style/properties/longhand/padding.mako.rs b/components/style/properties/longhand/padding.mako.rs index 53035c32efb..49d9b1bd722 100644 --- a/components/style/properties/longhand/padding.mako.rs +++ b/components/style/properties/longhand/padding.mako.rs @@ -14,11 +14,10 @@ if side[1]: spec = "https://drafts.csswg.org/css-logical-props/#propdef-padding-%s" % side[1] %> - ${helpers.predefined_type("padding-%s" % side[0], "LengthOrPercentage", - "computed::LengthOrPercentage::Length(Au(0))", - "parse_non_negative", + ${helpers.predefined_type("padding-%s" % side[0], "NonNegativeLengthOrPercentage", + "computed::NonNegativeLengthOrPercentage::zero()", alias=maybe_moz_logical_alias(product, side, "-moz-padding-%s"), - animation_value_type="ComputedValue", + animation_value_type="NonNegativeLengthOrPercentage", logical = side[1], spec = spec, flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_PLACEHOLDER", diff --git a/components/style/properties/longhand/position.mako.rs b/components/style/properties/longhand/position.mako.rs index c5e06f235cd..78c94e26215 100644 --- a/components/style/properties/longhand/position.mako.rs +++ b/components/style/properties/longhand/position.mako.rs @@ -249,11 +249,10 @@ ${helpers.predefined_type("object-position", % for kind in ["row", "column"]: ${helpers.predefined_type("grid-%s-gap" % kind, - "LengthOrPercentage", - "computed::LengthOrPercentage::Length(Au(0))", - "parse_non_negative", + "NonNegativeLengthOrPercentage", + "computed::NonNegativeLengthOrPercentage::zero()", spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-gap" % kind, - animation_value_type="ComputedValue", + animation_value_type="NonNegativeLengthOrPercentage", products="gecko")} % for range in ["start", "end"]: diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 7973e7f2c0f..6e21f42f994 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -2192,10 +2192,10 @@ impl ComputedValuesInner { pub fn logical_padding(&self) -> LogicalMargin { let padding_style = self.get_padding(); LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new( - padding_style.padding_top, - padding_style.padding_right, - padding_style.padding_bottom, - padding_style.padding_left, + padding_style.padding_top.0, + padding_style.padding_right.0, + padding_style.padding_bottom.0, + padding_style.padding_left.0, )) } diff --git a/components/style/properties/shorthand/padding.mako.rs b/components/style/properties/shorthand/padding.mako.rs index 2972fb45259..592048cf56f 100644 --- a/components/style/properties/shorthand/padding.mako.rs +++ b/components/style/properties/shorthand/padding.mako.rs @@ -4,6 +4,6 @@ <%namespace name="helpers" file="/helpers.mako.rs" /> -${helpers.four_sides_shorthand("padding", "padding-%s", "specified::LengthOrPercentage::parse_non_negative", +${helpers.four_sides_shorthand("padding", "padding-%s", "specified::NonNegativeLengthOrPercentage::parse", spec="https://drafts.csswg.org/css-box-3/#propdef-padding", allow_quirks=True)} diff --git a/components/style/properties/shorthand/position.mako.rs b/components/style/properties/shorthand/position.mako.rs index acc98a990a3..f4221eae312 100644 --- a/components/style/properties/shorthand/position.mako.rs +++ b/components/style/properties/shorthand/position.mako.rs @@ -459,7 +459,7 @@ use properties::longhands::grid_auto_flow::computed_value::{AutoFlow, T as SpecifiedAutoFlow}; use values::{Either, None_}; use values::generics::grid::{GridTemplateComponent, TrackListType}; - use values::specified::{GenericGridTemplateComponent, LengthOrPercentage, TrackSize}; + use values::specified::{GenericGridTemplateComponent, NonNegativeLengthOrPercentage, TrackSize}; pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { @@ -520,8 +520,8 @@ grid_auto_columns: auto_cols, grid_auto_flow: flow, // This shorthand also resets grid gap - grid_row_gap: LengthOrPercentage::zero(), - grid_column_gap: LengthOrPercentage::zero(), + grid_row_gap: NonNegativeLengthOrPercentage::zero(), + grid_column_gap: NonNegativeLengthOrPercentage::zero(), }) } @@ -539,8 +539,8 @@ fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { // `grid` shorthand resets these properties. If they are not zero, that means they // are changed by longhands and in that case we should fail serializing `grid`. - if *self.grid_row_gap != LengthOrPercentage::zero() || - *self.grid_column_gap != LengthOrPercentage::zero() { + if *self.grid_row_gap != NonNegativeLengthOrPercentage::zero() || + *self.grid_column_gap != NonNegativeLengthOrPercentage::zero() { return Ok(()); } diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs index 2a7ab83a67b..05e828d785f 100644 --- a/components/style/values/animated/mod.rs +++ b/components/style/values/animated/mod.rs @@ -13,6 +13,7 @@ use std::cmp::max; use values::computed::Angle as ComputedAngle; use values::computed::GreaterThanOrEqualToOneNumber as ComputedGreaterThanOrEqualToOneNumber; use values::computed::NonNegativeAu; +use values::computed::NonNegativeLengthOrPercentage as ComputedNonNegativeLengthOrPercentage; use values::computed::NonNegativeNumber as ComputedNonNegativeNumber; use values::computed::PositiveInteger as ComputedPositiveInteger; use values::specified::url::SpecifiedUrl; @@ -149,6 +150,27 @@ impl ToAnimatedValue for ComputedPositiveInteger { } } +impl ToAnimatedValue for ComputedNonNegativeLengthOrPercentage { + type AnimatedValue = Self; + + #[inline] + fn to_animated_value(self) -> Self { + self + } + + #[inline] + fn from_animated_value(animated: Self::AnimatedValue) -> Self { + use values::computed::{LengthOrPercentage, Percentage}; + match animated.0 { + LengthOrPercentage::Length(au) => LengthOrPercentage::Length(max(au, Au(0))).into(), + LengthOrPercentage::Percentage(percentage) => { + LengthOrPercentage::Percentage(Percentage(percentage.0.max(0.))).into() + }, + _ => animated + } + } +} + /// Returns a value similar to `self` that represents zero. pub trait ToAnimatedZero: Sized { /// Returns a value that, when added with an underlying value, will produce the underlying diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 0f724a12c14..292292f93d6 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -12,6 +12,7 @@ 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::generics::NonNegative; use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength}; use values::specified::length::ViewportPercentageLength; @@ -551,6 +552,36 @@ impl ToComputedValue for specified::LengthOrPercentageOrNone { } } +/// A wrapper of LengthOrPercentage, whose value must be >= 0. +pub type NonNegativeLengthOrPercentage = NonNegative; + +impl From for NonNegativeLengthOrPercentage { + #[inline] + fn from(lop: LengthOrPercentage) -> Self { + NonNegative::(lop) + } +} + +impl NonNegativeLengthOrPercentage { + /// Get zero value. + #[inline] + pub fn zero() -> Self { + NonNegative::(LengthOrPercentage::zero()) + } + + /// Returns true if the computed value is absolute 0 or 0%. + #[inline] + pub fn is_definitely_zero(&self) -> bool { + self.0.is_definitely_zero() + } + + /// Returns the used value. + #[inline] + pub fn to_used_value(&self, containing_length: Au) -> Au { + self.0.to_used_value(containing_length) + } +} + /// A computed `` value. pub type Length = Au; diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 9871a8e11d2..53fa20dbf8f 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -44,6 +44,7 @@ pub use super::generics::grid::GridLine; pub use super::specified::url::SpecifiedUrl; pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNone, LengthOrNumber, LengthOrPercentage}; pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength, Percentage}; +pub use self::length::NonNegativeLengthOrPercentage; pub use self::position::Position; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray}; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing}; diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index a911ef738a5..a9675bcbd24 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -1224,6 +1224,41 @@ impl Parse for LengthOrPercentageOrNone { } } +/// A wrapper of LengthOrPercentage, whose value must be >= 0. +pub type NonNegativeLengthOrPercentage = NonNegative; + +impl From for NonNegativeLengthOrPercentage { + #[inline] + fn from(len: NoCalcLength) -> Self { + NonNegative::(LengthOrPercentage::from(len)) + } +} + +impl Parse for NonNegativeLengthOrPercentage { + #[inline] + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { + LengthOrPercentage::parse_non_negative(context, input).map(NonNegative::) + } +} + +impl NonNegativeLengthOrPercentage { + #[inline] + /// Returns a `zero` length. + pub fn zero() -> Self { + NonNegative::(LengthOrPercentage::zero()) + } + + /// Parses a length or a percentage, allowing the unitless length quirk. + /// https://quirks.spec.whatwg.org/#the-unitless-length-quirk + #[inline] + pub fn parse_quirky<'i, 't>(context: &ParserContext, + input: &mut Parser<'i, 't>, + allow_quirks: AllowQuirks) -> Result> { + LengthOrPercentage::parse_non_negative_quirky(context, input, allow_quirks) + .map(NonNegative::) + } +} + /// Either a `` or the `none` keyword. pub type LengthOrNone = Either; diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index db43432d256..bebe9750259 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -42,6 +42,7 @@ pub use self::length::{FontRelativeLength, Length, LengthOrNone, LengthOrNumber} pub use self::length::{LengthOrPercentage, LengthOrPercentageOrAuto}; pub use self::length::{LengthOrPercentageOrNone, MaxLength, MozLength}; pub use self::length::{NoCalcLength, Percentage, ViewportPercentageLength}; +pub use self::length::NonNegativeLengthOrPercentage; pub use self::rect::LengthOrNumberRect; pub use self::position::{Position, PositionComponent}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray}; diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs index 9e5f639f8e7..202bdf808a2 100644 --- a/tests/unit/style/properties/serialization.rs +++ b/tests/unit/style/properties/serialization.rs @@ -268,10 +268,12 @@ mod shorthand_serialization { #[test] fn padding_should_serialize_correctly() { + use style::values::specified::NonNegativeLengthOrPercentage; + let mut properties = Vec::new(); - let px_10 = LengthOrPercentage::Length(NoCalcLength::from_px(10f32)); - let px_15 = LengthOrPercentage::Length(NoCalcLength::from_px(15f32)); + let px_10: NonNegativeLengthOrPercentage = NoCalcLength::from_px(10f32).into(); + let px_15: NonNegativeLengthOrPercentage = NoCalcLength::from_px(15f32).into(); properties.push(PropertyDeclaration::PaddingTop(px_10.clone())); properties.push(PropertyDeclaration::PaddingRight(px_15.clone())); properties.push(PropertyDeclaration::PaddingBottom(px_10));