From 9556141e571757ccf261712a696ec65736b78a0b Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Tue, 11 Aug 2015 17:20:23 -0400 Subject: [PATCH 01/22] Implement Calc for LengthOrPercentage --- components/layout/block.rs | 9 +- components/layout/display_list_builder.rs | 2 + components/layout/inline.rs | 7 +- components/layout/model.rs | 4 +- components/style/properties.mako.rs | 23 ++-- components/style/values.rs | 133 ++++++++++++++++++++++ 6 files changed, 165 insertions(+), 13 deletions(-) diff --git a/components/layout/block.rs b/components/layout/block.rs index d697cad97a9..e573e422448 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -331,9 +331,8 @@ impl CandidateBSizeIterator { (LengthOrPercentageOrAuto::Length(length), _) => MaybeAuto::Specified(length), }; let max_block_size = match (fragment.style.max_block_size(), block_container_block_size) { - (LengthOrPercentageOrNone::Percentage(percent), Some(block_container_block_size)) => { - Some(block_container_block_size.scale_by(percent)) - } + (LengthOrPercentageOrNone::Percentage(percent), Some(block_container_block_size)) => + Some(block_container_block_size.scale_by(percent)), (LengthOrPercentageOrNone::Percentage(_), None) | (LengthOrPercentageOrNone::None, _) => None, (LengthOrPercentageOrNone::Length(length), _) => Some(length), @@ -342,6 +341,10 @@ impl CandidateBSizeIterator { (LengthOrPercentage::Percentage(percent), Some(block_container_block_size)) => { block_container_block_size.scale_by(percent) } + (LengthOrPercentage::Calc(calc), Some(block_container_block_size)) => { + calc.length() + block_container_block_size.scale_by(calc.percentage()) + } + (LengthOrPercentage::Calc(calc), None) => calc.length(), (LengthOrPercentage::Percentage(_), None) => Au(0), (LengthOrPercentage::Length(length), _) => length, }; diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 0485d549c4a..3f8400792d0 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -1955,6 +1955,8 @@ fn position_to_offset(position: LengthOrPercentage, Au(total_length): Au) -> f32 fmin(1.0, (length as f32) / (total_length as f32)) } LengthOrPercentage::Percentage(percentage) => percentage as f32, + LengthOrPercentage::Calc(calc) => + fmin(1.0, calc.percentage() + (calc.length().0 as f32) / (total_length as f32)), } } diff --git a/components/layout/inline.rs b/components/layout/inline.rs index 4b5a6b985c7..cbbb3bddff6 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -988,7 +988,12 @@ impl InlineFlow { let percent_offset = line_height.scale_by(p); offset_from_baseline = offset_from_baseline - percent_offset } - } + vertical_align::T::Calc(calc) => { + let line_height = fragment.calculate_line_height(layout_context); + let percent_offset = line_height.scale_by(calc.percentage()); + offset_from_baseline = offset_from_baseline - percent_offset - calc.length() + } + } } (offset_from_baseline - ascent, largest_size_updated) } diff --git a/components/layout/model.rs b/components/layout/model.rs index 6b7fdcbb58e..ca50b7790d3 100644 --- a/components/layout/model.rs +++ b/components/layout/model.rs @@ -416,7 +416,9 @@ pub fn specified_or_none(length: LengthOrPercentageOrNone, containing_length: Au pub fn specified(length: LengthOrPercentage, containing_length: Au) -> Au { match length { LengthOrPercentage::Length(length) => length, - LengthOrPercentage::Percentage(p) => containing_length.scale_by(p) + LengthOrPercentage::Percentage(p) => containing_length.scale_by(p), + LengthOrPercentage::Calc(calc) => + containing_length.scale_by(calc.percentage()) + calc.length(), } } diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index 33508b4220a..fa9aa4e9617 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -756,7 +756,7 @@ pub mod longhands { pub mod computed_value { use std::fmt; use util::geometry::Au; - use values::CSSFloat; + use values::{CSSFloat, computed}; #[allow(non_camel_case_types)] #[derive(PartialEq, Copy, Clone, HeapSizeOf)] pub enum T { @@ -765,6 +765,7 @@ pub mod longhands { % endfor Length(Au), Percentage(CSSFloat), + Calc(computed::Calc), } impl fmt::Debug for T { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -774,6 +775,8 @@ pub mod longhands { % endfor &T::Length(length) => write!(f, "{:?}", length), &T::Percentage(number) => write!(f, "{}%", number), + // XXX HACK WRONG + &T::Calc(calc) => write!(f, "{}%", 10.), } } } @@ -785,6 +788,7 @@ pub mod longhands { % endfor T::Length(value) => value.to_css(dest), T::Percentage(percentage) => write!(dest, "{}%", percentage * 100.), + T::Calc(calc) => calc.to_css(dest), } } } @@ -805,12 +809,12 @@ pub mod longhands { % endfor SpecifiedValue::LengthOrPercentage(value) => { match value.to_computed_value(context) { - computed::LengthOrPercentage::Length(value) => { - computed_value::T::Length(value) - } - computed::LengthOrPercentage::Percentage(value) => { - computed_value::T::Percentage(value) - } + computed::LengthOrPercentage::Length(value) => + computed_value::T::Length(value), + computed::LengthOrPercentage::Percentage(value) => + computed_value::T::Percentage(value), + computed::LengthOrPercentage::Calc(value) => + computed_value::T::Calc(value), } } } @@ -1909,7 +1913,10 @@ pub mod longhands { .map(|value| match value { specified::LengthOrPercentage::Length(value) => value, specified::LengthOrPercentage::Percentage(value) => - specified::Length::FontRelative(specified::FontRelativeLength::Em(value)) + specified::Length::FontRelative(specified::FontRelativeLength::Em(value)), + // XXX WRONG HACK + specified::LengthOrPercentage::Calc(calc) => + specified::Length::FontRelative(specified::FontRelativeLength::Em(20.)), }) .or_else(|()| { match_ignore_ascii_case! { try!(input.expect_ident()), diff --git a/components/style/values.rs b/components/style/values.rs index 7e5774d9262..a3dcac5a81a 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -353,11 +353,93 @@ pub mod specified { } } + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] + pub struct Calc { + pub absolute: Option, + pub font_relative: Option, + pub viewport_percentage: Option, + pub percentage: Option, + } + impl Calc { + pub fn parse_component(&mut self, input: &mut Parser) -> Result<(), ()> { + match try!(input.next()) { + Token::Dimension(ref value, ref unit) => { + let value = value.value; + match_ignore_ascii_case! { unit, + "px" => self.absolute = + Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_PX) as i32)), + "in" => self.absolute = + Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_IN) as i32)), + "cm" => self.absolute = + Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_CM) as i32)), + "mm" => self.absolute = + Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_MM) as i32)), + "pt" => self.absolute = + Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_PT) as i32)), + "pc" => self.absolute = + Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_PC) as i32)) + // font-relative + /*"em" => Ok(Length::FontRelative(FontRelativeLength::Em(value))), + "ex" => Ok(Length::FontRelative(FontRelativeLength::Ex(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)))*/ + // Handle em, ex, rem, vw, vh, vmin, vmax + _ => return Err(()) + } + }, + Token::Percentage(ref value) => + self.percentage = Some(self.percentage.unwrap_or(0.) + value.unit_value), + Token::Number(ref value) if value.value == 0. => + self.absolute = self.absolute.or(Some(Au(0))), + _ => return Err(()) + }; + Ok(()) + } + + pub fn parse(input: &mut Parser) -> Result { + let mut calc = Calc { + absolute: None, + font_relative: None, + viewport_percentage: None, + percentage: None, + }; + + try!(calc.parse_component(input)); + let operator = try!(input.next()); + match operator { + Token::Delim('+') => (), + _ => return Err(()) + }; + + try!(calc.parse_component(input)); + Ok(calc) + } + } + + impl ToCss for Calc { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + // XXX WRONG HACK + try!(write!(dest, "calc(")); + if let Some(absolute) = self.absolute { + try!(write!(dest, "{}px", Au::to_px(absolute))); + } + if let Some(FontRelativeLength::Em(font_relative)) = self.font_relative { + try!(write!(dest, "{}em", font_relative)); + } + + write!(dest, ")") + } + } #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub enum LengthOrPercentage { Length(Length), Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] + Calc(Calc), } impl ToCss for LengthOrPercentage { @@ -366,6 +448,7 @@ pub mod specified { &LengthOrPercentage::Length(length) => length.to_css(dest), &LengthOrPercentage::Percentage(percentage) => write!(dest, "{}%", percentage * 100.), + &LengthOrPercentage::Calc(calc) => calc.to_css(dest), } } } @@ -384,6 +467,10 @@ pub mod specified { Ok(LengthOrPercentage::Percentage(value.unit_value)), Token::Number(ref value) if value.value == 0. => Ok(LengthOrPercentage::Length(Length::Absolute(Au(0)))), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + let calc = try!(input.parse_nested_block(Calc::parse)); + Ok(LengthOrPercentage::Calc(calc)) + }, _ => Err(()) } } @@ -938,10 +1025,50 @@ pub mod computed { } } + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] + pub struct Calc { + length: Option, + percentage: Option, + } + + impl Calc { + pub fn length(&self) -> Au { + self.length.unwrap_or(Au(0)) + } + + pub fn percentage(&self) -> CSSFloat { + self.percentage.unwrap_or(0.) + } + } + + impl ::cssparser::ToCss for Calc { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match (self.length, self.percentage) { + (None, Some(p)) => write!(dest, "{}%", p), + (Some(l), None) => write!(dest, "{}px", Au::to_px(l)), + (Some(l), Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p * 100.), + _ => unreachable!() + } + } + } + + impl ToComputedValue for specified::Calc { + type ComputedValue = Calc; + + fn to_computed_value(&self, context: &Context) -> Calc { + let length = self.absolute; + let percentage = self.percentage; + + Calc { length: length, percentage: percentage } + } + } + + #[derive(PartialEq, Clone, Copy, HeapSizeOf)] pub enum LengthOrPercentage { Length(Au), Percentage(CSSFloat), + Calc(Calc), } impl LengthOrPercentage { @@ -955,6 +1082,8 @@ pub mod computed { match self { &LengthOrPercentage::Length(length) => write!(f, "{:?}", length), &LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage * 100.), + // XXX HACK WRONG + &LengthOrPercentage::Calc(calc) => write!(f, "{}%", 100.), } } } @@ -970,6 +1099,9 @@ pub mod computed { specified::LengthOrPercentage::Percentage(value) => { LengthOrPercentage::Percentage(value) } + specified::LengthOrPercentage::Calc(calc) => { + LengthOrPercentage::Calc(calc.to_computed_value(context)) + } } } } @@ -980,6 +1112,7 @@ pub mod computed { &LengthOrPercentage::Length(length) => length.to_css(dest), &LengthOrPercentage::Percentage(percentage) => write!(dest, "{}%", percentage * 100.), + &LengthOrPercentage::Calc(calc) => calc.to_css(dest), } } } From cb4d878169666ddd8ceffc625f30f36103726cf1 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Tue, 11 Aug 2015 21:08:05 -0400 Subject: [PATCH 02/22] Implement Calc for LengthOrPercentageOrAuto --- components/layout/block.rs | 10 ++++++++++ components/layout/fragment.rs | 11 +++++++++++ components/layout/model.rs | 3 +++ components/layout/table.rs | 2 ++ components/layout/table_row.rs | 3 +++ components/style/values.rs | 13 +++++++++++++ components/style/viewport.rs | 2 ++ 7 files changed, 44 insertions(+) diff --git a/components/layout/block.rs b/components/layout/block.rs index e573e422448..7c54df6e17c 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -327,8 +327,12 @@ impl CandidateBSizeIterator { (LengthOrPercentageOrAuto::Percentage(percent), Some(block_container_block_size)) => { MaybeAuto::Specified(block_container_block_size.scale_by(percent)) } + (LengthOrPercentageOrAuto::Calc(calc), Some(block_container_block_size)) => { + MaybeAuto::Specified(calc.length() + block_container_block_size.scale_by(calc.percentage())) + } (LengthOrPercentageOrAuto::Percentage(_), None) | (LengthOrPercentageOrAuto::Auto, _) => MaybeAuto::Auto, (LengthOrPercentageOrAuto::Length(length), _) => MaybeAuto::Specified(length), + (LengthOrPercentageOrAuto::Calc(calc), _) => MaybeAuto::Specified(calc.length()), }; let max_block_size = match (fragment.style.max_block_size(), block_container_block_size) { (LengthOrPercentageOrNone::Percentage(percent), Some(block_container_block_size)) => @@ -1118,6 +1122,12 @@ impl BlockFlow { let content_block_size = self.fragment.style().content_block_size(); match (content_block_size, containing_block_size) { + (LengthOrPercentageOrAuto::Calc(calc), Some(container_size)) => { + Some(container_size.scale_by(calc.percentage()) + calc.length()) + } + (LengthOrPercentageOrAuto::Calc(calc), _) => { + Some(calc.length()) + }, (LengthOrPercentageOrAuto::Length(length), _) => Some(length), (LengthOrPercentageOrAuto::Percentage(percent), Some(container_size)) => { Some(container_size.scale_by(percent)) diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 02af5569d84..8e3c92cad5e 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -463,6 +463,12 @@ impl ReplacedImageFragmentInfo { MaybeAuto::Specified(container_size.scale_by(pc)) } (LengthOrPercentageOrAuto::Percentage(_), _, None) => MaybeAuto::Auto, + (LengthOrPercentageOrAuto::Calc(calc), _, Some(container_size)) => { + MaybeAuto::Specified(calc.length() + container_size.scale_by(calc.percentage())) + } + (LengthOrPercentageOrAuto::Calc(calc), _, None) => { + MaybeAuto::Specified(calc.length()) + } (LengthOrPercentageOrAuto::Auto, Some(dom_length), _) => MaybeAuto::Specified(dom_length), (LengthOrPercentageOrAuto::Auto, None, _) => MaybeAuto::Auto, } @@ -616,6 +622,10 @@ impl IframeFragmentInfo { let computed_size = match (content_size, containing_size) { (LengthOrPercentageOrAuto::Length(length), _) => length, (LengthOrPercentageOrAuto::Percentage(pc), Some(container_size)) => container_size.scale_by(pc), + (LengthOrPercentageOrAuto::Calc(calc), Some(container_size)) => { + container_size.scale_by(calc.percentage()) + calc.length() + }, + (LengthOrPercentageOrAuto::Calc(calc), None) => calc.length(), (LengthOrPercentageOrAuto::Percentage(_), None) => default_size, (LengthOrPercentageOrAuto::Auto, _) => default_size, }; @@ -1285,6 +1295,7 @@ impl Fragment { } (Some(dom_inline_size), _) => dom_inline_size, (None, LengthOrPercentageOrAuto::Length(length)) => length, + (None, LengthOrPercentageOrAuto::Calc(calc)) => calc.length(), }; result.union_block(&IntrinsicISizes { minimum_inline_size: image_inline_size, diff --git a/components/layout/model.rs b/components/layout/model.rs index ca50b7790d3..45efadf1246 100644 --- a/components/layout/model.rs +++ b/components/layout/model.rs @@ -379,6 +379,9 @@ impl MaybeAuto { LengthOrPercentageOrAuto::Percentage(percent) => { MaybeAuto::Specified(containing_length.scale_by(percent)) } + LengthOrPercentageOrAuto::Calc(calc) => { + MaybeAuto::Specified(calc.length() + containing_length.scale_by(calc.percentage())) + } LengthOrPercentageOrAuto::Length(length) => MaybeAuto::Specified(length) } } diff --git a/components/layout/table.rs b/components/layout/table.rs index f5ef95f1989..2e351b117fa 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -267,11 +267,13 @@ impl Flow for TableFlow { self.column_intrinsic_inline_sizes.push(ColumnIntrinsicInlineSize { minimum_length: match *specified_inline_size { LengthOrPercentageOrAuto::Auto | + LengthOrPercentageOrAuto::Calc(_) | LengthOrPercentageOrAuto::Percentage(_) => Au(0), LengthOrPercentageOrAuto::Length(length) => length, }, percentage: match *specified_inline_size { LengthOrPercentageOrAuto::Auto | + LengthOrPercentageOrAuto::Calc(_) | LengthOrPercentageOrAuto::Length(_) => 0.0, LengthOrPercentageOrAuto::Percentage(percentage) => percentage, }, diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index e2b155bca78..eb02eade5b1 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -272,6 +272,7 @@ impl Flow for TableRowFlow { let child_column_inline_size = ColumnIntrinsicInlineSize { minimum_length: match child_specified_inline_size { LengthOrPercentageOrAuto::Auto | + LengthOrPercentageOrAuto::Calc(_) | LengthOrPercentageOrAuto::Percentage(_) => { child_base.intrinsic_inline_sizes.minimum_inline_size } @@ -279,6 +280,7 @@ impl Flow for TableRowFlow { }, percentage: match child_specified_inline_size { LengthOrPercentageOrAuto::Auto | + LengthOrPercentageOrAuto::Calc(_) | LengthOrPercentageOrAuto::Length(_) => 0.0, LengthOrPercentageOrAuto::Percentage(percentage) => percentage, }, @@ -286,6 +288,7 @@ impl Flow for TableRowFlow { constrained: match child_specified_inline_size { LengthOrPercentageOrAuto::Length(_) => true, LengthOrPercentageOrAuto::Auto | + LengthOrPercentageOrAuto::Calc(_) | LengthOrPercentageOrAuto::Percentage(_) => false, }, }; diff --git a/components/style/values.rs b/components/style/values.rs index a3dcac5a81a..c44190fff9d 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -490,6 +490,7 @@ pub mod specified { Length(Length), Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] Auto, + Calc(Calc), } impl ToCss for LengthOrPercentageOrAuto { @@ -499,6 +500,7 @@ pub mod specified { &LengthOrPercentageOrAuto::Percentage(percentage) => write!(dest, "{}%", percentage * 100.), &LengthOrPercentageOrAuto::Auto => dest.write_str("auto"), + &LengthOrPercentageOrAuto::Calc(calc) => calc.to_css(dest), } } } @@ -516,6 +518,10 @@ pub mod specified { Ok(LengthOrPercentageOrAuto::Length(Length::Absolute(Au(0)))), Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") => Ok(LengthOrPercentageOrAuto::Auto), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + let calc = try!(input.parse_nested_block(Calc::parse)); + Ok(LengthOrPercentageOrAuto::Calc(calc)) + }, _ => Err(()) } } @@ -1122,6 +1128,7 @@ pub mod computed { Length(Au), Percentage(CSSFloat), Auto, + Calc(Calc), } impl fmt::Debug for LengthOrPercentageOrAuto { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1129,6 +1136,8 @@ pub mod computed { &LengthOrPercentageOrAuto::Length(length) => write!(f, "{:?}", length), &LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage * 100.), &LengthOrPercentageOrAuto::Auto => write!(f, "auto"), + // XXX HACK WRONG + &LengthOrPercentageOrAuto::Calc(calc) => write!(f, "{}%", 100.), } } } @@ -1148,6 +1157,9 @@ pub mod computed { specified::LengthOrPercentageOrAuto::Auto => { LengthOrPercentageOrAuto::Auto } + specified::LengthOrPercentageOrAuto::Calc(calc) => { + LengthOrPercentageOrAuto::Calc(calc.to_computed_value(context)) + } } } } @@ -1159,6 +1171,7 @@ pub mod computed { &LengthOrPercentageOrAuto::Percentage(percentage) => write!(dest, "{}%", percentage * 100.), &LengthOrPercentageOrAuto::Auto => dest.write_str("auto"), + &LengthOrPercentageOrAuto::Calc(calc) => calc.to_css(dest), } } } diff --git a/components/style/viewport.rs b/components/style/viewport.rs index 15dcac2eefe..bb38050f9b4 100644 --- a/components/style/viewport.rs +++ b/components/style/viewport.rs @@ -437,6 +437,8 @@ impl ViewportConstraints { LengthOrPercentageOrAuto::Percentage(value) => Some(initial_viewport.$dimension.scale_by(value)), LengthOrPercentageOrAuto::Auto => None, + // XXX WRONG HACK + LengthOrPercentageOrAuto::Calc(calc) => None, } } else { None From 2bb6b4582aeffa2a5f09329aa82cfdbd1c7c93de Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Wed, 12 Aug 2015 03:13:14 -0400 Subject: [PATCH 03/22] Implement proper calc parsing --- components/style/lib.rs | 1 + components/style/values.rs | 256 +++++++++++++++++++++++++++++++------ 2 files changed, 215 insertions(+), 42 deletions(-) diff --git a/components/style/lib.rs b/components/style/lib.rs index a6a53464c26..99390a4bc3a 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -4,6 +4,7 @@ #![feature(arc_unique)] #![feature(box_syntax)] +#![feature(box_patterns)] #![feature(core_intrinsics)] #![feature(custom_attribute)] #![feature(custom_derive)] diff --git a/components/style/values.rs b/components/style/values.rs index c44190fff9d..809a9aebdca 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -353,6 +353,31 @@ pub mod specified { } } + #[derive(Clone, Debug)] + struct CalcSumNode { + products: Vec, + } + + #[derive(Clone, Debug)] + struct CalcProductNode { + values: Vec + } + + #[derive(Clone, Debug)] + enum CalcValueNode { + Length(Length), + Percentage(CSSFloat), + Number(CSSFloat), + Sum(Box), + } + + #[derive(Clone, Debug)] + enum CalcAstNode { + Add(CalcSumNode), + Multiply(CalcProductNode), + Value(CalcValueNode), + } + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub struct Calc { pub absolute: Option, @@ -361,46 +386,184 @@ pub mod specified { pub percentage: Option, } impl Calc { - pub fn parse_component(&mut self, input: &mut Parser) -> Result<(), ()> { - match try!(input.next()) { - Token::Dimension(ref value, ref unit) => { - let value = value.value; - match_ignore_ascii_case! { unit, - "px" => self.absolute = - Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_PX) as i32)), - "in" => self.absolute = - Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_IN) as i32)), - "cm" => self.absolute = - Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_CM) as i32)), - "mm" => self.absolute = - Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_MM) as i32)), - "pt" => self.absolute = - Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_PT) as i32)), - "pc" => self.absolute = - Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_PC) as i32)) - // font-relative - /*"em" => Ok(Length::FontRelative(FontRelativeLength::Em(value))), - "ex" => Ok(Length::FontRelative(FontRelativeLength::Ex(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)))*/ - // Handle em, ex, rem, vw, vh, vmin, vmax - _ => return Err(()) + fn parse_sum(input: &mut Parser) -> Result { + let mut products = Vec::new(); + products.push(try!(Calc::parse_product(input))); + + loop { + let next = input.next(); + match next { + Ok(Token::Delim('+')) => { + products.push(try!(Calc::parse_product(input))); } + Ok(Token::Delim('-')) => { + let mut right = try!(Calc::parse_product(input)); + right.values.push(CalcValueNode::Number(-1.)); + products.push(right); + } + Ok(_) => return Err(()), + _ => break + } + } + + let sum = CalcSumNode { products: products }; + println!("Parsed sum {:?} ", sum); + Ok(sum) + } + + fn parse_product(input: &mut Parser) -> Result { + let mut values = Vec::new(); + values.push(try!(Calc::parse_value(input))); + + loop { + let position = input.position(); + let next = input.next(); + match next { + Ok(Token::Delim('*')) => { + values.push(try!(Calc::parse_value(input))); + } + Ok(Token::Delim('/')) => { + if let Ok(Token::Number(ref value)) = input.next() { + if value.value == 0. { + return Err(()); + } + values.push(CalcValueNode::Number(1. / value.value)); + } else { + return Err(()); + } + } + _ => { + input.reset(position); + break + } + } + } + + let sum = CalcProductNode { values: values }; + println!("Parsed product {:?} ", sum); + Ok(sum) + } + + fn parse_value(input: &mut Parser) -> Result { + let next = input.next(); + match next { + Ok(Token::Number(ref value)) => Ok(CalcValueNode::Number(value.value)), + Ok(Token::Dimension(ref value, ref unit)) => + Length::parse_dimension(value.value, unit).map(CalcValueNode::Length), + Ok(Token::Percentage(ref value)) => + Ok(CalcValueNode::Percentage(value.unit_value)), + Ok(Token::ParenthesisBlock) => { + let result = try!(input.parse_nested_block(Calc::parse_sum)); + Ok(CalcValueNode::Sum(box result)) }, - Token::Percentage(ref value) => - self.percentage = Some(self.percentage.unwrap_or(0.) + value.unit_value), - Token::Number(ref value) if value.value == 0. => - self.absolute = self.absolute.or(Some(Au(0))), - _ => return Err(()) - }; - Ok(()) + _ => Err(()) + } + } + + fn simplify_ast(node: CalcSumNode) -> Result { + let mut simplified = Vec::new(); + for node in node.products { + let node = try!(Calc::simplify_product(node)); + match node { + CalcAstNode::Value(value) => { + let product = CalcProductNode { values: vec!(value) }; + simplified.push(product); + } + _ => return Err(()) + } + } + + Ok(CalcSumNode {products: simplified} ) + } + + fn simplify_product(node: CalcProductNode) -> Result { + let mut multiplier = 1.; + let mut node_with_unit: Option = None; + let mut node_hack: CalcAstNode; + for node in node.values { + node_hack = try!(Calc::simplify_value(node)); + if let CalcAstNode::Value(CalcValueNode::Number(n)) = node_hack { + multiplier *= n; + } else if node_with_unit.is_none() { + node_with_unit = Some(node_hack); + } else { + return Err(()); + } + } + + match node_with_unit { + None => Ok(CalcAstNode::Value(CalcValueNode::Number(multiplier))), + Some(CalcAstNode::Add(sum)) => + Ok(CalcAstNode::Add(CalcSumNode { + products: sum.products + .iter() + .map(|p| Calc::multiply_product(p, multiplier)) + .collect() + })), + Some(CalcAstNode::Value(ref value)) => + Ok(CalcAstNode::Value(Calc::multiply_value(value, multiplier))), + _ => unreachable!() + } + } + + fn multiply_product(node: &CalcProductNode, multiplier: CSSFloat) -> CalcProductNode { + CalcProductNode { + values: node.values + .iter() + .map(|v| Calc::multiply_value(v, multiplier)) + .collect() + } + } + + fn multiply_value(node: &CalcValueNode, multiplier: CSSFloat) -> CalcValueNode { + match node { + &CalcValueNode::Number(_) => unreachable!(), + &CalcValueNode::Percentage(p) => CalcValueNode::Percentage(p * multiplier), + &CalcValueNode::Sum(_) => unreachable!(), + &CalcValueNode::Length(l) => CalcValueNode::Length(Calc::multiply_length(l, multiplier)) + } + } + + fn multiply_length(length: Length, multiplier: CSSFloat) -> Length { + match length { + Length::Absolute(Au(au)) => + Length::Absolute(Au((au as CSSFloat * multiplier) as i32)), + _ => panic!() + } + } + + fn simplify_sum(node: CalcSumNode) -> Result { + let mut simplified = Vec::new(); + let length = node.products.len(); + for node in node.products { + let node = try!(Calc::simplify_product(node)); + match node { + CalcAstNode::Value(value) => { + let product = CalcProductNode { values: vec!(value) }; + if length == 1 { + return Ok(CalcAstNode::Multiply(product)); + } + simplified.push(product); + } + CalcAstNode::Add(sum) => simplified.push_all(&sum.products), + _ => return Err(()) + } + } + + Ok(CalcAstNode::Add(CalcSumNode {products: simplified} )) + } + + fn simplify_value(node: CalcValueNode) -> Result { + match node { + CalcValueNode::Sum(box sum) => Calc::simplify_sum(sum), + node => Ok(CalcAstNode::Value(node)) + } } pub fn parse(input: &mut Parser) -> Result { + + let ast = try!(Calc::parse_sum(input)); + let ast = try!(Calc::simplify_sum(ast)); let mut calc = Calc { absolute: None, font_relative: None, @@ -408,14 +571,23 @@ pub mod specified { percentage: None, }; - try!(calc.parse_component(input)); - let operator = try!(input.next()); - match operator { - Token::Delim('+') => (), - _ => return Err(()) - }; + if let CalcAstNode::Add(ast) = ast { + for value in ast.products { + assert!(value.values.len() == 1); + match value.values[0] { + CalcValueNode::Percentage(p) => + calc.percentage = Some(calc.percentage.unwrap_or(0.) + p), + CalcValueNode::Length(Length::Absolute(Au(au))) => + calc.absolute = Some(calc.absolute.unwrap_or(Au(0)) + Au(au)), + //CalcValueNode::Length(Length::FontRelative(Au(au))) + //calc.absolute = Some(calc.absolute.unwrap_or(0.) + au), + _ => return Err(()) + } + } + } else { + unreachable!() + } - try!(calc.parse_component(input)); Ok(calc) } } From 5df4b82a6b3e703998125c78bcd544e502661f10 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Wed, 12 Aug 2015 17:42:26 -0400 Subject: [PATCH 04/22] Implement font relative and viewport relative units for calc --- components/style/values.rs | 134 +++++++++++++++++++++++++------------ 1 file changed, 91 insertions(+), 43 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index 809a9aebdca..fb84901239a 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -381,8 +381,13 @@ pub mod specified { #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub struct Calc { pub absolute: Option, - pub font_relative: Option, - pub viewport_percentage: Option, + pub vw: Option, + pub vh: Option, + pub vmin: Option, + pub vmax: Option, + pub em: Option, + pub ex: Option, + pub rem: Option, pub percentage: Option, } impl Calc { @@ -460,22 +465,6 @@ pub mod specified { } } - fn simplify_ast(node: CalcSumNode) -> Result { - let mut simplified = Vec::new(); - for node in node.products { - let node = try!(Calc::simplify_product(node)); - match node { - CalcAstNode::Value(value) => { - let product = CalcProductNode { values: vec!(value) }; - simplified.push(product); - } - _ => return Err(()) - } - } - - Ok(CalcSumNode {products: simplified} ) - } - fn simplify_product(node: CalcProductNode) -> Result { let mut multiplier = 1.; let mut node_with_unit: Option = None; @@ -520,15 +509,7 @@ pub mod specified { &CalcValueNode::Number(_) => unreachable!(), &CalcValueNode::Percentage(p) => CalcValueNode::Percentage(p * multiplier), &CalcValueNode::Sum(_) => unreachable!(), - &CalcValueNode::Length(l) => CalcValueNode::Length(Calc::multiply_length(l, multiplier)) - } - } - - fn multiply_length(length: Length, multiplier: CSSFloat) -> Length { - match length { - Length::Absolute(Au(au)) => - Length::Absolute(Au((au as CSSFloat * multiplier) as i32)), - _ => panic!() + &CalcValueNode::Length(l) => CalcValueNode::Length(l * multiplier), } } @@ -564,23 +545,45 @@ pub mod specified { let ast = try!(Calc::parse_sum(input)); let ast = try!(Calc::simplify_sum(ast)); - let mut calc = Calc { - absolute: None, - font_relative: None, - viewport_percentage: None, - percentage: None, - }; + + let mut absolute = None; + let mut vw = None; + let mut vh = None; + let mut vmax = None; + let mut vmin = None; + let mut em = None; + let mut ex = None; + let mut rem = None; + let mut percentage = None; if let CalcAstNode::Add(ast) = ast { for value in ast.products { assert!(value.values.len() == 1); match value.values[0] { CalcValueNode::Percentage(p) => - calc.percentage = Some(calc.percentage.unwrap_or(0.) + p), + percentage = Some(percentage.unwrap_or(0.) + p), CalcValueNode::Length(Length::Absolute(Au(au))) => - calc.absolute = Some(calc.absolute.unwrap_or(Au(0)) + Au(au)), - //CalcValueNode::Length(Length::FontRelative(Au(au))) - //calc.absolute = Some(calc.absolute.unwrap_or(0.) + au), + absolute = Some(absolute.unwrap_or(0) + au), + CalcValueNode::Length(Length::ViewportPercentage(v)) => + match v { + ViewportPercentageLength::Vw(val) => + vw = Some(vw.unwrap_or(0.) + val), + ViewportPercentageLength::Vh(val) => + vh = Some(vh.unwrap_or(0.) + val), + ViewportPercentageLength::Vmin(val) => + vmin = Some(vmin.unwrap_or(0.) + val), + ViewportPercentageLength::Vmax(val) => + vmax = Some(vmax.unwrap_or(0.) + val), + }, + CalcValueNode::Length(Length::FontRelative(f)) => + match f { + FontRelativeLength::Em(val) => + em = Some(em.unwrap_or(0.) + val), + FontRelativeLength::Ex(val) => + ex = Some(ex.unwrap_or(0.) + val), + FontRelativeLength::Rem(val) => + rem = Some(rem.unwrap_or(0.) + val), + }, _ => return Err(()) } } @@ -588,7 +591,17 @@ pub mod specified { unreachable!() } - Ok(calc) + Ok(Calc { + absolute: absolute.map(Au), + vw: vw.map(ViewportPercentageLength::Vw), + vh: vh.map(ViewportPercentageLength::Vh), + vmax: vmax.map(ViewportPercentageLength::Vmax), + vmin: vmin.map(ViewportPercentageLength::Vmin), + em: em.map(FontRelativeLength::Em), + ex: ex.map(FontRelativeLength::Ex), + rem: rem.map(FontRelativeLength::Rem), + percentage: percentage, + }) } } @@ -596,12 +609,31 @@ pub mod specified { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { // XXX WRONG HACK try!(write!(dest, "calc(")); + if let Some(FontRelativeLength::Em(em)) = self.em { + try!(write!(dest, "{}em", em)); + } + if let Some(FontRelativeLength::Ex(ex)) = self.ex { + try!(write!(dest, "{}ex", ex)); + } if let Some(absolute) = self.absolute { try!(write!(dest, "{}px", Au::to_px(absolute))); } - if let Some(FontRelativeLength::Em(font_relative)) = self.font_relative { - try!(write!(dest, "{}em", font_relative)); + if let Some(FontRelativeLength::Rem(rem)) = self.rem { + try!(write!(dest, "{}rem", rem)); } + if let Some(ViewportPercentageLength::Vh(vh)) = self.vh { + try!(write!(dest, "{}vh", vh)); + } + if let Some(ViewportPercentageLength::Vmax(vmax)) = self.vmax { + try!(write!(dest, "{}vmax", vmax)); + } + if let Some(ViewportPercentageLength::Vmin(vmin)) = self.vmin { + try!(write!(dest, "{}vmin", vmin)); + } + if let Some(ViewportPercentageLength::Vw(vw)) = self.vw { + try!(write!(dest, "{}vw", vw)); + } + write!(dest, ")") } @@ -1234,10 +1266,26 @@ pub mod computed { type ComputedValue = Calc; fn to_computed_value(&self, context: &Context) -> Calc { - let length = self.absolute; - let percentage = self.percentage; + let mut length = None; - Calc { length: length, percentage: percentage } + if let Some(absolute) = self.absolute { + length = Some(length.unwrap_or(Au(0)) + absolute); + } + + for val in vec!(self.vw, self.vh, self.vmin, self.vmax) { + if let Some(val) = val { + length = Some(length.unwrap_or(Au(0)) + + val.to_computed_value(context.viewport_size)); + } + } + for val in vec!(self.em, self.ex, self.rem) { + if let Some(val) = val { + length = Some(length.unwrap_or(Au(0)) + + val.to_computed_value(context.font_size, context.root_font_size)); + } + } + + Calc { length: length, percentage: self.percentage } } } From af4d2e910e2134f4ac597053488f572eb70ba3df Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Wed, 12 Aug 2015 23:18:16 -0400 Subject: [PATCH 05/22] Clean up serialization and other hacks --- components/style/properties.mako.rs | 9 ++-- components/style/values.rs | 84 ++++++++++++++++++----------- components/style/viewport.rs | 44 ++++++++++----- 3 files changed, 89 insertions(+), 48 deletions(-) diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index fa9aa4e9617..1ec5b97bd2c 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -775,8 +775,7 @@ pub mod longhands { % endfor &T::Length(length) => write!(f, "{:?}", length), &T::Percentage(number) => write!(f, "{}%", number), - // XXX HACK WRONG - &T::Calc(calc) => write!(f, "{}%", 10.), + &T::Calc(calc) => write!(f, "{:?}", calc) } } } @@ -1914,9 +1913,9 @@ pub mod longhands { specified::LengthOrPercentage::Length(value) => value, specified::LengthOrPercentage::Percentage(value) => specified::Length::FontRelative(specified::FontRelativeLength::Em(value)), - // XXX WRONG HACK - specified::LengthOrPercentage::Calc(calc) => - specified::Length::FontRelative(specified::FontRelativeLength::Em(20.)), + // FIXME(dzbarsky) handle calc for font-size + specified::LengthOrPercentage::Calc(_) => + specified::Length::FontRelative(specified::FontRelativeLength::Em(1.)), }) .or_else(|()| { match_ignore_ascii_case! { try!(input.expect_ident()), diff --git a/components/style/values.rs b/components/style/values.rs index fb84901239a..92f61754df6 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -607,35 +607,61 @@ pub mod specified { impl ToCss for Calc { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - // XXX WRONG HACK - try!(write!(dest, "calc(")); - if let Some(FontRelativeLength::Em(em)) = self.em { - try!(write!(dest, "{}em", em)); - } - if let Some(FontRelativeLength::Ex(ex)) = self.ex { - try!(write!(dest, "{}ex", ex)); - } - if let Some(absolute) = self.absolute { - try!(write!(dest, "{}px", Au::to_px(absolute))); - } - if let Some(FontRelativeLength::Rem(rem)) = self.rem { - try!(write!(dest, "{}rem", rem)); - } - if let Some(ViewportPercentageLength::Vh(vh)) = self.vh { - try!(write!(dest, "{}vh", vh)); - } - if let Some(ViewportPercentageLength::Vmax(vmax)) = self.vmax { - try!(write!(dest, "{}vmax", vmax)); - } - if let Some(ViewportPercentageLength::Vmin(vmin)) = self.vmin { - try!(write!(dest, "{}vmin", vmin)); - } - if let Some(ViewportPercentageLength::Vw(vw)) = self.vw { - try!(write!(dest, "{}vw", vw)); + + macro_rules! count { + ( $( $val:ident ),* ) => { + { + let mut count = 0; + $( + if let Some(_) = self.$val { + count += 1; + } + )* + count + } + }; } + macro_rules! serialize { + ( $( [$val:ident; $name:expr] ),* ) => { + { + let mut first_value = true; + $( + if let Some(val) = self.$val { + if !first_value { + try!(write!(dest, " + ")); + } else { + first_value = false; + } + try!(write!(dest, "{:?}{}", val, $name)); + } + )* + } + }; + } - write!(dest, ")") + let count = count!(em, ex, absolute, rem, vh, vmax, vmin, vw, percentage); + assert!(count > 0); + + if count > 1 { + try!(write!(dest, "calc(")); + } + + serialize!( + [em; "em"], + [ex; "ex"], + [absolute; "px"], + [rem; "rem"], + [vh; "vh"], + [vmax; "vmax"], + [vmin; "vmin"], + [vw; "vw"], + [percentage; "%"]); + + if count > 1 { + try!(write!(dest, ")")); + } + Ok(()) } } @@ -1308,8 +1334,7 @@ pub mod computed { match self { &LengthOrPercentage::Length(length) => write!(f, "{:?}", length), &LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage * 100.), - // XXX HACK WRONG - &LengthOrPercentage::Calc(calc) => write!(f, "{}%", 100.), + &LengthOrPercentage::Calc(calc) => write!(f, "{:?}", calc), } } } @@ -1356,8 +1381,7 @@ pub mod computed { &LengthOrPercentageOrAuto::Length(length) => write!(f, "{:?}", length), &LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage * 100.), &LengthOrPercentageOrAuto::Auto => write!(f, "auto"), - // XXX HACK WRONG - &LengthOrPercentageOrAuto::Calc(calc) => write!(f, "{}%", 100.), + &LengthOrPercentageOrAuto::Calc(calc) => write!(f, "{:?}", calc), } } } diff --git a/components/style/viewport.rs b/components/style/viewport.rs index bb38050f9b4..cc56030e226 100644 --- a/components/style/viewport.rs +++ b/components/style/viewport.rs @@ -9,7 +9,8 @@ use parser::{ParserContext, log_css_error}; use properties::longhands; use stylesheets::Origin; use util::geometry::{Au, PagePx, ViewportPx}; -use values::specified::{AllowedNumericType, Length, LengthOrPercentageOrAuto}; +use values::computed::{Context, ToComputedValue}; +use values::specified::{AllowedNumericType, LengthOrPercentageOrAuto}; use std::ascii::AsciiExt; use std::collections::hash_map::{Entry, HashMap}; @@ -420,25 +421,42 @@ impl ViewportConstraints { let initial_viewport = Size2D::new(Au::from_f32_px(initial_viewport.width.get()), Au::from_f32_px(initial_viewport.height.get())); + + let context = Context { + is_root_element: false, + viewport_size: initial_viewport, + inherited_font_weight: longhands::font_weight::get_initial_value(), + inherited_font_size: longhands::font_size::get_initial_value(), + inherited_text_decorations_in_effect: longhands::_servo_text_decorations_in_effect::get_initial_value(), + font_size: longhands::font_size::get_initial_value(), + root_font_size: longhands::font_size::get_initial_value(), + display: longhands::display::get_initial_value(), + color: longhands::color::get_initial_value(), + text_decoration: longhands::text_decoration::get_initial_value(), + overflow_x: longhands::overflow_x::get_initial_value(), + overflow_y: longhands::overflow_y::get_initial_value(), + positioned: false, + floated: false, + border_top_present: false, + border_right_present: false, + border_bottom_present: false, + border_left_present: false, + outline_style_present: false, + }; + macro_rules! to_pixel_length { ($value:ident, $dimension:ident) => { if let Some($value) = $value { match $value { - LengthOrPercentageOrAuto::Length(ref value) => Some(match value { - &Length::Absolute(length) => length, - &Length::FontRelative(length) => { - let initial_font_size = longhands::font_size::get_initial_value(); - length.to_computed_value(initial_font_size, initial_font_size) - } - &Length::ViewportPercentage(length) => - length.to_computed_value(initial_viewport), - _ => unreachable!() - }), + LengthOrPercentageOrAuto::Length(value) => + Some(value.to_computed_value(&context)), LengthOrPercentageOrAuto::Percentage(value) => Some(initial_viewport.$dimension.scale_by(value)), LengthOrPercentageOrAuto::Auto => None, - // XXX WRONG HACK - LengthOrPercentageOrAuto::Calc(calc) => None, + LengthOrPercentageOrAuto::Calc(calc) => { + let calc = calc.to_computed_value(&context); + Some(initial_viewport.$dimension.scale_by(calc.percentage()) + calc.length()) + } } } else { None From 64dc95436d6eb31e15a33fd37a5d7f9334e5df03 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Thu, 13 Aug 2015 00:43:34 -0400 Subject: [PATCH 06/22] Clean up serialization code a little --- components/style/values.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index 92f61754df6..4d6ce56e659 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -623,7 +623,7 @@ pub mod specified { } macro_rules! serialize { - ( $( [$val:ident; $name:expr] ),* ) => { + ( $( $val:ident ),* ) => { { let mut first_value = true; $( @@ -633,7 +633,7 @@ pub mod specified { } else { first_value = false; } - try!(write!(dest, "{:?}{}", val, $name)); + try!(val.to_css(dest)); } )* } @@ -647,16 +647,7 @@ pub mod specified { try!(write!(dest, "calc(")); } - serialize!( - [em; "em"], - [ex; "ex"], - [absolute; "px"], - [rem; "rem"], - [vh; "vh"], - [vmax; "vmax"], - [vmin; "vmin"], - [vw; "vw"], - [percentage; "%"]); + serialize!(em, ex, absolute, rem, vh, vmax, vmin, vw, percentage); if count > 1 { try!(write!(dest, ")")); From cfa1e467f16e2cb8667362e21145ded6b1eca0aa Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Thu, 13 Aug 2015 01:49:20 -0400 Subject: [PATCH 07/22] Clean up AST simplification code --- components/style/values.rs | 85 ++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index 4d6ce56e659..70ec4c46901 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -374,7 +374,6 @@ pub mod specified { #[derive(Clone, Debug)] enum CalcAstNode { Add(CalcSumNode), - Multiply(CalcProductNode), Value(CalcValueNode), } @@ -412,7 +411,6 @@ pub mod specified { } let sum = CalcSumNode { products: products }; - println!("Parsed sum {:?} ", sum); Ok(sum) } @@ -445,7 +443,6 @@ pub mod specified { } let sum = CalcProductNode { values: values }; - println!("Parsed product {:?} ", sum); Ok(sum) } @@ -491,7 +488,6 @@ pub mod specified { })), Some(CalcAstNode::Value(ref value)) => Ok(CalcAstNode::Value(Calc::multiply_value(value, multiplier))), - _ => unreachable!() } } @@ -520,14 +516,12 @@ pub mod specified { let node = try!(Calc::simplify_product(node)); match node { CalcAstNode::Value(value) => { - let product = CalcProductNode { values: vec!(value) }; if length == 1 { - return Ok(CalcAstNode::Multiply(product)); + return Ok(CalcAstNode::Value(value)); } - simplified.push(product); + simplified.push(CalcProductNode { values: vec!(value) }); } CalcAstNode::Add(sum) => simplified.push_all(&sum.products), - _ => return Err(()) } } @@ -546,6 +540,8 @@ pub mod specified { let ast = try!(Calc::parse_sum(input)); let ast = try!(Calc::simplify_sum(ast)); + println!("Simlified ast {:?} ", ast); + let mut absolute = None; let mut vw = None; let mut vh = None; @@ -556,42 +552,49 @@ pub mod specified { let mut rem = None; let mut percentage = None; - if let CalcAstNode::Add(ast) = ast { - for value in ast.products { - assert!(value.values.len() == 1); - match value.values[0] { - CalcValueNode::Percentage(p) => - percentage = Some(percentage.unwrap_or(0.) + p), - CalcValueNode::Length(Length::Absolute(Au(au))) => - absolute = Some(absolute.unwrap_or(0) + au), - CalcValueNode::Length(Length::ViewportPercentage(v)) => - match v { - ViewportPercentageLength::Vw(val) => - vw = Some(vw.unwrap_or(0.) + val), - ViewportPercentageLength::Vh(val) => - vh = Some(vh.unwrap_or(0.) + val), - ViewportPercentageLength::Vmin(val) => - vmin = Some(vmin.unwrap_or(0.) + val), - ViewportPercentageLength::Vmax(val) => - vmax = Some(vmax.unwrap_or(0.) + val), - }, - CalcValueNode::Length(Length::FontRelative(f)) => - match f { - FontRelativeLength::Em(val) => - em = Some(em.unwrap_or(0.) + val), - FontRelativeLength::Ex(val) => - ex = Some(ex.unwrap_or(0.) + val), - FontRelativeLength::Rem(val) => - rem = Some(rem.unwrap_or(0.) + val), - }, - _ => return Err(()) - } + let values = match ast { + CalcAstNode::Add(sum) => { + let mut values = Vec::new(); + for product in sum.products { + assert!(product.values.len() == 1); + values.push(product.values[0].clone()); + } + values + }, + CalcAstNode::Value(value) => vec!(value) + }; + + for value in values { + match value { + CalcValueNode::Percentage(p) => + percentage = Some(percentage.unwrap_or(0.) + p), + CalcValueNode::Length(Length::Absolute(Au(au))) => + absolute = Some(absolute.unwrap_or(0) + au), + CalcValueNode::Length(Length::ViewportPercentage(v)) => + match v { + ViewportPercentageLength::Vw(val) => + vw = Some(vw.unwrap_or(0.) + val), + ViewportPercentageLength::Vh(val) => + vh = Some(vh.unwrap_or(0.) + val), + ViewportPercentageLength::Vmin(val) => + vmin = Some(vmin.unwrap_or(0.) + val), + ViewportPercentageLength::Vmax(val) => + vmax = Some(vmax.unwrap_or(0.) + val), + }, + CalcValueNode::Length(Length::FontRelative(f)) => + match f { + FontRelativeLength::Em(val) => + em = Some(em.unwrap_or(0.) + val), + FontRelativeLength::Ex(val) => + ex = Some(ex.unwrap_or(0.) + val), + FontRelativeLength::Rem(val) => + rem = Some(rem.unwrap_or(0.) + val), + }, + _ => return Err(()) } - } else { - unreachable!() } - Ok(Calc { + Ok(Calc { absolute: absolute.map(Au), vw: vw.map(ViewportPercentageLength::Vw), vh: vh.map(ViewportPercentageLength::Vh), From 6573e8088ca2a4017553faff8190cc847db59d09 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Thu, 13 Aug 2015 14:33:21 -0400 Subject: [PATCH 08/22] Properly serialize % values in calc expressions --- components/script/dom/element.rs | 6 ++-- components/style/properties.mako.rs | 31 ++++++++--------- components/style/values.rs | 52 ++++++++++++++++------------- components/style/viewport.rs | 2 +- 4 files changed, 50 insertions(+), 41 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index cb0eda2a10f..859a38ba282 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -367,7 +367,8 @@ impl RawLayoutElementHelpers for Element { match width { LengthOrPercentageOrAuto::Auto => {} LengthOrPercentageOrAuto::Percentage(percentage) => { - let width_value = specified::LengthOrPercentageOrAuto::Percentage(percentage); + let width_value = + specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage)); hints.push(from_declaration( PropertyDeclaration::Width(SpecifiedValue(width_value)))); } @@ -390,7 +391,8 @@ impl RawLayoutElementHelpers for Element { match height { LengthOrPercentageOrAuto::Auto => {} LengthOrPercentageOrAuto::Percentage(percentage) => { - let height_value = specified::LengthOrPercentageOrAuto::Percentage(percentage); + let height_value = + specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage)); hints.push(from_declaration( PropertyDeclaration::Height(SpecifiedValue(height_value)))); } diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index 1ec5b97bd2c..2df2e339939 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -1912,7 +1912,7 @@ pub mod longhands { .map(|value| match value { specified::LengthOrPercentage::Length(value) => value, specified::LengthOrPercentage::Percentage(value) => - specified::Length::FontRelative(specified::FontRelativeLength::Em(value)), + specified::Length::FontRelative(specified::FontRelativeLength::Em(value.0)), // FIXME(dzbarsky) handle calc for font-size specified::LengthOrPercentage::Calc(_) => specified::Length::FontRelative(specified::FontRelativeLength::Em(1.)), @@ -3986,6 +3986,7 @@ pub mod longhands { } pub fn parse_origin(_: &ParserContext, input: &mut Parser) -> Result { + use values::specified::{LengthOrPercentage, Percentage}; let (mut horizontal, mut vertical, mut depth) = (None, None, None); loop { if let Err(_) = input.try(|input| { @@ -3994,37 +3995,37 @@ pub mod longhands { token, "left" => { if horizontal.is_none() { - horizontal = Some(specified::LengthOrPercentage::Percentage(0.0)) + horizontal = Some(LengthOrPercentage::Percentage(Percentage(0.0))) } else { return Err(()) } }, "center" => { if horizontal.is_none() { - horizontal = Some(specified::LengthOrPercentage::Percentage(0.5)) + horizontal = Some(LengthOrPercentage::Percentage(Percentage(0.5))) } else if vertical.is_none() { - vertical = Some(specified::LengthOrPercentage::Percentage(0.5)) + vertical = Some(LengthOrPercentage::Percentage(Percentage(0.5))) } else { return Err(()) } }, "right" => { if horizontal.is_none() { - horizontal = Some(specified::LengthOrPercentage::Percentage(1.0)) + horizontal = Some(LengthOrPercentage::Percentage(Percentage(1.0))) } else { return Err(()) } }, "top" => { if vertical.is_none() { - vertical = Some(specified::LengthOrPercentage::Percentage(0.0)) + vertical = Some(LengthOrPercentage::Percentage(Percentage(0.0))) } else { return Err(()) } }, "bottom" => { if vertical.is_none() { - vertical = Some(specified::LengthOrPercentage::Percentage(1.0)) + vertical = Some(LengthOrPercentage::Percentage(Percentage(1.0))) } else { return Err(()) } @@ -4033,13 +4034,13 @@ pub mod longhands { } Ok(()) }) { - match specified::LengthOrPercentage::parse(input) { + match LengthOrPercentage::parse(input) { Ok(value) => { if horizontal.is_none() { horizontal = Some(value); } else if vertical.is_none() { vertical = Some(value); - } else if let specified::LengthOrPercentage::Length(length) = value { + } else if let LengthOrPercentage::Length(length) = value { depth = Some(length); } else { break; @@ -4067,7 +4068,7 @@ pub mod longhands { <%self:longhand name="transform-origin"> use values::computed::Context; - use values::specified::{Length, LengthOrPercentage}; + use values::specified::{Length, LengthOrPercentage, Percentage}; use cssparser::ToCss; use std::fmt; @@ -4123,8 +4124,8 @@ pub mod longhands { pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { let result = try!(super::parse_origin(context, input)); Ok(SpecifiedValue { - horizontal: result.horizontal.unwrap_or(LengthOrPercentage::Percentage(0.5)), - vertical: result.vertical.unwrap_or(LengthOrPercentage::Percentage(0.5)), + horizontal: result.horizontal.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))), + vertical: result.vertical.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))), depth: result.depth.unwrap_or(Length::Absolute(Au(0))), }) } @@ -4149,7 +4150,7 @@ pub mod longhands { <%self:longhand name="perspective-origin"> use values::computed::Context; - use values::specified::LengthOrPercentage; + use values::specified::{LengthOrPercentage, Percentage}; use cssparser::ToCss; use std::fmt; @@ -4199,8 +4200,8 @@ pub mod longhands { match result.depth { Some(_) => Err(()), None => Ok(SpecifiedValue { - horizontal: result.horizontal.unwrap_or(LengthOrPercentage::Percentage(0.5)), - vertical: result.vertical.unwrap_or(LengthOrPercentage::Percentage(0.5)), + horizontal: result.horizontal.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))), + vertical: result.vertical.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))), }) } } diff --git a/components/style/values.rs b/components/style/values.rs index 70ec4c46901..76f34f69941 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -387,7 +387,7 @@ pub mod specified { pub em: Option, pub ex: Option, pub rem: Option, - pub percentage: Option, + pub percentage: Option, } impl Calc { fn parse_sum(input: &mut Parser) -> Result { @@ -603,7 +603,7 @@ pub mod specified { em: em.map(FontRelativeLength::Em), ex: ex.map(FontRelativeLength::Ex), rem: rem.map(FontRelativeLength::Rem), - percentage: percentage, + percentage: percentage.map(Percentage), }) } } @@ -659,10 +659,19 @@ pub mod specified { } } + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] + pub struct Percentage(pub CSSFloat); // [0 .. 100%] maps to [0.0 .. 1.0] + + impl ToCss for Percentage { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + write!(dest, "{}%", self.0 * 100.) + } + } + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub enum LengthOrPercentage { Length(Length), - Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] + Percentage(Percentage), Calc(Calc), } @@ -670,8 +679,7 @@ pub mod specified { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match self { &LengthOrPercentage::Length(length) => length.to_css(dest), - &LengthOrPercentage::Percentage(percentage) - => write!(dest, "{}%", percentage * 100.), + &LengthOrPercentage::Percentage(percentage) => percentage.to_css(dest), &LengthOrPercentage::Calc(calc) => calc.to_css(dest), } } @@ -688,7 +696,7 @@ pub mod specified { Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => Length::parse_dimension(value.value, unit).map(LengthOrPercentage::Length), Token::Percentage(ref value) if context.is_ok(value.unit_value) => - Ok(LengthOrPercentage::Percentage(value.unit_value)), + Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))), Token::Number(ref value) if value.value == 0. => Ok(LengthOrPercentage::Length(Length::Absolute(Au(0)))), Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { @@ -712,7 +720,7 @@ pub mod specified { #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub enum LengthOrPercentageOrAuto { Length(Length), - Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] + Percentage(Percentage), Auto, Calc(Calc), } @@ -721,8 +729,7 @@ pub mod specified { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match self { &LengthOrPercentageOrAuto::Length(length) => length.to_css(dest), - &LengthOrPercentageOrAuto::Percentage(percentage) - => write!(dest, "{}%", percentage * 100.), + &LengthOrPercentageOrAuto::Percentage(percentage) => percentage.to_css(dest), &LengthOrPercentageOrAuto::Auto => dest.write_str("auto"), &LengthOrPercentageOrAuto::Calc(calc) => calc.to_css(dest), } @@ -737,7 +744,7 @@ pub mod specified { Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrAuto::Length), Token::Percentage(ref value) if context.is_ok(value.unit_value) => - Ok(LengthOrPercentageOrAuto::Percentage(value.unit_value)), + Ok(LengthOrPercentageOrAuto::Percentage(Percentage(value.unit_value))), Token::Number(ref value) if value.value == 0. => Ok(LengthOrPercentageOrAuto::Length(Length::Absolute(Au(0)))), Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") => @@ -762,7 +769,7 @@ pub mod specified { #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub enum LengthOrPercentageOrNone { Length(Length), - Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] + Percentage(Percentage), None, } @@ -770,8 +777,7 @@ pub mod specified { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match self { &LengthOrPercentageOrNone::Length(length) => length.to_css(dest), - &LengthOrPercentageOrNone::Percentage(percentage) => - write!(dest, "{}%", percentage * 100.), + &LengthOrPercentageOrNone::Percentage(percentage) => percentage.to_css(dest), &LengthOrPercentageOrNone::None => dest.write_str("none"), } } @@ -784,7 +790,7 @@ pub mod specified { Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrNone::Length), Token::Percentage(ref value) if context.is_ok(value.unit_value) => - Ok(LengthOrPercentageOrNone::Percentage(value.unit_value)), + Ok(LengthOrPercentageOrNone::Percentage(Percentage(value.unit_value))), Token::Number(ref value) if value.value == 0. => Ok(LengthOrPercentageOrNone::Length(Length::Absolute(Au(0)))), Token::Ident(ref value) if value.eq_ignore_ascii_case("none") => @@ -846,7 +852,7 @@ pub mod specified { #[derive(Clone, PartialEq, Copy)] pub enum PositionComponent { Length(Length), - Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] + Percentage(Percentage), Center, Left, Right, @@ -861,7 +867,7 @@ pub mod specified { .map(PositionComponent::Length) } Token::Percentage(ref value) => { - Ok(PositionComponent::Percentage(value.unit_value)) + Ok(PositionComponent::Percentage(Percentage(value.unit_value))) } Token::Number(ref value) if value.value == 0. => { Ok(PositionComponent::Length(Length::Absolute(Au(0)))) @@ -884,11 +890,11 @@ pub mod specified { match self { PositionComponent::Length(x) => LengthOrPercentage::Length(x), PositionComponent::Percentage(x) => LengthOrPercentage::Percentage(x), - PositionComponent::Center => LengthOrPercentage::Percentage(0.5), + PositionComponent::Center => LengthOrPercentage::Percentage(Percentage(0.5)), PositionComponent::Left | - PositionComponent::Top => LengthOrPercentage::Percentage(0.0), + PositionComponent::Top => LengthOrPercentage::Percentage(Percentage(0.0)), PositionComponent::Right | - PositionComponent::Bottom => LengthOrPercentage::Percentage(1.0), + PositionComponent::Bottom => LengthOrPercentage::Percentage(Percentage(1.0)), } } } @@ -1305,7 +1311,7 @@ pub mod computed { } } - Calc { length: length, percentage: self.percentage } + Calc { length: length, percentage: self.percentage.map(|p| p.0) } } } @@ -1342,7 +1348,7 @@ pub mod computed { LengthOrPercentage::Length(value.to_computed_value(context)) } specified::LengthOrPercentage::Percentage(value) => { - LengthOrPercentage::Percentage(value) + LengthOrPercentage::Percentage(value.0) } specified::LengthOrPercentage::Calc(calc) => { LengthOrPercentage::Calc(calc.to_computed_value(context)) @@ -1390,7 +1396,7 @@ pub mod computed { LengthOrPercentageOrAuto::Length(value.to_computed_value(context)) } specified::LengthOrPercentageOrAuto::Percentage(value) => { - LengthOrPercentageOrAuto::Percentage(value) + LengthOrPercentageOrAuto::Percentage(value.0) } specified::LengthOrPercentageOrAuto::Auto => { LengthOrPercentageOrAuto::Auto @@ -1440,7 +1446,7 @@ pub mod computed { LengthOrPercentageOrNone::Length(value.to_computed_value(context)) } specified::LengthOrPercentageOrNone::Percentage(value) => { - LengthOrPercentageOrNone::Percentage(value) + LengthOrPercentageOrNone::Percentage(value.0) } specified::LengthOrPercentageOrNone::None => { LengthOrPercentageOrNone::None diff --git a/components/style/viewport.rs b/components/style/viewport.rs index cc56030e226..247cd6400ae 100644 --- a/components/style/viewport.rs +++ b/components/style/viewport.rs @@ -451,7 +451,7 @@ impl ViewportConstraints { LengthOrPercentageOrAuto::Length(value) => Some(value.to_computed_value(&context)), LengthOrPercentageOrAuto::Percentage(value) => - Some(initial_viewport.$dimension.scale_by(value)), + Some(initial_viewport.$dimension.scale_by(value.0)), LengthOrPercentageOrAuto::Auto => None, LengthOrPercentageOrAuto::Calc(calc) => { let calc = calc.to_computed_value(&context); From 663e0f606c7d8d0f0503ca6d66e76a9fa3894200 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Thu, 13 Aug 2015 15:36:07 -0400 Subject: [PATCH 09/22] Simplify like terms in all sum expressions, not just toplevel calc --- components/style/values.rs | 117 ++++++++++++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 16 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index 76f34f69941..3736538cc9e 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -511,21 +511,106 @@ pub mod specified { fn simplify_sum(node: CalcSumNode) -> Result { let mut simplified = Vec::new(); - let length = node.products.len(); for node in node.products { let node = try!(Calc::simplify_product(node)); match node { - CalcAstNode::Value(value) => { - if length == 1 { - return Ok(CalcAstNode::Value(value)); + CalcAstNode::Value(value) => simplified.push(value), + CalcAstNode::Add(sum) => { + for product in sum.products { + assert!(product.values.len() == 1); + simplified.push(product.values[0].clone()); } - simplified.push(CalcProductNode { values: vec!(value) }); } - CalcAstNode::Add(sum) => simplified.push_all(&sum.products), } } - Ok(CalcAstNode::Add(CalcSumNode {products: simplified} )) + let mut absolute = None; + let mut vw = None; + let mut vh = None; + let mut vmax = None; + let mut vmin = None; + let mut em = None; + let mut ex = None; + let mut rem = None; + let mut percentage = None; + let mut number = None; + + for value in simplified { + match value { + CalcValueNode::Percentage(p) => + percentage = Some(percentage.unwrap_or(0.) + p), + CalcValueNode::Length(Length::Absolute(Au(au))) => + absolute = Some(absolute.unwrap_or(0) + au), + CalcValueNode::Length(Length::ViewportPercentage(v)) => + match v { + ViewportPercentageLength::Vw(val) => + vw = Some(vw.unwrap_or(0.) + val), + ViewportPercentageLength::Vh(val) => + vh = Some(vh.unwrap_or(0.) + val), + ViewportPercentageLength::Vmin(val) => + vmin = Some(vmin.unwrap_or(0.) + val), + ViewportPercentageLength::Vmax(val) => + vmax = Some(vmax.unwrap_or(0.) + val), + }, + CalcValueNode::Length(Length::FontRelative(f)) => + match f { + FontRelativeLength::Em(val) => + em = Some(em.unwrap_or(0.) + val), + FontRelativeLength::Ex(val) => + ex = Some(ex.unwrap_or(0.) + val), + FontRelativeLength::Rem(val) => + rem = Some(rem.unwrap_or(0.) + val), + }, + CalcValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val), + _ => unreachable!() + } + } + + fn viewport_node(length: ViewportPercentageLength) -> CalcValueNode { + CalcValueNode::Length(Length::ViewportPercentage(length)) + } + fn font_node(length: FontRelativeLength) -> CalcValueNode { + CalcValueNode::Length(Length::FontRelative(length)) + } + + let mut new_values = Vec::new(); + if let Some(absolute) = absolute { + new_values.push(CalcValueNode::Length(Length::Absolute(Au(absolute)))); + } + if let Some(vw) = vw { + new_values.push(viewport_node(ViewportPercentageLength::Vw(vw))); + } + if let Some(vh) = vh { + new_values.push(viewport_node(ViewportPercentageLength::Vh(vh))); + } + if let Some(vmin) = vmin { + new_values.push(viewport_node(ViewportPercentageLength::Vmin(vmin))); + } + if let Some(vmax) = vmax { + new_values.push(viewport_node(ViewportPercentageLength::Vmax(vmax))); + } + if let Some(em) = em { + new_values.push(font_node(FontRelativeLength::Em(em))); + } + if let Some(ex) = ex { + new_values.push(font_node(FontRelativeLength::Ex(ex))); + } + if let Some(rem) = rem { + new_values.push(font_node(FontRelativeLength::Rem(rem))); + } + if let Some(number) = number { + new_values.push(CalcValueNode::Number(number)); + } + + assert!(new_values.len() > 0); + if new_values.len() == 1 { + Ok(CalcAstNode::Value(new_values[0].clone())) + } else { + let new_products = new_values.iter() + .map(|v| CalcProductNode { values: vec!(v.clone()) }) + .collect(); + Ok(CalcAstNode::Add(CalcSumNode {products: new_products} )) + } } fn simplify_value(node: CalcValueNode) -> Result { @@ -567,28 +652,28 @@ pub mod specified { for value in values { match value { CalcValueNode::Percentage(p) => - percentage = Some(percentage.unwrap_or(0.) + p), + percentage = Some(p), CalcValueNode::Length(Length::Absolute(Au(au))) => - absolute = Some(absolute.unwrap_or(0) + au), + absolute = Some(au), CalcValueNode::Length(Length::ViewportPercentage(v)) => match v { ViewportPercentageLength::Vw(val) => - vw = Some(vw.unwrap_or(0.) + val), + vw = Some(val), ViewportPercentageLength::Vh(val) => - vh = Some(vh.unwrap_or(0.) + val), + vh = Some(val), ViewportPercentageLength::Vmin(val) => - vmin = Some(vmin.unwrap_or(0.) + val), + vmin = Some(val), ViewportPercentageLength::Vmax(val) => - vmax = Some(vmax.unwrap_or(0.) + val), + vmax = Some(val), }, CalcValueNode::Length(Length::FontRelative(f)) => match f { FontRelativeLength::Em(val) => - em = Some(em.unwrap_or(0.) + val), + em = Some(val), FontRelativeLength::Ex(val) => - ex = Some(ex.unwrap_or(0.) + val), + ex = Some(val), FontRelativeLength::Rem(val) => - rem = Some(rem.unwrap_or(0.) + val), + rem = Some(val), }, _ => return Err(()) } From 63d0429bed70dd6eea6a49d485b02134b100769a Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Thu, 13 Aug 2015 17:12:21 -0400 Subject: [PATCH 10/22] Simplify the calc AST simplification code --- components/style/values.rs | 172 ++++++++++--------------------------- 1 file changed, 44 insertions(+), 128 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index 3736538cc9e..aa6f2603bc4 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -462,31 +462,58 @@ pub mod specified { } } - fn simplify_product(node: CalcProductNode) -> Result { + fn simplify_value_numerically(node: &CalcValueNode) -> Option { + match node { + &CalcValueNode::Number(number) => Some(number), + &CalcValueNode::Sum(box ref sum) => Calc::simplify_sum_numerically(sum), + _ => None + } + } + + fn simplify_sum_numerically(node: &CalcSumNode) -> Option { + let node = node.clone(); + let mut sum = 0.; + for product in node.products { + match Calc::simplify_product_numerically(product) { + Some(number) => sum += number, + _ => return None + } + } + Some(sum) + } + + fn simplify_product_numerically(node: CalcProductNode) -> Option { + let mut product = 1.; + for value in node.values { + match Calc::simplify_value_numerically(&value) { + Some(number) => product *= number, + _ => return None + } + } + Some(product) + } + + fn simplify_products(node: CalcProductNode) -> Result { let mut multiplier = 1.; - let mut node_with_unit: Option = None; - let mut node_hack: CalcAstNode; + let mut node_with_unit = None; for node in node.values { - node_hack = try!(Calc::simplify_value(node)); - if let CalcAstNode::Value(CalcValueNode::Number(n)) = node_hack { - multiplier *= n; - } else if node_with_unit.is_none() { - node_with_unit = Some(node_hack); - } else { - return Err(()); + match Calc::simplify_value_numerically(&node) { + Some(number) => multiplier *= number, + _ if node_with_unit.is_none() => node_with_unit = Some(node), + _ => return Err(()), } } match node_with_unit { None => Ok(CalcAstNode::Value(CalcValueNode::Number(multiplier))), - Some(CalcAstNode::Add(sum)) => + Some(CalcValueNode::Sum(box sum)) => Ok(CalcAstNode::Add(CalcSumNode { products: sum.products .iter() .map(|p| Calc::multiply_product(p, multiplier)) .collect() })), - Some(CalcAstNode::Value(ref value)) => + Some(ref value) => Ok(CalcAstNode::Value(Calc::multiply_value(value, multiplier))), } } @@ -509,10 +536,12 @@ pub mod specified { } } - fn simplify_sum(node: CalcSumNode) -> Result { + pub fn parse(input: &mut Parser) -> Result { + let ast = try!(Calc::parse_sum(input)); + let mut simplified = Vec::new(); - for node in node.products { - let node = try!(Calc::simplify_product(node)); + for node in ast.products { + let node = try!(Calc::simplify_products(node)); match node { CalcAstNode::Value(value) => simplified.push(value), CalcAstNode::Add(sum) => { @@ -566,119 +595,6 @@ pub mod specified { } } - fn viewport_node(length: ViewportPercentageLength) -> CalcValueNode { - CalcValueNode::Length(Length::ViewportPercentage(length)) - } - fn font_node(length: FontRelativeLength) -> CalcValueNode { - CalcValueNode::Length(Length::FontRelative(length)) - } - - let mut new_values = Vec::new(); - if let Some(absolute) = absolute { - new_values.push(CalcValueNode::Length(Length::Absolute(Au(absolute)))); - } - if let Some(vw) = vw { - new_values.push(viewport_node(ViewportPercentageLength::Vw(vw))); - } - if let Some(vh) = vh { - new_values.push(viewport_node(ViewportPercentageLength::Vh(vh))); - } - if let Some(vmin) = vmin { - new_values.push(viewport_node(ViewportPercentageLength::Vmin(vmin))); - } - if let Some(vmax) = vmax { - new_values.push(viewport_node(ViewportPercentageLength::Vmax(vmax))); - } - if let Some(em) = em { - new_values.push(font_node(FontRelativeLength::Em(em))); - } - if let Some(ex) = ex { - new_values.push(font_node(FontRelativeLength::Ex(ex))); - } - if let Some(rem) = rem { - new_values.push(font_node(FontRelativeLength::Rem(rem))); - } - if let Some(number) = number { - new_values.push(CalcValueNode::Number(number)); - } - - assert!(new_values.len() > 0); - if new_values.len() == 1 { - Ok(CalcAstNode::Value(new_values[0].clone())) - } else { - let new_products = new_values.iter() - .map(|v| CalcProductNode { values: vec!(v.clone()) }) - .collect(); - Ok(CalcAstNode::Add(CalcSumNode {products: new_products} )) - } - } - - fn simplify_value(node: CalcValueNode) -> Result { - match node { - CalcValueNode::Sum(box sum) => Calc::simplify_sum(sum), - node => Ok(CalcAstNode::Value(node)) - } - } - - pub fn parse(input: &mut Parser) -> Result { - - let ast = try!(Calc::parse_sum(input)); - let ast = try!(Calc::simplify_sum(ast)); - - println!("Simlified ast {:?} ", ast); - - let mut absolute = None; - let mut vw = None; - let mut vh = None; - let mut vmax = None; - let mut vmin = None; - let mut em = None; - let mut ex = None; - let mut rem = None; - let mut percentage = None; - - let values = match ast { - CalcAstNode::Add(sum) => { - let mut values = Vec::new(); - for product in sum.products { - assert!(product.values.len() == 1); - values.push(product.values[0].clone()); - } - values - }, - CalcAstNode::Value(value) => vec!(value) - }; - - for value in values { - match value { - CalcValueNode::Percentage(p) => - percentage = Some(p), - CalcValueNode::Length(Length::Absolute(Au(au))) => - absolute = Some(au), - CalcValueNode::Length(Length::ViewportPercentage(v)) => - match v { - ViewportPercentageLength::Vw(val) => - vw = Some(val), - ViewportPercentageLength::Vh(val) => - vh = Some(val), - ViewportPercentageLength::Vmin(val) => - vmin = Some(val), - ViewportPercentageLength::Vmax(val) => - vmax = Some(val), - }, - CalcValueNode::Length(Length::FontRelative(f)) => - match f { - FontRelativeLength::Em(val) => - em = Some(val), - FontRelativeLength::Ex(val) => - ex = Some(val), - FontRelativeLength::Rem(val) => - rem = Some(val), - }, - _ => return Err(()) - } - } - Ok(Calc { absolute: absolute.map(Au), vw: vw.map(ViewportPercentageLength::Vw), From 67db4fbc2eb2083a01b36a1480850b95477711a9 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Thu, 13 Aug 2015 17:56:44 -0400 Subject: [PATCH 11/22] Remove stray changes --- components/layout/inline.rs | 2 +- components/style/values.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/components/layout/inline.rs b/components/layout/inline.rs index cbbb3bddff6..6307061d7ef 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -993,7 +993,7 @@ impl InlineFlow { let percent_offset = line_height.scale_by(calc.percentage()); offset_from_baseline = offset_from_baseline - percent_offset - calc.length() } - } + } } (offset_from_baseline - ascent, largest_size_updated) } diff --git a/components/style/values.rs b/components/style/values.rs index aa6f2603bc4..b2ab6407af4 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -410,8 +410,7 @@ pub mod specified { } } - let sum = CalcSumNode { products: products }; - Ok(sum) + Ok(CalcSumNode { products: products }) } fn parse_product(input: &mut Parser) -> Result { @@ -442,8 +441,7 @@ pub mod specified { } } - let sum = CalcProductNode { values: values }; - Ok(sum) + Ok(CalcProductNode { values: values }) } fn parse_value(input: &mut Parser) -> Result { From f8bd7c46ae78c749195313b5fcf41e14cebb9571 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Fri, 14 Aug 2015 02:39:45 -0400 Subject: [PATCH 12/22] Fix some calc parsing panics --- components/style/values.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index b2ab6407af4..dfbf9680e3a 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -504,13 +504,8 @@ pub mod specified { match node_with_unit { None => Ok(CalcAstNode::Value(CalcValueNode::Number(multiplier))), - Some(CalcValueNode::Sum(box sum)) => - Ok(CalcAstNode::Add(CalcSumNode { - products: sum.products - .iter() - .map(|p| Calc::multiply_product(p, multiplier)) - .collect() - })), + Some(CalcValueNode::Sum(box ref sum)) => + Ok(CalcAstNode::Add(Calc::multiply_sum(sum, multiplier))), Some(ref value) => Ok(CalcAstNode::Value(Calc::multiply_value(value, multiplier))), } @@ -525,11 +520,22 @@ pub mod specified { } } + fn multiply_sum(node: &CalcSumNode, multiplier: CSSFloat) -> CalcSumNode { + CalcSumNode { + products: node.products + .iter() + .map(|p| Calc::multiply_product(p, multiplier)) + .collect() + } + } + fn multiply_value(node: &CalcValueNode, multiplier: CSSFloat) -> CalcValueNode { + println!("multiplying {:?} by {}", node, multiplier); match node { - &CalcValueNode::Number(_) => unreachable!(), + &CalcValueNode::Number(num) => CalcValueNode::Number(num * multiplier), &CalcValueNode::Percentage(p) => CalcValueNode::Percentage(p * multiplier), - &CalcValueNode::Sum(_) => unreachable!(), + &CalcValueNode::Sum(box ref sum) => + CalcValueNode::Sum(box Calc::multiply_sum(sum, multiplier)), &CalcValueNode::Length(l) => CalcValueNode::Length(l * multiplier), } } @@ -544,6 +550,7 @@ pub mod specified { CalcAstNode::Value(value) => simplified.push(value), CalcAstNode::Add(sum) => { for product in sum.products { + println!(" Matching product AST: {:?}", product); assert!(product.values.len() == 1); simplified.push(product.values[0].clone()); } From 164af05ba9d1b19a3cd478c3ea83a95772f5f371 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Fri, 14 Aug 2015 22:43:17 -0400 Subject: [PATCH 13/22] Expand out nested products --- components/style/values.rs | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index dfbf9680e3a..6ee9bea1100 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -491,13 +491,39 @@ pub mod specified { Some(product) } - fn simplify_products(node: CalcProductNode) -> Result { + fn simplify_products_in_sum(node: &CalcSumNode) -> Result { + let mut simplified = Vec::new(); + let node = node.clone(); + for product in node.products { + match try!(Calc::simplify_product(product)) { + CalcAstNode::Value(val) => + simplified.push(CalcProductNode { values: vec!(val) }), + CalcAstNode::Add(sum) => simplified.push_all(&sum.products), + } + } + + if simplified.len() == 1 { + assert!(simplified[0].values.len() == 1); + Ok(simplified[0].values[0].clone()) + } else { + Ok(CalcValueNode::Sum(box CalcSumNode { products: simplified } )) + } + } + + fn simplify_product(node: CalcProductNode) -> Result { let mut multiplier = 1.; let mut node_with_unit = None; for node in node.values { match Calc::simplify_value_numerically(&node) { Some(number) => multiplier *= number, - _ if node_with_unit.is_none() => node_with_unit = Some(node), + _ if node_with_unit.is_none() => { + node_with_unit = Some(match node { + CalcValueNode::Sum(box ref sum) => + try!(Calc::simplify_products_in_sum(sum)), + val => val, + }) + }, + //_ if node_with_unit.is_none() => node_with_unit = Some(node), _ => return Err(()), } } @@ -545,7 +571,7 @@ pub mod specified { let mut simplified = Vec::new(); for node in ast.products { - let node = try!(Calc::simplify_products(node)); + let node = try!(Calc::simplify_product(node)); match node { CalcAstNode::Value(value) => simplified.push(value), CalcAstNode::Add(sum) => { From dcac654057d1ee08365cb15be4bd1d6a24b44f86 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Fri, 14 Aug 2015 23:44:25 -0400 Subject: [PATCH 14/22] Use the type system to enforce that product nodes are simplified away --- components/style/values.rs | 130 ++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 68 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index 6ee9bea1100..37fcc46d3a0 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -372,9 +372,42 @@ pub mod specified { } #[derive(Clone, Debug)] - enum CalcAstNode { - Add(CalcSumNode), - Value(CalcValueNode), + struct SimplifiedSumNode { + values: Vec, + } + impl<'a> Mul for &'a SimplifiedSumNode { + type Output = SimplifiedSumNode; + + #[inline] + fn mul(self, scalar: CSSFloat) -> SimplifiedSumNode { + SimplifiedSumNode { + values: self.values.iter().map(|p| p * scalar).collect() + } + } + } + + #[derive(Clone, Debug)] + enum SimplifiedValueNode { + Length(Length), + Percentage(CSSFloat), + Number(CSSFloat), + Sum(Box), + } + impl<'a> Mul for &'a SimplifiedValueNode { + type Output = SimplifiedValueNode; + + #[inline] + fn mul(self, scalar: CSSFloat) -> SimplifiedValueNode { + match self { + &SimplifiedValueNode::Length(l) => SimplifiedValueNode::Length(l * scalar), + &SimplifiedValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p * scalar), + &SimplifiedValueNode::Number(n) => SimplifiedValueNode::Number(n * scalar), + &SimplifiedValueNode::Sum(box ref s) => { + let sum = s * scalar; + SimplifiedValueNode::Sum(box sum) + } + } + } } #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] @@ -460,19 +493,19 @@ pub mod specified { } } - fn simplify_value_numerically(node: &CalcValueNode) -> Option { + fn simplify_value_to_number(node: &CalcValueNode) -> Option { match node { &CalcValueNode::Number(number) => Some(number), - &CalcValueNode::Sum(box ref sum) => Calc::simplify_sum_numerically(sum), + &CalcValueNode::Sum(box ref sum) => Calc::simplify_sum_to_number(sum), _ => None } } - fn simplify_sum_numerically(node: &CalcSumNode) -> Option { + fn simplify_sum_to_number(node: &CalcSumNode) -> Option { let node = node.clone(); let mut sum = 0.; for product in node.products { - match Calc::simplify_product_numerically(product) { + match Calc::simplify_product_to_number(product) { Some(number) => sum += number, _ => return None } @@ -480,10 +513,10 @@ pub mod specified { Some(sum) } - fn simplify_product_numerically(node: CalcProductNode) -> Option { + fn simplify_product_to_number(node: CalcProductNode) -> Option { let mut product = 1.; for value in node.values { - match Calc::simplify_value_numerically(&value) { + match Calc::simplify_value_to_number(&value) { Some(number) => product *= number, _ => return None } @@ -491,36 +524,36 @@ pub mod specified { Some(product) } - fn simplify_products_in_sum(node: &CalcSumNode) -> Result { + fn simplify_products_in_sum(node: &CalcSumNode) -> Result { let mut simplified = Vec::new(); let node = node.clone(); for product in node.products { match try!(Calc::simplify_product(product)) { - CalcAstNode::Value(val) => - simplified.push(CalcProductNode { values: vec!(val) }), - CalcAstNode::Add(sum) => simplified.push_all(&sum.products), + SimplifiedValueNode::Sum(box sum) => simplified.push_all(&sum.values), + val => simplified.push(val), } } if simplified.len() == 1 { - assert!(simplified[0].values.len() == 1); - Ok(simplified[0].values[0].clone()) + Ok(simplified[0].clone()) } else { - Ok(CalcValueNode::Sum(box CalcSumNode { products: simplified } )) + Ok(SimplifiedValueNode::Sum(box SimplifiedSumNode { values: simplified } )) } } - fn simplify_product(node: CalcProductNode) -> Result { + fn simplify_product(node: CalcProductNode) -> Result { let mut multiplier = 1.; let mut node_with_unit = None; for node in node.values { - match Calc::simplify_value_numerically(&node) { + match Calc::simplify_value_to_number(&node) { Some(number) => multiplier *= number, _ if node_with_unit.is_none() => { node_with_unit = Some(match node { CalcValueNode::Sum(box ref sum) => try!(Calc::simplify_products_in_sum(sum)), - val => val, + CalcValueNode::Length(l) => SimplifiedValueNode::Length(l), + CalcValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p), + _ => unreachable!("Numbers should have been handled by simplify_value_to_nubmer") }) }, //_ if node_with_unit.is_none() => node_with_unit = Some(node), @@ -529,40 +562,8 @@ pub mod specified { } match node_with_unit { - None => Ok(CalcAstNode::Value(CalcValueNode::Number(multiplier))), - Some(CalcValueNode::Sum(box ref sum)) => - Ok(CalcAstNode::Add(Calc::multiply_sum(sum, multiplier))), - Some(ref value) => - Ok(CalcAstNode::Value(Calc::multiply_value(value, multiplier))), - } - } - - fn multiply_product(node: &CalcProductNode, multiplier: CSSFloat) -> CalcProductNode { - CalcProductNode { - values: node.values - .iter() - .map(|v| Calc::multiply_value(v, multiplier)) - .collect() - } - } - - fn multiply_sum(node: &CalcSumNode, multiplier: CSSFloat) -> CalcSumNode { - CalcSumNode { - products: node.products - .iter() - .map(|p| Calc::multiply_product(p, multiplier)) - .collect() - } - } - - fn multiply_value(node: &CalcValueNode, multiplier: CSSFloat) -> CalcValueNode { - println!("multiplying {:?} by {}", node, multiplier); - match node { - &CalcValueNode::Number(num) => CalcValueNode::Number(num * multiplier), - &CalcValueNode::Percentage(p) => CalcValueNode::Percentage(p * multiplier), - &CalcValueNode::Sum(box ref sum) => - CalcValueNode::Sum(box Calc::multiply_sum(sum, multiplier)), - &CalcValueNode::Length(l) => CalcValueNode::Length(l * multiplier), + None => Ok(SimplifiedValueNode::Number(multiplier)), + Some(ref value) => Ok(value * multiplier) } } @@ -571,16 +572,9 @@ pub mod specified { let mut simplified = Vec::new(); for node in ast.products { - let node = try!(Calc::simplify_product(node)); - match node { - CalcAstNode::Value(value) => simplified.push(value), - CalcAstNode::Add(sum) => { - for product in sum.products { - println!(" Matching product AST: {:?}", product); - assert!(product.values.len() == 1); - simplified.push(product.values[0].clone()); - } - } + match try!(Calc::simplify_product(node)) { + SimplifiedValueNode::Sum(sum) => simplified.push_all(&sum.values), + value => simplified.push(value), } } @@ -597,11 +591,11 @@ pub mod specified { for value in simplified { match value { - CalcValueNode::Percentage(p) => + SimplifiedValueNode::Percentage(p) => percentage = Some(percentage.unwrap_or(0.) + p), - CalcValueNode::Length(Length::Absolute(Au(au))) => + SimplifiedValueNode::Length(Length::Absolute(Au(au))) => absolute = Some(absolute.unwrap_or(0) + au), - CalcValueNode::Length(Length::ViewportPercentage(v)) => + SimplifiedValueNode::Length(Length::ViewportPercentage(v)) => match v { ViewportPercentageLength::Vw(val) => vw = Some(vw.unwrap_or(0.) + val), @@ -612,7 +606,7 @@ pub mod specified { ViewportPercentageLength::Vmax(val) => vmax = Some(vmax.unwrap_or(0.) + val), }, - CalcValueNode::Length(Length::FontRelative(f)) => + SimplifiedValueNode::Length(Length::FontRelative(f)) => match f { FontRelativeLength::Em(val) => em = Some(em.unwrap_or(0.) + val), @@ -621,7 +615,7 @@ pub mod specified { FontRelativeLength::Rem(val) => rem = Some(rem.unwrap_or(0.) + val), }, - CalcValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val), + SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val), _ => unreachable!() } } From 53e8f7d823f6d89c9548768859b550d3d1d9d636 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Sat, 15 Aug 2015 01:11:55 -0400 Subject: [PATCH 15/22] Get rid of some cloning --- components/style/values.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index 37fcc46d3a0..c768a010843 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -502,9 +502,8 @@ pub mod specified { } fn simplify_sum_to_number(node: &CalcSumNode) -> Option { - let node = node.clone(); let mut sum = 0.; - for product in node.products { + for product in &node.products { match Calc::simplify_product_to_number(product) { Some(number) => sum += number, _ => return None @@ -513,10 +512,10 @@ pub mod specified { Some(sum) } - fn simplify_product_to_number(node: CalcProductNode) -> Option { + fn simplify_product_to_number(node: &CalcProductNode) -> Option { let mut product = 1.; - for value in node.values { - match Calc::simplify_value_to_number(&value) { + for value in &node.values { + match Calc::simplify_value_to_number(value) { Some(number) => product *= number, _ => return None } @@ -526,8 +525,7 @@ pub mod specified { fn simplify_products_in_sum(node: &CalcSumNode) -> Result { let mut simplified = Vec::new(); - let node = node.clone(); - for product in node.products { + for product in &node.products { match try!(Calc::simplify_product(product)) { SimplifiedValueNode::Sum(box sum) => simplified.push_all(&sum.values), val => simplified.push(val), From 5ac205b3e5c555b2311ce3bb1e130a1ab9c9704f Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Sat, 15 Aug 2015 09:13:40 -0400 Subject: [PATCH 16/22] Clean up some stray lines --- components/style/values.rs | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index c768a010843..05c837d33c1 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -428,8 +428,7 @@ pub mod specified { products.push(try!(Calc::parse_product(input))); loop { - let next = input.next(); - match next { + match input.next() { Ok(Token::Delim('+')) => { products.push(try!(Calc::parse_product(input))); } @@ -452,8 +451,7 @@ pub mod specified { loop { let position = input.position(); - let next = input.next(); - match next { + match input.next() { Ok(Token::Delim('*')) => { values.push(try!(Calc::parse_value(input))); } @@ -478,8 +476,7 @@ pub mod specified { } fn parse_value(input: &mut Parser) -> Result { - let next = input.next(); - match next { + match input.next() { Ok(Token::Number(ref value)) => Ok(CalcValueNode::Number(value.value)), Ok(Token::Dimension(ref value, ref unit)) => Length::parse_dimension(value.value, unit).map(CalcValueNode::Length), @@ -503,7 +500,7 @@ pub mod specified { fn simplify_sum_to_number(node: &CalcSumNode) -> Option { let mut sum = 0.; - for product in &node.products { + for ref product in &node.products { match Calc::simplify_product_to_number(product) { Some(number) => sum += number, _ => return None @@ -514,7 +511,7 @@ pub mod specified { fn simplify_product_to_number(node: &CalcProductNode) -> Option { let mut product = 1.; - for value in &node.values { + for ref value in &node.values { match Calc::simplify_value_to_number(value) { Some(number) => product *= number, _ => return None @@ -539,22 +536,21 @@ pub mod specified { } } - fn simplify_product(node: CalcProductNode) -> Result { + fn simplify_product(node: &CalcProductNode) -> Result { let mut multiplier = 1.; let mut node_with_unit = None; - for node in node.values { + for node in &node.values { match Calc::simplify_value_to_number(&node) { Some(number) => multiplier *= number, _ if node_with_unit.is_none() => { node_with_unit = Some(match node { - CalcValueNode::Sum(box ref sum) => + &CalcValueNode::Sum(box ref sum) => try!(Calc::simplify_products_in_sum(sum)), - CalcValueNode::Length(l) => SimplifiedValueNode::Length(l), - CalcValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p), + &CalcValueNode::Length(l) => SimplifiedValueNode::Length(l), + &CalcValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p), _ => unreachable!("Numbers should have been handled by simplify_value_to_nubmer") }) }, - //_ if node_with_unit.is_none() => node_with_unit = Some(node), _ => return Err(()), } } @@ -569,7 +565,7 @@ pub mod specified { let ast = try!(Calc::parse_sum(input)); let mut simplified = Vec::new(); - for node in ast.products { + for ref node in ast.products { match try!(Calc::simplify_product(node)) { SimplifiedValueNode::Sum(sum) => simplified.push_all(&sum.values), value => simplified.push(value), From cdae523cd4838b299b9773ec9b5bab8ac21249d6 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Sun, 23 Aug 2015 00:48:07 -0400 Subject: [PATCH 17/22] Address review comments --- components/layout/block.rs | 18 +++--- components/layout/flex.rs | 1 + components/layout/fragment.rs | 4 +- components/style/properties.mako.rs | 13 ++-- components/style/values.rs | 10 ++-- tests/wpt/mozilla/meta/MANIFEST.json | 6 ++ tests/wpt/mozilla/meta/mozilla/calc.html.ini | 8 +++ tests/wpt/mozilla/tests/mozilla/calc.html | 62 ++++++++++++++++++++ 8 files changed, 97 insertions(+), 25 deletions(-) create mode 100644 tests/wpt/mozilla/meta/mozilla/calc.html.ini create mode 100644 tests/wpt/mozilla/tests/mozilla/calc.html diff --git a/components/layout/block.rs b/components/layout/block.rs index 7c54df6e17c..ca3ee670beb 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -330,13 +330,15 @@ impl CandidateBSizeIterator { (LengthOrPercentageOrAuto::Calc(calc), Some(block_container_block_size)) => { MaybeAuto::Specified(calc.length() + block_container_block_size.scale_by(calc.percentage())) } - (LengthOrPercentageOrAuto::Percentage(_), None) | (LengthOrPercentageOrAuto::Auto, _) => MaybeAuto::Auto, + (LengthOrPercentageOrAuto::Percentage(_), None) | + (LengthOrPercentageOrAuto::Auto, _) | + (LengthOrPercentageOrAuto::Calc(_), _) => MaybeAuto::Auto, (LengthOrPercentageOrAuto::Length(length), _) => MaybeAuto::Specified(length), - (LengthOrPercentageOrAuto::Calc(calc), _) => MaybeAuto::Specified(calc.length()), }; let max_block_size = match (fragment.style.max_block_size(), block_container_block_size) { - (LengthOrPercentageOrNone::Percentage(percent), Some(block_container_block_size)) => - Some(block_container_block_size.scale_by(percent)), + (LengthOrPercentageOrNone::Percentage(percent), Some(block_container_block_size)) => { + Some(block_container_block_size.scale_by(percent)) + } (LengthOrPercentageOrNone::Percentage(_), None) | (LengthOrPercentageOrNone::None, _) => None, (LengthOrPercentageOrNone::Length(length), _) => Some(length), @@ -1125,16 +1127,12 @@ impl BlockFlow { (LengthOrPercentageOrAuto::Calc(calc), Some(container_size)) => { Some(container_size.scale_by(calc.percentage()) + calc.length()) } - (LengthOrPercentageOrAuto::Calc(calc), _) => { - Some(calc.length()) - }, (LengthOrPercentageOrAuto::Length(length), _) => Some(length), (LengthOrPercentageOrAuto::Percentage(percent), Some(container_size)) => { Some(container_size.scale_by(percent)) } - (LengthOrPercentageOrAuto::Percentage(_), None) => { - None - } + (LengthOrPercentageOrAuto::Percentage(_), None) | + (LengthOrPercentageOrAuto::Calc(_), None) | (LengthOrPercentageOrAuto::Auto, None) => { None } diff --git a/components/layout/flex.rs b/components/layout/flex.rs index 3c34aeaf728..0124330e9b8 100644 --- a/components/layout/flex.rs +++ b/components/layout/flex.rs @@ -167,6 +167,7 @@ impl FlexFlow { } (LengthOrPercentageOrAuto::Percentage(_), None) | (LengthOrPercentageOrAuto::Auto, _) => None, + (LengthOrPercentageOrAuto::Calc(_), _) => None, (LengthOrPercentageOrAuto::Length(length), _) => Some(length), }; diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 8e3c92cad5e..9ac26393c3f 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -466,9 +466,7 @@ impl ReplacedImageFragmentInfo { (LengthOrPercentageOrAuto::Calc(calc), _, Some(container_size)) => { MaybeAuto::Specified(calc.length() + container_size.scale_by(calc.percentage())) } - (LengthOrPercentageOrAuto::Calc(calc), _, None) => { - MaybeAuto::Specified(calc.length()) - } + (LengthOrPercentageOrAuto::Calc(_), _, None) => MaybeAuto::Auto, (LengthOrPercentageOrAuto::Auto, Some(dom_length), _) => MaybeAuto::Specified(dom_length), (LengthOrPercentageOrAuto::Auto, None, _) => MaybeAuto::Auto, } diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index 2df2e339939..b2cfe39d013 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -1908,15 +1908,14 @@ pub mod longhands { } /// | | | pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - input.try(specified::LengthOrPercentage::parse_non_negative) - .map(|value| match value { - specified::LengthOrPercentage::Length(value) => value, + let value = try!(input.try(specified::LengthOrPercentage::parse_non_negative)); + match value { + specified::LengthOrPercentage::Length(value) => Ok(value), specified::LengthOrPercentage::Percentage(value) => - specified::Length::FontRelative(specified::FontRelativeLength::Em(value.0)), + Ok(specified::Length::FontRelative(specified::FontRelativeLength::Em(value.0))), // FIXME(dzbarsky) handle calc for font-size - specified::LengthOrPercentage::Calc(_) => - specified::Length::FontRelative(specified::FontRelativeLength::Em(1.)), - }) + specified::LengthOrPercentage::Calc(_) => return Err(()) + } .or_else(|()| { match_ignore_ascii_case! { try!(input.expect_ident()), "xx-small" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 3 / 5)), diff --git a/components/style/values.rs b/components/style/values.rs index 05c837d33c1..9b74427368f 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -1300,7 +1300,7 @@ pub mod computed { impl ::cssparser::ToCss for Calc { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match (self.length, self.percentage) { - (None, Some(p)) => write!(dest, "{}%", p), + (None, Some(p)) => write!(dest, "{}%", p * 100.), (Some(l), None) => write!(dest, "{}px", Au::to_px(l)), (Some(l), Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p * 100.), _ => unreachable!() @@ -1318,14 +1318,14 @@ pub mod computed { length = Some(length.unwrap_or(Au(0)) + absolute); } - for val in vec!(self.vw, self.vh, self.vmin, self.vmax) { - if let Some(val) = val { + for val in &[self.vw, self.vh, self.vmin, self.vmax] { + if let Some(val) = *val { length = Some(length.unwrap_or(Au(0)) + val.to_computed_value(context.viewport_size)); } } - for val in vec!(self.em, self.ex, self.rem) { - if let Some(val) = val { + for val in &[self.em, self.ex, self.rem] { + if let Some(val) = *val { length = Some(length.unwrap_or(Au(0)) + val.to_computed_value(context.font_size, context.root_font_size)); } diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index b0719a029b5..772bceec7d2 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -299,6 +299,12 @@ "url": "/_mozilla/mozilla/body_listener.html" } ], + "mozilla/calc.html": [ + { + "path": "mozilla/calc.html", + "url": "/_mozilla/mozilla/calc.html" + } + ], "mozilla/caption.html": [ { "path": "mozilla/caption.html", diff --git a/tests/wpt/mozilla/meta/mozilla/calc.html.ini b/tests/wpt/mozilla/meta/mozilla/calc.html.ini new file mode 100644 index 00000000000..6a2e6b9c885 --- /dev/null +++ b/tests/wpt/mozilla/meta/mozilla/calc.html.ini @@ -0,0 +1,8 @@ +[calc.html] + type: testharness + [calc(1px + 1pt + 1pc + 1in + 1cm + 1mm)] + expected: FAIL + + [calc(0px + 0pt + 0pc + 0in + 0cm + 0mm + 0rem + 0em + 0ex + 0% + 0vw + 0vh + 0vmin + 0vmax)] + expected: FAIL + diff --git a/tests/wpt/mozilla/tests/mozilla/calc.html b/tests/wpt/mozilla/tests/mozilla/calc.html new file mode 100644 index 00000000000..519fa1d88fa --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/calc.html @@ -0,0 +1,62 @@ + + + + + + + +
FOO
+ + + From 25829bbb125cae71a6b78b60d4341ab1a6afcdb8 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Wed, 26 Aug 2015 14:48:34 -0700 Subject: [PATCH 18/22] Add calc reftest --- tests/ref/basic.list | 1 + tests/ref/calc-basic-ref.html | 19 +++++++++++++++++++ tests/ref/calc-basic.html | 19 +++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 tests/ref/calc-basic-ref.html create mode 100644 tests/ref/calc-basic.html diff --git a/tests/ref/basic.list b/tests/ref/basic.list index 01dc9d43cab..2c85fe77f99 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -80,6 +80,7 @@ flaky_cpu == append_style_a.html append_style_b.html == box_sizing_border_box_a.html box_sizing_border_box_ref.html == box_sizing_sanity_check_a.html box_sizing_sanity_check_ref.html == br.html br-ref.html +== calc-basic.html calc-basic-ref.html == canvas_as_block_element_a.html canvas_as_block_element_ref.html == canvas_linear_gradient_a.html canvas_linear_gradient_ref.html == canvas_radial_gradient_a.html canvas_radial_gradient_ref.html diff --git a/tests/ref/calc-basic-ref.html b/tests/ref/calc-basic-ref.html new file mode 100644 index 00000000000..f2120ffdd68 --- /dev/null +++ b/tests/ref/calc-basic-ref.html @@ -0,0 +1,19 @@ + +
+
+
+
+ + + diff --git a/tests/ref/calc-basic.html b/tests/ref/calc-basic.html new file mode 100644 index 00000000000..ae972fff38e --- /dev/null +++ b/tests/ref/calc-basic.html @@ -0,0 +1,19 @@ + +
+
+
+
+ + + From 2591a89a91945629cee5ea5df8598eff5334f24e Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Wed, 26 Aug 2015 15:33:51 -0700 Subject: [PATCH 19/22] Add calc parsing tests for the other properties --- tests/wpt/mozilla/meta/mozilla/calc.html.ini | 120 +++++++++++++++++++ tests/wpt/mozilla/tests/mozilla/calc.html | 91 ++++++++++++++ 2 files changed, 211 insertions(+) diff --git a/tests/wpt/mozilla/meta/mozilla/calc.html.ini b/tests/wpt/mozilla/meta/mozilla/calc.html.ini index 6a2e6b9c885..ad1ebaf3617 100644 --- a/tests/wpt/mozilla/meta/mozilla/calc.html.ini +++ b/tests/wpt/mozilla/meta/mozilla/calc.html.ini @@ -6,3 +6,123 @@ [calc(0px + 0pt + 0pc + 0in + 0cm + 0mm + 0rem + 0em + 0ex + 0% + 0vw + 0vh + 0vmin + 0vmax)] expected: FAIL + [calc for border-width] + expected: FAIL + + [calc for border-top-width] + expected: FAIL + + [calc for border-left-width] + expected: FAIL + + [calc for border-right-width] + expected: FAIL + + [calc for border-bottom-width] + expected: FAIL + + [calc for outline-width] + expected: FAIL + + [calc for outline-offset] + expected: FAIL + + [calc for letter-spacing] + expected: FAIL + + [calc for word-spacing] + expected: FAIL + + [calc for border-spacing] + expected: FAIL + + [calc for column-width] + expected: FAIL + + [calc for column-gap] + expected: FAIL + + [calc for perspective] + expected: FAIL + + [calc for border-top-left-radius] + expected: FAIL + + [calc for border-bottom-left-radius] + expected: FAIL + + [calc for border-top-right-radius] + expected: FAIL + + [calc for border-bottom-right-radius] + expected: FAIL + + [calc for top] + expected: FAIL + + [calc for left] + expected: FAIL + + [calc for bottom] + expected: FAIL + + [calc for right] + expected: FAIL + + [calc for width] + expected: FAIL + + [calc for height] + expected: FAIL + + [calc for min-width] + expected: FAIL + + [calc for min-height] + expected: FAIL + + [calc for max-width] + expected: FAIL + + [calc for max-height] + expected: FAIL + + [calc for line-height] + expected: FAIL + + [calc for vertical-align] + expected: FAIL + + [calc for background-position] + expected: FAIL + + [calc for background-size] + expected: FAIL + + [calc for font-size] + expected: FAIL + + [calc for text-indent] + expected: FAIL + + [calc for transform-origin] + expected: FAIL + + [calc for perspective-origin] + expected: FAIL + + [calc for transition-delay] + expected: FAIL + + [calc for z-index] + expected: FAIL + + [calc for column-count] + expected: FAIL + + [calc for opacity] + expected: FAIL + + [calc for transition-duration] + expected: FAIL + diff --git a/tests/wpt/mozilla/tests/mozilla/calc.html b/tests/wpt/mozilla/tests/mozilla/calc.html index 519fa1d88fa..b69c28e67d0 100644 --- a/tests/wpt/mozilla/tests/mozilla/calc.html +++ b/tests/wpt/mozilla/tests/mozilla/calc.html @@ -57,6 +57,97 @@ widthTests.forEach(function(item) { assert_equals(window.getComputedStyle(div).getPropertyValue('width'), item[2]); }, item[0]); }); + +var lengthProperties = [ + 'border-width', + 'border-top-width', + 'border-left-width', + 'border-right-width', + 'border-bottom-width', + 'outline-width', + 'outline-offset', + 'letter-spacing', + 'word-spacing', + 'border-spacing', + 'column-width', + 'column-gap', + 'perspective', +]; + +lengthProperties.forEach(function(prop) { + test(function() { + div.style.setProperty(prop, 'calc(1px)'); + assert_equals(div.style.getPropertyValue(prop), '1px'); + assert_equals(window.getComputedStyle(div).getPropertyValue(prop), '1px'); + }, 'calc for ' + prop); +}); + +var lengthOrPercentageProperties = [ + 'border-top-left-radius', + 'border-bottom-left-radius', + 'border-top-right-radius', + 'border-bottom-right-radius', + 'top', + 'left', + 'bottom', + 'right', + 'width', + 'height', + 'min-width', + 'min-height', + 'max-width', + 'max-height', + 'line-height', + 'vertical-align', + 'background-position', + 'background-size', + 'font-size', + 'text-indent', + 'transform-origin', + 'perspective-origin', +]; + +lengthOrPercentageProperties.forEach(function(prop) { + test(function() { + div.style.setProperty(prop, 'calc(1px + 0%)'); + assert_equals(div.style.getPropertyValue(prop), 'calc(1px + 0%)'); + assert_equals(window.getComputedStyle(div).getPropertyValue(prop), '1px'); + }, 'calc for ' + prop); +}); + +var timeProperties = [ + 'transition-delay', +]; + +timeProperties.forEach(function(prop) { + test(function() { + div.style.setProperty(prop, 'calc(1s)'); + assert_equals(div.style.getPropertyValue(prop), '1s'); + assert_equals(window.getComputedStyle(div).getPropertyValue(prop), '1s'); + }, 'calc for ' + prop); +}); + +var numberProperties = [ + 'z-index', + 'column-count', + 'opacity', + 'transition-duration', +]; + +numberProperties.forEach(function(prop) { + test(function() { + div.style.setProperty(prop, 'calc(1)'); + assert_equals(div.style.getPropertyValue(prop), '1'); + assert_equals(window.getComputedStyle(div).getPropertyValue(prop), '1'); + }, 'calc for ' + prop); +}); + + +/* TODO: test these: + counter-increment, counter-reset, + color, box-shadow, clip, text-shadow, transform + transition-timing-function + */ From b30c4f70f936ed63ae2448a88fb2e66916b111be Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 1 Sep 2015 18:45:14 +0200 Subject: [PATCH 20/22] Add support for the ch unit in calc() --- components/style/values.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index a9addcae8c4..b8158059abe 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -424,6 +424,7 @@ pub mod specified { pub vmax: Option, pub em: Option, pub ex: Option, + pub ch: Option, pub rem: Option, pub percentage: Option, } @@ -584,6 +585,7 @@ pub mod specified { let mut vmin = None; let mut em = None; let mut ex = None; + let mut ch = None; let mut rem = None; let mut percentage = None; let mut number = None; @@ -611,6 +613,8 @@ pub mod specified { em = Some(em.unwrap_or(0.) + val), FontRelativeLength::Ex(val) => ex = Some(ex.unwrap_or(0.) + val), + FontRelativeLength::Ch(val) => + ch = Some(ch.unwrap_or(0.) + val), FontRelativeLength::Rem(val) => rem = Some(rem.unwrap_or(0.) + val), }, @@ -627,6 +631,7 @@ pub mod specified { vmin: vmin.map(ViewportPercentageLength::Vmin), em: em.map(FontRelativeLength::Em), ex: ex.map(FontRelativeLength::Ex), + ch: ex.map(FontRelativeLength::Ch), rem: rem.map(FontRelativeLength::Rem), percentage: percentage.map(Percentage), }) @@ -668,14 +673,14 @@ pub mod specified { }; } - let count = count!(em, ex, absolute, rem, vh, vmax, vmin, vw, percentage); + let count = count!(em, ex, ch, absolute, rem, vh, vmax, vmin, vw, percentage); assert!(count > 0); if count > 1 { try!(write!(dest, "calc(")); } - serialize!(em, ex, absolute, rem, vh, vmax, vmin, vw, percentage); + serialize!(em, ex, ch, absolute, rem, vh, vmax, vmin, vw, percentage); if count > 1 { try!(write!(dest, ")")); @@ -1329,7 +1334,7 @@ pub mod computed { val.to_computed_value(context.viewport_size)); } } - for val in &[self.em, self.ex, self.rem] { + for val in &[self.em, self.ex, self.ch, self.rem] { if let Some(val) = *val { length = Some(length.unwrap_or(Au(0)) + val.to_computed_value(context.font_size, context.root_font_size)); From 9f48dcd85861f7018e326b7a75c4c22716770e70 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 2 Sep 2015 09:54:38 +0200 Subject: [PATCH 21/22] Fix font-size keywords parsing. --- components/style/properties.mako.rs | 8 ++++---- tests/ref/font_size.html | 1 + tests/ref/font_size_ref.html | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index ddb70e83d87..346add6c935 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -1912,14 +1912,14 @@ pub mod longhands { } /// | | | pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - let value = try!(input.try(specified::LengthOrPercentage::parse_non_negative)); - match value { + input.try(specified::LengthOrPercentage::parse_non_negative) + .and_then(|value| match value { specified::LengthOrPercentage::Length(value) => Ok(value), specified::LengthOrPercentage::Percentage(value) => Ok(specified::Length::FontRelative(specified::FontRelativeLength::Em(value.0))), // FIXME(dzbarsky) handle calc for font-size - specified::LengthOrPercentage::Calc(_) => return Err(()) - } + specified::LengthOrPercentage::Calc(_) => Err(()) + }) .or_else(|()| { match_ignore_ascii_case! { try!(input.expect_ident()), "xx-small" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 3 / 5)), diff --git a/tests/ref/font_size.html b/tests/ref/font_size.html index 6d534378724..7c500513bcb 100644 --- a/tests/ref/font_size.html +++ b/tests/ref/font_size.html @@ -1,5 +1,6 @@ font-size (issues #1435, #3417) +

24pt is 32px.

2em is 40px. diff --git a/tests/ref/font_size_ref.html b/tests/ref/font_size_ref.html index 0c5d50fb8b7..62adacf79f3 100644 --- a/tests/ref/font_size_ref.html +++ b/tests/ref/font_size_ref.html @@ -1,5 +1,6 @@ font-size (issues #1435, #3417) +

24pt is 32px.

2em is 40px. From b51b7dd2cef16f91c9451e42415e18260b99ee48 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 2 Sep 2015 10:14:00 +0200 Subject: [PATCH 22/22] Fix ch/em confusion. --- components/style/values.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/style/values.rs b/components/style/values.rs index b8158059abe..bc5be3ed2fa 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -631,7 +631,7 @@ pub mod specified { vmin: vmin.map(ViewportPercentageLength::Vmin), em: em.map(FontRelativeLength::Em), ex: ex.map(FontRelativeLength::Ex), - ch: ex.map(FontRelativeLength::Ch), + ch: ch.map(FontRelativeLength::Ch), rem: rem.map(FontRelativeLength::Rem), percentage: percentage.map(Percentage), }) @@ -673,14 +673,14 @@ pub mod specified { }; } - let count = count!(em, ex, ch, absolute, rem, vh, vmax, vmin, vw, percentage); + let count = count!(ch, em, ex, absolute, rem, vh, vmax, vmin, vw, percentage); assert!(count > 0); if count > 1 { try!(write!(dest, "calc(")); } - serialize!(em, ex, ch, absolute, rem, vh, vmax, vmin, vw, percentage); + serialize!(ch, em, ex, absolute, rem, vh, vmax, vmin, vw, percentage); if count > 1 { try!(write!(dest, ")")); @@ -1334,7 +1334,7 @@ pub mod computed { val.to_computed_value(context.viewport_size)); } } - for val in &[self.em, self.ex, self.ch, self.rem] { + for val in &[self.ch, self.em, self.ex, self.rem] { if let Some(val) = *val { length = Some(length.unwrap_or(Au(0)) + val.to_computed_value(context.font_size, context.root_font_size));