Auto merge of #12458 - Manishearth:style-gecko-only, r=emilio

Cleanups in autoarray helper

Addresses @emilio's comments from #11851

- Replace gecko_autoarray_longhand with vector_longhand, make it configurable
- Allow for empty vectors, use empty vector longhand in box-shadow

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/12458)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-07-15 22:31:37 -07:00 committed by GitHub
commit a8a6d83d07
4 changed files with 68 additions and 94 deletions

View file

@ -37,12 +37,18 @@
// and handle the empty case correctly // and handle the empty case correctly
<%doc> <%doc>
To be used in cases where we have a grammar like To be used in cases where we have a grammar like
"<thing> [ , <thing> ]*", but only support a single value "<thing> [ , <thing> ]*". `gecko_only` should be set
in servo to True for cases where Servo takes a single value
and Stylo supports vector values.
Setting allow_empty to False allows for cases where the vector
is empty. The grammar for these is usually "none | <thing> [ , <thing> ]*".
We assume that the default/initial value is an empty vector for these.
`initial_value` need not be defined for these.
</%doc> </%doc>
<%def name="gecko_autoarray_longhand(name, **kwargs)"> <%def name="vector_longhand(name, gecko_only=False, allow_empty=False, **kwargs)">
<%call expr="longhand(name, **kwargs)"> <%call expr="longhand(name, **kwargs)">
% if product == "gecko": % if product == "gecko" or not gecko_only:
use cssparser::ToCss; use cssparser::ToCss;
use std::fmt; use std::fmt;
@ -63,10 +69,17 @@
impl ToCss for computed_value::T { impl ToCss for computed_value::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 {
if !self.0.is_empty() { let mut iter = self.0.iter();
try!(self.0[0].to_css(dest)); if let Some(val) = iter.next() {
try!(val.to_css(dest));
} else {
% if allow_empty:
try!(dest.write_str("none"));
% else:
error!("Found empty value for property ${name}");
% endif
} }
for i in self.0.iter().skip(1) { for i in iter {
try!(dest.write_str(", ")); try!(dest.write_str(", "));
try!(i.to_css(dest)); try!(i.to_css(dest));
} }
@ -80,10 +93,17 @@
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() { let mut iter = self.0.iter();
try!(self.0[0].to_css(dest)) if let Some(val) = iter.next() {
try!(val.to_css(dest));
} else {
% if allow_empty:
try!(dest.write_str("none"));
% else:
error!("Found empty value for property ${name}");
% endif
} }
for i in self.0.iter().skip(1) { for i in iter {
try!(dest.write_str(", ")); try!(dest.write_str(", "));
try!(i.to_css(dest)); try!(i.to_css(dest));
} }
@ -91,12 +111,26 @@
} }
} }
pub fn get_initial_value() -> computed_value::T { pub fn get_initial_value() -> computed_value::T {
computed_value::T(vec![single_value::get_initial_value()]) % if allow_empty:
computed_value::T(vec![])
% else:
computed_value::T(vec![single_value::get_initial_value()])
% endif
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
input.parse_comma_separated(|parser| { % if allow_empty:
single_value::parse(context, parser) if input.try(|input| input.expect_ident_matching("none")).is_ok() {
}).map(|ok| SpecifiedValue(ok)) Ok(SpecifiedValue(Vec::new()))
} else {
input.parse_comma_separated(|parser| {
single_value::parse(context, parser)
}).map(SpecifiedValue)
}
% else:
input.parse_comma_separated(|parser| {
single_value::parse(context, parser)
}).map(SpecifiedValue)
% endif
} }
impl ToComputedValue for SpecifiedValue { impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T; type ComputedValue = computed_value::T;

View file

@ -16,7 +16,7 @@ use properties::longhands::line_height::computed_value::T as LineHeight;
use properties::longhands::text_shadow::computed_value::T as TextShadowList; use properties::longhands::text_shadow::computed_value::T as TextShadowList;
use properties::longhands::text_shadow::computed_value::TextShadow; use properties::longhands::text_shadow::computed_value::TextShadow;
use properties::longhands::box_shadow::computed_value::T as BoxShadowList; use properties::longhands::box_shadow::computed_value::T as BoxShadowList;
use properties::longhands::box_shadow::computed_value::BoxShadow; use properties::longhands::box_shadow::single_value::computed_value::T as BoxShadow;
use properties::longhands::transform::computed_value::ComputedMatrix; use properties::longhands::transform::computed_value::ComputedMatrix;
use properties::longhands::transform::computed_value::ComputedOperation as TransformOperation; use properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
use properties::longhands::transform::computed_value::T as TransformList; use properties::longhands::transform::computed_value::T as TransformList;

View file

@ -10,7 +10,7 @@ ${helpers.predefined_type("background-color", "CSSColor",
"::cssparser::Color::RGBA(::cssparser::RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */", "::cssparser::Color::RGBA(::cssparser::RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */",
animatable=True)} animatable=True)}
<%helpers:gecko_autoarray_longhand name="background-image" animatable="False"> <%helpers:vector_longhand gecko_only="True" name="background-image" animatable="False">
use cssparser::ToCss; use cssparser::ToCss;
use std::fmt; use std::fmt;
use values::specified::Image; use values::specified::Image;
@ -70,7 +70,7 @@ ${helpers.predefined_type("background-color", "CSSColor",
} }
} }
} }
</%helpers:gecko_autoarray_longhand> </%helpers:vector_longhand>
<%helpers:longhand name="background-position" animatable="True"> <%helpers:longhand name="background-position" animatable="True">
use cssparser::ToCss; use cssparser::ToCss;

