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

@ -5,11 +5,14 @@
//! CSS handling for the [`basic-shape`](https://drafts.csswg.org/css-shapes/#typedef-basic-shape)
//! types that are generic over their `ToCss` implementations.
use cssparser::Parser;
use euclid::size::Size2D;
use parser::{Parse, ParserContext};
use properties::shorthands::serialize_four_sides;
use std::ascii::AsciiExt;
use std::fmt;
use style_traits::ToCss;
use values::computed::{Context, ToComputedValue};
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
use values::generics::BorderRadiusSize;
/// 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(),
}
}
}