Auto merge of #12878 - Manishearth:clip-path, r=heycam

stylo: Support clip-path

Todo:

 - [x] `set_clip_path` (probably needs a bunch of gecko bindings for running constructors/destructors)
 - [ ] Ensure that I've ordered the coordinates correctly
 - [ ] Check that it works
 - [x] Might want to convert NS_STYLE_FILL_RULE and NS_RADIUS to enum classes

Depends on:

 - https://github.com/servo/rust-bindgen/pull/29
 - https://github.com/Manishearth/gecko-dev/compare/servo:stylo...Manishearth:clip-path

<!-- 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/12878)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-08-19 14:24:08 -05:00 committed by GitHub
commit 609d47b44f
14 changed files with 627 additions and 14 deletions

View file

@ -8,13 +8,111 @@
//! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape
use cssparser::{Parser, ToCss};
use parser::{ParserContext, Parse};
use properties::shorthands::{parse_four_sides, serialize_four_sides};
use std::fmt;
use url::Url;
use values::computed::basic_shape as computed_basic_shape;
use values::computed::{Context, ToComputedValue, ComputedValueAsSpecified};
use values::specified::UrlExtraData;
use values::specified::position::Position;
use values::specified::{BorderRadiusSize, LengthOrPercentage, Percentage};
/// A shape source, for some reference box
///
/// clip-path uses ShapeSource<GeometryBox>,
/// shape-outside uses ShapeSource<ShapeBox>
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum ShapeSource<T> {
Url(Url, UrlExtraData),
Shape(BasicShape, Option<T>),
Box(T),
None,
}
impl<T> Default for ShapeSource<T> {
fn default() -> Self {
ShapeSource::None
}
}
impl<T: ToCss> ToCss for ShapeSource<T> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
use values::LocalToCss;
match *self {
ShapeSource::Url(ref url, _) => url.to_css(dest),
ShapeSource::Shape(ref shape, Some(ref reference)) => {
try!(shape.to_css(dest));
try!(dest.write_str(" "));
reference.to_css(dest)
}
ShapeSource::Shape(ref shape, None) => shape.to_css(dest),
ShapeSource::Box(ref reference) => reference.to_css(dest),
ShapeSource::None => dest.write_str("none"),
}
}
}
impl<T: Parse + PartialEq + Copy> ShapeSource<T> {
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if let Ok(_) = input.try(|input| input.expect_ident_matching("none")) {
Ok(ShapeSource::None)
} else if let Ok(url) = input.try(|input| input.expect_url()) {
match UrlExtraData::make_from(context) {
Some(extra_data) => {
Ok(ShapeSource::Url(context.parse_url(&url), extra_data))
},
None => Err(()),
}
} else {
fn parse_component<U: Parse>(input: &mut Parser, component: &mut Option<U>) -> bool {
if component.is_some() {
return false; // already parsed this component
}
*component = input.try(U::parse).ok();
component.is_some()
}
let mut shape = None;
let mut reference = None;
loop {
if !parse_component(input, &mut shape) &&
!parse_component(input, &mut reference) {
break;
}
}
match (shape, reference) {
(Some(shape), _) => Ok(ShapeSource::Shape(shape, reference)),
(None, Some(reference)) => Ok(ShapeSource::Box(reference)),
(None, None) => Err(()),
}
}
}
}
impl<T: ToComputedValue> ToComputedValue for ShapeSource<T> {
type ComputedValue = computed_basic_shape::ShapeSource<T::ComputedValue>;
#[inline]
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
match *self {
ShapeSource::Url(ref url, ref data) => {
computed_basic_shape::ShapeSource::Url(url.clone(), data.clone())
}
ShapeSource::Shape(ref shape, ref reference) => {
computed_basic_shape::ShapeSource::Shape(
shape.to_computed_value(cx),
reference.as_ref().map(|ref r| r.to_computed_value(cx)))
}
ShapeSource::Box(ref reference) => {
computed_basic_shape::ShapeSource::Box(reference.to_computed_value(cx))
}
ShapeSource::None => computed_basic_shape::ShapeSource::None,
}
}
}
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum BasicShape {
@ -24,8 +122,8 @@ pub enum BasicShape {
Polygon(Polygon),
}
impl BasicShape {
pub fn parse(input: &mut Parser) -> Result<BasicShape, ()> {
impl Parse for BasicShape {
fn parse(input: &mut Parser) -> Result<BasicShape, ()> {
match_ignore_ascii_case! { try!(input.expect_function()),
"inset" => {
Ok(BasicShape::Inset(
@ -528,3 +626,77 @@ impl ToCss for FillRule {
}
}
}
/// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box
#[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum GeometryBox {
Fill,
Stroke,
View,
ShapeBox(ShapeBox),
}
impl Parse for GeometryBox {
fn parse(input: &mut Parser) -> Result<Self, ()> {
if let Ok(shape_box) = input.try(ShapeBox::parse) {
Ok(GeometryBox::ShapeBox(shape_box))
} else {
match_ignore_ascii_case! { try!(input.expect_ident()),
"fill-box" => Ok(GeometryBox::Fill),
"stroke-box" => Ok(GeometryBox::Stroke),
"view-box" => Ok(GeometryBox::View),
_ => Err(())
}
}
}
}
impl ToCss for GeometryBox {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
GeometryBox::Fill => dest.write_str("fill-box"),
GeometryBox::Stroke => dest.write_str("stroke-box"),
GeometryBox::View => dest.write_str("view-box"),
GeometryBox::ShapeBox(s) => s.to_css(dest),
}
}
}
impl ComputedValueAsSpecified for GeometryBox {}
// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box
#[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum ShapeBox {
Margin,
// https://drafts.csswg.org/css-backgrounds-3/#box
Border,
Padding,
Content,
}
impl Parse for ShapeBox {
fn parse(input: &mut Parser) -> Result<Self, ()> {
match_ignore_ascii_case! { try!(input.expect_ident()),
"margin-box" => Ok(ShapeBox::Margin),
"border-box" => Ok(ShapeBox::Border),
"padding-box" => Ok(ShapeBox::Padding),
"content-box" => Ok(ShapeBox::Content),
_ => Err(())
}
}
}
impl ToCss for ShapeBox {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
ShapeBox::Margin => dest.write_str("margin-box"),
ShapeBox::Border => dest.write_str("border-box"),
ShapeBox::Padding => dest.write_str("padding-box"),
ShapeBox::Content => dest.write_str("content-box"),
}
}
}
impl ComputedValueAsSpecified for ShapeBox {}