Split the Length type (introduce NoCalcLength)

This commit is contained in:
Ravi Shankar 2017-01-15 21:46:48 +05:30
parent 556a46f537
commit 4035bbd738
4 changed files with 154 additions and 89 deletions

View file

@ -17,6 +17,45 @@ pub use super::image::{EndingShape as GradientShape, Gradient, GradientKind, Ima
pub use super::image::{LengthOrKeyword, LengthOrPercentageOrKeyword}; pub use super::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone}; pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
impl ToComputedValue for specified::NoCalcLength {
type ComputedValue = Au;
#[inline]
fn to_computed_value(&self, context: &Context) -> Au {
match *self {
specified::NoCalcLength::Absolute(length) => length,
specified::NoCalcLength::FontRelative(length) =>
length.to_computed_value(context, /* use inherited */ false),
specified::NoCalcLength::ViewportPercentage(length) =>
length.to_computed_value(context.viewport_size()),
specified::NoCalcLength::ServoCharacterWidth(length) =>
length.to_computed_value(context.style().get_font().clone_font_size())
}
}
#[inline]
fn from_computed_value(computed: &Au) -> Self {
specified::NoCalcLength::Absolute(*computed)
}
}
impl ToComputedValue for specified::Length {
type ComputedValue = Au;
#[inline]
fn to_computed_value(&self, context: &Context) -> Au {
match *self {
specified::Length::NoCalc(l) => l.to_computed_value(context),
specified::Length::Calc(ref calc, range) => range.clamp(calc.to_computed_value(context).length()),
}
}
#[inline]
fn from_computed_value(computed: &Au) -> Self {
specified::Length::NoCalc(specified::NoCalcLength::from_computed_value(computed))
}
}
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)] #[allow(missing_docs)]

View file

@ -121,30 +121,6 @@ impl ToComputedValue for specified::CSSColor {
impl ComputedValueAsSpecified for specified::BorderStyle {} impl ComputedValueAsSpecified for specified::BorderStyle {}
impl ToComputedValue for specified::Length {
type ComputedValue = Au;
#[inline]
fn to_computed_value(&self, context: &Context) -> Au {
match *self {
specified::Length::Absolute(length) => length,
specified::Length::Calc(ref calc, range) => range.clamp(calc.to_computed_value(context).length()),
specified::Length::FontRelative(length) =>
length.to_computed_value(context, /* use inherited */ false),
specified::Length::ViewportPercentage(length) =>
length.to_computed_value(context.viewport_size()),
specified::Length::ServoCharacterWidth(length) =>
length.to_computed_value(context.style().get_font().clone_font_size())
}
}
#[inline]
fn from_computed_value(computed: &Au) -> Self {
specified::Length::Absolute(*computed)
}
}
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)] #[allow(missing_docs)]

View file

