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), } } }