mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Factor out ClipRect type into values; use Either for clip
MozReview-Commit-ID: C3R1erJdiID
This commit is contained in:
parent
8b7bb97aa9
commit
6b0d3902de
10 changed files with 223 additions and 238 deletions
|
@ -1176,10 +1176,11 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
fn adjust_clip_for_style(&self,
|
||||
parent_clip: &mut ClippingRegion,
|
||||
stacking_relative_border_box: &Rect<Au>) {
|
||||
use style::values::Either;
|
||||
// Account for `clip` per CSS 2.1 § 11.1.2.
|
||||
let style_clip_rect = match (self.style().get_box().position,
|
||||
self.style().get_effects().clip.0) {
|
||||
(position::T::absolute, Some(style_clip_rect)) => style_clip_rect,
|
||||
self.style().get_effects().clip) {
|
||||
(position::T::absolute, Either::First(style_clip_rect)) => style_clip_rect,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
We assume that the default/initial value is an empty vector for these.
|
||||
`initial_value` need not be defined for these.
|
||||
</%doc>
|
||||
<%def name="vector_longhand(name, gecko_only=False, allow_empty=False, **kwargs)">
|
||||
<%def name="vector_longhand(name, gecko_only=False, allow_empty=False, delegate_animate=False, **kwargs)">
|
||||
<%call expr="longhand(name, **kwargs)">
|
||||
% if not gecko_only:
|
||||
use std::fmt;
|
||||
|
@ -97,6 +97,15 @@
|
|||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct T(pub Vec<single_value::T>);
|
||||
|
||||
% if delegate_animate:
|
||||
use properties::animated_properties::Interpolate;
|
||||
impl Interpolate for T {
|
||||
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
||||
self.0.interpolate(&other.0, progress).map(T)
|
||||
}
|
||||
}
|
||||
% endif
|
||||
}
|
||||
|
||||
impl ToCss for computed_value::T {
|
||||
|
|
|
@ -10,8 +10,6 @@ use euclid::{Point2D, Size2D};
|
|||
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID;
|
||||
use properties::{DeclaredValue, PropertyDeclaration};
|
||||
use properties::longhands;
|
||||
use properties::longhands::background_position_x::computed_value::T as BackgroundPositionX;
|
||||
use properties::longhands::background_position_y::computed_value::T as BackgroundPositionY;
|
||||
use properties::longhands::background_size::computed_value::T as BackgroundSize;
|
||||
use properties::longhands::font_weight::computed_value::T as FontWeight;
|
||||
use properties::longhands::line_height::computed_value::T as LineHeight;
|
||||
|
@ -33,7 +31,7 @@ use super::ComputedValues;
|
|||
use values::CSSFloat;
|
||||
use values::Either;
|
||||
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
|
||||
use values::computed::{BorderRadiusSize, LengthOrNone};
|
||||
use values::computed::{BorderRadiusSize, ClipRect, LengthOrNone};
|
||||
use values::computed::{CalcLengthOrPercentage, Context, LengthOrPercentage};
|
||||
use values::computed::position::{HorizontalPosition, Position, VerticalPosition};
|
||||
use values::computed::ToComputedValue;
|
||||
|
@ -724,17 +722,16 @@ impl Interpolate for VerticalPosition {
|
|||
|
||||
impl RepeatableListInterpolate for VerticalPosition {}
|
||||
|
||||
impl Interpolate for BackgroundPositionX {
|
||||
/// https://drafts.csswg.org/css-transitions/#animtype-rect
|
||||
impl Interpolate for ClipRect {
|
||||
#[inline]
|
||||
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
||||
Ok(BackgroundPositionX(try!(self.0.interpolate(&other.0, progress))))
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpolate for BackgroundPositionY {
|
||||
#[inline]
|
||||
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
||||
Ok(BackgroundPositionY(try!(self.0.interpolate(&other.0, progress))))
|
||||
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)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,8 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
|||
</%helpers:vector_longhand>
|
||||
|
||||
<%helpers:vector_longhand name="background-position-x" animatable="True"
|
||||
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x">
|
||||
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x"
|
||||
delegate_animate="True">
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::HasViewportPercentage;
|
||||
|
@ -139,7 +140,8 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
|||
</%helpers:vector_longhand>
|
||||
|
||||
<%helpers:vector_longhand name="background-position-y" animatable="True"
|
||||
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-y">
|
||||
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-y"
|
||||
delegate_animate="True">
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::HasViewportPercentage;
|
||||
|
|
|
@ -1054,7 +1054,7 @@ ${helpers.predefined_type("scroll-snap-destination",
|
|||
"computed::Position::zero()",
|
||||
products="gecko",
|
||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)",
|
||||
animatable=False)}
|
||||
animatable=True)}
|
||||
|
||||
${helpers.predefined_type("scroll-snap-coordinate",
|
||||
"Position",
|
||||
|
@ -1062,8 +1062,10 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
|||
vector=True,
|
||||
products="gecko",
|
||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)",
|
||||
animatable=False,
|
||||
allow_empty=True)}
|
||||
animatable=True,
|
||||
allow_empty=True,
|
||||
delegate_animate=True)}
|
||||
|
||||
|
||||
|
||||
<%helpers:longhand name="transform" products="gecko servo" extra_prefixes="webkit"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -216,7 +216,7 @@ ${helpers.predefined_type("object-position",
|
|||
products="gecko",
|
||||
boxed="True",
|
||||
spec="https://drafts.csswg.org/css-images-3/#the-object-position",
|
||||
animatable=False)}
|
||||
animatable=True)}
|
||||
|
||||
<% grid_longhands = ["grid-row-start", "grid-row-end", "grid-column-start", "grid-column-end"] %>
|
||||
|
||||
|
|
|
@ -1589,7 +1589,7 @@ impl ComputedValues {
|
|||
// TODO(gw): Add clip-path, isolation, mask-image, mask-border-source when supported.
|
||||
if effects.opacity < 1.0 ||
|
||||
!effects.filter.is_empty() ||
|
||||
effects.clip.0.is_some() {
|
||||
!effects.clip.is_auto() {
|
||||
effects.mix_blend_mode != mix_blend_mode::T::normal ||
|
||||
return transform_style::T::flat;
|
||||
}
|
||||
|
@ -2290,10 +2290,10 @@ pub fn modify_style_for_text(style: &mut Arc<ComputedValues>) {
|
|||
/// doesn't clip its children.
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn modify_style_for_inline_absolute_hypothetical_fragment(style: &mut Arc<ComputedValues>) {
|
||||
if style.get_effects().clip.0.is_some() {
|
||||
if !style.get_effects().clip.is_auto() {
|
||||
let mut style = Arc::make_mut(style);
|
||||
let effects_style = Arc::make_mut(&mut style.effects);
|
||||
effects_style.clip.0 = None
|
||||
effects_style.clip = Either::auto()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ use super::{CSSFloat, specified};
|
|||
pub use cssparser::Color as CSSColor;
|
||||
pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image};
|
||||
pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
|
||||
pub use super::{Either, None_};
|
||||
pub use super::{Auto, Either, None_};
|
||||
pub use super::specified::{Angle, BorderStyle, GridLine, Time, UrlOrNone};
|
||||
pub use super::specified::url::UrlExtraData;
|
||||
pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||
|
@ -177,3 +177,57 @@ pub type Number = CSSFloat;
|
|||
|
||||
/// A type used for opacity.
|
||||
pub type Opacity = CSSFloat;
|
||||
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
/// A computed cliprect for clip and image-region
|
||||
pub struct ClipRect {
|
||||
pub top: Au,
|
||||
pub right: Option<Au>,
|
||||
pub bottom: Option<Au>,
|
||||
pub left: Au,
|
||||
}
|
||||
|
||||
impl ToCss for ClipRect {
|
||||
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(right) = self.right {
|
||||
try!(right.to_css(dest));
|
||||
try!(dest.write_str(", "));
|
||||
} else {
|
||||
try!(dest.write_str("auto, "));
|
||||
}
|
||||
|
||||
if let Some(bottom) = self.bottom {
|
||||
try!(bottom.to_css(dest));
|
||||
try!(dest.write_str(", "));
|
||||
} else {
|
||||
try!(dest.write_str("auto, "));
|
||||
}
|
||||
|
||||
try!(self.left.to_css(dest));
|
||||
dest.write_str(")")
|
||||
}
|
||||
}
|
||||
|
||||
/// rect(...) | auto
|
||||
pub type ClipRectOrAuto = Either<ClipRect, Auto>;
|
||||
|
||||
impl ClipRectOrAuto {
|
||||
/// Return an auto (default for clip-rect and image-region) value
|
||||
pub fn auto() -> Self {
|
||||
Either::Second(Auto)
|
||||
}
|
||||
|
||||
/// Check if it is auto
|
||||
pub fn is_auto(&self) -> bool {
|
||||
match *self {
|
||||
Either::Second(_) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ use std::f32::consts::PI;
|
|||
use std::fmt;
|
||||
use std::ops::Mul;
|
||||
use style_traits::ToCss;
|
||||
use super::{CSSFloat, HasViewportPercentage, Either, None_};
|
||||
use super::{Auto, CSSFloat, HasViewportPercentage, Either, None_};
|
||||
use super::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
|
||||
use super::computed::Shadow as ComputedShadow;
|
||||
|
||||
|
@ -665,3 +665,127 @@ impl Shadow {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl HasViewportPercentage for ClipRect {
|
||||
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))]
|
||||
/// rect(<top>, <left>, <bottom>, <right>) used by clip and image-region
|
||||
pub struct ClipRect {
|
||||
/// <top> (<length> | <auto>). Auto maps to 0
|
||||
pub top: Length,
|
||||
/// <right> (<length> | <auto>)
|
||||
pub right: Option<Length>,
|
||||
/// <bottom> (<length> | <auto>)
|
||||
pub bottom: Option<Length>,
|
||||
/// <left> (<length> | <auto>). Auto maps to 0
|
||||
pub left: Length,
|
||||
}
|
||||
|
||||
|
||||
impl ToCss for ClipRect {
|
||||
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 ToComputedValue for ClipRect {
|
||||
type ComputedValue = super::computed::ClipRect;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, context: &Context) -> super::computed::ClipRect {
|
||||
super::computed::ClipRect {
|
||||
top: self.top.to_computed_value(context),
|
||||
right: self.right.as_ref().map(|right| right.to_computed_value(context)),
|
||||
bottom: self.bottom.as_ref().map(|bottom| bottom.to_computed_value(context)),
|
||||
left: self.left.to_computed_value(context),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_computed_value(computed: &super::computed::ClipRect) -> Self {
|
||||
ClipRect {
|
||||
top: ToComputedValue::from_computed_value(&computed.top),
|
||||
right: computed.right.map(|right| ToComputedValue::from_computed_value(&right)),
|
||||
bottom: computed.bottom.map(|bottom| ToComputedValue::from_computed_value(&bottom)),
|
||||
left: ToComputedValue::from_computed_value(&computed.left),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for ClipRect {
|
||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||
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 !try!(input.expect_function()).eq_ignore_ascii_case("rect") {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
// NB: `top` and `left` are 0 if `auto` per CSS 2.1 11.1.2.
|
||||
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(ClipRect {
|
||||
top: top.unwrap_or(Length::zero()),
|
||||
right: right,
|
||||
bottom: bottom,
|
||||
left: left.unwrap_or(Length::zero()),
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// rect(...) | auto
|
||||
pub type ClipRectOrAuto = Either<ClipRect, Auto>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue