Bug 1415150 - Update Cargo lockfiles and re-vendor rust dependencies. r?jrmuizel draft
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 10 Nov 2017 10:55:12 -0500
changeset 696391 fada18de148198b89babf8cbc3271e0797055cf1
parent 696390 880fc769ccf99ecdb54120e33a71f44f988887ad
child 696392 4012f1a591be5cdd5eec807887aa653b087c5dd3
push id88700
push userkgupta@mozilla.com
push dateFri, 10 Nov 2017 16:04:46 +0000
reviewersjrmuizel
bugs1415150
milestone58.0a1
Bug 1415150 - Update Cargo lockfiles and re-vendor rust dependencies. r?jrmuizel MozReview-Commit-ID: 3U2Ve2XOv6
third_party/rust/euclid/.cargo-checksum.json
third_party/rust/euclid/Cargo.toml
third_party/rust/euclid/src/lib.rs
third_party/rust/euclid/src/point.rs
third_party/rust/euclid/src/rect.rs
third_party/rust/euclid/src/rotation.rs
third_party/rust/euclid/src/size.rs
third_party/rust/euclid/src/transform2d.rs
third_party/rust/euclid/src/transform3d.rs
third_party/rust/euclid/src/vector.rs
toolkit/library/gtest/rust/Cargo.lock
toolkit/library/rust/Cargo.lock
--- a/third_party/rust/euclid/.cargo-checksum.json
+++ b/third_party/rust/euclid/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".travis.yml":"13574ca06216b94913348afb2beae9db9929f8964fbc45b3c00344ee281e1f52","COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"dee3baa3cf47f241e948f89f443d685a09095748dbd0891f3902a03884e21d36","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6cf810ad389c73a27141a7a67454ed12d4b01c3c16605b9a7414b389bc0615dd","src/length.rs":"73b0aed12a0c9acfd77a6b9ac0cd3a7ec522c41ffafad4448753cb6bba47b6a4","src/lib.rs":"4d0961f56e4232ae09b41da4838324af21efc318555f625b4151a81fe99a0217","src/macros.rs":"a3f4deaa4323da6398546720548dda20b0b39427603ccc35ab49d220a83467a8","src/num.rs":"749b201289fc6663199160a2f9204e17925fd3053f8ab7779e7bfb377ad06227","src/point.rs":"e57a5e7633ce870ad22718bf4f550ecea39c43560af82216d27879bf0d61d94a","src/rect.rs":"00ef63d706d5ccd8a6fb377e2bcc58b1453080fbbdc8e41a2c6c6a1a42a76085","src/scale_factor.rs":"b093243256df3f2b8a2e2bf98236e6ec1032c3d358596f384313614dbefaca49","src/side_offsets.rs":"fd95ffc9a74e9e84314875c388e763d0780486eb7f9034423e3a22048361e379","src/size.rs":"1a438f2774e668eb37759e858af18bb17bffe99c7ce61bd2b3c5679dda023c17","src/transform2d.rs":"4fe4fef7266b06b7790cd400d990ad02e6e605499a1a33c8e39b5e00364389ba","src/transform3d.rs":"0cbf5585cfc0b2a660180e63d0294c57ff732b4aec46ecf7731b7cc7c3af74c0","src/trig.rs":"ef290927af252ca90a29ba9f17158b591ed591604e66cb9df045dd47b9cfdca5","src/vector.rs":"b30ce6ff791eb657f7d9898cf13afe3600bb871797b787b341dad038aeb2a632"},"package":"50c9e4c3b53de731815135191f0b77969bea953211b8bbd3cc3083a7b10e190e"}
\ No newline at end of file
+{"files":{".travis.yml":"13574ca06216b94913348afb2beae9db9929f8964fbc45b3c00344ee281e1f52","COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"1951103509b9ee4036df52e5f11c9d1e2ba18c09eab673de25c37ad1f6dabab4","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6cf810ad389c73a27141a7a67454ed12d4b01c3c16605b9a7414b389bc0615dd","src/length.rs":"73b0aed12a0c9acfd77a6b9ac0cd3a7ec522c41ffafad4448753cb6bba47b6a4","src/lib.rs":"43b594eebf1cd2c8fb7a7f4616d872d9e09f5e0c7c0172a16d4e5841ab552328","src/macros.rs":"a3f4deaa4323da6398546720548dda20b0b39427603ccc35ab49d220a83467a8","src/num.rs":"749b201289fc6663199160a2f9204e17925fd3053f8ab7779e7bfb377ad06227","src/point.rs":"859e3da88bf45123b10d90642b807b9ef35751699594d85012cb32b45e9e970b","src/rect.rs":"761b3e1c841c03ec87e99ed9dd9c37d669bec6967c2dac2b6be2f056e9c8b7e0","src/rotation.rs":"0b0a299268a76fbc15c58aec788ad0bfc27f7f68bcfeade3dce71cd2585166f2","src/scale_factor.rs":"b093243256df3f2b8a2e2bf98236e6ec1032c3d358596f384313614dbefaca49","src/side_offsets.rs":"fd95ffc9a74e9e84314875c388e763d0780486eb7f9034423e3a22048361e379","src/size.rs":"5ecb66be6c42f07770662c925017a7ef6e1d0e332b3576e1884c488fbf9d4b59","src/transform2d.rs":"82b5a41881fc4ab947df0b337ad2ac2e1dce7d532df1a225eb5abf2d32776007","src/transform3d.rs":"3b944cae37968b3c4e98a25323ac57ba331d97638b0a747fff28f139fcb6043c","src/trig.rs":"ef290927af252ca90a29ba9f17158b591ed591604e66cb9df045dd47b9cfdca5","src/vector.rs":"7f076e77a9a6fbecf44c1802233e9c2d59015a94cccf94fd9d8832cfb037bdb8"},"package":"f5ed7d77e46f6600f490463ad7b6349c3ebb2d2319af56e679e279e4c66495d9"}
\ No newline at end of file
--- a/third_party/rust/euclid/Cargo.toml
+++ b/third_party/rust/euclid/Cargo.toml
@@ -7,36 +7,36 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "euclid"
-version = "0.15.2"
+version = "0.15.5"
 authors = ["The Servo Project Developers"]
 description = "Geometry primitives"
 documentation = "https://docs.rs/euclid/"
 keywords = ["matrix", "vector", "linear-algebra", "geometry"]
 categories = ["science"]
 license = "MIT / Apache-2.0"
 repository = "https://github.com/servo/euclid"
+[dependencies.heapsize]
+version = "0.4"
+
 [dependencies.num-traits]
 version = "0.1.32"
 default-features = false
 
 [dependencies.log]
 version = "0.3.1"
 
 [dependencies.serde]
 version = "1.0"
-
-[dependencies.heapsize]
-version = "0.4"
 [dev-dependencies.serde_test]
 version = "1.0"
 
 [dev-dependencies.rand]
 version = "0.3.7"
 
 [features]
 unstable = []
--- a/third_party/rust/euclid/src/lib.rs
+++ b/third_party/rust/euclid/src/lib.rs
@@ -2,17 +2,17 @@
 // file at the top-level directory of this distribution.
 //
 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![cfg_attr(feature = "unstable", feature(asm, repr_simd, test))]
+#![cfg_attr(feature = "unstable", feature(asm, repr_simd, test, fn_must_use))]
 
 //! A collection of strongly typed math tools for computer graphics with an inclination
 //! towards 2d graphics and layout.
 //!
 //! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
 //! and tagged with a generic Unit parameter which is useful to prevent mixing
 //! values from different spaces. For example it should not be legal to translate
 //! a screen-space position by a world-space vector and this can be expressed using
@@ -76,30 +76,32 @@ pub use point::{
     Point3D, TypedPoint3D, point3,
 };
 pub use vector::{
     Vector2D, TypedVector2D, vec2,
     Vector3D, TypedVector3D, vec3,
 };
 
 pub use rect::{Rect, TypedRect, rect};
+pub use rotation::{TypedRotation2D, Rotation2D, TypedRotation3D, Rotation3D};
 pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
 #[cfg(feature = "unstable")] pub use side_offsets::SideOffsets2DSimdI32;
 pub use size::{Size2D, TypedSize2D, size2};
 pub use trig::Trig;
 
 pub mod approxeq;
 pub mod num;
 mod length;
 #[macro_use]
 mod macros;
 mod transform2d;
 mod transform3d;
 mod point;
 mod rect;
+mod rotation;
 mod scale_factor;
 mod side_offsets;
 mod size;
 mod trig;
 mod vector;
 
 /// The default unit.
 #[derive(Clone, Copy)]
@@ -127,9 +129,8 @@ pub type TypedMatrix2D<T, Src, Dst> = Ty
 
 /// Temporary alias to facilitate the transition to the new naming scheme
 #[deprecated]
 pub type Matrix4D<T> = Transform3D<T>;
 
 /// Temporary alias to facilitate the transition to the new naming scheme
 #[deprecated]
 pub type TypedMatrix4D<T, Src, Dst> = TypedTransform3D<T, Src, Dst>;
-
--- a/third_party/rust/euclid/src/point.rs
+++ b/third_party/rust/euclid/src/point.rs
@@ -234,41 +234,41 @@ impl<T: Copy + Div<T, Output=T>, U1, U2>
 }
 
 impl<T: Round, U> TypedPoint2D<T, U> {
     /// Rounds each component to the nearest integer value.
     ///
     /// This behavior is preserved for negative values (unlike the basic cast).
     /// For example `{ -0.1, -0.8 }.round() == { 0.0, -1.0 }`.
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn round(&self) -> Self {
         point2(self.x.round(), self.y.round())
     }
 }
 
 impl<T: Ceil, U> TypedPoint2D<T, U> {
     /// Rounds each component to the smallest integer equal or greater than the original value.
     ///
     /// This behavior is preserved for negative values (unlike the basic cast).
     /// For example `{ -0.1, -0.8 }.ceil() == { 0.0, 0.0 }`.
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn ceil(&self) -> Self {
         point2(self.x.ceil(), self.y.ceil())
     }
 }
 
 impl<T: Floor, U> TypedPoint2D<T, U> {
     /// Rounds each component to the biggest integer equal or lower than the original value.
     ///
     /// This behavior is preserved for negative values (unlike the basic cast).
     /// For example `{ -0.1, -0.8 }.floor() == { -1.0, -1.0 }`.
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn floor(&self) -> Self {
         point2(self.x.floor(), self.y.floor())
     }
 }
 
 impl<T: NumCast + Copy, U> TypedPoint2D<T, U> {
     /// Cast from one numeric representation to another, preserving the units.
     ///
@@ -563,39 +563,39 @@ impl<T: Float, U> TypedPoint3D<T, U> {
     }
 }
 
 impl<T: Round, U> TypedPoint3D<T, U> {
     /// Rounds each component to the nearest integer value.
     ///
     /// This behavior is preserved for negative values (unlike the basic cast).
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn round(&self) -> Self {
         point3(self.x.round(), self.y.round(), self.z.round())
     }
 }
 
 impl<T: Ceil, U> TypedPoint3D<T, U> {
     /// Rounds each component to the smallest integer equal or greater than the original value.
     ///
     /// This behavior is preserved for negative values (unlike the basic cast).
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn ceil(&self) -> Self {
         point3(self.x.ceil(), self.y.ceil(), self.z.ceil())
     }
 }
 
 impl<T: Floor, U> TypedPoint3D<T, U> {
     /// Rounds each component to the biggest integer equal or lower than the original value.
     ///
     /// This behavior is preserved for negative values (unlike the basic cast).
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn floor(&self) -> Self {
         point3(self.x.floor(), self.y.floor(), self.z.floor())
     }
 }
 
 impl<T: NumCast + Copy, U> TypedPoint3D<T, U> {
     /// Cast from one numeric representation to another, preserving the units.
     ///
--- a/third_party/rust/euclid/src/rect.rs
+++ b/third_party/rust/euclid/src/rect.rs
@@ -162,17 +162,17 @@ where T: Copy + Clone + Zero + PartialOr
         let lower_right_y = min(self.max_y(), other.max_y());
 
         Some(TypedRect::new(upper_left, TypedSize2D::new(lower_right_x - upper_left.x,
                                                     lower_right_y - upper_left.y)))
     }
 
     /// Returns the same rectangle, translated by a vector.
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn translate(&self, by: &TypedVector2D<T, U>) -> Self {
         Self::new(self.origin + *by, self.size)
     }
 
     /// Returns true if this rectangle contains the point. Points are considered
     /// in the rectangle if they are on the left or top edge, but outside if they
     /// are on the right or bottom edge.
     #[inline]
@@ -187,26 +187,26 @@ where T: Copy + Clone + Zero + PartialOr
     #[inline]
     pub fn contains_rect(&self, rect: &Self) -> bool {
         rect.is_empty() ||
             (self.min_x() <= rect.min_x() && rect.max_x() <= self.max_x() &&
              self.min_y() <= rect.min_y() && rect.max_y() <= self.max_y())
     }
 
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn inflate(&self, width: T, height: T) -> Self {
         TypedRect::new(
             TypedPoint2D::new(self.origin.x - width, self.origin.y - height),
             TypedSize2D::new(self.size.width + width + width, self.size.height + height + height),
         )
     }
 
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn inflate_typed(&self, width: Length<T, U>, height: Length<T, U>) -> Self {
         self.inflate(width.get(), height.get())
     }
 
     #[inline]
     pub fn top_right(&self) -> TypedPoint2D<T, U> {
         TypedPoint2D::new(self.max_x(), self.origin.y)
     }
@@ -217,17 +217,17 @@ where T: Copy + Clone + Zero + PartialOr
     }
 
     #[inline]
     pub fn bottom_right(&self) -> TypedPoint2D<T, U> {
         TypedPoint2D::new(self.max_x(), self.max_y())
     }
 
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn translate_by_size(&self, size: &TypedSize2D<T, U>) -> Self {
         self.translate(&size.to_vector())
     }
 
     /// Returns the smallest rectangle containing the four points.
     pub fn from_points(points: &[TypedPoint2D<T, U>]) -> Self {
         if points.len() == 0 {
             return TypedRect::zero();
@@ -389,35 +389,35 @@ impl<T: Floor + Ceil + Round + Add<T, Ou
     /// the returned rectangle has the same set of pixel centers as the original
     /// one.
     /// Edges at offset 0.5 round up.
     /// Suitable for most places where integral device coordinates
     /// are needed, but note that any translation should be applied first to
     /// avoid pixel rounding errors.
     /// Note that this is *not* rounding to nearest integer if the values are negative.
     /// They are always rounding as floor(n + 0.5).
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn round(&self) -> Self {
         let origin = self.origin.round();
         let size = self.origin.add_size(&self.size).round() - origin;
         TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
     }
 
     /// Return a rectangle with edges rounded to integer coordinates, such that
     /// the original rectangle contains the resulting rectangle.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn round_in(&self) -> Self {
         let origin = self.origin.ceil();
         let size = self.origin.add_size(&self.size).floor() - origin;
         TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
     }
 
     /// Return a rectangle with edges rounded to integer coordinates, such that
     /// the original rectangle is contained in the resulting rectangle.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn round_out(&self) -> Self {
         let origin = self.origin.floor();
         let size = self.origin.add_size(&self.size).ceil() - origin;
         TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
     }
 }
 
 // Convenience functions for common casts
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid/src/rotation.rs
@@ -0,0 +1,696 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use approxeq::ApproxEq;
+use num_traits::{Float, One, Zero};
+use std::fmt;
+use std::ops::{Add, Neg, Mul, Sub, Div};
+use std::marker::PhantomData;
+use trig::Trig;
+use {TypedPoint2D, TypedPoint3D, TypedVector2D, TypedVector3D, Vector3D, point2, point3, vec3};
+use {TypedTransform3D, TypedTransform2D, UnknownUnit, Radians};
+
+
+define_matrix! {
+    /// A transform that can represent rotations in 2d, represented as an angle in radians.
+    pub struct TypedRotation2D<T, Src, Dst> {
+        pub angle : T,
+    }
+}
+
+/// The default 2d rotation type with no units.
+pub type Rotation2D<T> = TypedRotation2D<T, UnknownUnit, UnknownUnit>;
+
+impl<T, Src, Dst> TypedRotation2D<T, Src, Dst> {
+    #[inline]
+    /// Creates a rotation from an angle in radians.
+    pub fn new(angle: Radians<T>) -> Self {
+        TypedRotation2D {
+            angle: angle.0,
+            _unit: PhantomData,
+        }
+    }
+
+    pub fn radians(angle: T) -> Self {
+        Self::new(Radians::new(angle))
+    }
+
+    /// Creates the identity rotation.
+    #[inline]
+    pub fn identity() -> Self where T: Zero {
+        Self::radians(T::zero())
+    }
+}
+
+impl<T, Src, Dst> TypedRotation2D<T, Src, Dst> where T: Clone
+{
+    /// Returns self.angle as a strongly typed `Radians<T>`.
+    pub fn get_angle(&self) -> Radians<T> {
+        Radians::new(self.angle.clone())
+    }
+}
+
+
+impl<T, Src, Dst> TypedRotation2D<T, Src, Dst>
+where T: Copy + Clone +
+         Add<T, Output=T> +
+         Sub<T, Output=T> +
+         Mul<T, Output=T> +
+         Div<T, Output=T> +
+         Neg<Output=T> +
+         ApproxEq<T> +
+         PartialOrd +
+         Float +
+         One + Zero
+{
+    /// Creates a 3d rotation (around the z axis) from this 2d rotation.
+    #[inline]
+    pub fn to_3d(&self) -> TypedRotation3D<T, Src, Dst> {
+        TypedRotation3D::around_z(self.get_angle())
+    }
+
+    /// Returns the inverse of this rotation.
+    #[inline]
+    pub fn inverse(&self) -> TypedRotation2D<T, Dst, Src> {
+        TypedRotation2D::radians(-self.angle)
+    }
+
+    /// Returns a rotation representing the other rotation followed by this rotation.
+    #[inline]
+    pub fn pre_rotate<NewSrc>(&self, other: &TypedRotation2D<T, NewSrc, Src>) -> TypedRotation2D<T, NewSrc, Dst> {
+        TypedRotation2D::radians(self.angle + other.angle)
+    }
+
+    /// Returns a rotation representing this rotation followed by the other rotation.
+    #[inline]
+    pub fn post_rotate<NewDst>(&self, other: &TypedRotation2D<T, Dst, NewDst>) -> TypedRotation2D<T, Src, NewDst> {
+        other.pre_rotate(self)
+    }
+
+    /// Returns the given 2d point transformed by this rotation.
+    ///
+    /// The input point must be use the unit Src, and the returned point has the unit Dst.
+    #[inline]
+    pub fn transform_point(&self, point: &TypedPoint2D<T, Src>) -> TypedPoint2D<T, Dst> {
+        let (sin, cos) = Float::sin_cos(self.angle);
+        point2(
+            point.x * cos - point.y * sin,
+            point.y * cos + point.x * sin,
+        )
+    }
+
+    /// Returns the given 2d vector transformed by this rotation.
+    ///
+    /// The input point must be use the unit Src, and the returned point has the unit Dst.
+    #[inline]
+    pub fn transform_vector(&self, vector: &TypedVector2D<T, Src>) -> TypedVector2D<T, Dst> {
+        self.transform_point(&vector.to_point()).to_vector()
+    }
+}
+
+impl<T, Src, Dst> TypedRotation2D<T, Src, Dst>
+where T: Copy + Clone +
+         Add<T, Output=T> +
+         Mul<T, Output=T> +
+         Div<T, Output=T> +
+         Sub<T, Output=T> +
+         Trig +
+         PartialOrd +
+         One + Zero
+{
+    /// Returns the matrix representation of this rotation.
+    #[inline]
+    pub fn to_transform(&self) -> TypedTransform2D<T, Src, Dst> {
+        TypedTransform2D::create_rotation(self.get_angle())
+    }
+}
+
+define_matrix! {
+    /// A transform that can represent rotations in 3d, represented as a quaternion.
+    ///
+    /// Most methods expect the quaternion to be normalized.
+    /// When in doubt, use `unit_quaternion` instead of `quaternion` to create
+    /// a rotation as the former will ensure that its result is normalized.
+    ///
+    /// Some people use the `x, y, z, w` (or `w, x, y, z`) notations. The equivalence is
+    /// as follows: `x -> i`, `y -> j`, `z -> k`, `w -> r`.
+    /// The memory layout of this type corresponds to the `x, y, z, w` notation
+    pub struct TypedRotation3D<T, Src, Dst> {
+        // Component multiplied by the imaginary number `i`.
+        pub i: T,
+        // Component multiplied by the imaginary number `j`.
+        pub j: T,
+        // Component multiplied by the imaginary number `k`.
+        pub k: T,
+        // The real part.
+        pub r: T,
+    }
+}
+
+/// The default 3d rotation type with no units.
+pub type Rotation3D<T> = TypedRotation3D<T, UnknownUnit, UnknownUnit>;
+
+impl<T, Src, Dst> TypedRotation3D<T, Src, Dst> {
+    /// Creates a rotation around from a quaternion representation.
+    ///
+    /// The parameters are a, b, c and r compose the quaternion `a*i + b*j + c*k + r`
+    /// where `a`, `b` and `c` describe the vector part and the last parameter `r` is
+    /// the real part.
+    ///
+    /// The resulting quaternion is not necessarily normalized. See `unit_quaternion`.
+    #[inline]
+    pub fn quaternion(a: T, b: T, c: T, r: T) -> Self {
+        TypedRotation3D { i: a, j: b, k: c, r, _unit: PhantomData }
+    }
+}
+
+
+impl<T, Src, Dst> TypedRotation3D<T, Src, Dst> where T: Copy {
+    /// Returns the vector part (i, j, k) of this quaternion.
+    #[inline]
+    pub fn vector_part(&self) -> Vector3D<T> { vec3(self.i, self.j, self.k) }
+}
+
+impl<T, Src, Dst> TypedRotation3D<T, Src, Dst>
+where T: Copy + Clone +
+         Add<T, Output=T> +
+         Sub<T, Output=T> +
+         Mul<T, Output=T> +
+         Div<T, Output=T> +
+         Neg<Output=T> +
+         ApproxEq<T> +
+         PartialOrd +
+         Float +
+         One + Zero
+{
+    /// Creates the identity rotation.
+    #[inline]
+    pub fn identity() -> Self {
+        let zero = T::zero();
+        let one = T::one();
+        Self::quaternion(zero, zero, zero, one)
+    }
+
+    /// Creates a rotation around from a quaternion representation and normalizes it.
+    ///
+    /// The parameters are a, b, c and r compose the quaternion `a*i + b*j + c*k + r`
+    /// before normalization, where `a`, `b` and `c` describe the vector part and the
+    /// last parameter `r` is the real part.
+    #[inline]
+    pub fn unit_quaternion(i: T, j: T, k: T, r: T) -> Self {
+        Self::quaternion(i, j, k, r).normalize()
+    }
+
+    /// Creates a rotation around a given axis.
+    pub fn around_axis(axis: TypedVector3D<T, Src>, angle: Radians<T>) -> Self {
+        let axis = axis.normalize();
+        let two = T::one() + T::one();
+        let (sin, cos) = Float::sin_cos(angle.get() / two);
+        Self::quaternion(axis.x * sin, axis.y * sin, axis.z * sin, cos)
+    }
+
+    /// Creates a rotation around the x axis.
+    pub fn around_x(angle: Radians<T>) -> Self {
+        let zero = Zero::zero();
+        let two = T::one() + T::one();
+        let (sin, cos) = Float::sin_cos(angle.get() / two);
+        Self::quaternion(sin, zero, zero, cos)
+    }
+
+    /// Creates a rotation around the y axis.
+    pub fn around_y(angle: Radians<T>) -> Self {
+        let zero = Zero::zero();
+        let two = T::one() + T::one();
+        let (sin, cos) = Float::sin_cos(angle.get() / two);
+        Self::quaternion(zero, sin, zero, cos)
+    }
+
+    /// Creates a rotation around the z axis.
+    pub fn around_z(angle: Radians<T>) -> Self {
+        let zero = Zero::zero();
+        let two = T::one() + T::one();
+        let (sin, cos) = Float::sin_cos(angle.get() / two);
+        Self::quaternion(zero, zero, sin, cos)
+    }
+
+    /// Creates a rotation from euler angles.
+    ///
+    /// The rotations are applied in roll then pitch then yaw order.
+    ///
+    ///  - Roll (also calld bank) is a rotation around the x axis.
+    ///  - Pitch (also calld bearing) is a rotation around the y axis.
+    ///  - Yaw (also calld heading) is a rotation around the z axis.
+    pub fn euler(roll: Radians<T>, pitch: Radians<T>, yaw: Radians<T>) -> Self {
+        let half = T::one() / (T::one() + T::one());
+
+	    let (sy, cy) = Float::sin_cos(half * yaw.get());
+	    let (sp, cp) = Float::sin_cos(half * pitch.get());
+	    let (sr, cr) = Float::sin_cos(half * roll.get());
+
+        Self::quaternion(
+            cy * sr * cp - sy * cr * sp,
+            cy * cr * sp + sy * sr * cp,
+            sy * cr * cp - cy * sr * sp,
+            cy * cr * cp + sy * sr * sp,
+        )
+    }
+
+    /// Returns the inverse of this rotation.
+    #[inline]
+    pub fn inverse(&self) -> TypedRotation3D<T, Dst, Src> {
+        TypedRotation3D::quaternion(-self.i, -self.j, -self.k, self.r)
+    }
+
+    /// Computes the norm of this quaternion
+    #[inline]
+    pub fn norm(&self) -> T {
+        self.square_norm().sqrt()
+    }
+
+    #[inline]
+    pub fn square_norm(&self) -> T {
+        (self.i * self.i + self.j * self.j + self.k * self.k + self.r *self.r)
+    }
+
+    /// Returns a unit quaternion from this one.
+    #[inline]
+    pub fn normalize(&self) -> Self {
+        self.mul(T::one() / self.norm())
+    }
+
+    #[inline]
+    pub fn is_normalized(&self) -> bool {
+        // TODO: we might need to relax the threshold here, because of floating point imprecision.
+        self.square_norm().approx_eq(&T::one())
+    }
+
+    /// Spherical linear interpolation between this rotation and another rotation.
+    ///
+    /// `t` is expected to be between zero and one.
+    pub fn slerp(&self, other: &Self, t: T) -> Self {
+        debug_assert!(self.is_normalized());
+        debug_assert!(other.is_normalized());
+
+        let r1 = *self;
+        let mut r2 = *other;
+
+        let mut dot = r1.i * r2.i + r1.j * r2.j + r1.k * r2.k + r1.r * r2.r;
+
+        let one = T::one();
+
+        if dot.approx_eq(&T::one()) {
+            // If the inputs are too close, linearly interpolate to avoid precision issues.
+            return r1.lerp(&r2, t);
+        }
+
+        // If the dot product is negative, the quaternions
+        // have opposite handed-ness and slerp won't take
+        // the shorter path. Fix by reversing one quaternion.
+        if dot < T::zero() {
+            r2 = r2.mul(-T::one());
+            dot = -dot;
+        }
+
+        // For robustness, stay within the domain of acos.
+        dot = Float::min(dot, one);
+
+        // Angle between r1 and the result.
+        let theta = Float::acos(dot) * t;
+
+        // r1 and r3 form an orthonormal basis.
+        let r3 = r2.sub(r1.mul(dot)).normalize();
+        let (sin, cos) = Float::sin_cos(theta);
+        r1.mul(cos).add(r3.mul(sin))
+    }
+
+    /// Basic Linear interpolation between this rotation and another rotation.
+    ///
+    /// `t` is expected to be between zero and one.
+    #[inline]
+    pub fn lerp(&self, other: &Self, t: T) -> Self {
+        let one_t = T::one() - t;
+        return self.mul(one_t).add(other.mul(t)).normalize();
+    }
+
+    /// Returns the given 3d point transformed by this rotation.
+    ///
+    /// The input point must be use the unit Src, and the returned point has the unit Dst.
+    pub fn rotate_point3d(&self, point: &TypedPoint3D<T, Src>) -> TypedPoint3D<T, Dst> {
+        debug_assert!(self.is_normalized());
+
+        let two = T::one() + T::one();
+        let cross = self.vector_part().cross(point.to_vector().to_untyped()) * two;
+
+        point3(
+            point.x + self.r * cross.x + self.j * cross.z - self.k * cross.y,
+            point.y + self.r * cross.y + self.k * cross.x - self.i * cross.z,
+            point.z + self.r * cross.z + self.i * cross.y - self.j * cross.x,
+        )
+    }
+
+    /// Returns the given 2d point transformed by this rotation then projected on the xy plane.
+    ///
+    /// The input point must be use the unit Src, and the returned point has the unit Dst.
+    #[inline]
+    pub fn rotate_point2d(&self, point: &TypedPoint2D<T, Src>) -> TypedPoint2D<T, Dst> {
+        self.rotate_point3d(&point.to_3d()).xy()
+    }
+
+    /// Returns the given 3d vector transformed by this rotation then projected on the xy plane.
+    ///
+    /// The input vector must be use the unit Src, and the returned point has the unit Dst.
+    #[inline]
+    pub fn rotate_vector3d(&self, vector: &TypedVector3D<T, Src>) -> TypedVector3D<T, Dst> {
+        self.rotate_point3d(&vector.to_point()).to_vector()
+    }
+
+    /// Returns the given 2d vector transformed by this rotation then projected on the xy plane.
+    ///
+    /// The input vector must be use the unit Src, and the returned point has the unit Dst.
+    #[inline]
+    pub fn rotate_vector2d(&self, vector: &TypedVector2D<T, Src>) -> TypedVector2D<T, Dst> {
+        self.rotate_vector3d(&vector.to_3d()).xy()
+    }
+
+    /// Returns the matrix representation of this rotation.
+    #[inline]
+    pub fn to_transform(&self) -> TypedTransform3D<T, Src, Dst> {
+        debug_assert!(self.is_normalized());
+
+        let i2 = self.i + self.i;
+        let j2 = self.j + self.j;
+        let k2 = self.k + self.k;
+        let ii = self.i * i2;
+        let ij = self.i * j2;
+        let ik = self.i * k2;
+        let jj = self.j * j2;
+        let jk = self.j * k2;
+        let kk = self.k * k2;
+        let ri = self.r * i2;
+        let rj = self.r * j2;
+        let rk = self.r * k2;
+
+        let one = T::one();
+        let zero = T::zero();
+
+        let m11 = one - (jj + kk);
+        let m12 = ij + rk;
+        let m13 = ik - rj;
+
+        let m21 = ij - rk;
+        let m22 = one - (ii + kk);
+        let m23 = jk + ri;
+
+        let m31 = ik + rj;
+        let m32 = jk - ri;
+        let m33 = one - (ii + jj);
+
+        TypedTransform3D::row_major(
+            m11,  m12,  m13, zero,
+            m21,  m22,  m23, zero,
+            m31,  m32,  m33, zero,
+            zero, zero, zero, one,
+        )
+    }
+
+    /// Returns a rotation representing the other rotation followed by this rotation.
+    pub fn pre_rotate<NewSrc>(&self, other: &TypedRotation3D<T, NewSrc, Src>) -> TypedRotation3D<T, NewSrc, Dst> {
+        debug_assert!(self.is_normalized());
+        TypedRotation3D::quaternion(
+            self.i * other.r + self.r * other.i + self.j * other.k - self.k * other.j,
+            self.j * other.r + self.r * other.j + self.k * other.i - self.i * other.k,
+            self.k * other.r + self.r * other.k + self.i * other.j - self.j * other.i,
+            self.r * other.r - self.i * other.i - self.j * other.j - self.k * other.k,
+        )
+    }
+
+    /// Returns a rotation representing this rotation followed by the other rotation.
+    #[inline]
+    pub fn post_rotate<NewDst>(&self, other: &TypedRotation3D<T, Dst, NewDst>) -> TypedRotation3D<T, Src, NewDst> {
+        other.pre_rotate(self)
+    }
+
+    // add, sub and mul are used internally for intermediate computation but aren't public
+    // because they don't carry real semantic meanings (I think?).
+
+    #[inline]
+    fn add(&self, other: Self) -> Self {
+        Self::quaternion(
+            self.i + other.i,
+            self.j + other.j,
+            self.k + other.k,
+            self.r + other.r,
+        )
+    }
+
+    #[inline]
+    fn sub(&self, other: Self) -> Self {
+        Self::quaternion(
+            self.i - other.i,
+            self.j - other.j,
+            self.k - other.k,
+            self.r - other.r,
+        )
+    }
+
+    #[inline]
+    fn mul(&self, factor: T) -> Self {
+        Self::quaternion(
+            self.i * factor,
+            self.j * factor,
+            self.k * factor,
+            self.r * factor,
+        )
+    }
+}
+
+impl<T: fmt::Debug, Src, Dst> fmt::Debug for TypedRotation3D<T, Src, Dst> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Quat({:?}*i + {:?}*j + {:?}*k + {:?})", self.i, self.j, self.k, self.r)
+    }
+}
+
+impl<T: fmt::Display, Src, Dst> fmt::Display for TypedRotation3D<T, Src, Dst> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Quat({}*i + {}*j + {}*k + {})", self.i, self.j, self.k, self.r)
+    }
+}
+
+impl<T, Src, Dst> ApproxEq<T> for TypedRotation3D<T, Src, Dst>
+where
+    T: Copy + Neg<Output=T> + ApproxEq<T>
+{
+    fn approx_epsilon() -> T {
+        T::approx_epsilon()
+    }
+
+    fn approx_eq(&self, other: &Self) -> bool {
+        self.approx_eq_eps(other, &Self::approx_epsilon())
+    }
+
+    fn approx_eq_eps(&self, other: &Self, eps: &T) -> bool {
+        (
+            self.i.approx_eq_eps(&other.i, eps)
+            && self.j.approx_eq_eps(&other.j, eps)
+            && self.k.approx_eq_eps(&other.k, eps)
+            && self.r.approx_eq_eps(&other.r, eps)
+        ) || (
+            self.i.approx_eq_eps(&-other.i, eps)
+            && self.j.approx_eq_eps(&-other.j, eps)
+            && self.k.approx_eq_eps(&-other.k, eps)
+            && self.r.approx_eq_eps(&-other.r, eps)
+        )
+    }
+}
+
+#[test]
+fn simple_rotation_2d() {
+    use std::f32::consts::{PI, FRAC_PI_2};
+    let ri = Rotation2D::identity();
+    let r90 = Rotation2D::radians(FRAC_PI_2);
+    let rm90 = Rotation2D::radians(-FRAC_PI_2);
+    let r180 = Rotation2D::radians(PI);
+
+    assert!(ri.transform_point(&point2(1.0, 2.0)).approx_eq(&point2(1.0, 2.0)));
+    assert!(r90.transform_point(&point2(1.0, 2.0)).approx_eq(&point2(-2.0, 1.0)));
+    assert!(rm90.transform_point(&point2(1.0, 2.0)).approx_eq(&point2(2.0, -1.0)));
+    assert!(r180.transform_point(&point2(1.0, 2.0)).approx_eq(&point2(-1.0, -2.0)));
+
+    assert!(
+        r90.inverse().inverse().transform_point(&point2(1.0, 2.0)).approx_eq(
+            &r90.transform_point(&point2(1.0, 2.0))
+        )
+    );
+}
+
+#[test]
+fn simple_rotation_3d_in_2d() {
+    use std::f32::consts::{PI, FRAC_PI_2};
+    let ri = Rotation3D::identity();
+    let r90 = Rotation3D::around_z(Radians::new(FRAC_PI_2));
+    let rm90 = Rotation3D::around_z(Radians::new(-FRAC_PI_2));
+    let r180 = Rotation3D::around_z(Radians::new(PI));
+
+    assert!(ri.rotate_point2d(&point2(1.0, 2.0)).approx_eq(&point2(1.0, 2.0)));
+    assert!(r90.rotate_point2d(&point2(1.0, 2.0)).approx_eq(&point2(-2.0, 1.0)));
+    assert!(rm90.rotate_point2d(&point2(1.0, 2.0)).approx_eq(&point2(2.0, -1.0)));
+    assert!(r180.rotate_point2d(&point2(1.0, 2.0)).approx_eq(&point2(-1.0, -2.0)));
+
+    assert!(
+        r90.inverse().inverse().rotate_point2d(&point2(1.0, 2.0)).approx_eq(
+            &r90.rotate_point2d(&point2(1.0, 2.0))
+        )
+    );
+}
+
+#[test]
+fn pre_post() {
+    use std::f32::consts::{FRAC_PI_2};
+    let r1 = Rotation3D::around_x(Radians::new(FRAC_PI_2));
+    let r2 = Rotation3D::around_y(Radians::new(FRAC_PI_2));
+    let r3 = Rotation3D::around_z(Radians::new(FRAC_PI_2));
+
+    let t1 = r1.to_transform();
+    let t2 = r2.to_transform();
+    let t3 = r3.to_transform();
+
+    let p = point3(1.0, 2.0, 3.0);
+
+    // Check that the order of transformations is correct (corresponds to what
+    // we do in Transfor3D).
+    let p1 = r1.post_rotate(&r2).post_rotate(&r3).rotate_point3d(&p);
+    let p2 = t1.post_mul(&t2).post_mul(&t3).transform_point3d(&p);
+
+    assert!(p1.approx_eq(&p2));
+
+    // Check that changing the order indeed matters.
+    let p3 = t3.post_mul(&t1).post_mul(&t2).transform_point3d(&p);
+    assert!(!p1.approx_eq(&p3));
+}
+
+#[test]
+fn to_transform3d() {
+    use std::f32::consts::{PI, FRAC_PI_2};
+    let rotations = [
+        Rotation3D::identity(),
+        Rotation3D::around_x(Radians::new(FRAC_PI_2)),
+        Rotation3D::around_x(Radians::new(-FRAC_PI_2)),
+        Rotation3D::around_x(Radians::new(PI)),
+        Rotation3D::around_y(Radians::new(FRAC_PI_2)),
+        Rotation3D::around_y(Radians::new(-FRAC_PI_2)),
+        Rotation3D::around_y(Radians::new(PI)),
+        Rotation3D::around_z(Radians::new(FRAC_PI_2)),
+        Rotation3D::around_z(Radians::new(-FRAC_PI_2)),
+        Rotation3D::around_z(Radians::new(PI)),
+    ];
+
+    let points = [
+        point3(0.0, 0.0, 0.0),
+        point3(1.0, 2.0, 3.0),
+        point3(-5.0, 3.0, -1.0),
+        point3(-0.5, -1.0, 1.5),
+    ];
+
+    for rotation in &rotations {
+        for point in &points {
+            let p1 = rotation.rotate_point3d(point);
+            let p2 = rotation.to_transform().transform_point3d(point);
+            assert!(p1.approx_eq(&p2));
+        }
+    }
+}
+
+#[test]
+fn slerp() {
+    let q1 = Rotation3D::quaternion(1.0, 0.0, 0.0, 0.0);
+    let q2 = Rotation3D::quaternion(0.0, 1.0, 0.0, 0.0);
+    let q3 = Rotation3D::quaternion(0.0, 0.0, -1.0, 0.0);
+
+    // The values below can be obtained with a python program:
+    // import numpy
+    // import quaternion
+    // q1 = numpy.quaternion(1, 0, 0, 0)
+    // q2 = numpy.quaternion(0, 1, 0, 0)
+    // quaternion.slerp_evaluate(q1, q2, 0.2)
+
+    assert!(q1.slerp(&q2, 0.0).approx_eq(&q1));
+    assert!(q1.slerp(&q2, 0.2).approx_eq(&Rotation3D::quaternion(0.951056516295154, 0.309016994374947, 0.0, 0.0)));
+    assert!(q1.slerp(&q2, 0.4).approx_eq(&Rotation3D::quaternion(0.809016994374947, 0.587785252292473, 0.0, 0.0)));
+    assert!(q1.slerp(&q2, 0.6).approx_eq(&Rotation3D::quaternion(0.587785252292473, 0.809016994374947, 0.0, 0.0)));
+    assert!(q1.slerp(&q2, 0.8).approx_eq(&Rotation3D::quaternion(0.309016994374947, 0.951056516295154, 0.0, 0.0)));
+    assert!(q1.slerp(&q2, 1.0).approx_eq(&q2));
+
+    assert!(q1.slerp(&q3, 0.0).approx_eq(&q1));
+    assert!(q1.slerp(&q3, 0.2).approx_eq(&Rotation3D::quaternion(0.951056516295154, 0.0, -0.309016994374947, 0.0)));
+    assert!(q1.slerp(&q3, 0.4).approx_eq(&Rotation3D::quaternion(0.809016994374947, 0.0, -0.587785252292473, 0.0)));
+    assert!(q1.slerp(&q3, 0.6).approx_eq(&Rotation3D::quaternion(0.587785252292473, 0.0, -0.809016994374947, 0.0)));
+    assert!(q1.slerp(&q3, 0.8).approx_eq(&Rotation3D::quaternion(0.309016994374947, 0.0, -0.951056516295154, 0.0)));
+    assert!(q1.slerp(&q3, 1.0).approx_eq(&q3));
+}
+
+#[test]
+fn around_axis() {
+    use std::f32::consts::{PI, FRAC_PI_2};
+
+    // Two sort of trivial cases:
+    let r1 = Rotation3D::around_axis(vec3(1.0, 1.0, 0.0), Radians::new(PI));
+    let r2 = Rotation3D::around_axis(vec3(1.0, 1.0, 0.0), Radians::new(FRAC_PI_2));
+    assert!(r1.rotate_point3d(&point3(1.0, 2.0, 0.0)).approx_eq(&point3(2.0, 1.0, 0.0)));
+    assert!(r2.rotate_point3d(&point3(1.0, 0.0, 0.0)).approx_eq(&point3(0.5, 0.5, -0.5.sqrt())));
+
+    // A more arbitray test (made up with numpy):
+    let r3 = Rotation3D::around_axis(vec3(0.5, 1.0, 2.0), Radians::new(2.291288));
+    assert!(r3.rotate_point3d(&point3(1.0, 0.0, 0.0)).approx_eq(&point3(-0.58071821,  0.81401868, -0.01182979)));
+}
+
+#[test]
+fn from_euler() {
+    use std::f32::consts::FRAC_PI_2;
+
+    // First test simple separate yaw pitch and roll rotations, because it is easy to come
+    // up with the corresponding quaternion.
+    // Since several quaternions can represent the same transformation we compare the result
+    // of transforming a point rather than the values of each qauetrnions.
+    let p = point3(1.0, 2.0, 3.0);
+
+    let angle = Radians::new(FRAC_PI_2);
+    let zero = Radians::new(0.0);
+
+    // roll
+    let roll_re = Rotation3D::euler(angle, zero, zero);
+    let roll_rq = Rotation3D::around_x(angle);
+    let roll_pe = roll_re.rotate_point3d(&p);
+    let roll_pq = roll_rq.rotate_point3d(&p);
+
+    // pitch
+    let pitch_re = Rotation3D::euler(zero, angle, zero);
+    let pitch_rq = Rotation3D::around_y(angle);
+    let pitch_pe = pitch_re.rotate_point3d(&p);
+    let pitch_pq = pitch_rq.rotate_point3d(&p);
+
+    // yaw
+    let yaw_re = Rotation3D::euler(zero, zero, angle);
+    let yaw_rq = Rotation3D::around_z(angle);
+    let yaw_pe = yaw_re.rotate_point3d(&p);
+    let yaw_pq = yaw_rq.rotate_point3d(&p);
+
+    assert!(roll_pe.approx_eq(&roll_pq));
+    assert!(pitch_pe.approx_eq(&pitch_pq));
+    assert!(yaw_pe.approx_eq(&yaw_pq));
+
+    // Now check that the yaw pitch and roll transformations when compined are applied in
+    // the proper order: roll -> pitch -> yaw.
+    let ypr_e = Rotation3D::euler(angle, angle, angle);
+    let ypr_q = roll_rq.post_rotate(&pitch_rq).post_rotate(&yaw_rq);
+    let ypr_pe = ypr_e.rotate_point3d(&p);
+    let ypr_pq = ypr_q.rotate_point3d(&p);
+
+    assert!(ypr_pe.approx_eq(&ypr_pq));
+}
+
--- a/third_party/rust/euclid/src/size.rs
+++ b/third_party/rust/euclid/src/size.rs
@@ -8,17 +8,17 @@
 // except according to those terms.
 
 use super::UnknownUnit;
 use length::Length;
 use scale_factor::ScaleFactor;
 use vector::{TypedVector2D, vec2};
 use num::*;
 
