Skip to content

Commit

Permalink
Split the Length type (introduce NoCalcLength)
Browse files Browse the repository at this point in the history
  • Loading branch information
wafflespeanut committed Jan 28, 2017
1 parent 556a46f commit 4035bbd
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 89 deletions.
39 changes: 39 additions & 0 deletions components/style/values/computed/length.rs
Expand Up @@ -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)]
Expand Down
24 changes: 0 additions & 24 deletions components/style/values/computed/mod.rs
Expand Up @@ -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)]
Expand Down
175 changes: 112 additions & 63 deletions components/style/values/specified/length.rs
Expand Up @@ -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.
Expand Down Expand Up @@ -205,12 +213,12 @@ impl CharacterWidth {
}
}

/// A length.
/// A `<length>` 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

Expand All @@ -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<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.
///
/// https://drafts.csswg.org/css-values/#calc-notation
Expand All @@ -242,22 +339,17 @@ 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
}
}
}

impl ToCss for Length {
fn to_css<W>(&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),
}
}
}
Expand All @@ -268,11 +360,8 @@ impl Mul<CSSFloat> 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!"),
}
}
}
Expand Down Expand Up @@ -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 {
/// https://drafts.csswg.org/css-fonts-3/#font-size-prop
pub fn from_str(s: &str) -> Option<Length> {
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<Length, ()> {
NoCalcLength::parse_dimension(value, unit).map(Length::NoCalc)
}

#[inline]
Expand All @@ -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<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.
#[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
Expand Down Expand Up @@ -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),
Expand All @@ -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),
Expand Down
5 changes: 3 additions & 2 deletions components/style/values/specified/mod.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -109,13 +109,14 @@ impl<'a> Mul<CSSFloat> 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<SimplifiedSumNode>),
}

impl<'a> Mul<CSSFloat> for &'a SimplifiedValueNode {
type Output = SimplifiedValueNode;

Expand Down

0 comments on commit 4035bbd

Please sign in to comment.