diff options
author | Anthony Ramine <n.oxyde@gmail.com> | 2017-08-10 10:54:56 +0200 |
---|---|---|
committer | Anthony Ramine <n.oxyde@gmail.com> | 2017-08-11 10:25:03 +0200 |
commit | c4e33d9dca12a0434bdeed4fe9844226093e5ce0 (patch) | |
tree | 531888d4f7c5c16050745969cc524aa169293e28 /components | |
parent | 56f5fc41fae732ba28f63acec6755559da31d47f (diff) | |
download | servo-c4e33d9dca12a0434bdeed4fe9844226093e5ce0.tar.gz servo-c4e33d9dca12a0434bdeed4fe9844226093e5ce0.zip |
Animate basic shapes
Diffstat (limited to 'components')
-rw-r--r-- | components/style/gecko/conversions.rs | 67 | ||||
-rw-r--r-- | components/style/properties/gecko.mako.rs | 4 | ||||
-rw-r--r-- | components/style/properties/helpers/animated_properties.mako.rs | 29 | ||||
-rw-r--r-- | components/style/properties/longhand/box.mako.rs | 16 | ||||
-rw-r--r-- | components/style/properties/longhand/svg.mako.rs | 15 | ||||
-rw-r--r-- | components/style/values/generics/basic_shape.rs | 297 | ||||
-rw-r--r-- | components/style/values/generics/border.rs | 57 | ||||
-rw-r--r-- | components/style/values/generics/rect.rs | 19 |
8 files changed, 456 insertions, 48 deletions
diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 5877e3917d8..9d4b6f230b1 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -590,8 +590,8 @@ pub mod basic_shape { use gecko::values::GeckoStyleCoordConvertible; use gecko_bindings::structs; use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleFillRule}; + use gecko_bindings::structs::{StyleGeometryBox, StyleShapeSource, StyleShapeSourceType}; use gecko_bindings::structs::{nsStyleCoord, nsStyleCorners}; - use gecko_bindings::structs::StyleGeometryBox; use gecko_bindings::sugar::ns_style_coord::{CoordDataMut, CoordDataValue}; use std::borrow::Borrow; use values::computed::basic_shape::{BasicShape, ShapeRadius}; @@ -600,14 +600,42 @@ pub mod basic_shape { use values::computed::position; use values::generics::basic_shape::{BasicShape as GenericBasicShape, InsetRect, Polygon}; use values::generics::basic_shape::{Circle, Ellipse, FillRule}; - use values::generics::basic_shape::{GeometryBox, ShapeBox}; + use values::generics::basic_shape::{GeometryBox, ShapeBox, ShapeSource}; use values::generics::border::BorderRadius as GenericBorderRadius; use values::generics::rect::Rect; + use values::specified::url::SpecifiedUrl; - // using Borrow so that we can have a non-moving .into() - impl<T: Borrow<StyleBasicShape>> From<T> for BasicShape { - fn from(other: T) -> Self { - let other = other.borrow(); + impl<'a, ReferenceBox> From<&'a StyleShapeSource> for ShapeSource<BasicShape, ReferenceBox, SpecifiedUrl> + where + ReferenceBox: From<StyleGeometryBox>, + { + fn from(other: &'a StyleShapeSource) -> Self { + match other.mType { + StyleShapeSourceType::None => ShapeSource::None, + StyleShapeSourceType::Box => ShapeSource::Box(other.mReferenceBox.into()), + StyleShapeSourceType::URL => { + unsafe { + let other_url = &(**other.__bindgen_anon_1.mURL.as_ref()); + let url = SpecifiedUrl::from_url_value_data(&other_url._base).unwrap(); + ShapeSource::Url(url) + } + }, + StyleShapeSourceType::Shape => { + let other_shape = unsafe { &(**other.__bindgen_anon_1.mBasicShape.as_ref()) }; + let shape = other_shape.into(); + let reference_box = if other.mReferenceBox == StyleGeometryBox::NoBox { + None + } else { + Some(other.mReferenceBox.into()) + }; + ShapeSource::Shape(shape, reference_box) + } + } + } + } + + impl<'a> From<&'a StyleBasicShape> for BasicShape { + fn from(other: &'a StyleBasicShape) -> Self { match other.mType { StyleBasicShapeType::Inset => { let t = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[0]); @@ -664,9 +692,8 @@ pub mod basic_shape { } } - impl<T: Borrow<nsStyleCorners>> From<T> for BorderRadius { - fn from(other: T) -> Self { - let other = other.borrow(); + impl<'a> From<&'a nsStyleCorners> for BorderRadius { + fn from(other: &'a nsStyleCorners) -> Self { let get_corner = |index| { BorderCornerRadius::new( LengthOrPercentage::from_gecko_style_coord(&other.data_at(index)) @@ -722,17 +749,16 @@ pub mod basic_shape { } } - impl<T: Borrow<nsStyleCoord>> From<T> for ShapeRadius { - fn from(other: T) -> Self { + impl<'a> From<&'a nsStyleCoord> for ShapeRadius { + fn from(other: &'a nsStyleCoord) -> Self { let other = other.borrow(); ShapeRadius::from_gecko_style_coord(other) .expect("<shape-radius> should be a length, percentage, calc, or keyword value") } } - impl<T: Borrow<structs::Position>> From<T> for position::Position { - fn from(other: T) -> Self { - let other = other.borrow(); + impl<'a> From<&'a structs::Position> for position::Position { + fn from(other: &'a structs::Position) -> Self { position::Position { horizontal: other.mXPosition.into(), vertical: other.mYPosition.into(), @@ -782,6 +808,19 @@ pub mod basic_shape { } } } + + impl From<StyleGeometryBox> for ShapeBox { + fn from(reference: StyleGeometryBox) -> Self { + use gecko_bindings::structs::StyleGeometryBox::*; + match reference { + ContentBox => ShapeBox::ContentBox, + PaddingBox => ShapeBox::PaddingBox, + BorderBox => ShapeBox::BorderBox, + MarginBox => ShapeBox::MarginBox, + other => panic!("Unexpected StyleGeometryBox::{:?} while converting to ShapeBox", other), + } + } + } } impl From<RulesMutateError> for nsresult { diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 7785e8aa47a..f09798e80c4 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -5086,6 +5086,10 @@ fn static_assert() { } + pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { + (&self.gecko.${gecko_ffi_name}).into() + } + pub fn copy_${ident}_from(&mut self, other: &Self) { use gecko_bindings::bindings::Gecko_CopyShapeSourceFrom; unsafe { diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 07031c2f67a..1b4755b4bb7 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -50,7 +50,6 @@ use values::computed::{NonNegativeAu, NonNegativeNumber, PositiveIntegerOrAuto}; use values::computed::length::{NonNegativeLengthOrAuto, NonNegativeLengthOrNormal}; use values::computed::length::NonNegativeLengthOrPercentage; use values::generics::{GreaterThanOrEqualToOne, NonNegative}; -use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; use values::generics::effects::Filter; use values::generics::position as generic_position; use values::generics::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray}; @@ -1004,33 +1003,25 @@ impl<T: Animatable + Copy> Animatable for Size2D<T> { Ok(Size2D::new(width, height)) } -} -impl<T: Animatable + Copy> Animatable for Point2D<T> { #[inline] - fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> { - let x = self.x.add_weighted(&other.x, self_portion, other_portion)?; - let y = self.y.add_weighted(&other.y, self_portion, other_portion)?; - - Ok(Point2D::new(x, y)) + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + Ok(self.compute_squared_distance(other)?.sqrt()) } -} -impl Animatable for BorderCornerRadius { #[inline] - fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> { - self.0.add_weighted(&other.0, self_portion, other_portion).map(GenericBorderCornerRadius) + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + Ok(self.width.compute_squared_distance(&other.width)? + self.height.compute_squared_distance(&other.height)?) } +} +impl<T: Animatable + Copy> Animatable for Point2D<T> { #[inline] - fn compute_distance(&self, other: &Self) -> Result<f64, ()> { - self.compute_squared_distance(other).map(|sd| sd.sqrt()) - } + fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> { + let x = self.x.add_weighted(&other.x, self_portion, other_portion)?; + let y = self.y.add_weighted(&other.y, self_portion, other_portion)?; - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { - Ok(self.0.width.compute_squared_distance(&other.0.width)? + - self.0.height.compute_squared_distance(&other.0.height)?) + Ok(Point2D::new(x, y)) } } diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 37f111b42b5..ea72cc6857e 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -1902,12 +1902,16 @@ ${helpers.single_keyword("-moz-orient", } </%helpers:longhand> -${helpers.predefined_type("shape-outside", "basic_shape::FloatAreaShape", - "generics::basic_shape::ShapeSource::None", - products="gecko", boxed="True", - animation_value_type="none", - flags="APPLIES_TO_FIRST_LETTER", - spec="https://drafts.csswg.org/css-shapes/#shape-outside-property")} +${helpers.predefined_type( + "shape-outside", + "basic_shape::FloatAreaShape", + "generics::basic_shape::ShapeSource::None", + products="gecko", + boxed=True, + animation_value_type="discrete", + flags="APPLIES_TO_FIRST_LETTER", + spec="https://drafts.csswg.org/css-shapes/#shape-outside-property", +)} <%helpers:longhand name="touch-action" products="gecko" diff --git a/components/style/properties/longhand/svg.mako.rs b/components/style/properties/longhand/svg.mako.rs index eaeba146ec5..43db3322ca3 100644 --- a/components/style/properties/longhand/svg.mako.rs +++ b/components/style/properties/longhand/svg.mako.rs @@ -57,11 +57,16 @@ ${helpers.single_keyword("mask-type", "luminance alpha", products="gecko", animation_value_type="discrete", spec="https://drafts.fxtf.org/css-masking/#propdef-mask-type")} -${helpers.predefined_type("clip-path", "basic_shape::ClippingShape", - "generics::basic_shape::ShapeSource::None", - products="gecko", boxed="True", - animation_value_type="none", flags="CREATES_STACKING_CONTEXT", - spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path")} +${helpers.predefined_type( + "clip-path", + "basic_shape::ClippingShape", + "generics::basic_shape::ShapeSource::None", + products="gecko", + boxed=True, + animation_value_type="ComputedValue", + flags="CREATES_STACKING_CONTEXT", + spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path", +)} ${helpers.single_keyword("mask-mode", "match-source alpha luminance", diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs index 98f9cd7690b..f218fd41ba8 100644 --- a/components/style/values/generics/basic_shape.rs +++ b/components/style/values/generics/basic_shape.rs @@ -5,15 +5,17 @@ //! CSS handling for the [`basic-shape`](https://drafts.csswg.org/css-shapes/#typedef-basic-shape) //! types that are generic over their `ToCss` implementations. +use properties::animated_properties::Animatable; use std::fmt; use style_traits::{HasViewportPercentage, ToCss}; +use values::animated::ToAnimatedZero; use values::computed::ComputedValueAsSpecified; use values::generics::border::BorderRadius; use values::generics::position::Position; use values::generics::rect::Rect; /// A clipping shape, for `clip-path`. -pub type ClippingShape<BasicShape, UrlShapeSource> = ShapeSource<BasicShape, GeometryBox, UrlShapeSource>; +pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, Url>; /// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box #[allow(missing_docs)] @@ -28,7 +30,7 @@ pub enum GeometryBox { impl ComputedValueAsSpecified for GeometryBox {} /// A float area shape, for `shape-outside`. -pub type FloatAreaShape<BasicShape, UrlShapeSource> = ShapeSource<BasicShape, ShapeBox, UrlShapeSource>; +pub type FloatAreaShape<BasicShape, Url> = ShapeSource<BasicShape, ShapeBox, Url>; // https://drafts.csswg.org/css-shapes-1/#typedef-shape-box define_css_keyword_enum!(ShapeBox: @@ -43,8 +45,8 @@ add_impls_for_keyword_enum!(ShapeBox); #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Clone, Debug, PartialEq, ToComputedValue, ToCss)] -pub enum ShapeSource<BasicShape, ReferenceBox, UrlShapeSource> { - Url(UrlShapeSource), +pub enum ShapeSource<BasicShape, ReferenceBox, Url> { + Url(Url), Shape(BasicShape, Option<ReferenceBox>), Box(ReferenceBox), None, @@ -120,11 +122,158 @@ define_css_keyword_enum!(FillRule: ); add_impls_for_keyword_enum!(FillRule); +impl<B, T, U> Animatable for ShapeSource<B, T, U> +where + B: Animatable, + T: Clone + PartialEq, +{ + fn add_weighted( + &self, + other: &Self, + self_portion: f64, + other_portion: f64, + ) -> Result<Self, ()> { + match (self, other) { + ( + &ShapeSource::Shape(ref this, ref this_box), + &ShapeSource::Shape(ref other, ref other_box), + ) if this_box == other_box => { + let shape = this.add_weighted(other, self_portion, other_portion)?; + Ok(ShapeSource::Shape(shape, this_box.clone())) + }, + _ => Err(()), + } + } + + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + match (self, other) { + ( + &ShapeSource::Shape(ref this, ref this_box), + &ShapeSource::Shape(ref other, ref other_box), + ) if this_box == other_box => { + this.compute_distance(other) + }, + _ => Err(()), + } + } + + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + match (self, other) { + ( + &ShapeSource::Shape(ref this, ref this_box), + &ShapeSource::Shape(ref other, ref other_box), + ) if this_box == other_box => { + this.compute_squared_distance(other) + }, + _ => Err(()), + } + } +} + +impl<B, T, U> ToAnimatedZero for ShapeSource<B, T, U> { + fn to_animated_zero(&self) -> Result<Self, ()> { + Err(()) + } +} + impl<B, T, U> HasViewportPercentage for ShapeSource<B, T, U> { #[inline] fn has_viewport_percentage(&self) -> bool { false } } +impl<H, V, L> Animatable for BasicShape<H, V, L> +where + H: Animatable, + V: Animatable, + L: Animatable + Copy, +{ + fn add_weighted( + &self, + other: &Self, + self_portion: f64, + other_portion: f64, + ) -> Result<Self, ()> { + match (self, other) { + (&BasicShape::Circle(ref this), &BasicShape::Circle(ref other)) => { + Ok(BasicShape::Circle(this.add_weighted(other, self_portion, other_portion)?)) + }, + (&BasicShape::Ellipse(ref this), &BasicShape::Ellipse(ref other)) => { + Ok(BasicShape::Ellipse(this.add_weighted(other, self_portion, other_portion)?)) + }, + (&BasicShape::Inset(ref this), &BasicShape::Inset(ref other)) => { + Ok(BasicShape::Inset(this.add_weighted(other, self_portion, other_portion)?)) + }, + (&BasicShape::Polygon(ref this), &BasicShape::Polygon(ref other)) => { + Ok(BasicShape::Polygon(this.add_weighted(other, self_portion, other_portion)?)) + }, + _ => Err(()), + } + } + + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + match (self, other) { + (&BasicShape::Circle(ref this), &BasicShape::Circle(ref other)) => { + this.compute_distance(other) + }, + (&BasicShape::Ellipse(ref this), &BasicShape::Ellipse(ref other)) => { + this.compute_distance(other) + }, + (&BasicShape::Inset(ref this), &BasicShape::Inset(ref other)) => { + this.compute_distance(other) + }, + (&BasicShape::Polygon(ref this), &BasicShape::Polygon(ref other)) => { + this.compute_distance(other) + }, + _ => Err(()), + } + } + + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + match (self, other) { + (&BasicShape::Circle(ref this), &BasicShape::Circle(ref other)) => { + this.compute_squared_distance(other) + }, + (&BasicShape::Ellipse(ref this), &BasicShape::Ellipse(ref other)) => { + this.compute_squared_distance(other) + }, + (&BasicShape::Inset(ref this), &BasicShape::Inset(ref other)) => { + this.compute_squared_distance(other) + }, + (&BasicShape::Polygon(ref this), &BasicShape::Polygon(ref other)) => { + this.compute_squared_distance(other) + }, + _ => Err(()), + } + } +} + +impl<L> Animatable for InsetRect<L> +where + L: Animatable + Copy, +{ + fn add_weighted( + &self, + other: &Self, + self_portion: f64, + other_portion: f64, + ) -> Result<Self, ()> { + let rect = self.rect.add_weighted(&other.rect, self_portion, other_portion)?; + let round = self.round.add_weighted(&other.round, self_portion, other_portion)?; + Ok(InsetRect { rect, round }) + } + + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + Ok(self.compute_squared_distance(other)?.sqrt()) + } + + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + Ok( + self.rect.compute_squared_distance(&other.rect)? + + self.round.compute_squared_distance(&other.round)?, + ) + } +} + impl<L> ToCss for InsetRect<L> where L: ToCss + PartialEq { @@ -139,11 +288,151 @@ impl<L> ToCss for InsetRect<L> } } +impl<H, V, L> Animatable for Circle<H, V, L> +where + H: Animatable, + V: Animatable, + L: Animatable, +{ + fn add_weighted( + &self, + other: &Self, + self_portion: f64, + other_portion: f64, + ) -> Result<Self, ()> { + let position = self.position.add_weighted(&other.position, self_portion, other_portion)?; + let radius = self.radius.add_weighted(&other.radius, self_portion, other_portion)?; + Ok(Circle { position, radius }) + } + + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + Ok(self.compute_squared_distance(other)?.sqrt()) + } + + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + Ok( + self.position.compute_squared_distance(&other.position)? + + self.radius.compute_squared_distance(&other.radius)?, + ) + } +} + +impl<H, V, L> Animatable for Ellipse<H, V, L> +where + H: Animatable, + V: Animatable, + L: Animatable, +{ + fn add_weighted( + &self, + other: &Self, + self_portion: f64, + other_portion: f64, + ) -> Result<Self, ()> { + let position = self.position.add_weighted(&other.position, self_portion, other_portion)?; + let semiaxis_x = self.semiaxis_x.add_weighted(&other.semiaxis_x, self_portion, other_portion)?; + let semiaxis_y = self.semiaxis_y.add_weighted(&other.semiaxis_y, self_portion, other_portion)?; + Ok(Ellipse { position, semiaxis_x, semiaxis_y }) + } + + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + Ok(self.compute_squared_distance(other)?.sqrt()) + } + + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + Ok( + self.position.compute_squared_distance(&other.position)? + + self.semiaxis_x.compute_squared_distance(&other.semiaxis_x)? + + self.semiaxis_y.compute_squared_distance(&other.semiaxis_y)?, + ) + } +} + +impl<L> Animatable for ShapeRadius<L> +where + L: Animatable, +{ + fn add_weighted( + &self, + other: &Self, + self_portion: f64, + other_portion: f64, + ) -> Result<Self, ()> { + match (self, other) { + (&ShapeRadius::Length(ref this), &ShapeRadius::Length(ref other)) => { + Ok(ShapeRadius::Length(this.add_weighted(other, self_portion, other_portion)?)) + }, + _ => Err(()), + } + } + + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + match (self, other) { + (&ShapeRadius::Length(ref this), &ShapeRadius::Length(ref other)) => { + this.compute_distance(other) + }, + _ => Err(()), + } + } + + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + match (self, other) { + (&ShapeRadius::Length(ref this), &ShapeRadius::Length(ref other)) => { + this.compute_squared_distance(other) + }, + _ => Err(()), + } + } +} + impl<L> Default for ShapeRadius<L> { #[inline] fn default() -> Self { ShapeRadius::ClosestSide } } +impl<L> Animatable for Polygon<L> +where + L: Animatable, +{ + fn add_weighted( + &self, + other: &Self, + self_portion: f64, + other_portion: f64, + ) -> Result<Self, ()> { + if self.fill != other.fill { + return Err(()); + } + if self.coordinates.len() != other.coordinates.len() { + return Err(()); + } + let coordinates = self.coordinates.iter().zip(other.coordinates.iter()).map(|(this, other)| { + let x = this.0.add_weighted(&other.0, self_portion, other_portion)?; + let y = this.1.add_weighted(&other.1, self_portion, other_portion)?; + Ok((x, y)) + }).collect::<Result<Vec<_>, _>>()?; + Ok(Polygon { fill: self.fill, coordinates }) + } + + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + Ok(self.compute_squared_distance(other)?.sqrt()) + } + + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + if self.fill != other.fill { + return Err(()); + } + if self.coordinates.len() != other.coordinates.len() { + return Err(()); + } + self.coordinates.iter().zip(other.coordinates.iter()).map(|(this, other)| { + let x = this.0.compute_squared_distance(&other.0)?; + let y = this.1.compute_squared_distance(&other.1)?; + Ok(x + y) + }).sum() + } +} + 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(")?; diff --git a/components/style/values/generics/border.rs b/components/style/values/generics/border.rs index 5d8c9032e6a..e70504e7e87 100644 --- a/components/style/values/generics/border.rs +++ b/components/style/values/generics/border.rs @@ -5,6 +5,7 @@ //! Generic types for CSS values related to borders. use euclid::Size2D; +use properties::animated_properties::Animatable; use std::fmt; use style_traits::ToCss; use values::generics::rect::Rect; @@ -112,6 +113,37 @@ impl<L> BorderRadius<L> } } +impl<L> Animatable for BorderRadius<L> +where + L: Animatable + Copy, +{ + fn add_weighted( + &self, + other: &Self, + self_portion: f64, + other_portion: f64, + ) -> Result<Self, ()> { + let tl = self.top_left.add_weighted(&other.top_left, self_portion, other_portion)?; + let tr = self.top_right.add_weighted(&other.top_right, self_portion, other_portion)?; + let br = self.bottom_right.add_weighted(&other.bottom_right, self_portion, other_portion)?; + let bl = self.bottom_left.add_weighted(&other.bottom_left, self_portion, other_portion)?; + Ok(BorderRadius::new(tl, tr, br, bl)) + } + + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + Ok(self.compute_squared_distance(other)?.sqrt()) + } + + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + Ok( + self.top_left.compute_squared_distance(&other.top_left)? + + self.top_right.compute_squared_distance(&other.top_right)? + + self.bottom_right.compute_squared_distance(&other.bottom_right)? + + self.bottom_left.compute_squared_distance(&other.bottom_left)?, + ) + } +} + impl<L> ToCss for BorderRadius<L> where L: PartialEq + ToCss { @@ -144,6 +176,31 @@ impl<L: Clone> From<L> for BorderCornerRadius<L> { } } +impl<L> Animatable for BorderCornerRadius<L> +where + L: Animatable + Copy, +{ + #[inline] + fn add_weighted( + &self, + other: &Self, + self_portion: f64, + other_portion: f64, + ) -> Result<Self, ()> { + Ok(BorderCornerRadius(self.0.add_weighted(&other.0, self_portion, other_portion)?)) + } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + self.0.compute_distance(&other.0) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + self.0.compute_squared_distance(&other.0) + } +} + impl<L> ToCss for BorderCornerRadius<L> where L: ToCss, { diff --git a/components/style/values/generics/rect.rs b/components/style/values/generics/rect.rs index 1ac00766f88..3dc9e095890 100644 --- a/components/style/values/generics/rect.rs +++ b/components/style/values/generics/rect.rs @@ -6,6 +6,7 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; +use properties::animated_properties::Animatable; use std::fmt; use style_traits::{ToCss, ParseError}; @@ -51,6 +52,24 @@ impl<T> Rect<T> } } +impl<L> Animatable for Rect<L> +where + L: Animatable, +{ + fn add_weighted( + &self, + other: &Self, + self_portion: f64, + other_portion: f64, + ) -> Result<Self, ()> { + let first = self.0.add_weighted(&other.0, self_portion, other_portion)?; + let second = self.1.add_weighted(&other.1, self_portion, other_portion)?; + let third = self.2.add_weighted(&other.2, self_portion, other_portion)?; + let fourth = self.3.add_weighted(&other.3, self_portion, other_portion)?; + Ok(Rect(first, second, third, fourth)) + } +} + impl<T> From<T> for Rect<T> where T: Clone { |