diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 2449e88975a..d0b4a504660 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -487,6 +487,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", use parser::{Parse, ParserContext}; use std::fmt; use style_traits::ToCss; + use values::specified; pub use super::parse; @@ -498,7 +499,9 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", } impl ToCss for T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, dest: &mut W) -> fmt::Result + where W: fmt::Write, + { match *self { T::CubicBezier(p1, p2) => { try!(dest.write_str("cubic-bezier(")); @@ -512,7 +515,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", dest.write_str(")") } T::Steps(steps, start_end) => { - super::serialize_steps(dest, steps, start_end) + super::serialize_steps(dest, specified::Integer::new(steps as i32), start_end) } } } @@ -526,7 +529,9 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", } impl ToCss for StartEnd { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, dest: &mut W) -> fmt::Result + where W: fmt::Write, + { match *self { StartEnd::Start => dest.write_str("start"), StartEnd::End => dest.write_str("end"), @@ -548,7 +553,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum SpecifiedValue { CubicBezier(Point2D, Point2D), - Steps(u32, StartEnd), + Steps(specified::Integer, StartEnd), Keyword(FunctionKeyword), } @@ -578,10 +583,10 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", Ok(SpecifiedValue::CubicBezier(p1, p2)) }, "steps" => { - let (mut step_count, mut start_end) = (0, StartEnd::End); + let (mut step_count, mut start_end) = (specified::Integer::new(0), StartEnd::End); try!(input.parse_nested_block(|input| { step_count = try!(specified::parse_integer(input)); - if step_count < 1 { + if step_count.value() < 1 { return Err(()) } @@ -595,7 +600,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", } Ok(()) })); - Ok(SpecifiedValue::Steps(step_count as u32, start_end)) + Ok(SpecifiedValue::Steps(step_count, start_end)) }, _ => Err(()) } @@ -604,8 +609,11 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", } } - fn serialize_steps(dest: &mut W, steps: u32, - start_end: StartEnd) -> fmt::Result where W: fmt::Write { + fn serialize_steps(dest: &mut W, + steps: specified::Integer, + start_end: StartEnd) -> fmt::Result + where W: fmt::Write, + { try!(dest.write_str("steps(")); try!(steps.to_css(dest)); if let StartEnd::Start = start_end { @@ -635,10 +643,10 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", SpecifiedValue::Keyword(keyword) => { match keyword { FunctionKeyword::StepStart => { - serialize_steps(dest, 1, StartEnd::Start) + serialize_steps(dest, specified::Integer::new(1), StartEnd::Start) }, FunctionKeyword::StepEnd => { - serialize_steps(dest, 1, StartEnd::End) + serialize_steps(dest, specified::Integer::new(1), StartEnd::End) }, _ => { keyword.to_css(dest) @@ -661,7 +669,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", Point2D::new(p2.x.to_computed_value(context), p2.y.to_computed_value(context))) }, SpecifiedValue::Steps(count, start_end) => { - computed_value::T::Steps(count, start_end) + computed_value::T::Steps(count.to_computed_value(context) as u32, start_end) }, SpecifiedValue::Keyword(keyword) => { match keyword { @@ -687,7 +695,8 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", Number::from_computed_value(&p2.y))) }, computed_value::T::Steps(count, start_end) => { - SpecifiedValue::Steps(count, start_end) + let int_count = count as i32; + SpecifiedValue::Steps(specified::Integer::from_computed_value(&int_count), start_end) }, } } diff --git a/components/style/properties/longhand/counters.mako.rs b/components/style/properties/longhand/counters.mako.rs index c4bbba8785a..f87003c6da4 100644 --- a/components/style/properties/longhand/counters.mako.rs +++ b/components/style/properties/longhand/counters.mako.rs @@ -246,17 +246,63 @@ use style_traits::ToCss; use super::content; use values::HasViewportPercentage; - use values::computed::ComputedValueAsSpecified; use cssparser::{Token, serialize_identifier}; use std::borrow::{Cow, ToOwned}; - pub use self::computed_value::T as SpecifiedValue; + #[derive(Debug, Clone, PartialEq)] + pub struct SpecifiedValue(Vec<(String, specified::Integer)>); pub mod computed_value { + use std::fmt; + use style_traits::ToCss; + #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct T(pub Vec<(String,i32)>); + pub struct T(pub Vec<(String, i32)>); + + impl ToCss for T { + fn to_css(&self, dest: &mut W) -> fmt::Result + where W: fmt::Write, + { + use cssparser::serialize_identifier; + if self.0.is_empty() { + return dest.write_str("none") + } + + let mut first = true; + for pair in &self.0 { + if !first { + try!(dest.write_str(" ")); + } + first = false; + try!(serialize_identifier(&pair.0, dest)); + try!(dest.write_str(" ")); + try!(pair.1.to_css(dest)); + } + Ok(()) + } + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + let mut ret = Vec::with_capacity(self.0.len()); + for entry in &self.0 { + ret.push((entry.0.clone(), entry.1.to_computed_value(context))); + } + computed_value::T(ret) + } + + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + let mut ret = Vec::with_capacity(computed.0.len()); + for entry in &computed.0 { + ret.push((entry.0.clone(), specified::Integer::from_computed_value(&entry.1))); + } + SpecifiedValue(ret) + } } #[inline] @@ -264,15 +310,15 @@ computed_value::T(Vec::new()) } - impl ComputedValueAsSpecified for SpecifiedValue {} no_viewport_percentage!(SpecifiedValue); impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, dest: &mut W) -> fmt::Result + where W: fmt::Write, + { if self.0.is_empty() { return dest.write_str("none"); } - let mut first = true; for pair in &self.0 { if !first { @@ -280,18 +326,19 @@ } first = false; try!(serialize_identifier(&pair.0, dest)); - try!(write!(dest, " {}", pair.1)); + try!(dest.write_str(" ")); + try!(pair.1.to_css(dest)); } Ok(()) } } - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { parse_common(1, input) } - pub fn parse_common(default_value: i32, input: &mut Parser) -> Result { + pub fn parse_common(default_value: i32, input: &mut Parser) -> Result { if input.try(|input| input.expect_ident_matching("none")).is_ok() { return Ok(SpecifiedValue(Vec::new())) } @@ -307,7 +354,7 @@ return Err(()) } let counter_delta = - input.try(|input| specified::parse_integer(input)).unwrap_or(default_value); + input.try(|input| specified::parse_integer(input)).unwrap_or(specified::Integer::new(default_value)); counters.push((counter_name, counter_delta)) } @@ -322,7 +369,7 @@ <%helpers:longhand name="counter-reset" animatable="False" spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset"> pub use super::counter_increment::{SpecifiedValue, computed_value, get_initial_value}; - use super::counter_increment::{parse_common}; + use super::counter_increment::parse_common; pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { parse_common(0, input) diff --git a/components/style/properties/longhand/position.mako.rs b/components/style/properties/longhand/position.mako.rs index db4aeb518be..2e7a445e548 100644 --- a/components/style/properties/longhand/position.mako.rs +++ b/components/style/properties/longhand/position.mako.rs @@ -130,27 +130,9 @@ ${helpers.predefined_type("flex-shrink", "Number", % endif // https://drafts.csswg.org/css-flexbox/#propdef-order -<%helpers:longhand name="order" animatable="True" extra_prefixes="webkit" - spec="https://drafts.csswg.org/css-flexbox/#order-property"> - use values::computed::ComputedValueAsSpecified; - - impl ComputedValueAsSpecified for SpecifiedValue {} - - pub type SpecifiedValue = computed_value::T; - - pub mod computed_value { - pub type T = i32; - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - 0 - } - - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - specified::parse_integer(input) - } - +${helpers.predefined_type("order", "Integer", "0", + animatable=True, + spec="https://drafts.csswg.org/css-flexbox/#order-property")} // FIXME: Gecko doesn't support content value yet. // FIXME: This property should be animatable. diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 30784a2ba59..dfdc88c20af 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -203,11 +203,13 @@ impl<'a> Mul for &'a SimplifiedValueNode { } #[allow(missing_docs)] -pub fn parse_integer(input: &mut Parser) -> Result { +pub fn parse_integer(input: &mut Parser) -> Result { match try!(input.next()) { - Token::Number(ref value) => value.int_value.ok_or(()), + Token::Number(ref value) => value.int_value.ok_or(()).map(Integer::new), Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { - let ast = try!(input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, CalcUnit::Integer))); + let ast = try!(input.parse_nested_block(|i| { + CalcLengthOrPercentage::parse_sum(i, CalcUnit::Integer) + })); let mut result = None; @@ -220,7 +222,7 @@ pub fn parse_integer(input: &mut Parser) -> Result { } match result { - Some(result) => Ok(result), + Some(result) => Ok(Integer::from_calc(result)), _ => Err(()) } } @@ -771,21 +773,47 @@ impl ToCss for Opacity { #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] -pub struct Integer(pub CSSInteger); +pub struct Integer { + value: CSSInteger, + was_calc: bool, +} + +impl Integer { + /// Trivially constructs a new `Integer` value. + pub fn new(val: CSSInteger) -> Self { + Integer { + value: val, + was_calc: false, + } + } + + /// Returns the integer value associated with this value. + pub fn value(&self) -> CSSInteger { + self.value + } + + /// Trivially constructs a new integer value from a `calc()` expression. + pub fn from_calc(val: CSSInteger) -> Self { + Integer { + value: val, + was_calc: true, + } + } +} no_viewport_percentage!(Integer); impl Parse for Integer { fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - parse_integer(input).map(Integer) + parse_integer(input) } } impl Integer { fn parse_with_minimum(input: &mut Parser, min: i32) -> Result { match parse_integer(input) { - Ok(value) if value < min => Err(()), - value => value.map(Integer), + Ok(value) if value.value() >= min => Ok(value), + _ => Err(()), } } @@ -804,17 +832,26 @@ impl ToComputedValue for Integer { type ComputedValue = i32; #[inline] - fn to_computed_value(&self, _: &Context) -> i32 { self.0 } + fn to_computed_value(&self, _: &Context) -> i32 { self.value } #[inline] fn from_computed_value(computed: &i32) -> Self { - Integer(*computed) + Integer::new(*computed) } } impl ToCss for Integer { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - write!(dest, "{}", self.0) + fn to_css(&self, dest: &mut W) -> fmt::Result + where W: fmt::Write, + { + if self.was_calc { + dest.write_str("calc(")?; + } + write!(dest, "{}", self.value)?; + if self.was_calc { + dest.write_str(")")?; + } + Ok(()) } } @@ -823,9 +860,11 @@ pub type IntegerOrAuto = Either; impl IntegerOrAuto { #[allow(missing_docs)] - pub fn parse_positive(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_positive(context: &ParserContext, + input: &mut Parser) + -> Result { match IntegerOrAuto::parse(context, input) { - Ok(Either::First(Integer(value))) if value <= 0 => Err(()), + Ok(Either::First(integer)) if integer.value() <= 0 => Err(()), result => result, } }