-use num_traits::NumCast;
+use num_traits::{NumCast, Signed};
 use std::fmt;
 use std::ops::{Add, Div, Mul, Sub};
 use std::marker::PhantomData;
 
 /// A 2d size tagged with a unit.
 define_matrix! {
     pub struct TypedSize2D<T, U> {
         pub width: T,
@@ -240,16 +240,27 @@ impl<T: NumCast + Copy, Unit> TypedSize2
     /// When casting from floating point sizes, it is worth considering whether
     /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
     /// the desired conversion behavior.
     pub fn to_i64(&self) -> TypedSize2D<i64, Unit> {
         self.cast().unwrap()
     }
 }
 
+impl<T, U> TypedSize2D<T, U>
+where T: Signed {
+    pub fn abs(&self) -> Self {
+        size2(self.width.abs(), self.height.abs())
+    }
+
+    pub fn is_positive(&self) -> bool {
+        self.width.is_positive() && self.height.is_positive()
+    }
+}
+
 /// Shorthand for `TypedSize2D::new(w, h)`.
 pub fn size2<T, U>(w: T, h: T) -> TypedSize2D<T, U> {
     TypedSize2D::new(w, h)
 }
 
 #[cfg(test)]
 mod size2d {
     use super::Size2D;
--- a/third_party/rust/euclid/src/transform2d.rs
+++ b/third_party/rust/euclid/src/transform2d.rs
@@ -7,21 +7,23 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
 use super::{UnknownUnit, Radians};
 use num::{One, Zero};
 use point::TypedPoint2D;
 use vector::{TypedVector2D, vec2};
 use rect::TypedRect;
-use std::ops::{Add, Mul, Div, Sub};
+use transform3d::TypedTransform3D;
+use std::ops::{Add, Mul, Div, Sub, Neg};
 use std::marker::PhantomData;
 use approxeq::ApproxEq;
 use trig::Trig;
 use std::fmt;
+use num_traits::NumCast;
 
 define_matrix! {
     /// A 2d transform stored as a 2 by 3 matrix in row-major order in memory.
     ///
     /// Transforms can be parametrized over the source and destination units, to describe a
     /// transformation from a space to another.
     /// For example, `TypedTransform2D<f32, WordSpace, ScreenSpace>::transform_point4d`
     /// takes a `TypedPoint2D<f32, WordSpace>` and returns a `TypedPoint2D<f32, ScreenSpace>`.
@@ -123,16 +125,34 @@ impl<T: Copy, Src, Dst> TypedTransform2D
         TypedTransform2D::row_major(
             p.m11, p.m12,
             p.m21, p.m22,
             p.m31, p.m32
         )
     }
 }
 
+impl<T0: NumCast + Copy, Src, Dst> TypedTransform2D<T0, Src, Dst> {
+    /// Cast from one numeric representation to another, preserving the units.
+    pub fn cast<T1: NumCast + Copy>(&self) -> Option<TypedTransform2D<T1, Src, Dst>> {
+        match (NumCast::from(self.m11), NumCast::from(self.m12),
+               NumCast::from(self.m21), NumCast::from(self.m22),
+               NumCast::from(self.m31), NumCast::from(self.m32)) {
+            (Some(m11), Some(m12),
+             Some(m21), Some(m22),
+             Some(m31), Some(m32)) => {
+                Some(TypedTransform2D::row_major(m11, m12,
+                                                 m21, m22,
+                                                 m31, m32))
+            },
+            _ => None
+        }
+    }
+}
+
 impl<T, Src, Dst> TypedTransform2D<T, Src, Dst>
 where T: Copy +
          PartialEq +
          One + Zero {
     pub fn identity() -> Self {
         let (_0, _1) = (Zero::zero(), One::one());
         TypedTransform2D::row_major(
            _1, _0,
@@ -156,75 +176,75 @@ where T: Copy + Clone +
          Div<T, Output=T> +
          Sub<T, Output=T> +
          Trig +
          PartialOrd +
          One + Zero  {
 
     /// Returns the multiplication of the two matrices such that mat's transformation
     /// applies after self's transformation.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn post_mul<NewDst>(&self, mat: &TypedTransform2D<T, Dst, NewDst>) -> TypedTransform2D<T, Src, NewDst> {
         TypedTransform2D::row_major(
             self.m11 * mat.m11 + self.m12 * mat.m21,
             self.m11 * mat.m12 + self.m12 * mat.m22,
             self.m21 * mat.m11 + self.m22 * mat.m21,
             self.m21 * mat.m12 + self.m22 * mat.m22,
             self.m31 * mat.m11 + self.m32 * mat.m21 + mat.m31,
             self.m31 * mat.m12 + self.m32 * mat.m22 + mat.m32,
         )
     }
 
     /// Returns the multiplication of the two matrices such that mat's transformation
     /// applies before self's transformation.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn pre_mul<NewSrc>(&self, mat: &TypedTransform2D<T, NewSrc, Src>) -> TypedTransform2D<T, NewSrc, Dst> {
         mat.post_mul(self)
     }
 
     /// Returns a translation transform.
     pub fn create_translation(x: T, y: T) -> Self {
          let (_0, _1): (T, T) = (Zero::zero(), One::one());
          TypedTransform2D::row_major(
             _1, _0,
             _0, _1,
              x,  y
         )
     }
 
     /// Applies a translation after self's transformation and returns the resulting transform.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn post_translate(&self, v: TypedVector2D<T, Dst>) -> Self {
         self.post_mul(&TypedTransform2D::create_translation(v.x, v.y))
     }
 
     /// Applies a translation before self's transformation and returns the resulting transform.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn pre_translate(&self, v: TypedVector2D<T, Src>) -> Self {
         self.pre_mul(&TypedTransform2D::create_translation(v.x, v.y))
     }
 
     /// Returns a scale transform.
     pub fn create_scale(x: T, y: T) -> Self {
         let _0 = Zero::zero();
         TypedTransform2D::row_major(
              x, _0,
             _0,  y,
             _0, _0
         )
     }
 
     /// Applies a scale after self's transformation and returns the resulting transform.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn post_scale(&self, x: T, y: T) -> Self {
         self.post_mul(&TypedTransform2D::create_scale(x, y))
     }
 
     /// Applies a scale before self's transformation and returns the resulting transform.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn pre_scale(&self, x: T, y: T) -> Self {
         TypedTransform2D::row_major(
             self.m11 * x, self.m12,
             self.m21,     self.m22 * y,
             self.m31,     self.m32
         )
     }
 