View file

@ -12,18 +12,14 @@ ${helpers.predefined_type("opacity",
"1.0", "1.0",
animatable=True)} animatable=True)}
<%helpers:longhand name="box-shadow" animatable="True"> <%helpers:vector_longhand name="box-shadow" allow_empty="True" animatable="True">
use cssparser::{self, ToCss}; use cssparser::{self, ToCss};
use std::fmt; use std::fmt;
use values::LocalToCss; use values::LocalToCss;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SpecifiedValue(Vec<SpecifiedBoxShadow>); pub struct SpecifiedValue {
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SpecifiedBoxShadow {
pub offset_x: specified::Length, pub offset_x: specified::Length,
pub offset_y: specified::Length, pub offset_y: specified::Length,
pub blur_radius: specified::Length, pub blur_radius: specified::Length,
@ -33,23 +29,6 @@ ${helpers.predefined_type("opacity",
} }
impl ToCss for SpecifiedValue { impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
let mut iter = self.0.iter();
if let Some(shadow) = iter.next() {
try!(shadow.to_css(dest));
} else {
try!(dest.write_str("none"));
return Ok(())
}
for shadow in iter {
try!(dest.write_str(", "));
try!(shadow.to_css(dest));
}
Ok(())
}
}
impl ToCss for SpecifiedBoxShadow {
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.inset { if self.inset {
try!(dest.write_str("inset ")); try!(dest.write_str("inset "));
@ -75,13 +54,9 @@ ${helpers.predefined_type("opacity",
use std::fmt; use std::fmt;
use values::computed; use values::computed;
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub Vec<BoxShadow>);
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct BoxShadow { pub struct T {
pub offset_x: Au, pub offset_x: Au,
pub offset_y: Au, pub offset_y: Au,
pub blur_radius: Au, pub blur_radius: Au,
@ -92,23 +67,6 @@ ${helpers.predefined_type("opacity",
} }
impl ToCss for computed_value::T { impl ToCss for computed_value::T {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
let mut iter = self.0.iter();
if let Some(shadow) = iter.next() {
try!(shadow.to_css(dest));
} else {
try!(dest.write_str("none"));
return Ok(())
}
for shadow in iter {
try!(dest.write_str(", "));
try!(shadow.to_css(dest));
}
Ok(())
}
}
impl ToCss for computed_value::BoxShadow {
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.inset { if self.inset {
try!(dest.write_str("inset ")); try!(dest.write_str("inset "));
@ -126,44 +84,26 @@ ${helpers.predefined_type("opacity",
} }
} }
#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T(Vec::new())
}
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
Ok(SpecifiedValue(Vec::new()))
} else {
input.parse_comma_separated(parse_one_box_shadow).map(SpecifiedValue)
}
}
impl ToComputedValue for SpecifiedValue { impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T; type ComputedValue = computed_value::T;
#[inline] #[inline]
fn to_computed_value<Cx: TContext>(&self, context: &Cx) -> computed_value::T { fn to_computed_value<Cx: TContext>(&self, context: &Cx) -> computed_value::T {
computed_value::T(self.0.iter().map(|value| compute_one_box_shadow(value, context)).collect()) computed_value::T {
offset_x: self.offset_x.to_computed_value(context),
offset_y: self.offset_y.to_computed_value(context),
blur_radius: self.blur_radius.to_computed_value(context),
spread_radius: self.spread_radius.to_computed_value(context),
color: self.color
.as_ref()
.map(|color| color.parsed)
.unwrap_or(cssparser::Color::CurrentColor),
inset: self.inset,
}
} }
} }
pub fn compute_one_box_shadow<Cx: TContext>(value: &SpecifiedBoxShadow, context: &Cx) pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
-> computed_value::BoxShadow {
computed_value::BoxShadow {
offset_x: value.offset_x.to_computed_value(context),
offset_y: value.offset_y.to_computed_value(context),
blur_radius: value.blur_radius.to_computed_value(context),
spread_radius: value.spread_radius.to_computed_value(context),
color: value.color
.as_ref()
.map(|color| color.parsed)
.unwrap_or(cssparser::Color::CurrentColor),
inset: value.inset,
}
}
pub fn parse_one_box_shadow(input: &mut Parser) -> Result<SpecifiedBoxShadow, ()> {
use app_units::Au; use app_units::Au;
let mut lengths = [specified::Length::Absolute(Au(0)); 4]; let mut lengths = [specified::Length::Absolute(Au(0)); 4];
let mut lengths_parsed = false; let mut lengths_parsed = false;
@ -213,7 +153,7 @@ ${helpers.predefined_type("opacity",
return Err(()) return Err(())
} }
Ok(SpecifiedBoxShadow { Ok(SpecifiedValue {
offset_x: lengths[0], offset_x: lengths[0],
offset_y: lengths[1], offset_y: lengths[1],
blur_radius: lengths[2], blur_radius: lengths[2],
@ -222,7 +162,7 @@ ${helpers.predefined_type("opacity",
inset: inset, inset: inset,
}) })
} }
</%helpers:longhand> </%helpers:vector_longhand>
// FIXME: This prop should be animatable // FIXME: This prop should be animatable
<%helpers:longhand name="clip" animatable="False"> <%helpers:longhand name="clip" animatable="False">