--- a/servo/components/style/gecko/values.rs
+++ b/servo/components/style/gecko/values.rs
@@ -14,16 +14,17 @@ use gecko_bindings::structs::{StyleGridT
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, NonNegativeAu};
use values::computed::{MaxLength, MozLength, Percentage};
+use values::computed::NonNegativeLengthOrPercentage;
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.
pub trait GeckoStyleCoordConvertible : Sized {
@@ -116,16 +117,26 @@ impl GeckoStyleCoordConvertible for Leng
CoordDataValue::Coord(coord) => Some(LengthOrPercentage::Length(Au(coord))),
CoordDataValue::Percent(p) => Some(LengthOrPercentage::Percentage(Percentage(p))),
CoordDataValue::Calc(calc) => Some(LengthOrPercentage::Calc(calc.into())),
_ => None,
}
}
}
+impl GeckoStyleCoordConvertible for NonNegativeLengthOrPercentage {
+ 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> {
+ LengthOrPercentage::from_gecko_style_coord(coord).map(NonNegativeLengthOrPercentage)
+ }
+}
+
impl GeckoStyleCoordConvertible for Au {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
coord.set_value(CoordDataValue::Coord(self.0));
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
match coord.as_value() {
CoordDataValue::Coord(coord) => Some(Au(coord)),
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -917,16 +917,17 @@ impl Clone for ${style_struct.gecko_stru
"Position": impl_position,
"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,
+ "NonNegativeLengthOrPercentage": impl_style_coord,
"NonNegativeNumber": impl_simple_wrapper,
"Number": impl_simple,
"Integer": impl_simple,
"Opacity": impl_simple,
"Color": impl_color,
"RGBAColor": impl_rgba_color,
"SVGPaint": impl_svg_paint,
"UrlOrNone": impl_css_url,
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -43,17 +43,17 @@ use values::animated::effects::FilterLis
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::{PositiveInteger, PositiveIntegerOrAuto};
use values::computed::length::{NonNegativeLengthOrAuto, NonNegativeLengthOrNormal};
-use values::computed::length::NonNegativeLengthOrNumber;
+use values::computed::length::{NonNegativeLengthOrNumber, NonNegativeLengthOrPercentage};
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
@@ -1228,16 +1228,36 @@ impl Animatable for LengthOrPercentage {
impl ToAnimatedZero for LengthOrPercentage {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(LengthOrPercentage::zero())
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
+impl Animatable for NonNegativeLengthOrPercentage {
+ #[inline]
+ fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+ self.0.add_weighted(&other.0, self_portion, other_portion).map(NonNegativeLengthOrPercentage)
+ }
+
+ #[inline]
+ fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
+ self.0.compute_distance(&other.0)
+ }
+}
+
+impl ToAnimatedZero for NonNegativeLengthOrPercentage {
+ #[inline]
+ fn to_animated_zero(&self) -> Result<Self, ()> {
+ Ok(NonNegativeLengthOrPercentage::zero())
+ }
+}
+
+/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
impl Animatable for LengthOrPercentageOrAuto {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(LengthOrPercentageOrAuto::Length(ref this),
LengthOrPercentageOrAuto::Length(ref other)) => {
this.add_weighted(other, self_portion, other_portion)
.map(LengthOrPercentageOrAuto::Length)
--- a/servo/components/style/properties/longhand/padding.mako.rs
+++ b/servo/components/style/properties/longhand/padding.mako.rs
@@ -9,18 +9,17 @@
// APPLIES_TO_PLACEHOLDER so we can set it in UA stylesheets. But we use a
// !important value there, so pages can't set it.
% for side in ALL_SIDES:
<%
spec = "https://drafts.csswg.org/css-box/#propdef-padding-%s" % side[0]
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",
allow_quirks=not side[1])}
% endfor
--- a/servo/components/style/properties/longhand/position.mako.rs
+++ b/servo/components/style/properties/longhand/position.mako.rs
@@ -244,21 +244,20 @@ macro_rules! impl_align_conversions {
"computed::Position::zero()",
products="gecko",
boxed="True",
spec="https://drafts.csswg.org/css-images-3/#the-object-position",
animation_value_type="ComputedValue")}
% 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"]:
${helpers.predefined_type("grid-%s-%s" % (kind, range),
"GridLine",
"Default::default()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-%s" % (kind, range),
--- a/servo/components/style/properties/shorthand/padding.mako.rs
+++ b/servo/components/style/properties/shorthand/padding.mako.rs
@@ -1,9 +1,9 @@
/* 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/. */
<%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)}
--- a/servo/components/style/properties/shorthand/position.mako.rs
+++ b/servo/components/style/properties/shorthand/position.mako.rs
@@ -454,17 +454,17 @@
spec="https://drafts.csswg.org/css-grid/#propdef-grid"
disable_when_testing="True"
products="gecko">
use parser::Parse;
use properties::longhands::{grid_auto_columns, grid_auto_rows, grid_auto_flow};
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<Longhands, ParseError<'i>> {
let mut temp_rows = GridTemplateComponent::None;
let mut temp_cols = GridTemplateComponent::None;
let mut temp_areas = Either::Second(None_);
let mut auto_rows = TrackSize::default();
let mut auto_cols = TrackSize::default();
@@ -515,18 +515,18 @@
Ok(expanded! {
grid_template_rows: temp_rows,
grid_template_columns: temp_cols,
grid_template_areas: temp_areas,
grid_auto_rows: auto_rows,
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(),
})
}
impl<'a> LonghandsToSerialize<'a> {
/// Returns true if other sub properties except template-{rows,columns} are initial.
fn is_grid_template(&self) -> bool {
*self.grid_template_areas == Either::Second(None_) &&
*self.grid_auto_rows == TrackSize::default() &&
@@ -534,18 +534,18 @@
*self.grid_auto_flow == grid_auto_flow::get_initial_value()
}
}
impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&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(());
}
if *self.grid_template_areas != Either::Second(None_) ||
(*self.grid_template_rows != GridTemplateComponent::None &&
*self.grid_template_columns != GridTemplateComponent::None) ||
self.is_grid_template() {
--- a/servo/components/style/values/animated/mod.rs
+++ b/servo/components/style/values/animated/mod.rs
@@ -9,16 +9,17 @@
//! module's raison d'ĂȘtre is to ultimately contain all these types.
use app_units::Au;
use values::computed::Angle as ComputedAngle;
use values::computed::NonNegativeAu;
use values::computed::NonNegativeNumber as ComputedNonNegativeNumber;
use values::computed::GreaterThanOrEqualToOneNumber as ComputedGreaterThanOrEqualToOneNumber;
use values::computed::PositiveInteger as ComputedPositiveInteger;
+use values::computed::NonNegativeLengthOrPercentage as ComputedNonNegativeLengthOrPercentage;
use values::specified::url::SpecifiedUrl;
pub mod effects;
/// Conversion between computed values and intermediate values for animations.
///
/// Notably, colors are represented as four floats during animations.
pub trait ToAnimatedValue {
@@ -143,16 +144,41 @@ impl ToAnimatedValue for ComputedPositiv
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated.max(ComputedPositiveInteger(1))
}
}
+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) => {
+ ComputedNonNegativeLengthOrPercentage(
+ LengthOrPercentage::Length(Au(::std::cmp::max(au.0, 0))))
+ },
+ LengthOrPercentage::Percentage(percentage) => {
+ ComputedNonNegativeLengthOrPercentage(
+ LengthOrPercentage::Percentage(Percentage(percentage.0.max(0.))))
+ },
+ _ => 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
/// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from
/// the zero value to the 'by' value, and then adds the result to the underlying value.
///
/// This is not the necessarily the same as the initial value of a property. For example, the
/// initial value of 'stroke-width' is 1, but the zero value is 0, since adding 1 to the
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -547,16 +547,42 @@ impl ToComputedValue for specified::Leng
specified::LengthOrPercentageOrNone::Calc(
Box::new(ToComputedValue::from_computed_value(&calc))
)
}
}
}
}
+/// A wrapper of LengthOrPercentage, whose value must be >= 0.
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Clone, Copy, PartialEq, Debug, ToCss)]
+pub struct NonNegativeLengthOrPercentage(pub LengthOrPercentage);
+
+impl ToComputedValue for specified::length::NonNegativeLengthOrPercentage {
+ type ComputedValue = NonNegativeLengthOrPercentage;
+
+ fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+ NonNegativeLengthOrPercentage(self.0.to_computed_value(context))
+ }
+
+ fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+ specified::length::NonNegativeLengthOrPercentage(
+ ToComputedValue::from_computed_value(&computed.0))
+ }
+}
+
+impl NonNegativeLengthOrPercentage {
+ /// Get zero value.
+ #[inline]
+ pub fn zero() -> Self {
+ NonNegativeLengthOrPercentage(LengthOrPercentage::zero())
+ }
+}
+
/// 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/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -38,16 +38,17 @@ pub use self::rect::LengthOrNumberRect;
pub use super::{Auto, Either, None_};
#[cfg(feature = "gecko")]
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
pub use super::specified::{BorderStyle, UrlOrNone};
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::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing};
pub use self::transform::{TimingFunction, TransformOrigin};
pub mod background;
pub mod basic_shape;
pub mod border;
pub mod color;
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -1193,16 +1193,53 @@ impl LengthOrPercentageOrNone {
impl Parse for LengthOrPercentageOrNone {
#[inline]
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_internal(context, input, AllowedLengthType::All, AllowQuirks::No)
}
}
+/// A wrapper of LengthOrPercentage, whose value must be >= 0.
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
+pub struct NonNegativeLengthOrPercentage(pub LengthOrPercentage);
+
+impl From<NoCalcLength> for NonNegativeLengthOrPercentage {
+ #[inline]
+ fn from(len: NoCalcLength) -> Self {
+ NonNegativeLengthOrPercentage(LengthOrPercentage::Length(len))
+ }
+}
+
+impl Parse for NonNegativeLengthOrPercentage {
+ #[inline]
+ fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
+ LengthOrPercentage::parse_non_negative(context, input).map(NonNegativeLengthOrPercentage)
+ }
+}
+
+impl NonNegativeLengthOrPercentage {
+ #[inline]
+ /// Returns a `zero` length.
+ pub fn zero() -> Self {
+ NonNegativeLengthOrPercentage(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<Self, ParseError<'i>> {
+ LengthOrPercentage::parse_non_negative_quirky(context, input, allow_quirks)
+ .map(NonNegativeLengthOrPercentage)
+ }
+}
+
/// 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>;
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -37,16 +37,17 @@ pub use self::flex::FlexBasis;
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::length::{AbsoluteLength, CalcLengthOrPercentage, CharacterWidth};
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::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing};
pub use self::transform::{TimingFunction, TransformOrigin};
pub use super::generics::grid::GridLine;
pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
#[cfg(feature = "gecko")]