diff --git a/servo/components/style/values/computed/length.rs b/servo/components/style/values/computed/length.rs index 8c90d38eefa0..5878fde0f512 100644 --- a/servo/components/style/values/computed/length.rs +++ b/servo/components/style/values/computed/length.rs @@ -223,7 +223,7 @@ impl specified::CalcLengthOrPercentage { let mut length = Au(0); if let Some(absolute) = self.absolute { - length += zoom_fn(absolute); + length += zoom_fn(absolute.to_computed_value(context)); } for val in &[self.vw.map(ViewportPercentageLength::Vw), @@ -269,7 +269,7 @@ impl ToComputedValue for specified::CalcLengthOrPercentage { fn from_computed_value(computed: &CalcLengthOrPercentage) -> Self { specified::CalcLengthOrPercentage { clamping_mode: computed.clamping_mode, - absolute: Some(computed.length), + absolute: Some(AbsoluteLength::from_computed_value(&computed.length)), percentage: computed.percentage, ..Default::default() } diff --git a/servo/components/style/values/specified/calc.rs b/servo/components/style/values/specified/calc.rs index 93db7730f375..408a5f4ab5b4 100644 --- a/servo/components/style/values/specified/calc.rs +++ b/servo/components/style/values/specified/calc.rs @@ -6,7 +6,6 @@ //! //! [calc]: https://drafts.csswg.org/css-values/#calc-notation -use app_units::Au; use cssparser::{Parser, Token, BasicParseError}; use parser::ParserContext; use std::ascii::AsciiExt; @@ -16,7 +15,8 @@ use style_traits::values::specified::AllowedLengthType; use values::{CSSInteger, CSSFloat}; use values::computed; use values::specified::{Angle, Time}; -use values::specified::length::{FontRelativeLength, NoCalcLength, ViewportPercentageLength}; +use values::specified::length::{AbsoluteLength, FontRelativeLength, NoCalcLength}; +use values::specified::length::ViewportPercentageLength; /// A node inside a `Calc` expression's AST. #[derive(Clone, Debug)] @@ -68,7 +68,7 @@ pub enum CalcUnit { #[allow(missing_docs)] pub struct CalcLengthOrPercentage { pub clamping_mode: AllowedLengthType, - pub absolute: Option, + pub absolute: Option, pub vw: Option, pub vh: Option, pub vmin: Option, @@ -118,6 +118,17 @@ impl ToCss for CalcLengthOrPercentage { }; } + macro_rules! serialize_abs { + ( $( $val:ident ),+ ) => { + $( + if let Some(AbsoluteLength::$val(v)) = self.absolute { + first_value_check!(v); + AbsoluteLength::$val(v.abs()).to_css(dest)?; + } + )+ + }; + } + dest.write_str("calc(")?; // NOTE(emilio): Percentages first because of web-compat problems, see: @@ -129,18 +140,17 @@ impl ToCss for CalcLengthOrPercentage { // NOTE(emilio): The order here it's very intentional, and alphabetic // per the spec linked above. - serialize!(ch, em, ex); + serialize!(ch); + serialize_abs!(Cm); + serialize!(em, ex); + serialize_abs!(In); #[cfg(feature = "gecko")] { serialize!(mozmm); } - if let Some(val) = self.absolute { - first_value_check!(val); - val.abs().to_css(dest)?; - } - + serialize_abs!(Mm, Pc, Pt, Px, Q); serialize!(rem, vh, vmax, vmin, vw); dest.write_str(")") @@ -349,8 +359,10 @@ impl CalcNode { match *l { NoCalcLength::Absolute(abs) => { ret.absolute = Some( - ret.absolute.unwrap_or(Au(0)) + - Au::from(abs).scale_by(factor) + match ret.absolute { + Some(value) => value + abs * factor, + None => abs * factor, + } ); } NoCalcLength::FontRelative(rel) => { diff --git a/servo/components/style/values/specified/length.rs b/servo/components/style/values/specified/length.rs index 6a0bd08b880f..da8fda5ca32d 100644 --- a/servo/components/style/values/specified/length.rs +++ b/servo/components/style/values/specified/length.rs @@ -13,7 +13,7 @@ use font_metrics::FontMetricsQueryResult; use parser::{Parse, ParserContext}; use std::{cmp, fmt, mem}; use std::ascii::AsciiExt; -use std::ops::Mul; +use std::ops::{Add, Mul}; use style_traits::{ToCss, ParseError, StyleParseError}; use style_traits::values::specified::AllowedLengthType; use stylesheets::CssRuleType; @@ -278,6 +278,23 @@ impl AbsoluteLength { | AbsoluteLength::Pc(v) => v == 0., } } + + /// Convert this into a pixel value. + #[inline] + pub fn to_px(&self) -> CSSFloat { + use std::f32; + + let pixel = match *self { + AbsoluteLength::Px(value) => value, + AbsoluteLength::In(value) => value * (AU_PER_IN / AU_PER_PX), + AbsoluteLength::Cm(value) => value * (AU_PER_CM / AU_PER_PX), + AbsoluteLength::Mm(value) => value * (AU_PER_MM / AU_PER_PX), + AbsoluteLength::Q(value) => value * (AU_PER_Q / AU_PER_PX), + AbsoluteLength::Pt(value) => value * (AU_PER_PT / AU_PER_PX), + AbsoluteLength::Pc(value) => value * (AU_PER_PC / AU_PER_PX), + }; + pixel.min(f32::MAX).max(f32::MIN) + } } impl ToComputedValue for AbsoluteLength { @@ -337,6 +354,24 @@ impl Mul for AbsoluteLength { } } +impl Add for AbsoluteLength { + type Output = Self; + + #[inline] + fn add(self, rhs: Self) -> Self { + match (self, rhs) { + (AbsoluteLength::Px(x), AbsoluteLength::Px(y)) => AbsoluteLength::Px(x + y), + (AbsoluteLength::In(x), AbsoluteLength::In(y)) => AbsoluteLength::In(x + y), + (AbsoluteLength::Cm(x), AbsoluteLength::Cm(y)) => AbsoluteLength::Cm(x + y), + (AbsoluteLength::Mm(x), AbsoluteLength::Mm(y)) => AbsoluteLength::Mm(x + y), + (AbsoluteLength::Q(x), AbsoluteLength::Q(y)) => AbsoluteLength::Q(x + y), + (AbsoluteLength::Pt(x), AbsoluteLength::Pt(y)) => AbsoluteLength::Pt(x + y), + (AbsoluteLength::Pc(x), AbsoluteLength::Pc(y)) => AbsoluteLength::Pc(x + y), + _ => AbsoluteLength::Px(self.to_px() + rhs.to_px()), + } + } +} + /// Represents a physical length (mozmm) based on DPI #[derive(Clone, Copy, Debug, PartialEq)] #[cfg(feature = "gecko")]