@@ -236,63 +256,63 @@ where T: Copy + Clone +
         TypedTransform2D::row_major(
             cos, _0 - sin,
             sin, cos,
              _0, _0
         )
     }
 
     /// Applies a rotation after self's transformation and returns the resulting transform.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn post_rotate(&self, theta: Radians<T>) -> Self {
         self.post_mul(&TypedTransform2D::create_rotation(theta))
     }
 
     /// Applies a rotation after self's transformation and returns the resulting transform.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn pre_rotate(&self, theta: Radians<T>) -> Self {
         self.pre_mul(&TypedTransform2D::create_rotation(theta))
     }
 
     /// Returns the given point transformed by this transform.
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn transform_point(&self, point: &TypedPoint2D<T, Src>) -> TypedPoint2D<T, Dst> {
         TypedPoint2D::new(point.x * self.m11 + point.y * self.m21 + self.m31,
                           point.x * self.m12 + point.y * self.m22 + self.m32)
     }
 
     /// Returns the given vector transformed by this matrix.
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn transform_vector(&self, vec: &TypedVector2D<T, Src>) -> TypedVector2D<T, Dst> {
         vec2(vec.x * self.m11 + vec.y * self.m21,
              vec.x * self.m12 + vec.y * self.m22)
     }
 
     /// Returns a rectangle that encompasses the result of transforming the given rectangle by this
     /// transform.
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn transform_rect(&self, rect: &TypedRect<T, Src>) -> TypedRect<T, Dst> {
         TypedRect::from_points(&[
             self.transform_point(&rect.origin),
             self.transform_point(&rect.top_right()),
             self.transform_point(&rect.bottom_left()),
             self.transform_point(&rect.bottom_right()),
         ])
     }
 
     /// Computes and returns the determinant of this transform.
     pub fn determinant(&self) -> T {
         self.m11 * self.m22 - self.m12 * self.m21
     }
 
     /// Returns the inverse transform if possible.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn inverse(&self) -> Option<TypedTransform2D<T, Dst, Src>> {
         let det = self.determinant();
 
         let _0: T = Zero::zero();
         let _1: T = One::one();
 
         if det == _0 {
           return None;
@@ -322,17 +342,35 @@ where T: Copy + Clone +
     /// Returns the same transform with a different source unit.
     #[inline]
     pub fn with_source<NewSrc>(&self) -> TypedTransform2D<T, NewSrc, Dst> {
         TypedTransform2D::row_major(
             self.m11, self.m12,
             self.m21, self.m22,
             self.m31, self.m32,
         )
+    }   
+}
+
+impl <T, Src, Dst> TypedTransform2D<T, Src, Dst>
+where T: Copy + Clone +
+         Add<T, Output=T> +
+         Sub<T, Output=T> +
+         Mul<T, Output=T> +
+         Div<T, Output=T> +
+         Neg<Output=T> +
+         ApproxEq<T> +
+         PartialOrd +
+         Trig +
+         One + Zero {
+    /// Create a 3D transform from the current transform
+    pub fn to_3d(&self) -> TypedTransform3D<T, Src, Dst> {
+        TypedTransform3D::row_major_2d(self.m11, self.m12, self.m21, self.m22, self.m31, self.m32)
     }
+
 }
 
 impl<T: ApproxEq<T>, Src, Dst> TypedTransform2D<T, Src, Dst> {
     pub fn approx_eq(&self, other: &Self) -> bool {
         self.m11.approx_eq(&other.m11) && self.m12.approx_eq(&other.m12) &&
         self.m21.approx_eq(&other.m21) && self.m22.approx_eq(&other.m22) &&
         self.m31.approx_eq(&other.m31) && self.m32.approx_eq(&other.m32)
     }
--- a/third_party/rust/euclid/src/transform3d.rs
+++ b/third_party/rust/euclid/src/transform3d.rs
@@ -14,16 +14,17 @@ use point::{TypedPoint2D, TypedPoint3D, 
 use vector::{TypedVector2D, TypedVector3D, vec2, vec3};
 use rect::TypedRect;
 use transform2d::TypedTransform2D;
 use scale_factor::ScaleFactor;
 use num::{One, Zero};
 use std::ops::{Add, Mul, Sub, Div, Neg};
 use std::marker::PhantomData;
 use std::fmt;
+use num_traits::NumCast;
 
 define_matrix! {
     /// A 3d transform stored as a 4 by 4 matrix in row-major order in memory.
     ///
     /// Transforms can be parametrized over the source and destination units, to describe a
     /// transformation from a space to another.
     /// For example, `TypedTransform3D<f32, WordSpace, ScreenSpace>::transform_point3d`
     /// takes a `TypedPoint3D<f32, WordSpace>` and returns a `TypedPoint3D<f32, ScreenSpace>`.
@@ -377,17 +378,17 @@ where T: Copy + Clone +
         self.m12 * self.m23 * self.m31 * self.m44 +
         self.m13 * self.m21 * self.m32 * self.m44 -
         self.m11 * self.m23 * self.m32 * self.m44 -
         self.m12 * self.m21 * self.m33 * self.m44 +
         self.m11 * self.m22 * self.m33 * self.m44
     }
 
     /// Multiplies all of the transform's component by a scalar and returns the result.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn mul_s(&self, x: T) -> Self {
         TypedTransform3D::row_major(
             self.m11 * x, self.m12 * x, self.m13 * x, self.m14 * x,
             self.m21 * x, self.m22 * x, self.m23 * x, self.m24 * x,
             self.m31 * x, self.m32 * x, self.m33 * x, self.m34 * x,
             self.m41 * x, self.m42 * x, self.m43 * x, self.m44 * x
         )
     }
@@ -464,51 +465,51 @@ where T: Copy + Clone +
             _1, _0, _0, _0,
             _0, _1, _0, _0,
             _0, _0, _1, _0,
              x,  y,  z, _1
         )
     }
 
     /// Returns a transform with a translation applied before self's transformation.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn pre_translate(&self, v: TypedVector3D<T, Src>) -> Self {
         self.pre_mul(&TypedTransform3D::create_translation(v.x, v.y, v.z))
     }
 
     /// Returns a transform with a translation applied after self's transformation.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn post_translate(&self, v: TypedVector3D<T, Dst>) -> Self {
         self.post_mul(&TypedTransform3D::create_translation(v.x, v.y, v.z))
     }
 
     /// Create a 3d scale transform
     pub fn create_scale(x: T, y: T, z: T) -> Self {
         let (_0, _1): (T, T) = (Zero::zero(), One::one());
         TypedTransform3D::row_major(
              x, _0, _0, _0,
             _0,  y, _0, _0,
             _0, _0,  z, _0,
             _0, _0, _0, _1
         )
     }
 
     /// Returns a transform with a scale applied before self's transformation.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn pre_scale(&self, x: T, y: T, z: T) -> Self {
         TypedTransform3D::row_major(
             self.m11 * x, self.m12,     self.m13,     self.m14,
             self.m21    , self.m22 * y, self.m23,     self.m24,
             self.m31    , self.m32,     self.m33 * z, self.m34,
             self.m41    , self.m42,     self.m43,     self.m44
         )
     }
 
     /// Returns a transform with a scale applied after self's transformation.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn post_scale(&self, x: T, y: T, z: T) -> Self {
         self.post_mul(&TypedTransform3D::create_scale(x, y, z))
     }
 
     /// Create a 3d rotation transform from an angle / axis.
     /// The supplied axis must be normalized.
     pub fn create_rotation(x: T, y: T, z: T, theta: Radians<T>) -> Self {
         let (_0, _1): (T, T) = (Zero::zero(), One::one());
@@ -541,23 +542,23 @@ where T: Copy + Clone +
             _0,
             _0,
             _0,
             _1
         )
     }
 
     /// Returns a transform with a rotation applied after self's transformation.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn post_rotate(&self, x: T, y: T, z: T, theta: Radians<T>) -> Self {
         self.post_mul(&TypedTransform3D::create_rotation(x, y, z, theta))
     }
 
     /// Returns a transform with a rotation applied before self's transformation.
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn pre_rotate(&self, x: T, y: T, z: T, theta: Radians<T>) -> Self {
         self.pre_mul(&TypedTransform3D::create_rotation(x, y, z, theta))
     }
 
     /// Create a 2d skew transform.
     ///
     /// See https://drafts.csswg.org/css-transforms/#funcdef-skew
     pub fn create_skew(alpha: Radians<T>, beta: Radians<T>) -> Self {
@@ -647,16 +648,41 @@ impl<T: Copy, Src, Dst> TypedTransform3D
             array[0][0], array[0][1], array[0][2], array[0][3],
             array[1][0], array[1][1], array[1][2], array[1][3],
             array[2][0], array[2][1], array[2][2], array[2][3],
             array[3][0], array[3][1], array[3][2], array[3][3],
         )
     }
 }
 
