style: Properly handle calc inside integer expressions.

This commit is contained in:
Emilio Cobos Álvarez 2017-03-27 02:49:37 +02:00
parent 8175bfd60b
commit 8205a0de90
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
4 changed files with 136 additions and 59 deletions

View file

@ -487,6 +487,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::ToCss;
use values::specified;
pub use super::parse; pub use super::parse;
@ -498,7 +499,9 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
} }
impl ToCss for T { impl ToCss for T {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write,
{
match *self { match *self {
T::CubicBezier(p1, p2) => { T::CubicBezier(p1, p2) => {
try!(dest.write_str("cubic-bezier(")); try!(dest.write_str("cubic-bezier("));
@ -512,7 +515,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
dest.write_str(")") dest.write_str(")")
} }
T::Steps(steps, start_end) => { 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 { impl ToCss for StartEnd {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write,
{
match *self { match *self {
StartEnd::Start => dest.write_str("start"), StartEnd::Start => dest.write_str("start"),
StartEnd::End => dest.write_str("end"), 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))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum SpecifiedValue { pub enum SpecifiedValue {
CubicBezier(Point2D<Number>, Point2D<Number>), CubicBezier(Point2D<Number>, Point2D<Number>),
Steps(u32, StartEnd), Steps(specified::Integer, StartEnd),
Keyword(FunctionKeyword), Keyword(FunctionKeyword),
} }
@ -578,10 +583,10 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
Ok(SpecifiedValue::CubicBezier(p1, p2)) Ok(SpecifiedValue::CubicBezier(p1, p2))
}, },
"steps" => { "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| { try!(input.parse_nested_block(|input| {
step_count = try!(specified::parse_integer(input)); step_count = try!(specified::parse_integer(input));
if step_count < 1 { if step_count.value() < 1 {
return Err(()) return Err(())
} }
@ -595,7 +600,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
} }
Ok(()) Ok(())
})); }));
Ok(SpecifiedValue::Steps(step_count as u32, start_end)) Ok(SpecifiedValue::Steps(step_count, start_end))
}, },
_ => Err(()) _ => Err(())
} }
@ -604,8 +609,11 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
} }
} }
fn serialize_steps<W>(dest: &mut W, steps: u32, fn serialize_steps<W>(dest: &mut W,
start_end: StartEnd) -> fmt::Result where W: fmt::Write { steps: specified::Integer,
start_end: StartEnd) -> fmt::Result
where W: fmt::Write,
{
try!(dest.write_str("steps(")); try!(dest.write_str("steps("));
try!(steps.to_css(dest)); try!(steps.to_css(dest));
if let StartEnd::Start = start_end { if let StartEnd::Start = start_end {
@ -635,10 +643,10 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
SpecifiedValue::Keyword(keyword) => { SpecifiedValue::Keyword(keyword) => {
match keyword { match keyword {
FunctionKeyword::StepStart => { FunctionKeyword::StepStart => {
serialize_steps(dest, 1, StartEnd::Start) serialize_steps(dest, specified::Integer::new(1), StartEnd::Start)
}, },
FunctionKeyword::StepEnd => { FunctionKeyword::StepEnd => {
serialize_steps(dest, 1, StartEnd::End) serialize_steps(dest, specified::Integer::new(1), StartEnd::End)
}, },
_ => { _ => {
keyword.to_css(dest) 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))) Point2D::new(p2.x.to_computed_value(context), p2.y.to_computed_value(context)))
}, },
SpecifiedValue::Steps(count, start_end) => { 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) => { SpecifiedValue::Keyword(keyword) => {
match keyword { match keyword {
@ -687,7 +695,8 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
Number::from_computed_value(&p2.y))) Number::from_computed_value(&p2.y)))
}, },
computed_value::T::Steps(count, start_end) => { 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)
}, },
} }
} }

View file

