Factor out ClipRect type into values; use Either for clip

MozReview-Commit-ID: C3R1erJdiID
This commit is contained in:
Manish Goregaokar 2017-02-08 16:18:56 -08:00 committed by Manish Goregaokar
parent 8b7bb97aa9
commit 6b0d3902de
10 changed files with 223 additions and 238 deletions

View file

@ -77,217 +77,13 @@ ${helpers.predefined_type("opacity",
</%helpers:vector_longhand>
// FIXME: This prop should be animatable
<%helpers:longhand name="clip" products="servo" animatable="False" boxed="True"
spec="https://drafts.fxtf.org/css-masking/#clip-property">
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
// NB: `top` and `left` are 0 if `auto` per CSS 2.1 11.1.2.
pub mod computed_value {
use app_units::Au;
use properties::animated_properties::Interpolate;
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct ClipRect {
pub top: Au,
pub right: Option<Au>,
pub bottom: Option<Au>,
pub left: Au,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub Option<ClipRect>);
/// https://drafts.csswg.org/css-transitions/#animtype-rect
impl Interpolate for ClipRect {
#[inline]
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
Ok(ClipRect {
top: try!(self.top.interpolate(&other.top, time)),
right: try!(self.right.interpolate(&other.right, time)),
bottom: try!(self.bottom.interpolate(&other.bottom, time)),
left: try!(self.left.interpolate(&other.left, time)),
})
}
}
}
impl ToCss for computed_value::T {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match self.0 {
None => dest.write_str("auto"),
Some(rect) => {
try!(dest.write_str("rect("));
try!(rect.top.to_css(dest));
try!(dest.write_str(", "));
if let Some(right) = rect.right {
try!(right.to_css(dest));
try!(dest.write_str(", "));
} else {
try!(dest.write_str("auto, "));
}
if let Some(bottom) = rect.bottom {
try!(bottom.to_css(dest));
try!(dest.write_str(", "));
} else {
try!(dest.write_str("auto, "));
}
try!(rect.left.to_css(dest));
try!(dest.write_str(")"));
Ok(())
}
}
}
}
impl HasViewportPercentage for SpecifiedClipRect {
fn has_viewport_percentage(&self) -> bool {
self.top.has_viewport_percentage() ||
self.right.as_ref().map_or(false, |x| x.has_viewport_percentage()) ||
self.bottom.as_ref().map_or(false, |x| x.has_viewport_percentage()) ||
self.left.has_viewport_percentage()
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SpecifiedClipRect {
pub top: specified::Length,
pub right: Option<specified::Length>,
pub bottom: Option<specified::Length>,
pub left: specified::Length,
}
impl HasViewportPercentage for SpecifiedValue {
fn has_viewport_percentage(&self) -> bool {
self.0.as_ref().map_or(false, |x| x.has_viewport_percentage())
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SpecifiedValue(Option<SpecifiedClipRect>);
impl ToCss for SpecifiedClipRect {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(dest.write_str("rect("));
try!(self.top.to_css(dest));
try!(dest.write_str(", "));
if let Some(ref right) = self.right {
try!(right.to_css(dest));
try!(dest.write_str(", "));
} else {
try!(dest.write_str("auto, "));
}
if let Some(ref bottom) = self.bottom {
try!(bottom.to_css(dest));
try!(dest.write_str(", "));
} else {
try!(dest.write_str("auto, "));
}
try!(self.left.to_css(dest));
try!(dest.write_str(")"));
Ok(())
}
}
impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
if let Some(ref rect) = self.0 {
rect.to_css(dest)
} else {
dest.write_str("auto")
}
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T(None)
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T {
computed_value::T(self.0.as_ref().map(|value| computed_value::ClipRect {
top: value.top.to_computed_value(context),
right: value.right.as_ref().map(|right| right.to_computed_value(context)),
bottom: value.bottom.as_ref().map(|bottom| bottom.to_computed_value(context)),
left: value.left.to_computed_value(context),
}))
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
SpecifiedValue(computed.0.map(|value| SpecifiedClipRect {
top: ToComputedValue::from_computed_value(&value.top),
right: value.right.map(|right| ToComputedValue::from_computed_value(&right)),
bottom: value.bottom.map(|bottom| ToComputedValue::from_computed_value(&bottom)),
left: ToComputedValue::from_computed_value(&value.left),
}))
}
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
use app_units::Au;
use std::ascii::AsciiExt;
use values::specified::Length;
fn parse_argument(context: &ParserContext, input: &mut Parser) -> Result<Option<Length>, ()> {
if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
Ok(None)
} else {
Length::parse(context, input).map(Some)
}
}
if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
return Ok(SpecifiedValue(None))
}
if !try!(input.expect_function()).eq_ignore_ascii_case("rect") {
return Err(())
}
input.parse_nested_block(|input| {
let top = try!(parse_argument(context, input));
let right;
let bottom;
let left;
if input.try(|input| input.expect_comma()).is_ok() {
right = try!(parse_argument(context, input));
try!(input.expect_comma());
bottom = try!(parse_argument(context, input));
try!(input.expect_comma());
left = try!(parse_argument(context, input));
} else {
right = try!(parse_argument(context, input));
bottom = try!(parse_argument(context, input));
left = try!(parse_argument(context, input));
}
Ok(SpecifiedValue(Some(SpecifiedClipRect {
top: top.unwrap_or(Length::zero()),
right: right,
bottom: bottom,
left: left.unwrap_or(Length::zero()),
})))
})
}
</%helpers:longhand>
${helpers.predefined_type("clip",
"ClipRectOrAuto",
"computed::ClipRectOrAuto::auto()",
animatable=False,
products="servo",
boxed="True",
spec="https://drafts.fxtf.org/css-masking/#clip-property")}
// FIXME: This prop should be animatable
<%helpers:longhand name="filter" animatable="False" extra_prefixes="webkit"