+impl<T0: NumCast + Copy, Src, Dst> TypedTransform3D<T0, Src, Dst> {
+    /// Cast from one numeric representation to another, preserving the units.
+    pub fn cast<T1: NumCast + Copy>(&self) -> Option<TypedTransform3D<T1, Src, Dst>> {
+        match (NumCast::from(self.m11), NumCast::from(self.m12),
+               NumCast::from(self.m13), NumCast::from(self.m14),
+               NumCast::from(self.m21), NumCast::from(self.m22),
+               NumCast::from(self.m23), NumCast::from(self.m24),
+               NumCast::from(self.m31), NumCast::from(self.m32),
+               NumCast::from(self.m33), NumCast::from(self.m34),
+               NumCast::from(self.m41), NumCast::from(self.m42),
+               NumCast::from(self.m43), NumCast::from(self.m44)) {
+            (Some(m11), Some(m12), Some(m13), Some(m14),
+             Some(m21), Some(m22), Some(m23), Some(m24),
+             Some(m31), Some(m32), Some(m33), Some(m34),
+             Some(m41), Some(m42), Some(m43), Some(m44)) => {
+                Some(TypedTransform3D::row_major(m11, m12, m13, m14,
+                                                 m21, m22, m23, m24,
+                                                 m31, m32, m33, m34,
+                                                 m41, m42, m43, m44))
+            },
+            _ => None
+        }
+    }
+}
+
 impl<T, Src, Dst> fmt::Debug for TypedTransform3D<T, Src, Dst>
 where T: Copy + fmt::Debug +
          PartialEq +
          One + Zero {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if self.is_identity() {
             write!(f, "[I]")
         } else {
--- a/third_party/rust/euclid/src/vector.rs
+++ b/third_party/rust/euclid/src/vector.rs
@@ -9,17 +9,17 @@
 
 use super::UnknownUnit;
 use approxeq::ApproxEq;
 use length::Length;
 use point::{TypedPoint2D, TypedPoint3D, point2, point3};
 use size::{TypedSize2D, size2};
 use scale_factor::ScaleFactor;
 use num::*;
-use num_traits::{Float, NumCast};
+use num_traits::{Float, NumCast, Signed};
 use std::fmt;
 use std::ops::{Add, Neg, Mul, Sub, Div, AddAssign, SubAssign, MulAssign, DivAssign};
 use std::marker::PhantomData;
 
 define_matrix! {
     /// A 2d Vector tagged with a unit.
     pub struct TypedVector2D<T, U> {
         pub x: T,
@@ -53,23 +53,25 @@ impl<T: fmt::Debug, U> fmt::Debug for Ty
 }
 
 impl<T: fmt::Display, U> fmt::Display for TypedVector2D<T, U> {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         write!(formatter, "({},{})", self.x, self.y)
     }
 }
 
-impl<T: Copy, U> TypedVector2D<T, U> {
+impl<T, U> TypedVector2D<T, U> {
     /// Constructor taking scalar values directly.
     #[inline]
     pub fn new(x: T, y: T) -> Self {
         TypedVector2D { x: x, y: y, _unit: PhantomData }
     }
+}
 
+impl<T: Copy, U> TypedVector2D<T, U> {
     /// Constructor taking properly typed Lengths instead of scalar values.
     #[inline]
     pub fn from_lengths(x: Length<T, U>, y: Length<T, U>) -> Self {
         vec2(x.0, y.0)
     }
 
     /// Create a 3d vector from this one, using the specified z value.
     #[inline]
@@ -267,41 +269,41 @@ impl<T: Copy + Div<T, Output=T>, U1, U2>
 }
 
 impl<T: Round, U> TypedVector2D<T, U> {
     /// Rounds each component to the nearest integer value.
     ///
     /// This behavior is preserved for negative values (unlike the basic cast).
     /// For example `{ -0.1, -0.8 }.round() == { 0.0, -1.0 }`.
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn round(&self) -> Self {
         vec2(self.x.round(), self.y.round())
     }
 }
 
 impl<T: Ceil, U> TypedVector2D<T, U> {
     /// Rounds each component to the smallest integer equal or greater than the original value.
     ///
     /// This behavior is preserved for negative values (unlike the basic cast).
     /// For example `{ -0.1, -0.8 }.ceil() == { 0.0, 0.0 }`.
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn ceil(&self) -> Self {
         vec2(self.x.ceil(), self.y.ceil())
     }
 }
 
 impl<T: Floor, U> TypedVector2D<T, U> {
     /// Rounds each component to the biggest integer equal or lower than the original value.
     ///
     /// This behavior is preserved for negative values (unlike the basic cast).
     /// For example `{ -0.1, -0.8 }.floor() == { -1.0, -1.0 }`.
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn floor(&self) -> Self {
         vec2(self.x.floor(), self.y.floor())
     }
 }
 
 impl<T: NumCast + Copy, U> TypedVector2D<T, U> {
     /// Cast from one numeric representation to another, preserving the units.
     ///
@@ -379,16 +381,23 @@ impl<T: Copy, U> Into<[T; 2]> for TypedV
 }
 
 impl<T: Copy, U> From<[T; 2]> for TypedVector2D<T, U> {
     fn from(array: [T; 2]) -> Self {
         vec2(array[0], array[1])
     }
 }
 
+impl<T, U> TypedVector2D<T, U>
+where T: Signed {
+    pub fn abs(&self) -> Self {
+        vec2(self.x.abs(), self.y.abs())
+    }
+}
+
 define_matrix! {
     /// A 3d Vector tagged with a unit.
     pub struct TypedVector3D<T, U> {
         pub x: T,
         pub y: T,
         pub z: T,
     }
 }
@@ -418,23 +427,25 @@ impl<T: fmt::Debug, U> fmt::Debug for Ty
 }
 
 impl<T: fmt::Display, U> fmt::Display for TypedVector3D<T, U> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "({},{},{})", self.x, self.y, self.z)
     }
 }
 
