style: Use NonNegative more in the border code.

This ended up not being so small of a patch as I'd have thought, since it
propagated a bit. But most of it is mechanical. Interesting part is
NonNegativeNumberOrPercentage and the actual uses of the NonNegative stuff and
during parsing.

This looks like it'd fix a few correctness issues during interpolation for all
the types except for BorderRadius and co (which handled it manually).

I should write tests for those in a different patch.

Differential Revision: https://phabricator.services.mozilla.com/D14673
This commit is contained in:
Emilio Cobos Álvarez 2018-12-17 21:35:14 +00:00
parent 19035590ce
commit ca1ad003bd
14 changed files with 161 additions and 106 deletions

View file

@ -5,6 +5,8 @@
//! This module contains conversion helpers between Servo and Gecko types //! This module contains conversion helpers between Servo and Gecko types
//! Ideally, it would be in geckolib itself, but coherence //! Ideally, it would be in geckolib itself, but coherence
//! forces us to keep the traits and implementations here //! forces us to keep the traits and implementations here
//!
//! FIXME(emilio): This file should generally just die.
#![allow(unsafe_code)] #![allow(unsafe_code)]
@ -22,6 +24,7 @@ use crate::values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image};
use crate::values::computed::{Integer, LengthOrPercentage}; use crate::values::computed::{Integer, LengthOrPercentage};
use crate::values::computed::{LengthOrPercentageOrAuto, NonNegativeLengthOrPercentageOrAuto}; use crate::values::computed::{LengthOrPercentageOrAuto, NonNegativeLengthOrPercentageOrAuto};
use crate::values::computed::{Percentage, TextAlign}; use crate::values::computed::{Percentage, TextAlign};
use crate::values::generics::NonNegative;
use crate::values::generics::box_::VerticalAlign; use crate::values::generics::box_::VerticalAlign;
use crate::values::generics::grid::{TrackListValue, TrackSize}; use crate::values::generics::grid::{TrackListValue, TrackSize};
use crate::values::generics::image::{CompatMode, GradientItem, Image as GenericImage}; use crate::values::generics::image::{CompatMode, GradientItem, Image as GenericImage};
@ -113,7 +116,6 @@ impl From<nsStyleCoord_CalcValue> for LengthOrPercentageOrAuto {
// disappear as we move more stuff to cbindgen. // disappear as we move more stuff to cbindgen.
impl From<nsStyleCoord_CalcValue> for NonNegativeLengthOrPercentageOrAuto { impl From<nsStyleCoord_CalcValue> for NonNegativeLengthOrPercentageOrAuto {
fn from(other: nsStyleCoord_CalcValue) -> Self { fn from(other: nsStyleCoord_CalcValue) -> Self {
use crate::values::generics::NonNegative;
use style_traits::values::specified::AllowedNumericType; use style_traits::values::specified::AllowedNumericType;
NonNegative(if other.mLength < 0 || other.mPercent < 0. { NonNegative(if other.mLength < 0 || other.mPercent < 0. {
LengthOrPercentageOrAuto::Calc(CalcLengthOrPercentage::with_clamping_mode( LengthOrPercentageOrAuto::Calc(CalcLengthOrPercentage::with_clamping_mode(
@ -675,6 +677,7 @@ pub mod basic_shape {
use crate::values::generics::basic_shape::{ use crate::values::generics::basic_shape::{
BasicShape as GenericBasicShape, InsetRect, Polygon, BasicShape as GenericBasicShape, InsetRect, Polygon,
}; };
use crate::values::generics::NonNegative;
use crate::values::generics::basic_shape::{Circle, Ellipse, Path, PolygonCoord}; use crate::values::generics::basic_shape::{Circle, Ellipse, Path, PolygonCoord};
use crate::values::generics::basic_shape::{GeometryBox, ShapeBox, ShapeSource}; use crate::values::generics::basic_shape::{GeometryBox, ShapeBox, ShapeSource};
use crate::values::generics::border::BorderRadius as GenericBorderRadius; use crate::values::generics::border::BorderRadius as GenericBorderRadius;
@ -838,10 +841,10 @@ pub mod basic_shape {
fn from(other: &'a nsStyleCorners) -> Self { fn from(other: &'a nsStyleCorners) -> Self {
let get_corner = |index| { let get_corner = |index| {
BorderCornerRadius::new( BorderCornerRadius::new(
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index)) NonNegative(LengthOrPercentage::from_gecko_style_coord(&other.data_at(index))
.expect("<border-radius> should be a length, percentage, or calc value"), .expect("<border-radius> should be a length, percentage, or calc value")),
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1)) NonNegative(LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1))
.expect("<border-radius> should be a length, percentage, or calc value"), .expect("<border-radius> should be a length, percentage, or calc value")),
) )
}; };

View file

@ -1687,8 +1687,8 @@ fn static_assert() {
pub fn clone_border_image_slice(&self) -> longhands::border_image_slice::computed_value::T { pub fn clone_border_image_slice(&self) -> longhands::border_image_slice::computed_value::T {
use crate::gecko_bindings::structs::NS_STYLE_BORDER_IMAGE_SLICE_FILL; use crate::gecko_bindings::structs::NS_STYLE_BORDER_IMAGE_SLICE_FILL;
use crate::values::computed::{BorderImageSlice, NumberOrPercentage}; use crate::values::computed::{BorderImageSlice, NonNegativeNumberOrPercentage};
type NumberOrPercentageRect = crate::values::generics::rect::Rect<NumberOrPercentage>; type NumberOrPercentageRect = crate::values::generics::rect::Rect<NonNegativeNumberOrPercentage>;
BorderImageSlice { BorderImageSlice {
offsets: offsets:

View file

@ -153,14 +153,15 @@ ${helpers.predefined_type(
${helpers.predefined_type( ${helpers.predefined_type(
"border-image-slice", "border-image-slice",
"BorderImageSlice", "BorderImageSlice",
initial_value="computed::NumberOrPercentage::Percentage(computed::Percentage(1.)).into()", initial_value="computed::BorderImageSlice::hundred_percent()",
initial_specified_value="specified::NumberOrPercentage::Percentage(specified::Percentage::new(1.)).into()", initial_specified_value="specified::BorderImageSlice::hundred_percent()",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice", spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",
animation_value_type="discrete", animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER", flags="APPLIES_TO_FIRST_LETTER",
boxed=True, boxed=True,
)} )}
// FIXME(emilio): Why does this live here? ;_;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl crate::values::computed::BorderImageWidth { impl crate::values::computed::BorderImageWidth {
pub fn to_gecko_rect(&self, sides: &mut crate::gecko_bindings::structs::nsStyleSides) { pub fn to_gecko_rect(&self, sides: &mut crate::gecko_bindings::structs::nsStyleSides) {
@ -177,7 +178,7 @@ impl crate::values::computed::BorderImageWidth {
l.to_gecko_style_coord(&mut sides.data_at_mut(${i})) l.to_gecko_style_coord(&mut sides.data_at_mut(${i}))
}, },
BorderImageSideWidth::Number(n) => { BorderImageSideWidth::Number(n) => {
sides.data_at_mut(${i}).set_value(CoordDataValue::Factor(n)) sides.data_at_mut(${i}).set_value(CoordDataValue::Factor(n.0))
}, },
} }
% endfor % endfor
@ -191,6 +192,7 @@ impl crate::values::computed::BorderImageWidth {
use crate::gecko::values::GeckoStyleCoordConvertible; use crate::gecko::values::GeckoStyleCoordConvertible;
use crate::values::computed::{LengthOrPercentage, Number}; use crate::values::computed::{LengthOrPercentage, Number};
use crate::values::generics::border::BorderImageSideWidth; use crate::values::generics::border::BorderImageSideWidth;
use crate::values::generics::NonNegative;
Some( Some(
crate::values::computed::BorderImageWidth::new( crate::values::computed::BorderImageWidth::new(
@ -201,13 +203,13 @@ impl crate::values::computed::BorderImageWidth {
}, },
eStyleUnit_Factor => { eStyleUnit_Factor => {
BorderImageSideWidth::Number( BorderImageSideWidth::Number(
Number::from_gecko_style_coord(&sides.data_at(${i})) NonNegative(Number::from_gecko_style_coord(&sides.data_at(${i}))
.expect("sides[${i}] could not convert to Number")) .expect("sides[${i}] could not convert to Number")))
}, },
_ => { _ => {
BorderImageSideWidth::Length( BorderImageSideWidth::Length(
LengthOrPercentage::from_gecko_style_coord(&sides.data_at(${i})) NonNegative(LengthOrPercentage::from_gecko_style_coord(&sides.data_at(${i}))
.expect("sides[${i}] could not convert to LengthOrPercentager")) .expect("sides[${i}] could not convert to LengthOrPercentage")))
}, },
}, },
% endfor % endfor

View file

@ -295,7 +295,7 @@ ${helpers.predefined_type(
"-webkit-text-stroke-width", "-webkit-text-stroke-width",
"BorderSideWidth", "BorderSideWidth",
"crate::values::computed::NonNegativeLength::new(0.)", "crate::values::computed::NonNegativeLength::new(0.)",
initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())", initial_specified_value="specified::BorderSideWidth::zero()",
computed_type="crate::values::computed::NonNegativeLength", computed_type="crate::values::computed::NonNegativeLength",
products="gecko", products="gecko",
gecko_pref="layout.css.prefixes.webkit", gecko_pref="layout.css.prefixes.webkit",

View file

@ -12,7 +12,6 @@ use crate::properties::PropertyId;
use crate::values::computed::length::CalcLengthOrPercentage; use crate::values::computed::length::CalcLengthOrPercentage;
use crate::values::computed::url::ComputedUrl; use crate::values::computed::url::ComputedUrl;
use crate::values::computed::Angle as ComputedAngle; use crate::values::computed::Angle as ComputedAngle;
use crate::values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
use crate::values::CSSFloat; use crate::values::CSSFloat;
use app_units::Au; use app_units::Au;
use euclid::{Point2D, Size2D}; use euclid::{Point2D, Size2D};
@ -340,23 +339,6 @@ trivial_to_animated_value!(ComputedUrl);
trivial_to_animated_value!(bool); trivial_to_animated_value!(bool);
trivial_to_animated_value!(f32); trivial_to_animated_value!(f32);
impl ToAnimatedValue for ComputedBorderCornerRadius {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
ComputedBorderCornerRadius::new(
(animated.0).0.width.clamp_to_non_negative(),
(animated.0).0.height.clamp_to_non_negative(),
)
}
}
impl ToAnimatedZero for Au { impl ToAnimatedZero for Au {
#[inline] #[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { fn to_animated_zero(&self) -> Result<Self, ()> {

View file

@ -8,7 +8,7 @@
//! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape //! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape
use crate::values::computed::url::ComputedUrl; use crate::values::computed::url::ComputedUrl;
use crate::values::computed::{Image, LengthOrPercentage}; use crate::values::computed::{Image, LengthOrPercentage, NonNegativeLengthOrPercentage};
use crate::values::generics::basic_shape as generic; use crate::values::generics::basic_shape as generic;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, ToCss};
@ -24,10 +24,10 @@ pub type FloatAreaShape = generic::FloatAreaShape<BasicShape, Image>;
/// A computed basic shape. /// A computed basic shape.
pub type BasicShape = pub type BasicShape =
generic::BasicShape<LengthOrPercentage, LengthOrPercentage, LengthOrPercentage>; generic::BasicShape<LengthOrPercentage, LengthOrPercentage, LengthOrPercentage, NonNegativeLengthOrPercentage>;
/// The computed value of `inset()` /// The computed value of `inset()`
pub type InsetRect = generic::InsetRect<LengthOrPercentage>; pub type InsetRect = generic::InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage>;
/// A computed circle. /// A computed circle.
pub type Circle = generic::Circle<LengthOrPercentage, LengthOrPercentage, LengthOrPercentage>; pub type Circle = generic::Circle<LengthOrPercentage, LengthOrPercentage, LengthOrPercentage>;

View file

@ -4,9 +4,9 @@
//! Computed types for CSS values related to borders. //! Computed types for CSS values related to borders.
use crate::values::animated::ToAnimatedZero; use crate::values::generics::NonNegative;
use crate::values::computed::length::{LengthOrPercentage, NonNegativeLength}; use crate::values::computed::length::{NonNegativeLengthOrPercentage, NonNegativeLength};
use crate::values::computed::{Number, NumberOrPercentage}; use crate::values::computed::{NonNegativeNumber, NonNegativeNumberOrPercentage};
use crate::values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; use crate::values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use crate::values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth; use crate::values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
use crate::values::generics::border::BorderImageSlice as GenericBorderImageSlice; use crate::values::generics::border::BorderImageSlice as GenericBorderImageSlice;
@ -22,16 +22,16 @@ pub use crate::values::specified::border::BorderImageRepeat;
pub type BorderImageWidth = Rect<BorderImageSideWidth>; pub type BorderImageWidth = Rect<BorderImageSideWidth>;
/// A computed value for a single side of a `border-image-width` property. /// A computed value for a single side of a `border-image-width` property.
pub type BorderImageSideWidth = GenericBorderImageSideWidth<LengthOrPercentage, Number>; pub type BorderImageSideWidth = GenericBorderImageSideWidth<NonNegativeLengthOrPercentage, NonNegativeNumber>;
/// A computed value for the `border-image-slice` property. /// A computed value for the `border-image-slice` property.
pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>; pub type BorderImageSlice = GenericBorderImageSlice<NonNegativeNumberOrPercentage>;
/// A computed value for the `border-radius` property. /// A computed value for the `border-radius` property.
pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>; pub type BorderRadius = GenericBorderRadius<NonNegativeLengthOrPercentage>;
/// A computed value for the `border-*-radius` longhand properties. /// A computed value for the `border-*-radius` longhand properties.
pub type BorderCornerRadius = GenericBorderCornerRadius<LengthOrPercentage>; pub type BorderCornerRadius = GenericBorderCornerRadius<NonNegativeLengthOrPercentage>;
/// A computed value for the `border-spacing` longhand property. /// A computed value for the `border-spacing` longhand property.
pub type BorderSpacing = GenericBorderSpacing<NonNegativeLength>; pub type BorderSpacing = GenericBorderSpacing<NonNegativeLength>;
@ -40,7 +40,18 @@ impl BorderImageSideWidth {
/// Returns `1`. /// Returns `1`.
#[inline] #[inline]
pub fn one() -> Self { pub fn one() -> Self {
GenericBorderImageSideWidth::Number(1.) GenericBorderImageSideWidth::Number(NonNegative(1.))
}
}
impl BorderImageSlice {
/// Returns the `100%` value.
#[inline]
pub fn hundred_percent() -> Self {
GenericBorderImageSlice {
offsets: Rect::all(NonNegativeNumberOrPercentage::hundred_percent()),
fill: false,
}
} }
} }
@ -68,26 +79,18 @@ impl BorderCornerRadius {
/// Returns `0 0`. /// Returns `0 0`.
pub fn zero() -> Self { pub fn zero() -> Self {
GenericBorderCornerRadius(Size::new( GenericBorderCornerRadius(Size::new(
LengthOrPercentage::zero(), NonNegativeLengthOrPercentage::zero(),
LengthOrPercentage::zero(), NonNegativeLengthOrPercentage::zero(),
)) ))
} }
} }
impl ToAnimatedZero for BorderCornerRadius {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
// FIXME(nox): Why?
Err(())
}
}
impl BorderRadius { impl BorderRadius {
/// Returns whether all the values are `0px`. /// Returns whether all the values are `0px`.
pub fn all_zero(&self) -> bool { pub fn all_zero(&self) -> bool {
fn all(corner: &BorderCornerRadius) -> bool { fn all(corner: &BorderCornerRadius) -> bool {
fn is_zero(l: &LengthOrPercentage) -> bool { fn is_zero(l: &NonNegativeLengthOrPercentage) -> bool {
*l == LengthOrPercentage::zero() *l == NonNegativeLengthOrPercentage::zero()
} }
is_zero(corner.0.width()) && is_zero(corner.0.height()) is_zero(corner.0.width()) && is_zero(corner.0.height())
} }

View file

@ -543,6 +543,15 @@ pub enum NumberOrPercentage {
Number(Number), Number(Number),
} }
impl NumberOrPercentage {
fn clamp_to_non_negative(self) -> Self {
match self {
NumberOrPercentage::Percentage(p) => NumberOrPercentage::Percentage(p.clamp_to_non_negative()),
NumberOrPercentage::Number(n) => NumberOrPercentage::Number(n.max(0.)),
}
}
}
impl ToComputedValue for specified::NumberOrPercentage { impl ToComputedValue for specified::NumberOrPercentage {
type ComputedValue = NumberOrPercentage; type ComputedValue = NumberOrPercentage;
@ -572,6 +581,31 @@ impl ToComputedValue for specified::NumberOrPercentage {
} }
} }
/// A non-negative <number-percentage>.
pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>;
impl NonNegativeNumberOrPercentage {
/// Returns the `100%` value.
#[inline]
pub fn hundred_percent() -> Self {
NonNegative(NumberOrPercentage::Percentage(Percentage::hundred()))
}
}
impl ToAnimatedValue for NonNegativeNumberOrPercentage {
type AnimatedValue = NumberOrPercentage;
#[inline]
fn to_animated_value(self) -> Self::AnimatedValue {
self.0
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
NonNegative(animated.clamp_to_non_negative())
}
}
/// A type used for opacity. /// A type used for opacity.
pub type Opacity = CSSFloat; pub type Opacity = CSSFloat;

View file

@ -85,8 +85,8 @@ pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> {
ToComputedValue, ToComputedValue,
ToCss, ToCss,
)] )]
pub enum BasicShape<H, V, LengthOrPercentage> { pub enum BasicShape<H, V, LengthOrPercentage, NonNegativeLengthOrPercentage> {
Inset(#[css(field_bound)] InsetRect<LengthOrPercentage>), Inset(#[css(field_bound)] InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage>),
Circle(#[css(field_bound)] Circle<H, V, LengthOrPercentage>), Circle(#[css(field_bound)] Circle<H, V, LengthOrPercentage>),
Ellipse(#[css(field_bound)] Ellipse<H, V, LengthOrPercentage>), Ellipse(#[css(field_bound)] Ellipse<H, V, LengthOrPercentage>),
Polygon(Polygon<LengthOrPercentage>), Polygon(Polygon<LengthOrPercentage>),
@ -105,9 +105,9 @@ pub enum BasicShape<H, V, LengthOrPercentage> {
SpecifiedValueInfo, SpecifiedValueInfo,
ToComputedValue, ToComputedValue,
)] )]
pub struct InsetRect<LengthOrPercentage> { pub struct InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage> {
pub rect: Rect<LengthOrPercentage>, pub rect: Rect<LengthOrPercentage>,
pub round: Option<BorderRadius<LengthOrPercentage>>, pub round: Option<BorderRadius<NonNegativeLengthOrPercentage>>,
} }
/// <https://drafts.csswg.org/css-shapes/#funcdef-circle> /// <https://drafts.csswg.org/css-shapes/#funcdef-circle>
@ -258,9 +258,10 @@ impl<B, T, U> ToAnimatedZero for ShapeSource<B, T, U> {
} }
} }
impl<L> ToCss for InsetRect<L> impl<Length, NonNegativeLength> ToCss for InsetRect<Length, NonNegativeLength>
where where
L: ToCss + PartialEq, Length: ToCss + PartialEq,
NonNegativeLength: ToCss + PartialEq,
{ {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where where

View file

@ -45,6 +45,8 @@ pub struct BorderImageSlice<NumberOrPercentage> {
MallocSizeOf, MallocSizeOf,
PartialEq, PartialEq,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue, ToComputedValue,
ToCss, ToCss,
)] )]
@ -106,19 +108,6 @@ pub struct BorderRadius<LengthOrPercentage> {
pub bottom_left: BorderCornerRadius<LengthOrPercentage>, pub bottom_left: BorderCornerRadius<LengthOrPercentage>,
} }
impl<N> From<N> for BorderImageSlice<N>
where
N: Clone,
{
#[inline]
fn from(value: N) -> Self {
Self {
offsets: Rect::all(value),
fill: false,
}
}
}
impl<L> BorderRadius<L> { impl<L> BorderRadius<L> {
/// Returns a new `BorderRadius<L>`. /// Returns a new `BorderRadius<L>`.
#[inline] #[inline]

View file

@ -16,7 +16,7 @@ use crate::values::specified::border::BorderRadius;
use crate::values::specified::image::Image; use crate::values::specified::image::Image;
use crate::values::specified::position::{HorizontalPosition, Position, VerticalPosition}; use crate::values::specified::position::{HorizontalPosition, Position, VerticalPosition};
use crate::values::specified::url::SpecifiedUrl; use crate::values::specified::url::SpecifiedUrl;
use crate::values::specified::LengthOrPercentage; use crate::values::specified::{LengthOrPercentage, NonNegativeLengthOrPercentage};
use crate::values::specified::SVGPathData; use crate::values::specified::SVGPathData;
use cssparser::Parser; use cssparser::Parser;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
@ -32,10 +32,10 @@ pub type ClippingShape = generic::ClippingShape<BasicShape, SpecifiedUrl>;
pub type FloatAreaShape = generic::FloatAreaShape<BasicShape, Image>; pub type FloatAreaShape = generic::FloatAreaShape<BasicShape, Image>;
/// A specified basic shape. /// A specified basic shape.
pub type BasicShape = generic::BasicShape<HorizontalPosition, VerticalPosition, LengthOrPercentage>; pub type BasicShape = generic::BasicShape<HorizontalPosition, VerticalPosition, LengthOrPercentage, NonNegativeLengthOrPercentage>;
/// The specified value of `inset()` /// The specified value of `inset()`
pub type InsetRect = generic::InsetRect<LengthOrPercentage>; pub type InsetRect = generic::InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage>;
/// A specified circle. /// A specified circle.
pub type Circle = generic::Circle<HorizontalPosition, VerticalPosition, LengthOrPercentage>; pub type Circle = generic::Circle<HorizontalPosition, VerticalPosition, LengthOrPercentage>;
@ -199,10 +199,7 @@ impl InsetRect {
} else { } else {
None None
}; };
Ok(generic::InsetRect { Ok(generic::InsetRect { rect, round })
rect: rect,
round: round,
})
} }
} }

View file

@ -13,8 +13,8 @@ use crate::values::generics::border::BorderRadius as GenericBorderRadius;
use crate::values::generics::border::BorderSpacing as GenericBorderSpacing; use crate::values::generics::border::BorderSpacing as GenericBorderSpacing;
use crate::values::generics::rect::Rect; use crate::values::generics::rect::Rect;
use crate::values::generics::size::Size; use crate::values::generics::size::Size;
use crate::values::specified::length::{Length, LengthOrPercentage, NonNegativeLength}; use crate::values::specified::length::{NonNegativeLengthOrPercentage, NonNegativeLength};
use crate::values::specified::{AllowQuirks, Number, NumberOrPercentage}; use crate::values::specified::{AllowQuirks, NonNegativeNumber, NonNegativeNumberOrPercentage};
use cssparser::Parser; use cssparser::Parser;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss}; use style_traits::{CssWriter, ParseError, ToCss};
@ -71,28 +71,45 @@ pub enum BorderSideWidth {
/// `thick` /// `thick`
Thick, Thick,
/// `<length>` /// `<length>`
Length(Length), Length(NonNegativeLength),
} }
/// A specified value for the `border-image-width` property. /// A specified value for the `border-image-width` property.
pub type BorderImageWidth = Rect<BorderImageSideWidth>; pub type BorderImageWidth = Rect<BorderImageSideWidth>;
/// A specified value for a single side of a `border-image-width` property. /// A specified value for a single side of a `border-image-width` property.
pub type BorderImageSideWidth = GenericBorderImageSideWidth<LengthOrPercentage, Number>; pub type BorderImageSideWidth = GenericBorderImageSideWidth<NonNegativeLengthOrPercentage, NonNegativeNumber>;
/// A specified value for the `border-image-slice` property. /// A specified value for the `border-image-slice` property.
pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>; pub type BorderImageSlice = GenericBorderImageSlice<NonNegativeNumberOrPercentage>;
/// A specified value for the `border-radius` property. /// A specified value for the `border-radius` property.
pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>; pub type BorderRadius = GenericBorderRadius<NonNegativeLengthOrPercentage>;
/// A specified value for the `border-*-radius` longhand properties. /// A specified value for the `border-*-radius` longhand properties.
pub type BorderCornerRadius = GenericBorderCornerRadius<LengthOrPercentage>; pub type BorderCornerRadius = GenericBorderCornerRadius<NonNegativeLengthOrPercentage>;
/// A specified value for the `border-spacing` longhand properties. /// A specified value for the `border-spacing` longhand properties.
pub type BorderSpacing = GenericBorderSpacing<NonNegativeLength>; pub type BorderSpacing = GenericBorderSpacing<NonNegativeLength>;
impl BorderImageSlice {
/// Returns the `100%` value.
#[inline]
pub fn hundred_percent() -> Self {
GenericBorderImageSlice {
offsets: Rect::all(NonNegativeNumberOrPercentage::hundred_percent()),
fill: false,
}
}
}
impl BorderSideWidth { impl BorderSideWidth {
/// Returns the `0px` value.
#[inline]
pub fn zero() -> Self {
BorderSideWidth::Length(NonNegativeLength::zero())
}
/// Parses, with quirks. /// Parses, with quirks.
pub fn parse_quirky<'i, 't>( pub fn parse_quirky<'i, 't>(
context: &ParserContext, context: &ParserContext,
@ -100,7 +117,7 @@ impl BorderSideWidth {
allow_quirks: AllowQuirks, allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
if let Ok(length) = if let Ok(length) =
input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks)) input.try(|i| NonNegativeLength::parse_quirky(context, i, allow_quirks))
{ {
return Ok(BorderSideWidth::Length(length)); return Ok(BorderSideWidth::Length(length));
} }
@ -130,9 +147,9 @@ impl ToComputedValue for BorderSideWidth {
// Spec: https://drafts.csswg.org/css-backgrounds-3/#line-width // Spec: https://drafts.csswg.org/css-backgrounds-3/#line-width
// Gecko: https://bugzilla.mozilla.org/show_bug.cgi?id=1312155#c0 // Gecko: https://bugzilla.mozilla.org/show_bug.cgi?id=1312155#c0
match *self { match *self {
BorderSideWidth::Thin => Length::from_px(1.).to_computed_value(context), BorderSideWidth::Thin => NonNegativeLength::from_px(1.).to_computed_value(context),
BorderSideWidth::Medium => Length::from_px(3.).to_computed_value(context), BorderSideWidth::Medium => NonNegativeLength::from_px(3.).to_computed_value(context),
BorderSideWidth::Thick => Length::from_px(5.).to_computed_value(context), BorderSideWidth::Thick => NonNegativeLength::from_px(5.).to_computed_value(context),
BorderSideWidth::Length(ref length) => length.to_computed_value(context), BorderSideWidth::Length(ref length) => length.to_computed_value(context),
} }
.into() .into()
@ -140,7 +157,7 @@ impl ToComputedValue for BorderSideWidth {
#[inline] #[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self { fn from_computed_value(computed: &Self::ComputedValue) -> Self {
BorderSideWidth::Length(ToComputedValue::from_computed_value(&computed.0)) BorderSideWidth::Length(ToComputedValue::from_computed_value(computed))
} }
} }
@ -148,7 +165,7 @@ impl BorderImageSideWidth {
/// Returns `1`. /// Returns `1`.
#[inline] #[inline]
pub fn one() -> Self { pub fn one() -> Self {
GenericBorderImageSideWidth::Number(Number::new(1.)) GenericBorderImageSideWidth::Number(NonNegativeNumber::new(1.))
} }
} }
@ -161,11 +178,11 @@ impl Parse for BorderImageSideWidth {
return Ok(GenericBorderImageSideWidth::Auto); return Ok(GenericBorderImageSideWidth::Auto);
} }
if let Ok(len) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) { if let Ok(len) = input.try(|i| NonNegativeLengthOrPercentage::parse(context, i)) {
return Ok(GenericBorderImageSideWidth::Length(len)); return Ok(GenericBorderImageSideWidth::Length(len));
} }
let num = Number::parse_non_negative(context, input)?; let num = NonNegativeNumber::parse(context, input)?;
Ok(GenericBorderImageSideWidth::Number(num)) Ok(GenericBorderImageSideWidth::Number(num))
} }
} }
@ -176,14 +193,11 @@ impl Parse for BorderImageSlice {
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
let mut fill = input.try(|i| i.expect_ident_matching("fill")).is_ok(); let mut fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
let offsets = Rect::parse_with(context, input, NumberOrPercentage::parse_non_negative)?; let offsets = Rect::parse_with(context, input, NonNegativeNumberOrPercentage::parse)?;
if !fill { if !fill {
fill = input.try(|i| i.expect_ident_matching("fill")).is_ok(); fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
} }
Ok(GenericBorderImageSlice { Ok(GenericBorderImageSlice { offsets, fill })
offsets: offsets,
fill: fill,
})
} }
} }
@ -192,9 +206,9 @@ impl Parse for BorderRadius {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
let widths = Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)?; let widths = Rect::parse_with(context, input, NonNegativeLengthOrPercentage::parse)?;
let heights = if input.try(|i| i.expect_delim('/')).is_ok() { let heights = if input.try(|i| i.expect_delim('/')).is_ok() {
Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)? Rect::parse_with(context, input, NonNegativeLengthOrPercentage::parse)?
} else { } else {
widths.clone() widths.clone()
}; };
@ -213,7 +227,7 @@ impl Parse for BorderCornerRadius {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
Size::parse_with(context, input, LengthOrPercentage::parse_non_negative) Size::parse_with(context, input, NonNegativeLengthOrPercentage::parse)
.map(GenericBorderCornerRadius) .map(GenericBorderCornerRadius)
} }
} }
@ -224,7 +238,7 @@ impl Parse for BorderSpacing {
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
Size::parse_with(context, input, |context, input| { Size::parse_with(context, input, |context, input| {
Length::parse_non_negative_quirky(context, input, AllowQuirks::Yes).map(From::from) NonNegativeLength::parse_quirky(context, input, AllowQuirks::Yes).map(From::from)
}) })
.map(GenericBorderSpacing) .map(GenericBorderSpacing)
} }