@ -24,6 +24,14 @@ pub use super::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingSh
pub use super::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword}; pub use super::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword};
pub use super::image::{SizeKeyword, VerticalDirection}; pub use super::image::{SizeKeyword, VerticalDirection};
const AU_PER_PX: CSSFloat = 60.;
const AU_PER_IN: CSSFloat = AU_PER_PX * 96.;
const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54;
const AU_PER_MM: CSSFloat = AU_PER_IN / 25.4;
const AU_PER_Q: CSSFloat = AU_PER_MM / 4.;
const AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
const AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A font relative length. /// A font relative length.
@ -205,12 +213,12 @@ impl CharacterWidth {
} }
} }
/// A length. /// A `<length>` without taking `calc` expressions into account
/// ///
/// https://drafts.csswg.org/css-values/#lengths /// https://drafts.csswg.org/css-values/#lengths
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Length { pub enum NoCalcLength {
/// An absolute length: https://drafts.csswg.org/css-values/#absolute-length /// An absolute length: https://drafts.csswg.org/css-values/#absolute-length
Absolute(Au), // application units Absolute(Au), // application units
@ -229,7 +237,96 @@ pub enum Length {
/// This cannot be specified by the user directly and is only generated by /// This cannot be specified by the user directly and is only generated by
/// `Stylist::synthesize_rules_for_legacy_attributes()`. /// `Stylist::synthesize_rules_for_legacy_attributes()`.
ServoCharacterWidth(CharacterWidth), ServoCharacterWidth(CharacterWidth),
}
impl HasViewportPercentage for NoCalcLength {
fn has_viewport_percentage(&self) -> bool {
match *self {
NoCalcLength::ViewportPercentage(_) => true,
_ => false,
}
}
}
impl ToCss for NoCalcLength {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
NoCalcLength::Absolute(length) => write!(dest, "{}px", length.to_f32_px()),
NoCalcLength::FontRelative(length) => length.to_css(dest),
NoCalcLength::ViewportPercentage(length) => length.to_css(dest),
/* This should only be reached from style dumping code */
NoCalcLength::ServoCharacterWidth(CharacterWidth(i)) => write!(dest, "CharWidth({})", i),
}
}
}
impl Mul<CSSFloat> for NoCalcLength {
type Output = NoCalcLength;
#[inline]
fn mul(self, scalar: CSSFloat) -> NoCalcLength {
match self {
NoCalcLength::Absolute(Au(v)) => NoCalcLength::Absolute(Au(((v as f32) * scalar) as i32)),
NoCalcLength::FontRelative(v) => NoCalcLength::FontRelative(v * scalar),
NoCalcLength::ViewportPercentage(v) => NoCalcLength::ViewportPercentage(v * scalar),
NoCalcLength::ServoCharacterWidth(_) => panic!("Can't multiply ServoCharacterWidth!"),
}
}
}
impl NoCalcLength {
/// https://drafts.csswg.org/css-fonts-3/#font-size-prop
pub fn from_str(s: &str) -> Option<NoCalcLength> {
Some(match_ignore_ascii_case! { s,
"xx-small" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 5),
"x-small" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 4),
"small" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX) * 8 / 9),
"medium" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX)),
"large" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX) * 6 / 5),
"x-large" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 2),
"xx-large" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX) * 2),
// https://github.com/servo/servo/issues/3423#issuecomment-56321664
"smaller" => NoCalcLength::FontRelative(FontRelativeLength::Em(0.85)),
"larger" => NoCalcLength::FontRelative(FontRelativeLength::Em(1.2)),
_ => return None
})
}
/// Parse a given absolute or relative dimension.
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<NoCalcLength, ()> {
match_ignore_ascii_case! { unit,
"px" => Ok(NoCalcLength::Absolute(Au((value * AU_PER_PX) as i32))),
"in" => Ok(NoCalcLength::Absolute(Au((value * AU_PER_IN) as i32))),
"cm" => Ok(NoCalcLength::Absolute(Au((value * AU_PER_CM) as i32))),
"mm" => Ok(NoCalcLength::Absolute(Au((value * AU_PER_MM) as i32))),
"q" => Ok(NoCalcLength::Absolute(Au((value * AU_PER_Q) as i32))),
"pt" => Ok(NoCalcLength::Absolute(Au((value * AU_PER_PT) as i32))),
"pc" => Ok(NoCalcLength::Absolute(Au((value * AU_PER_PC) as i32))),
// font-relative
"em" => Ok(NoCalcLength::FontRelative(FontRelativeLength::Em(value))),
"ex" => Ok(NoCalcLength::FontRelative(FontRelativeLength::Ex(value))),
"ch" => Ok(NoCalcLength::FontRelative(FontRelativeLength::Ch(value))),
"rem" => Ok(NoCalcLength::FontRelative(FontRelativeLength::Rem(value))),
// viewport percentages
"vw" => Ok(NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(value))),
"vh" => Ok(NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vh(value))),
"vmin" => Ok(NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vmin(value))),
"vmax" => Ok(NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vmax(value))),
_ => Err(())
}
}
}
/// An extension to `NoCalcLength` to parse `calc` expressions.
/// This is commonly used for the `<length>` values.
///
/// https://drafts.csswg.org/css-values/#lengths
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Length {
/// The `NoCalcLength` type that cannot parse `calc`
NoCalc(NoCalcLength),
/// A calc expression. /// A calc expression.
/// ///
/// https://drafts.csswg.org/css-values/#calc-notation /// https://drafts.csswg.org/css-values/#calc-notation
@ -242,9 +339,8 @@ pub enum Length {
impl HasViewportPercentage for Length { impl HasViewportPercentage for Length {
fn has_viewport_percentage(&self) -> bool { fn has_viewport_percentage(&self) -> bool {
match *self { match *self {
Length::ViewportPercentage(_) => true, Length::NoCalc(ref inner) => inner.has_viewport_percentage(),
Length::Calc(ref calc, _) => calc.has_viewport_percentage(), Length::Calc(ref calc, _) => calc.has_viewport_percentage(),
_ => false
} }
} }
} }
@ -252,12 +348,8 @@ impl HasViewportPercentage for Length {
impl ToCss for Length { impl ToCss for Length {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self { match *self {
Length::Absolute(length) => write!(dest, "{}px", length.to_f32_px()), Length::NoCalc(ref inner) => inner.to_css(dest),
Length::FontRelative(length) => length.to_css(dest),
Length::ViewportPercentage(length) => length.to_css(dest),
Length::Calc(ref calc, _) => calc.to_css(dest), Length::Calc(ref calc, _) => calc.to_css(dest),
/* This should only be reached from style dumping code */
Length::ServoCharacterWidth(CharacterWidth(i)) => write!(dest, "CharWidth({})", i),
} }
} }
} }
@ -268,11 +360,8 @@ impl Mul<CSSFloat> for Length {
#[inline] #[inline]
fn mul(self, scalar: CSSFloat) -> Length { fn mul(self, scalar: CSSFloat) -> Length {
match self { match self {
Length::Absolute(Au(v)) => Length::Absolute(Au(((v as f32) * scalar) as i32)), Length::NoCalc(inner) => Length::NoCalc(inner * scalar),
Length::FontRelative(v) => Length::FontRelative(v * scalar),
Length::ViewportPercentage(v) => Length::ViewportPercentage(v * scalar),
Length::Calc(..) => panic!("Can't multiply Calc!"), Length::Calc(..) => panic!("Can't multiply Calc!"),
Length::ServoCharacterWidth(_) => panic!("Can't multiply ServoCharacterWidth!"),
} }
} }
} }
@ -305,31 +394,15 @@ impl Mul<CSSFloat> for ViewportPercentageLength {
} }
} }
const AU_PER_PX: CSSFloat = 60.;
const AU_PER_IN: CSSFloat = AU_PER_PX * 96.;
const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54;
const AU_PER_MM: CSSFloat = AU_PER_IN / 25.4;
const AU_PER_Q: CSSFloat = AU_PER_MM / 4.;
const AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
const AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
impl Length { impl Length {
/// https://drafts.csswg.org/css-fonts-3/#font-size-prop /// https://drafts.csswg.org/css-fonts-3/#font-size-prop
pub fn from_str(s: &str) -> Option<Length> { pub fn from_str(s: &str) -> Option<Length> {
Some(match_ignore_ascii_case! { s, NoCalcLength::from_str(s).map(Length::NoCalc)
"xx-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 5), }
"x-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 4),
"small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 8 / 9),
"medium" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX)),
"large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 6 / 5),
"x-large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 2),
"xx-large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 2),
// https://github.com/servo/servo/issues/3423#issuecomment-56321664 /// Parse a given absolute or relative dimension.
"smaller" => Length::FontRelative(FontRelativeLength::Em(0.85)), pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> {
"larger" => Length::FontRelative(FontRelativeLength::Em(1.2)), NoCalcLength::parse_dimension(value, unit).map(Length::NoCalc)
_ => return None
})
} }
#[inline] #[inline]
@ -352,34 +425,10 @@ impl Length {
Length::parse_internal(input, AllowedNumericType::NonNegative) Length::parse_internal(input, AllowedNumericType::NonNegative)
} }
/// Parse a given absolute or relative dimension.
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> {
match_ignore_ascii_case! { unit,
"px" => Ok(Length::from_px(value)),
"in" => Ok(Length::Absolute(Au((value * AU_PER_IN) as i32))),
"cm" => Ok(Length::Absolute(Au((value * AU_PER_CM) as i32))),
"mm" => Ok(Length::Absolute(Au((value * AU_PER_MM) as i32))),
"q" => Ok(Length::Absolute(Au((value * AU_PER_Q) as i32))),
"pt" => Ok(Length::Absolute(Au((value * AU_PER_PT) as i32))),
"pc" => Ok(Length::Absolute(Au((value * AU_PER_PC) as i32))),
// font-relative
"em" => Ok(Length::FontRelative(FontRelativeLength::Em(value))),
"ex" => Ok(Length::FontRelative(FontRelativeLength::Ex(value))),
"ch" => Ok(Length::FontRelative(FontRelativeLength::Ch(value))),
"rem" => Ok(Length::FontRelative(FontRelativeLength::Rem(value))),
// viewport percentages
"vw" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vw(value))),
"vh" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vh(value))),
"vmin" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmin(value))),
"vmax" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmax(value))),
_ => Err(())
}
}
/// Get an absolute length from a px values. /// Get an absolute length from a px values.
#[inline] #[inline]
pub fn from_px(px_value: CSSFloat) -> Length { pub fn from_px(px_value: CSSFloat) -> Length {
Length::Absolute(Au((px_value * AU_PER_PX) as i32)) Length::NoCalc(NoCalcLength::Absolute(Au((px_value * AU_PER_PX) as i32)))
} }
/// Extract inner length without a clone, replacing it with a 0 Au /// Extract inner length without a clone, replacing it with a 0 Au
@ -648,9 +697,9 @@ impl CalcLengthOrPercentage {
match value { match value {
SimplifiedValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p) =>
percentage = Some(percentage.unwrap_or(0.) + p), percentage = Some(percentage.unwrap_or(0.) + p),
SimplifiedValueNode::Length(Length::Absolute(Au(au))) => SimplifiedValueNode::Length(NoCalcLength::Absolute(Au(au))) =>
absolute = Some(absolute.unwrap_or(0) + au), absolute = Some(absolute.unwrap_or(0) + au),
SimplifiedValueNode::Length(Length::ViewportPercentage(v)) => SimplifiedValueNode::Length(NoCalcLength::ViewportPercentage(v)) =>
match v { match v {
ViewportPercentageLength::Vw(val) => ViewportPercentageLength::Vw(val) =>
vw = Some(vw.unwrap_or(0.) + val), vw = Some(vw.unwrap_or(0.) + val),
@ -661,7 +710,7 @@ impl CalcLengthOrPercentage {
ViewportPercentageLength::Vmax(val) => ViewportPercentageLength::Vmax(val) =>
vmax = Some(vmax.unwrap_or(0.) + val), vmax = Some(vmax.unwrap_or(0.) + val),
}, },
SimplifiedValueNode::Length(Length::FontRelative(f)) => SimplifiedValueNode::Length(NoCalcLength::FontRelative(f)) =>
match f { match f {
FontRelativeLength::Em(val) => FontRelativeLength::Em(val) =>
em = Some(em.unwrap_or(0.) + val), em = Some(em.unwrap_or(0.) + val),

View file

@ -26,7 +26,7 @@ pub use self::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword,
pub use self::image::{SizeKeyword, VerticalDirection}; pub use self::image::{SizeKeyword, VerticalDirection};
pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage}; pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage};
pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto}; pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, CalcUnit}; pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength, CalcUnit};
pub mod basic_shape; pub mod basic_shape;
pub mod grid; pub mod grid;
@ -109,13 +109,14 @@ impl<'a> Mul<CSSFloat> for &'a SimplifiedSumNode {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub enum SimplifiedValueNode { pub enum SimplifiedValueNode {
Length(Length), Length(NoCalcLength),
Angle(Angle), Angle(Angle),
Time(Time), Time(Time),
Percentage(CSSFloat), Percentage(CSSFloat),
Number(CSSFloat), Number(CSSFloat),
Sum(Box<SimplifiedSumNode>), Sum(Box<SimplifiedSumNode>),
} }
impl<'a> Mul<CSSFloat> for &'a SimplifiedValueNode { impl<'a> Mul<CSSFloat> for &'a SimplifiedValueNode {
type Output = SimplifiedValueNode; type Output = SimplifiedValueNode;