aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorAnthony Ramine <n.oxyde@gmail.com>2017-08-10 10:54:56 +0200
committerAnthony Ramine <n.oxyde@gmail.com>2017-08-11 10:25:03 +0200
commitc4e33d9dca12a0434bdeed4fe9844226093e5ce0 (patch)
tree531888d4f7c5c16050745969cc524aa169293e28 /components
parent56f5fc41fae732ba28f63acec6755559da31d47f (diff)
downloadservo-c4e33d9dca12a0434bdeed4fe9844226093e5ce0.tar.gz
servo-c4e33d9dca12a0434bdeed4fe9844226093e5ce0.zip
Animate basic shapes
Diffstat (limited to 'components')
-rw-r--r--components/style/gecko/conversions.rs67
-rw-r--r--components/style/properties/gecko.mako.rs4
-rw-r--r--components/style/properties/helpers/animated_properties.mako.rs29
-rw-r--r--components/style/properties/longhand/box.mako.rs16
-rw-r--r--components/style/properties/longhand/svg.mako.rs15
-rw-r--r--components/style/values/generics/basic_shape.rs297
-rw-r--r--components/style/values/generics/border.rs57
-rw-r--r--components/style/values/generics/rect.rs19
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
{