diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index b2a3a983e0df..74c9fd6287f8 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -17,6 +17,45 @@ pub use super::image::{EndingShape as GradientShape, Gradient, GradientKind, Ima pub use super::image::{LengthOrKeyword, LengthOrPercentageOrKeyword}; 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)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 15aa9ceaf25f..a653d18918c0 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -121,30 +121,6 @@ impl ToComputedValue for specified::CSSColor { 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)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 5f53376bb09b..f6d306550648 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -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::{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)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] /// A font relative length. @@ -205,12 +213,12 @@ impl CharacterWidth { } } -/// A length. +/// A `` without taking `calc` expressions into account /// /// https://drafts.csswg.org/css-values/#lengths -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Copy, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub enum Length { +pub enum NoCalcLength { /// An absolute length: https://drafts.csswg.org/css-values/#absolute-length Absolute(Au), // application units @@ -229,7 +237,96 @@ pub enum Length { /// This cannot be specified by the user directly and is only generated by /// `Stylist::synthesize_rules_for_legacy_attributes()`. 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(&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 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 { + 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 { + 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 `` 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. /// /// https://drafts.csswg.org/css-values/#calc-notation @@ -242,9 +339,8 @@ pub enum Length { impl HasViewportPercentage for Length { fn has_viewport_percentage(&self) -> bool { match *self { - Length::ViewportPercentage(_) => true, + Length::NoCalc(ref inner) => inner.has_viewport_percentage(), Length::Calc(ref calc, _) => calc.has_viewport_percentage(), - _ => false } } } @@ -252,12 +348,8 @@ impl HasViewportPercentage for Length { impl ToCss for Length { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { - Length::Absolute(length) => write!(dest, "{}px", length.to_f32_px()), - Length::FontRelative(length) => length.to_css(dest), - Length::ViewportPercentage(length) => length.to_css(dest), + Length::NoCalc(ref inner) => inner.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 for Length { #[inline] fn mul(self, scalar: CSSFloat) -> Length { match self { - Length::Absolute(Au(v)) => Length::Absolute(Au(((v as f32) * scalar) as i32)), - Length::FontRelative(v) => Length::FontRelative(v * scalar), - Length::ViewportPercentage(v) => Length::ViewportPercentage(v * scalar), + Length::NoCalc(inner) => Length::NoCalc(inner * scalar), Length::Calc(..) => panic!("Can't multiply Calc!"), - Length::ServoCharacterWidth(_) => panic!("Can't multiply ServoCharacterWidth!"), } } } @@ -305,31 +394,15 @@ impl Mul 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 { /// https://drafts.csswg.org/css-fonts-3/#font-size-prop pub fn from_str(s: &str) -> Option { - Some(match_ignore_ascii_case! { s, - "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), + NoCalcLength::from_str(s).map(Length::NoCalc) + } - // https://github.com/servo/servo/issues/3423#issuecomment-56321664 - "smaller" => Length::FontRelative(FontRelativeLength::Em(0.85)), - "larger" => Length::FontRelative(FontRelativeLength::Em(1.2)), - _ => return None - }) + /// Parse a given absolute or relative dimension. + pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result { + NoCalcLength::parse_dimension(value, unit).map(Length::NoCalc) } #[inline] @@ -352,34 +425,10 @@ impl Length { Length::parse_internal(input, AllowedNumericType::NonNegative) } - /// Parse a given absolute or relative dimension. - pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result { - 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. #[inline] 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 @@ -648,9 +697,9 @@ impl CalcLengthOrPercentage { match value { SimplifiedValueNode::Percentage(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), - SimplifiedValueNode::Length(Length::ViewportPercentage(v)) => + SimplifiedValueNode::Length(NoCalcLength::ViewportPercentage(v)) => match v { ViewportPercentageLength::Vw(val) => vw = Some(vw.unwrap_or(0.) + val), @@ -661,7 +710,7 @@ impl CalcLengthOrPercentage { ViewportPercentageLength::Vmax(val) => vmax = Some(vmax.unwrap_or(0.) + val), }, - SimplifiedValueNode::Length(Length::FontRelative(f)) => + SimplifiedValueNode::Length(NoCalcLength::FontRelative(f)) => match f { FontRelativeLength::Em(val) => em = Some(em.unwrap_or(0.) + val), diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 1a5b98074059..253237528bc8 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -26,7 +26,7 @@ pub use self::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, pub use self::image::{SizeKeyword, VerticalDirection}; pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage}; 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 grid; @@ -109,13 +109,14 @@ impl<'a> Mul for &'a SimplifiedSumNode { #[derive(Clone, Debug)] #[allow(missing_docs)] pub enum SimplifiedValueNode { - Length(Length), + Length(NoCalcLength), Angle(Angle), Time(Time), Percentage(CSSFloat), Number(CSSFloat), Sum(Box), } + impl<'a> Mul for &'a SimplifiedValueNode { type Output = SimplifiedValueNode;