@ -246,17 +246,63 @@
use style_traits::ToCss; use style_traits::ToCss;
use super::content; use super::content;
use values::HasViewportPercentage; use values::HasViewportPercentage;
use values::computed::ComputedValueAsSpecified;
use cssparser::{Token, serialize_identifier}; use cssparser::{Token, serialize_identifier};
use std::borrow::{Cow, ToOwned}; 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 { pub mod computed_value {
use std::fmt;
use style_traits::ToCss;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[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<W>(&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] #[inline]
@ -264,15 +310,15 @@
computed_value::T(Vec::new()) computed_value::T(Vec::new())
} }
impl ComputedValueAsSpecified for SpecifiedValue {}
no_viewport_percentage!(SpecifiedValue); no_viewport_percentage!(SpecifiedValue);
impl ToCss for SpecifiedValue { impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write,
{
if self.0.is_empty() { if self.0.is_empty() {
return dest.write_str("none"); return dest.write_str("none");
} }
let mut first = true; let mut first = true;
for pair in &self.0 { for pair in &self.0 {
if !first { if !first {
@ -280,18 +326,19 @@
} }
first = false; first = false;
try!(serialize_identifier(&pair.0, dest)); try!(serialize_identifier(&pair.0, dest));
try!(write!(dest, " {}", pair.1)); try!(dest.write_str(" "));
try!(pair.1.to_css(dest));
} }
Ok(()) Ok(())
} }
} }
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
parse_common(1, input) parse_common(1, input)
} }
pub fn parse_common(default_value: i32, input: &mut Parser) -> Result<SpecifiedValue,()> { pub fn parse_common(default_value: i32, input: &mut Parser) -> Result<SpecifiedValue, ()> {
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(SpecifiedValue(Vec::new())) return Ok(SpecifiedValue(Vec::new()))
} }
@ -307,7 +354,7 @@
return Err(()) return Err(())
} }
let counter_delta = 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)) counters.push((counter_name, counter_delta))
} }
@ -322,7 +369,7 @@
<%helpers:longhand name="counter-reset" animatable="False" <%helpers:longhand name="counter-reset" animatable="False"
spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset"> spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset">
pub use super::counter_increment::{SpecifiedValue, computed_value, get_initial_value}; 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<SpecifiedValue,()> { pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
parse_common(0, input) parse_common(0, input)

View file

@ -130,27 +130,9 @@ ${helpers.predefined_type("flex-shrink", "Number",
% endif % endif
// https://drafts.csswg.org/css-flexbox/#propdef-order // https://drafts.csswg.org/css-flexbox/#propdef-order
<%helpers:longhand name="order" animatable="True" extra_prefixes="webkit" ${helpers.predefined_type("order", "Integer", "0",
spec="https://drafts.csswg.org/css-flexbox/#order-property"> animatable=True,
use values::computed::ComputedValueAsSpecified; spec="https://drafts.csswg.org/css-flexbox/#order-property")}
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<SpecifiedValue, ()> {
specified::parse_integer(input)
}
</%helpers:longhand>
// FIXME: Gecko doesn't support content value yet. // FIXME: Gecko doesn't support content value yet.
// FIXME: This property should be animatable. // FIXME: This property should be animatable.

View file

@ -203,11 +203,13 @@ impl<'a> Mul<CSSFloat> for &'a SimplifiedValueNode {
} }
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn parse_integer(input: &mut Parser) -> Result<i32, ()> { pub fn parse_integer(input: &mut Parser) -> Result<Integer, ()> {
match try!(input.next()) { 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") => { 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; let mut result = None;
@ -220,7 +222,7 @@ pub fn parse_integer(input: &mut Parser) -> Result<i32, ()> {
} }
match result { match result {
Some(result) => Ok(result), Some(result) => Ok(Integer::from_calc(result)),
_ => Err(()) _ => Err(())
} }
} }
@ -771,21 +773,47 @@ impl ToCss for Opacity {
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)] #[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); no_viewport_percentage!(Integer);
impl Parse for Integer { impl Parse for Integer {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
parse_integer(input).map(Integer) parse_integer(input)
} }
} }
impl Integer { impl Integer {
fn parse_with_minimum(input: &mut Parser, min: i32) -> Result<Integer, ()> { fn parse_with_minimum(input: &mut Parser, min: i32) -> Result<Integer, ()> {
match parse_integer(input) { match parse_integer(input) {
Ok(value) if value < min => Err(()), Ok(value) if value.value() >= min => Ok(value),
value => value.map(Integer), _ => Err(()),
} }
} }
@ -804,17 +832,26 @@ impl ToComputedValue for Integer {
type ComputedValue = i32; type ComputedValue = i32;
#[inline] #[inline]
fn to_computed_value(&self, _: &Context) -> i32 { self.0 } fn to_computed_value(&self, _: &Context) -> i32 { self.value }
#[inline] #[inline]
fn from_computed_value(computed: &i32) -> Self { fn from_computed_value(computed: &i32) -> Self {
Integer(*computed) Integer::new(*computed)
} }
} }
impl ToCss for Integer { impl ToCss for Integer {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut W) -> fmt::Result
write!(dest, "{}", self.0) 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<Integer, Auto>;
impl IntegerOrAuto { impl IntegerOrAuto {
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn parse_positive(context: &ParserContext, input: &mut Parser) -> Result<IntegerOrAuto, ()> { pub fn parse_positive(context: &ParserContext,
input: &mut Parser)
-> Result<IntegerOrAuto, ()> {
match IntegerOrAuto::parse(context, input) { 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, result => result,
} }
} }