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
//! Ideally, it would be in geckolib itself, but coherence
//! forces us to keep the traits and implementations here
//!
//! FIXME(emilio): This file should generally just die.
#![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::{LengthOrPercentageOrAuto, NonNegativeLengthOrPercentageOrAuto};
use crate::values::computed::{Percentage, TextAlign};
use crate::values::generics::NonNegative;
use crate::values::generics::box_::VerticalAlign;
use crate::values::generics::grid::{TrackListValue, TrackSize};
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.
impl From<nsStyleCoord_CalcValue> for NonNegativeLengthOrPercentageOrAuto {
fn from(other: nsStyleCoord_CalcValue) -> Self {
use crate::values::generics::NonNegative;
use style_traits::values::specified::AllowedNumericType;
NonNegative(if other.mLength < 0 || other.mPercent < 0. {
LengthOrPercentageOrAuto::Calc(CalcLengthOrPercentage::with_clamping_mode(
@ -675,6 +677,7 @@ pub mod basic_shape {
use crate::values::generics::basic_shape::{
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::{GeometryBox, ShapeBox, ShapeSource};
use crate::values::generics::border::BorderRadius as GenericBorderRadius;
@ -838,10 +841,10 @@ pub mod basic_shape {
fn from(other: &'a nsStyleCorners) -> Self {
let get_corner = |index| {
BorderCornerRadius::new(
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index))
.expect("<border-radius> should be a length, percentage, or calc value"),
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1))
.expect("<border-radius> should be a length, percentage, or calc value"),
NonNegative(LengthOrPercentage::from_gecko_style_coord(&other.data_at(index))
.expect("<border-radius> should be a length, percentage, or calc value")),
NonNegative(LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1))
.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 {
use crate::gecko_bindings::structs::NS_STYLE_BORDER_IMAGE_SLICE_FILL;
use crate::values::computed::{BorderImageSlice, NumberOrPercentage};
type NumberOrPercentageRect = crate::values::generics::rect::Rect<NumberOrPercentage>;
use crate::values::computed::{BorderImageSlice, NonNegativeNumberOrPercentage};
type NumberOrPercentageRect = crate::values::generics::rect::Rect<NonNegativeNumberOrPercentage>;
BorderImageSlice {
offsets:

View file

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

View file

@ -295,7 +295,7 @@ ${helpers.predefined_type(
"-webkit-text-stroke-width",
"BorderSideWidth",
"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",
products="gecko",
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::url::ComputedUrl;
use crate::values::computed::Angle as ComputedAngle;
use crate::values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
use crate::values::CSSFloat;
use app_units::Au;
use euclid::{Point2D, Size2D};
@ -340,23 +339,6 @@ trivial_to_animated_value!(ComputedUrl);
trivial_to_animated_value!(bool);
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 {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {

View file

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

View file

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

View file

@ -543,6 +543,15 @@ pub enum NumberOrPercentage {
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 {
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.
pub type Opacity = CSSFloat;

View file

@ -85,8 +85,8 @@ pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> {
ToComputedValue,
ToCss,
)]
pub enum BasicShape<H, V, LengthOrPercentage> {
Inset(#[css(field_bound)] InsetRect<LengthOrPercentage>),
pub enum BasicShape<H, V, LengthOrPercentage, NonNegativeLengthOrPercentage> {
Inset(#[css(field_bound)] InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage>),
Circle(#[css(field_bound)] Circle<H, V, LengthOrPercentage>),
Ellipse(#[css(field_bound)] Ellipse<H, V, LengthOrPercentage>),
Polygon(Polygon<LengthOrPercentage>),
@ -105,9 +105,9 @@ pub enum BasicShape<H, V, LengthOrPercentage> {
SpecifiedValueInfo,
ToComputedValue,
)]
pub struct InsetRect<LengthOrPercentage> {
pub struct InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage> {
pub rect: Rect<LengthOrPercentage>,
pub round: Option<BorderRadius<LengthOrPercentage>>,
pub round: Option<BorderRadius<NonNegativeLengthOrPercentage>>,
}
/// <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
L: ToCss + PartialEq,
Length: ToCss + PartialEq,
NonNegativeLength: ToCss + PartialEq,
{
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where

View file

@ -45,6 +45,8 @@ pub struct BorderImageSlice<NumberOrPercentage> {
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue,
ToCss,
)]
@ -106,19 +108,6 @@ pub struct BorderRadius<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> {
/// Returns a new `BorderRadius<L>`.
#[inline]

View file

@ -16,7 +16,7 @@ use crate::values::specified::border::BorderRadius;
use crate::values::specified::image::Image;
use crate::values::specified::position::{HorizontalPosition, Position, VerticalPosition};
use crate::values::specified::url::SpecifiedUrl;
use crate::values::specified::LengthOrPercentage;
use crate::values::specified::{LengthOrPercentage, NonNegativeLengthOrPercentage};
use crate::values::specified::SVGPathData;
use cssparser::Parser;
use std::fmt::{self, Write};
@ -32,10 +32,10 @@ pub type ClippingShape = generic::ClippingShape<BasicShape, SpecifiedUrl>;
pub type FloatAreaShape = generic::FloatAreaShape<BasicShape, Image>;
/// 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()`
pub type InsetRect = generic::InsetRect<LengthOrPercentage>;
pub type InsetRect = generic::InsetRect<LengthOrPercentage, NonNegativeLengthOrPercentage>;
/// A specified circle.
pub type Circle = generic::Circle<HorizontalPosition, VerticalPosition, LengthOrPercentage>;
@ -199,10 +199,7 @@ impl InsetRect {
} else {
None
};
Ok(generic::InsetRect {
rect: rect,
round: round,
})
Ok(generic::InsetRect { rect, 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::rect::Rect;
use crate::values::generics::size::Size;
use crate::values::specified::length::{Length, LengthOrPercentage, NonNegativeLength};
use crate::values::specified::{AllowQuirks, Number, NumberOrPercentage};
use crate::values::specified::length::{NonNegativeLengthOrPercentage, NonNegativeLength};
use crate::values::specified::{AllowQuirks, NonNegativeNumber, NonNegativeNumberOrPercentage};
use cssparser::Parser;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss};
@ -71,28 +71,45 @@ pub enum BorderSideWidth {
/// `thick`
Thick,
/// `<length>`
Length(Length),
Length(NonNegativeLength),
}
/// A specified value for the `border-image-width` property.
pub type BorderImageWidth = Rect<BorderImageSideWidth>;
/// 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.
pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>;
pub type BorderImageSlice = GenericBorderImageSlice<NonNegativeNumberOrPercentage>;
/// 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.
pub type BorderCornerRadius = GenericBorderCornerRadius<LengthOrPercentage>;
pub type BorderCornerRadius = GenericBorderCornerRadius<NonNegativeLengthOrPercentage>;
/// A specified value for the `border-spacing` longhand properties.
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 {
/// Returns the `0px` value.
#[inline]
pub fn zero() -> Self {
BorderSideWidth::Length(NonNegativeLength::zero())
}
/// Parses, with quirks.
pub fn parse_quirky<'i, 't>(
context: &ParserContext,
@ -100,7 +117,7 @@ impl BorderSideWidth {
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> {
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));
}
@ -130,9 +147,9 @@ impl ToComputedValue for BorderSideWidth {
// Spec: https://drafts.csswg.org/css-backgrounds-3/#line-width
// Gecko: https://bugzilla.mozilla.org/show_bug.cgi?id=1312155#c0
match *self {
BorderSideWidth::Thin => Length::from_px(1.).to_computed_value(context),
BorderSideWidth::Medium => Length::from_px(3.).to_computed_value(context),
BorderSideWidth::Thick => Length::from_px(5.).to_computed_value(context),
BorderSideWidth::Thin => NonNegativeLength::from_px(1.).to_computed_value(context),
BorderSideWidth::Medium => NonNegativeLength::from_px(3.).to_computed_value(context),
BorderSideWidth::Thick => NonNegativeLength::from_px(5.).to_computed_value(context),
BorderSideWidth::Length(ref length) => length.to_computed_value(context),
}
.into()
@ -140,7 +157,7 @@ impl ToComputedValue for BorderSideWidth {
#[inline]
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`.
#[inline]
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);
}
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));
}
let num = Number::parse_non_negative(context, input)?;
let num = NonNegativeNumber::parse(context, input)?;
Ok(GenericBorderImageSideWidth::Number(num))
}
}
@ -176,14 +193,11 @@ impl Parse for BorderImageSlice {
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
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 {
fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
}
Ok(GenericBorderImageSlice {
offsets: offsets,
fill: fill,
})
Ok(GenericBorderImageSlice { offsets, fill })
}
}
@ -192,9 +206,9 @@ impl Parse for BorderRadius {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> 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() {
Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)?
Rect::parse_with(context, input, NonNegativeLengthOrPercentage::parse)?
} else {
widths.clone()
};
@ -213,7 +227,7 @@ impl Parse for BorderCornerRadius {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Size::parse_with(context, input, LengthOrPercentage::parse_non_negative)
Size::parse_with(context, input, NonNegativeLengthOrPercentage::parse)
.map(GenericBorderCornerRadius)
}
}
@ -224,7 +238,7 @@ impl Parse for BorderSpacing {
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
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)
}

View file

@ -717,6 +717,16 @@ impl NonNegativeLength {
pub fn from_px(px_value: CSSFloat) -> Self {
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.

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)]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo, ToCss)]
pub struct Opacity(Number);