-impl<T: Copy, U> TypedVector3D<T, U> {
+impl<T, U> TypedVector3D<T, U> {
     /// Constructor taking scalar values directly.
     #[inline]
     pub fn new(x: T, y: T, z: T) -> Self {
         TypedVector3D { x: x, y: y, z: z, _unit: PhantomData }
     }
+}
 
+impl<T: Copy, U> TypedVector3D<T, U> {
     /// Constructor taking properly typed Lengths instead of scalar values.
     #[inline]
     pub fn from_lengths(x: Length<T, U>, y: Length<T, U>, z: Length<T, U>) -> TypedVector3D<T, U> {
         vec3(x.0, y.0, z.0)
     }
 
     /// Cast this vector into a point.
     ///
@@ -632,39 +643,39 @@ impl<T: Float, U> TypedVector3D<T, U> {
     }
 }
 
 impl<T: Round, U> TypedVector3D<T, U> {
     /// Rounds each component to the nearest integer value.
     ///
     /// This behavior is preserved for negative values (unlike the basic cast).
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn round(&self) -> Self {
         vec3(self.x.round(), self.y.round(), self.z.round())
     }
 }
 
 impl<T: Ceil, U> TypedVector3D<T, U> {
     /// Rounds each component to the smallest integer equal or greater than the original value.
     ///
     /// This behavior is preserved for negative values (unlike the basic cast).
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn ceil(&self) -> Self {
         vec3(self.x.ceil(), self.y.ceil(), self.z.ceil())
     }
 }
 
 impl<T: Floor, U> TypedVector3D<T, U> {
     /// Rounds each component to the biggest integer equal or lower than the original value.
     ///
     /// This behavior is preserved for negative values (unlike the basic cast).
     #[inline]
-    #[must_use]
+    #[cfg_attr(feature = "unstable", must_use)]
     pub fn floor(&self) -> Self {
         vec3(self.x.floor(), self.y.floor(), self.z.floor())
     }
 }
 
 impl<T: NumCast + Copy, U> TypedVector3D<T, U> {
     /// Cast from one numeric representation to another, preserving the units.
     ///
@@ -748,26 +759,32 @@ impl<T: Copy, U> Into<[T; 3]> for TypedV
 }
 
 impl<T: Copy, U> From<[T; 3]> for TypedVector3D<T, U> {
     fn from(array: [T; 3]) -> Self {
         vec3(array[0], array[1], array[2])
     }
 }
 
+impl<T, U> TypedVector3D<T, U>
+where T: Signed {
+    pub fn abs(&self) -> Self {
+        vec3(self.x.abs(), self.y.abs(), self.z.abs())
+    }
+}
 
 /// Convenience constructor.
 #[inline]
-pub fn vec2<T: Copy, U>(x: T, y: T) -> TypedVector2D<T, U> {
+pub fn vec2<T, U>(x: T, y: T) -> TypedVector2D<T, U> {
     TypedVector2D::new(x, y)
 }
 
 /// Convenience constructor.
 #[inline]
-pub fn vec3<T: Copy, U>(x: T, y: T, z: T) -> TypedVector3D<T, U> {
+pub fn vec3<T, U>(x: T, y: T, z: T) -> TypedVector3D<T, U> {
     TypedVector3D::new(x, y, z)
 }
 
 #[cfg(test)]
 mod vector2d {
     use super::{Vector2D, vec2};
     type Vec2 = Vector2D<f32>;
 
--- a/toolkit/library/gtest/rust/Cargo.lock
+++ b/toolkit/library/gtest/rust/Cargo.lock
@@ -430,17 +430,17 @@ dependencies = [
 
 [[package]]
 name = "error-chain"
 version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "euclid"
-version = "0.15.2"
+version = "0.15.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -723,17 +723,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "malloc_size_of"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "hashglobe 0.1.0",
  "servo_arc 0.0.1",
  "smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "malloc_size_of_derive"
@@ -1000,17 +1000,17 @@ version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "plane-split"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "precomputed-hash"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1234,17 +1234,17 @@ dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bindgen 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cfg-if 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "fallible 0.0.1",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "hashglobe 0.1.0",
  "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1287,17 +1287,17 @@ dependencies = [
 
 [[package]]
 name = "style_traits"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of 0.0.1",
  "malloc_size_of_derive 0.0.1",
  "selectors 0.19.0",
  "servo_arc 0.0.1",
 ]
 
 [[package]]
 name = "syn"
@@ -1477,17 +1477,17 @@ dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "plane-split 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1502,30 +1502,30 @@ version = "0.53.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender_bindings"
 version = "0.1.0"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.53.1",
  "webrender_api 0.53.1",
 ]
 
@@ -1600,17 +1600,17 @@ dependencies = [
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"
 "checksum dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36e3b27cd0b8a68e00f07e8d8e1e4f4d8a6b8b873290a734f63bd56d792d23e1"
 "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
 "checksum encoding_c 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "93ec52324ca72f423237a413ca0e1c60654c8b3d0934fcd5fd888508dfcc4ba7"
 "checksum encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f5215aabf22b83153be3ee44dfe3f940214541b2ce13d419c55e7a115c8c51a9"
 "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
 "checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
-"checksum euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "50c9e4c3b53de731815135191f0b77969bea953211b8bbd3cc3083a7b10e190e"
+"checksum euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ed7d77e46f6600f490463ad7b6349c3ebb2d2319af56e679e279e4c66495d9"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
 "checksum freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "398b8a11884898184d55aca9806f002b3cf68f0e860e0cbb4586f834ee39b0e7"
 "checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"
 "checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159"
 "checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82"
 "checksum futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "55f0008e13fc853f79ea8fc86e931486860d4c4c156cdffb59fa5f7fa833660a"
 "checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
 "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
--- a/toolkit/library/rust/Cargo.lock
+++ b/toolkit/library/rust/Cargo.lock
@@ -430,17 +430,17 @@ dependencies = [
 
 [[package]]
 name = "error-chain"
 version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "euclid"
-version = "0.15.2"
+version = "0.15.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -722,17 +722,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "malloc_size_of"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "hashglobe 0.1.0",
  "servo_arc 0.0.1",
  "smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "malloc_size_of_derive"
@@ -988,17 +988,17 @@ version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "plane-split"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "precomputed-hash"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1226,17 +1226,17 @@ dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bindgen 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cfg-if 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "fallible 0.0.1",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "hashglobe 0.1.0",
  "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1279,31 +1279,31 @@ dependencies = [
 
 [[package]]
 name = "style_traits"
 version = "0.0.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of 0.0.1",
  "malloc_size_of_derive 0.0.1",
  "selectors 0.19.0",
  "servo_arc 0.0.1",
 ]
 
 [[package]]
 name = "stylo_tests"
 version = "0.0.1"
 dependencies = [
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "geckoservo 0.0.1",
  "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of 0.0.1",
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.19.0",
  "size_of_test 0.0.1",
  "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1489,17 +1489,17 @@ dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "plane-split 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1514,30 +1514,30 @@ version = "0.53.1"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender_bindings"
 version = "0.1.0"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.53.1",
  "webrender_api 0.53.1",
 ]
 
@@ -1612,17 +1612,17 @@ dependencies = [
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"
 "checksum dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36e3b27cd0b8a68e00f07e8d8e1e4f4d8a6b8b873290a734f63bd56d792d23e1"
 "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
 "checksum encoding_c 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "93ec52324ca72f423237a413ca0e1c60654c8b3d0934fcd5fd888508dfcc4ba7"
 "checksum encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f5215aabf22b83153be3ee44dfe3f940214541b2ce13d419c55e7a115c8c51a9"
 "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
 "checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
-"checksum euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "50c9e4c3b53de731815135191f0b77969bea953211b8bbd3cc3083a7b10e190e"
+"checksum euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ed7d77e46f6600f490463ad7b6349c3ebb2d2319af56e679e279e4c66495d9"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
 "checksum freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "398b8a11884898184d55aca9806f002b3cf68f0e860e0cbb4586f834ee39b0e7"
 "checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"
 "checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159"
 "checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82"
 "checksum futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "55f0008e13fc853f79ea8fc86e931486860d4c4c156cdffb59fa5f7fa833660a"
 "checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
 "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"