mirror of
https://github.com/servo/servo.git
synced 2025-08-07 22:45:34 +01:00
Auto merge of #17783 - BorisChiou:stylo/animation/restrictions, r=nox
stylo: Bug 1374233 - Clamp interpolated values for properties which need to be restricted Some properties only accept non-negative values, or values greater than or equal to one. It is possible to produce an negative interpolated values while using negative timing functions, so we have to apply a restriction to these values to avoid getting invalid values. For example, line-height must be non-negative, but the output progress of some timing functions (e,g. cubic-bezier(0.25, -2, 0.75, 1)) may be a negative value, so the interpolated result of line-height is also negative. --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix Bug 1374233. - [X] These changes do not require tests because we have tests in Gecko side already. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17783) <!-- Reviewable:end -->
This commit is contained in:
commit
016ea11cba
56 changed files with 1039 additions and 371 deletions
|
@ -4,11 +4,10 @@
|
|||
|
||||
//! Specified types for CSS values related to borders.
|
||||
|
||||
use app_units::Au;
|
||||
use cssparser::Parser;
|
||||
use parser::{Parse, ParserContext};
|
||||
use style_traits::ParseError;
|
||||
use values::computed::{Context, ToComputedValue};
|
||||
use values::computed::{Context, NonNegativeAu, ToComputedValue};
|
||||
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
|
||||
use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
|
||||
use values::generics::border::BorderImageSlice as GenericBorderImageSlice;
|
||||
|
@ -72,7 +71,7 @@ impl Parse for BorderSideWidth {
|
|||
}
|
||||
|
||||
impl ToComputedValue for BorderSideWidth {
|
||||
type ComputedValue = Au;
|
||||
type ComputedValue = NonNegativeAu;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
|
@ -84,12 +83,12 @@ impl ToComputedValue for BorderSideWidth {
|
|||
BorderSideWidth::Medium => Length::from_px(3.).to_computed_value(context),
|
||||
BorderSideWidth::Thick => Length::from_px(5.).to_computed_value(context),
|
||||
BorderSideWidth::Length(ref length) => length.to_computed_value(context)
|
||||
}
|
||||
}.into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
BorderSideWidth::Length(ToComputedValue::from_computed_value(computed))
|
||||
BorderSideWidth::Length(ToComputedValue::from_computed_value(&computed.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,28 +9,29 @@ use parser::{Parse, ParserContext};
|
|||
use style_traits::{ParseError, StyleParseError};
|
||||
#[cfg(not(feature = "gecko"))]
|
||||
use values::Impossible;
|
||||
use values::computed::{Context, Number as ComputedNumber, ToComputedValue};
|
||||
use values::computed::{Context, NonNegativeNumber as ComputedNonNegativeNumber, ToComputedValue};
|
||||
use values::computed::effects::BoxShadow as ComputedBoxShadow;
|
||||
use values::computed::effects::SimpleShadow as ComputedSimpleShadow;
|
||||
use values::generics::NonNegative;
|
||||
use values::generics::effects::BoxShadow as GenericBoxShadow;
|
||||
use values::generics::effects::Filter as GenericFilter;
|
||||
use values::generics::effects::SimpleShadow as GenericSimpleShadow;
|
||||
use values::specified::{Angle, NumberOrPercentage};
|
||||
use values::specified::color::Color;
|
||||
use values::specified::length::Length;
|
||||
use values::specified::length::{Length, NonNegativeLength};
|
||||
#[cfg(feature = "gecko")]
|
||||
use values::specified::url::SpecifiedUrl;
|
||||
|
||||
/// A specified value for a single shadow of the `box-shadow` property.
|
||||
pub type BoxShadow = GenericBoxShadow<Option<Color>, Length, Option<Length>>;
|
||||
pub type BoxShadow = GenericBoxShadow<Option<Color>, Length, Option<NonNegativeLength>, Option<Length>>;
|
||||
|
||||
/// A specified value for a single `filter`.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub type Filter = GenericFilter<Angle, Factor, Length, SimpleShadow>;
|
||||
pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, SimpleShadow>;
|
||||
|
||||
/// A specified value for a single `filter`.
|
||||
#[cfg(not(feature = "gecko"))]
|
||||
pub type Filter = GenericFilter<Angle, Factor, Length, Impossible>;
|
||||
pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible>;
|
||||
|
||||
/// A value for the `<factor>` parts in `Filter`.
|
||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
|
||||
|
@ -48,25 +49,25 @@ impl Parse for Factor {
|
|||
}
|
||||
|
||||
impl ToComputedValue for Factor {
|
||||
type ComputedValue = ComputedNumber;
|
||||
type ComputedValue = ComputedNonNegativeNumber;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
use values::computed::NumberOrPercentage;
|
||||
match self.0.to_computed_value(context) {
|
||||
NumberOrPercentage::Number(n) => n,
|
||||
NumberOrPercentage::Percentage(p) => p.0,
|
||||
NumberOrPercentage::Number(n) => n.into(),
|
||||
NumberOrPercentage::Percentage(p) => p.0.into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
Factor(NumberOrPercentage::Number(ToComputedValue::from_computed_value(computed)))
|
||||
Factor(NumberOrPercentage::Number(ToComputedValue::from_computed_value(&computed.0)))
|
||||
}
|
||||
}
|
||||
|
||||
/// A specified value for the `drop-shadow()` filter.
|
||||
pub type SimpleShadow = GenericSimpleShadow<Option<Color>, Length, Option<Length>>;
|
||||
pub type SimpleShadow = GenericSimpleShadow<Option<Color>, Length, Option<NonNegativeLength>>;
|
||||
|
||||
impl Parse for BoxShadow {
|
||||
fn parse<'i, 't>(
|
||||
|
@ -91,7 +92,7 @@ impl Parse for BoxShadow {
|
|||
let (blur, spread) = match i.try::<_, _, ParseError>(|i| Length::parse_non_negative(context, i)) {
|
||||
Ok(blur) => {
|
||||
let spread = i.try(|i| Length::parse(context, i)).ok();
|
||||
(Some(blur), spread)
|
||||
(Some(blur.into()), spread)
|
||||
},
|
||||
Err(_) => (None, None),
|
||||
};
|
||||
|
@ -162,7 +163,7 @@ impl Parse for Filter {
|
|||
let function = input.expect_function()?.clone();
|
||||
input.parse_nested_block(|i| {
|
||||
try_match_ident_ignore_ascii_case! { function,
|
||||
"blur" => Ok(GenericFilter::Blur(Length::parse_non_negative(context, i)?)),
|
||||
"blur" => Ok(GenericFilter::Blur((Length::parse_non_negative(context, i)?).into())),
|
||||
"brightness" => Ok(GenericFilter::Brightness(Factor::parse(context, i)?)),
|
||||
"contrast" => Ok(GenericFilter::Contrast(Factor::parse(context, i)?)),
|
||||
"grayscale" => Ok(GenericFilter::Grayscale(Factor::parse(context, i)?)),
|
||||
|
@ -192,7 +193,7 @@ impl Parse for SimpleShadow {
|
|||
color: color,
|
||||
horizontal: horizontal,
|
||||
vertical: vertical,
|
||||
blur: blur,
|
||||
blur: blur.map(NonNegative::<Length>),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -208,7 +209,7 @@ impl ToComputedValue for SimpleShadow {
|
|||
horizontal: self.horizontal.to_computed_value(context),
|
||||
vertical: self.vertical.to_computed_value(context),
|
||||
blur:
|
||||
self.blur.as_ref().unwrap_or(&Length::zero()).to_computed_value(context),
|
||||
self.blur.as_ref().unwrap_or(&NonNegativeLength::zero()).to_computed_value(context),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ 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::generics::NonNegative;
|
||||
use values::specified::NonNegativeNumber;
|
||||
use values::specified::calc::CalcNode;
|
||||
|
||||
pub use values::specified::calc::CalcLengthOrPercentage;
|
||||
|
@ -92,8 +94,8 @@ impl FontBaseSize {
|
|||
pub fn resolve(&self, context: &Context) -> Au {
|
||||
match *self {
|
||||
FontBaseSize::Custom(size) => size,
|
||||
FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size(),
|
||||
FontBaseSize::InheritedStyle => context.style().get_parent_font().clone_font_size(),
|
||||
FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size().0,
|
||||
FontBaseSize::InheritedStyle => context.style().get_parent_font().clone_font_size().0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -703,6 +705,57 @@ impl<T: Parse> Either<Length, T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A wrapper of Length, whose value must be >= 0.
|
||||
pub type NonNegativeLength = NonNegative<Length>;
|
||||
|
||||
impl From<NoCalcLength> for NonNegativeLength {
|
||||
#[inline]
|
||||
fn from(len: NoCalcLength) -> Self {
|
||||
NonNegative::<Length>(Length::NoCalc(len))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Length> for NonNegativeLength {
|
||||
#[inline]
|
||||
fn from(len: Length) -> Self {
|
||||
NonNegative::<Length>(len)
|
||||
}
|
||||
}
|
||||
|
||||
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(NonNegative::<Length>).map(Either::First)
|
||||
}
|
||||
}
|
||||
|
||||
impl NonNegativeLength {
|
||||
/// Returns a `zero` length.
|
||||
#[inline]
|
||||
pub fn zero() -> Self {
|
||||
Length::zero().into()
|
||||
}
|
||||
|
||||
/// Get an absolute length from a px value.
|
||||
#[inline]
|
||||
pub fn from_px(px_value: CSSFloat) -> Self {
|
||||
Length::from_px(px_value.max(0.)).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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))]
|
||||
|
@ -1185,6 +1238,41 @@ impl Parse for LengthOrPercentageOrNone {
|
|||
}
|
||||
}
|
||||
|
||||
/// A wrapper of LengthOrPercentage, whose value must be >= 0.
|
||||
pub type NonNegativeLengthOrPercentage = NonNegative<LengthOrPercentage>;
|
||||
|
||||
impl From<NoCalcLength> for NonNegativeLengthOrPercentage {
|
||||
#[inline]
|
||||
fn from(len: NoCalcLength) -> Self {
|
||||
NonNegative::<LengthOrPercentage>(LengthOrPercentage::from(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(NonNegative::<LengthOrPercentage>)
|
||||
}
|
||||
}
|
||||
|
||||
impl NonNegativeLengthOrPercentage {
|
||||
#[inline]
|
||||
/// Returns a `zero` length.
|
||||
pub fn zero() -> Self {
|
||||
NonNegative::<LengthOrPercentage>(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(NonNegative::<LengthOrPercentage>)
|
||||
}
|
||||
}
|
||||
|
||||
/// Either a `<length>` or the `none` keyword.
|
||||
pub type LengthOrNone = Either<Length, None_>;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ use style_traits::{ToCss, ParseError, StyleParseError};
|
|||
use style_traits::values::specified::AllowedNumericType;
|
||||
use super::{Auto, CSSFloat, CSSInteger, Either, None_};
|
||||
use super::computed::{self, Context, ToComputedValue};
|
||||
use super::generics::{GreaterThanOrEqualToOne, NonNegative};
|
||||
use super::generics::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
|
||||
use super::generics::grid::TrackList as GenericTrackList;
|
||||
use values::computed::ComputedValueAsSpecified;
|
||||
|
@ -41,9 +42,10 @@ 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};
|
||||
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth};
|
||||
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing};
|
||||
pub use self::transform::{TimingFunction, TransformOrigin};
|
||||
pub use super::generics::grid::GridLine;
|
||||
|
@ -533,6 +535,33 @@ impl ToCss for Number {
|
|||
}
|
||||
}
|
||||
|
||||
/// A Number which is >= 0.0.
|
||||
pub type NonNegativeNumber = NonNegative<Number>;
|
||||
|
||||
impl Parse for NonNegativeNumber {
|
||||
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
|
||||
parse_number_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
|
||||
.map(NonNegative::<Number>)
|
||||
}
|
||||
}
|
||||
|
||||
impl NonNegativeNumber {
|
||||
/// Returns a new non-negative number with the value `val`.
|
||||
pub fn new(val: CSSFloat) -> Self {
|
||||
NonNegative::<Number>(Number::new(val.max(0.)))
|
||||
}
|
||||
}
|
||||
|
||||
/// A Number which is >= 1.0.
|
||||
pub type GreaterThanOrEqualToOneNumber = GreaterThanOrEqualToOne<Number>;
|
||||
|
||||
impl Parse for GreaterThanOrEqualToOneNumber {
|
||||
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
|
||||
parse_number_with_clamping_mode(context, input, AllowedNumericType::AtLeastOne)
|
||||
.map(GreaterThanOrEqualToOne::<Number>)
|
||||
}
|
||||
}
|
||||
|
||||
/// <number> | <percentage>
|
||||
///
|
||||
/// Accepts only non-negative numbers.
|
||||
|
@ -713,6 +742,19 @@ impl IntegerOrAuto {
|
|||
}
|
||||
}
|
||||
|
||||
/// A wrapper of Integer, with value >= 1.
|
||||
pub type PositiveInteger = GreaterThanOrEqualToOne<Integer>;
|
||||
|
||||
impl Parse for PositiveInteger {
|
||||
#[inline]
|
||||
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
|
||||
Integer::parse_positive(context, input).map(GreaterThanOrEqualToOne::<Integer>)
|
||||
}
|
||||
}
|
||||
|
||||
/// PositiveInteger | auto
|
||||
pub type PositiveIntegerOrAuto = Either<PositiveInteger, Auto>;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub type UrlOrNone = Either<SpecifiedUrl, None_>;
|
||||
|
||||
|
@ -732,19 +774,8 @@ pub type GridTemplateComponent = GenericGridTemplateComponent<LengthOrPercentage
|
|||
/// <length> | <percentage> | <number>
|
||||
pub type LengthOrPercentageOrNumber = Either<Number, LengthOrPercentage>;
|
||||
|
||||
impl LengthOrPercentageOrNumber {
|
||||
/// parse a <length-percentage> | <number> enforcing that the contents aren't negative
|
||||
pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
|
||||
-> Result<Self, ParseError<'i>> {
|
||||
// NB: Parse numbers before Lengths so we are consistent about how to
|
||||
// recognize and serialize "0".
|
||||
if let Ok(num) = input.try(|i| Number::parse_non_negative(context, i)) {
|
||||
return Ok(Either::First(num))
|
||||
}
|
||||
|
||||
LengthOrPercentage::parse_non_negative(context, input).map(Either::Second)
|
||||
}
|
||||
}
|
||||
/// NonNegativeLengthOrPercentage | NonNegativeNumber
|
||||
pub type NonNegativeLengthOrPercentageOrNumber = Either<NonNegativeNumber, NonNegativeLengthOrPercentage>;
|
||||
|
||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
|
|
|
@ -8,7 +8,7 @@ use cssparser::Parser;
|
|||
use parser::{Parse, ParserContext};
|
||||
use style_traits::{CommaWithSpace, ParseError, Separator, StyleParseError};
|
||||
use values::generics::svg as generic;
|
||||
use values::specified::{LengthOrPercentageOrNumber, Opacity};
|
||||
use values::specified::{LengthOrPercentageOrNumber, NonNegativeLengthOrPercentageOrNumber, Opacity};
|
||||
use values::specified::color::RGBAColor;
|
||||
|
||||
/// Specified SVG Paint value
|
||||
|
@ -54,30 +54,38 @@ impl Parse for SVGLength {
|
|||
}
|
||||
}
|
||||
|
||||
impl SVGLength {
|
||||
/// parse a non-negative SVG length
|
||||
pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
|
||||
-> Result<Self, ParseError<'i>> {
|
||||
input.try(|i| LengthOrPercentageOrNumber::parse_non_negative(context, i))
|
||||
.map(Into::into)
|
||||
.or_else(|_| parse_context_value(input, generic::SVGLength::ContextValue))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LengthOrPercentageOrNumber> for SVGLength {
|
||||
fn from(length: LengthOrPercentageOrNumber) -> Self {
|
||||
generic::SVGLength::Length(length)
|
||||
}
|
||||
}
|
||||
|
||||
/// A non-negative version of SVGLength.
|
||||
pub type SVGWidth = generic::SVGLength<NonNegativeLengthOrPercentageOrNumber>;
|
||||
|
||||
impl Parse for SVGWidth {
|
||||
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
|
||||
-> Result<Self, ParseError<'i>> {
|
||||
input.try(|i| NonNegativeLengthOrPercentageOrNumber::parse(context, i))
|
||||
.map(Into::into)
|
||||
.or_else(|_| parse_context_value(input, generic::SVGLength::ContextValue))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NonNegativeLengthOrPercentageOrNumber> for SVGWidth {
|
||||
fn from(length: NonNegativeLengthOrPercentageOrNumber) -> Self {
|
||||
generic::SVGLength::Length(length)
|
||||
}
|
||||
}
|
||||
|
||||
/// [ <length> | <percentage> | <number> ]# | context-value
|
||||
pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<LengthOrPercentageOrNumber>;
|
||||
pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<NonNegativeLengthOrPercentageOrNumber>;
|
||||
|
||||
impl Parse for SVGStrokeDashArray {
|
||||
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
|
||||
-> Result<Self, ParseError<'i>> {
|
||||
if let Ok(values) = input.try(|i| CommaWithSpace::parse(i, |i| {
|
||||
LengthOrPercentageOrNumber::parse_non_negative(context, i)
|
||||
NonNegativeLengthOrPercentageOrNumber::parse(context, i)
|
||||
})) {
|
||||
Ok(generic::SVGStrokeDashArray::Values(values))
|
||||
} else if let Ok(_) = input.try(|i| i.expect_ident_matching("none")) {
|
||||
|
|
|
@ -14,8 +14,9 @@ use values::computed::text::LineHeight as ComputedLineHeight;
|
|||
use values::generics::text::InitialLetter as GenericInitialLetter;
|
||||
use values::generics::text::LineHeight as GenericLineHeight;
|
||||
use values::generics::text::Spacing;
|
||||
use values::specified::{AllowQuirks, Integer, Number};
|
||||
use values::specified::{AllowQuirks, Integer, NonNegativeNumber, Number};
|
||||
use values::specified::length::{FontRelativeLength, Length, LengthOrPercentage, NoCalcLength};
|
||||
use values::specified::length::NonNegativeLengthOrPercentage;
|
||||
|
||||
/// A specified type for the `initial-letter` property.
|
||||
pub type InitialLetter = GenericInitialLetter<Number, Integer>;
|
||||
|
@ -27,7 +28,7 @@ pub type LetterSpacing = Spacing<Length>;
|
|||
pub type WordSpacing = Spacing<LengthOrPercentage>;
|
||||
|
||||
/// A specified value for the `line-height` property.
|
||||
pub type LineHeight = GenericLineHeight<Number, LengthOrPercentage>;
|
||||
pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeLengthOrPercentage>;
|
||||
|
||||
impl Parse for InitialLetter {
|
||||
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
|
||||
|
@ -58,11 +59,11 @@ impl Parse for WordSpacing {
|
|||
|
||||
impl Parse for LineHeight {
|
||||
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(number) = input.try(|i| Number::parse_non_negative(context, i)) {
|
||||
if let Ok(number) = input.try(|i| NonNegativeNumber::parse(context, i)) {
|
||||
return Ok(GenericLineHeight::Number(number))
|
||||
}
|
||||
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
|
||||
return Ok(GenericLineHeight::Length(lop))
|
||||
if let Ok(nlop) = input.try(|i| NonNegativeLengthOrPercentage::parse(context, i)) {
|
||||
return Ok(GenericLineHeight::Length(nlop))
|
||||
}
|
||||
let ident = input.expect_ident()?;
|
||||
match ident {
|
||||
|
@ -94,24 +95,29 @@ impl ToComputedValue for LineHeight {
|
|||
GenericLineHeight::Number(number) => {
|
||||
GenericLineHeight::Number(number.to_computed_value(context))
|
||||
},
|
||||
GenericLineHeight::Length(LengthOrPercentage::Length(ref length)) => {
|
||||
GenericLineHeight::Length(context.maybe_zoom_text(length.to_computed_value(context)))
|
||||
},
|
||||
GenericLineHeight::Length(LengthOrPercentage::Percentage(p)) => {
|
||||
let font_relative_length =
|
||||
Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(p.0)));
|
||||
GenericLineHeight::Length(font_relative_length.to_computed_value(context))
|
||||
},
|
||||
GenericLineHeight::Length(LengthOrPercentage::Calc(ref calc)) => {
|
||||
let computed_calc = calc.to_computed_value_zoomed(context);
|
||||
let font_relative_length =
|
||||
Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(computed_calc.percentage())));
|
||||
let absolute_length = computed_calc.unclamped_length();
|
||||
let computed_length = computed_calc.clamping_mode.clamp(
|
||||
absolute_length + font_relative_length.to_computed_value(context)
|
||||
);
|
||||
GenericLineHeight::Length(computed_length)
|
||||
},
|
||||
GenericLineHeight::Length(ref non_negative_lop) => {
|
||||
let result = match non_negative_lop.0 {
|
||||
LengthOrPercentage::Length(ref length) => {
|
||||
context.maybe_zoom_text(length.to_computed_value(context).into())
|
||||
},
|
||||
LengthOrPercentage::Percentage(ref p) => {
|
||||
let font_relative_length =
|
||||
Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(p.0)));
|
||||
font_relative_length.to_computed_value(context).into()
|
||||
}
|
||||
LengthOrPercentage::Calc(ref calc) => {
|
||||
let computed_calc = calc.to_computed_value_zoomed(context);
|
||||
let font_relative_length =
|
||||
Length::NoCalc(NoCalcLength::FontRelative(
|
||||
FontRelativeLength::Em(computed_calc.percentage())));
|
||||
let absolute_length = computed_calc.unclamped_length();
|
||||
computed_calc.clamping_mode.clamp(
|
||||
absolute_length + font_relative_length.to_computed_value(context)
|
||||
).into()
|
||||
}
|
||||
};
|
||||
GenericLineHeight::Length(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,12 +132,10 @@ impl ToComputedValue for LineHeight {
|
|||
GenericLineHeight::MozBlockHeight
|
||||
},
|
||||
GenericLineHeight::Number(ref number) => {
|
||||
GenericLineHeight::Number(Number::from_computed_value(number))
|
||||
GenericLineHeight::Number(NonNegativeNumber::from_computed_value(number))
|
||||
},
|
||||
GenericLineHeight::Length(ref length) => {
|
||||
GenericLineHeight::Length(LengthOrPercentage::Length(
|
||||
NoCalcLength::from_computed_value(length)
|
||||
))
|
||||
GenericLineHeight::Length(NoCalcLength::from_computed_value(&length.0).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue