Cleanup Polygon and make it generic

This commit is contained in:
Ravi Shankar 2017-04-12 23:47:48 +05:30
parent a36bf9efc4
commit f4b18643c2
4 changed files with 118 additions and 141 deletions

View file

@ -329,6 +329,7 @@ pub mod basic_shape {
use values::computed::basic_shape::*; use values::computed::basic_shape::*;
use values::computed::position; use values::computed::position;
use values::generics::BorderRadiusSize as GenericBorderRadiusSize; use values::generics::BorderRadiusSize as GenericBorderRadiusSize;
use values::generics::basic_shape::FillRule;
// using Borrow so that we can have a non-moving .into() // using Borrow so that we can have a non-moving .into()
impl<T: Borrow<StyleBasicShape>> From<T> for BasicShape { impl<T: Borrow<StyleBasicShape>> From<T> for BasicShape {

View file

@ -12,9 +12,11 @@ use style_traits::ToCss;
use values::computed::LengthOrPercentage; use values::computed::LengthOrPercentage;
use values::computed::position::Position; use values::computed::position::Position;
use values::generics::basic_shape::{BorderRadius as GenericBorderRadius, ShapeRadius as GenericShapeRadius}; use values::generics::basic_shape::{BorderRadius as GenericBorderRadius, ShapeRadius as GenericShapeRadius};
use values::generics::basic_shape::Polygon as GenericPolygon;
use values::specified::url::SpecifiedUrl; use values::specified::url::SpecifiedUrl;
pub use values::specified::basic_shape::{self, FillRule, GeometryBox, ShapeBox}; pub use values::generics::basic_shape::FillRule;
pub use values::specified::basic_shape::{self, GeometryBox, ShapeBox};
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@ -141,35 +143,8 @@ impl ToCss for Ellipse {
} }
} }
#[derive(Clone, PartialEq, Debug)] /// The computed value of `Polygon`
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub type Polygon = GenericPolygon<LengthOrPercentage>;
#[allow(missing_docs)]
/// https://drafts.csswg.org/css-shapes/#funcdef-polygon
pub struct Polygon {
pub fill: FillRule,
pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>,
}
impl ToCss for Polygon {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(dest.write_str("polygon("));
let mut need_space = false;
if self.fill != Default::default() {
try!(self.fill.to_css(dest));
try!(dest.write_str(", "));
}
for coord in &self.coordinates {
if need_space {
try!(dest.write_str(", "));
}
try!(coord.0.to_css(dest));
try!(dest.write_str(" "));
try!(coord.1.to_css(dest));
need_space = true;
}
dest.write_str(")")
}
}
/// The computed value of `BorderRadius` /// The computed value of `BorderRadius`
pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>; pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>;

View file

@ -5,11 +5,14 @@
//! CSS handling for the [`basic-shape`](https://drafts.csswg.org/css-shapes/#typedef-basic-shape) //! CSS handling for the [`basic-shape`](https://drafts.csswg.org/css-shapes/#typedef-basic-shape)
//! types that are generic over their `ToCss` implementations. //! types that are generic over their `ToCss` implementations.
use cssparser::Parser;
use euclid::size::Size2D; use euclid::size::Size2D;
use parser::{Parse, ParserContext};
use properties::shorthands::serialize_four_sides; use properties::shorthands::serialize_four_sides;
use std::ascii::AsciiExt;
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::ToCss;
use values::computed::{Context, ToComputedValue}; use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
use values::generics::BorderRadiusSize; use values::generics::BorderRadiusSize;
/// A generic type used for `border-radius`, `outline-radius` and `inset()` values. /// A generic type used for `border-radius`, `outline-radius` and `inset()` values.
@ -126,3 +129,108 @@ impl<L: ToComputedValue> ToComputedValue for ShapeRadius<L> {
} }
} }
} }
// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
// NOTE: Basic shapes spec says that these are the only two values, however
// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
// says that it can also be `inherit`
define_css_keyword_enum!(FillRule:
"nonzero" => NonZero,
"evenodd" => EvenOdd
);
impl ComputedValueAsSpecified for FillRule {}
impl Default for FillRule {
#[inline]
fn default() -> Self { FillRule::NonZero }
}
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A generic type for representing the `polygon()` function
///
/// https://drafts.csswg.org/css-shapes/#funcdef-polygon
pub struct Polygon<L> {
/// The filling rule for a polygon.
pub fill: FillRule,
/// A collection of (x, y) coordinates to draw the polygon.
pub coordinates: Vec<(L, L)>,
}
impl<L: Parse> Polygon<L> {
/// Parse the inner arguments of a `polygon` function.
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
let fill = input.try(|i| -> Result<_, ()> {
let fill = FillRule::parse(i)?;
i.expect_comma()?; // only eat the comma if there is something before it
Ok(fill)
}).ok().unwrap_or_default();
let buf = input.parse_comma_separated(|i| {
Ok((L::parse(context, i)?, L::parse(context, i)?))
})?;
Ok(Polygon {
fill: fill,
coordinates: buf,
})
}
}
impl<L: Parse> Parse for Polygon<L> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
match input.expect_function() {
Ok(ref s) if s.eq_ignore_ascii_case("polygon") =>
input.parse_nested_block(|i| Polygon::parse_function_arguments(context, i)),
_ => Err(())
}
}
}
impl<L: ToCss> ToCss for Polygon<L> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
dest.write_str("polygon(")?;
if self.fill != FillRule::default() {
self.fill.to_css(dest)?;
dest.write_str(", ")?;
}
for (i, coord) in self.coordinates.iter().enumerate() {
if i > 0 {
dest.write_str(", ")?;
}
coord.0.to_css(dest)?;
dest.write_str(" ")?;
coord.1.to_css(dest)?;
}
dest.write_str(")")
}
}
impl<L: ToComputedValue> ToComputedValue for Polygon<L> {
type ComputedValue = Polygon<L::ComputedValue>;
#[inline]
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
Polygon {
fill: self.fill.to_computed_value(cx),
coordinates: self.coordinates.iter().map(|c| {
(c.0.to_computed_value(cx), c.1.to_computed_value(cx))
}).collect(),
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Polygon {
fill: ToComputedValue::from_computed_value(&computed.fill),
coordinates: computed.coordinates.iter().map(|c| {
(ToComputedValue::from_computed_value(&c.0),
ToComputedValue::from_computed_value(&c.1))
}).collect(),
}
}
}