View file

@ -717,6 +717,16 @@ impl NonNegativeLength {
pub fn from_px(px_value: CSSFloat) -> Self { pub fn from_px(px_value: CSSFloat) -> Self {
Length::from_px(px_value.max(0.)).into() Length::from_px(px_value.max(0.)).into()
} }
/// Parses a non-negative length, optionally with quirks.
#[inline]
pub fn parse_quirky<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> {
Ok(NonNegative(Length::parse_non_negative_quirky(context, input, allow_quirks)?))
}
} }
/// Either a NonNegativeLength or the `auto` keyword. /// Either a NonNegativeLength or the `auto` keyword.

View file

@ -359,6 +359,26 @@ impl Parse for NumberOrPercentage {
} }
} }
/// A non-negative <number> | <percentage>.
pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>;
impl NonNegativeNumberOrPercentage {
/// Returns the `100%` value.
#[inline]
pub fn hundred_percent() -> Self {
NonNegative(NumberOrPercentage::Percentage(Percentage::hundred()))
}
}
impl Parse for NonNegativeNumberOrPercentage {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Ok(NonNegative(NumberOrPercentage::parse_non_negative(context, input)?))
}
}
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo, ToCss)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo, ToCss)]
pub struct Opacity(Number); pub struct Opacity(Number);