View file

@ -18,6 +18,7 @@ use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
use values::computed::basic_shape as computed_basic_shape; use values::computed::basic_shape as computed_basic_shape;
use values::generics::BorderRadiusSize; use values::generics::BorderRadiusSize;
use values::generics::basic_shape::{BorderRadius as GenericBorderRadius, ShapeRadius as GenericShapeRadius}; use values::generics::basic_shape::{BorderRadius as GenericBorderRadius, ShapeRadius as GenericShapeRadius};
use values::generics::basic_shape::Polygon as GenericPolygon;
use values::specified::{LengthOrPercentage, Percentage}; use values::specified::{LengthOrPercentage, Percentage};
use values::specified::position::{Keyword, Position}; use values::specified::position::{Keyword, Position};
use values::specified::url::SpecifiedUrl; use values::specified::url::SpecifiedUrl;
@ -520,99 +521,8 @@ impl ToComputedValue for Ellipse {
} }
} }
/// The specified value of `Polygon`
#[derive(Clone, PartialEq, Debug)] pub type Polygon = GenericPolygon<LengthOrPercentage>;
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// https://drafts.csswg.org/css-shapes/#funcdef-polygon
#[allow(missing_docs)]
pub struct Polygon {
pub fill: FillRule,
pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>,
}
impl Polygon {
#[allow(missing_docs)]
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Polygon, ()> {
let fill = input.try(|input| {
let fill = FillRule::parse(input);
// only eat the comma if there is something before it
try!(input.expect_comma());
fill
}).ok().unwrap_or_else(Default::default);
let buf = try!(input.parse_comma_separated(|input| {
Ok((try!(LengthOrPercentage::parse(context, input)),
try!(LengthOrPercentage::parse(context, input))))
}));
Ok(Polygon {
fill: fill,
coordinates: buf,
})
}
}
impl Parse for Polygon {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
match input.try(|i| i.expect_function()) {
Ok(ref s) if s.eq_ignore_ascii_case("polygon") =>
input.parse_nested_block(|i| Polygon::parse_function_arguments(context, i)),
_ => Err(())
}
}
}
impl ToCss for Polygon {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(dest.write_str("polygon("));
let mut need_space = false;
if self.fill != Default::default() {
try!(self.fill.to_css(dest));
try!(dest.write_str(", "));
}
for coord in &self.coordinates {
if need_space {
try!(dest.write_str(", "));
}
try!(coord.0.to_css(dest));
try!(dest.write_str(" "));
try!(coord.1.to_css(dest));
need_space = true;
}
dest.write_str(")")
}
}
impl ToComputedValue for Polygon {
type ComputedValue = computed_basic_shape::Polygon;
#[inline]
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
computed_basic_shape::Polygon {
fill: self.fill.to_computed_value(cx),
coordinates: self.coordinates.iter()
.map(|c| {
(c.0.to_computed_value(cx),
c.1.to_computed_value(cx))
}).collect(),
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Polygon {
fill: ToComputedValue::from_computed_value(&computed.fill),
coordinates: computed.coordinates.iter()
.map(|c| {
(ToComputedValue::from_computed_value(&c.0),
ToComputedValue::from_computed_value(&c.1))
}).collect(),
}
}
}
/// The specified value of `ShapeRadius` /// The specified value of `ShapeRadius`
pub type ShapeRadius = GenericShapeRadius<LengthOrPercentage>; pub type ShapeRadius = GenericShapeRadius<LengthOrPercentage>;
@ -677,23 +587,6 @@ fn parse_one_set_of_border_values(context: &ParserContext, mut input: &mut Parse
} }
} }
// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
// NOTE: Basic shapes spec says that these are the only two values, however
// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
// says that it can also be `inherit`
define_css_keyword_enum!(FillRule:
"nonzero" => NonZero,
"evenodd" => EvenOdd
);
impl ComputedValueAsSpecified for FillRule {}
impl Default for FillRule {
fn default() -> Self {
FillRule::NonZero
}
}
/// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box /// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]