Bug 1367734 - Revendor third-party rust packages. r?jrmuizel draft
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 31 May 2017 16:31:04 -0400
changeset 587271 ea3b67e9c1466f82e375ef0bc2cee19007c50452
parent 587270 218e91e9bd6078f7c8d87398f4006106f3eda58e
child 587272 983154256d629cfd00512d443a0310d63e55f90d
push id61673
push userkgupta@mozilla.com
push dateWed, 31 May 2017 20:32:21 +0000
reviewersjrmuizel
bugs1367734
milestone55.0a1
Bug 1367734 - Revendor third-party rust packages. r?jrmuizel MozReview-Commit-ID: 6neB2EUz5QZ
third_party/rust/euclid-0.11.3/.cargo-checksum.json
third_party/rust/euclid-0.11.3/.cargo-ok
third_party/rust/euclid-0.11.3/.gitignore
third_party/rust/euclid-0.11.3/.travis.yml
third_party/rust/euclid-0.11.3/COPYRIGHT
third_party/rust/euclid-0.11.3/Cargo.toml
third_party/rust/euclid-0.11.3/LICENSE-APACHE
third_party/rust/euclid-0.11.3/LICENSE-MIT
third_party/rust/euclid-0.11.3/README.md
third_party/rust/euclid-0.11.3/src/approxeq.rs
third_party/rust/euclid-0.11.3/src/length.rs
third_party/rust/euclid-0.11.3/src/lib.rs
third_party/rust/euclid-0.11.3/src/macros.rs
third_party/rust/euclid-0.11.3/src/matrix2d.rs
third_party/rust/euclid-0.11.3/src/matrix4d.rs
third_party/rust/euclid-0.11.3/src/num.rs
third_party/rust/euclid-0.11.3/src/point.rs
third_party/rust/euclid-0.11.3/src/rect.rs
third_party/rust/euclid-0.11.3/src/scale_factor.rs
third_party/rust/euclid-0.11.3/src/side_offsets.rs
third_party/rust/euclid-0.11.3/src/size.rs
third_party/rust/euclid-0.11.3/src/trig.rs
third_party/rust/euclid/.cargo-checksum.json
third_party/rust/euclid/Cargo.toml
third_party/rust/euclid/README.md
third_party/rust/euclid/src/approxeq.rs
third_party/rust/euclid/src/num.rs
third_party/rust/euclid/src/point.rs
third_party/rust/euclid/src/rect.rs
third_party/rust/euclid/src/size.rs
third_party/rust/euclid/src/trig.rs
third_party/rust/heapsize-0.3.8/.cargo-checksum.json
third_party/rust/heapsize-0.3.8/.cargo-ok
third_party/rust/heapsize-0.3.8/.gitignore
third_party/rust/heapsize-0.3.8/.travis.yml
third_party/rust/heapsize-0.3.8/Cargo.toml
third_party/rust/heapsize-0.3.8/README.md
third_party/rust/heapsize-0.3.8/appveyor.yml
third_party/rust/heapsize-0.3.8/build.rs
third_party/rust/heapsize-0.3.8/src/lib.rs
third_party/rust/heapsize-0.3.8/tests/tests.rs
third_party/rust/heapsize/.cargo-checksum.json
third_party/rust/heapsize/.travis.yml
third_party/rust/heapsize/Cargo.toml
third_party/rust/heapsize/src/lib.rs
third_party/rust/heapsize/tests/tests.rs
third_party/rust/plane-split/.cargo-checksum.json
third_party/rust/plane-split/Cargo.toml
third_party/rust/plane-split/src/bsp.rs
third_party/rust/plane-split/src/lib.rs
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"118514fd9c4958df0d25584cda4917186c46011569f55ef350530c1ad3fbdb48",".travis.yml":"13d3e5a7bf83b04c8e8cfa14f0297bd8366d68391d977dd547f64707dffc275a","COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"10cfe5580ee83ae883a60d96f504dda8ae7885ae5fd3a3faf95c2a2b8b38fad0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"52f974f01c1e15182413e4321c8817d5e66fe4d92c5ec223c857dd0440f5c229","src/approxeq.rs":"2987e046c90d948b6c7d7ddba52d10c8b7520d71dc0a50dbe7665de128d7410e","src/length.rs":"d7c6369f2fe2a17c845b57749bd48c471159f0571a7314d3bf90737d53f697d3","src/lib.rs":"e2e621f05304278d020429d0349acf7a4e7c7a9a72bd23fc0e55680267472ee9","src/macros.rs":"b63dabdb52df84ea170dc1dab5fe8d7a78c054562d1566bab416124708d2d7af","src/matrix2d.rs":"2361338f59813adf4eebaab76e4dd82be0fbfb9ff2461da8dd9ac9d43583b322","src/matrix4d.rs":"b8547bed6108b037192021c97169c00ad456120b849e9b7ac7bec40363edaec1","src/num.rs":"62286aa642ce3afa7ebd950f50bf2197d8722907f2e23a2e2ea6690484d8b250","src/point.rs":"53f3c9018c822e0a6dc5018005e153775479f41fe55c082d0be10f331fda773f","src/rect.rs":"db62b3af8939529509ae21b3bf6ae498d73a95b4ff3a6eba4db614be08e95f8b","src/scale_factor.rs":"df6dbd1f0f9f63210b92809f84a383dad982a74f09789cf22c7d8f9b62199d39","src/side_offsets.rs":"f85526a421ffda63ff01a3478d4162c8717eef68e942acfa2fd9a1adee02ebb2","src/size.rs":"19d1c08f678d793c6eff49a44f69e5b7179e574aa9b81fb4e73210733af38718","src/trig.rs":"6b207980052d13c625272f2a70a22f7741b59513c2a4882385926f497c763a63"},"package":"f5517462c626a893f3b027615e88d7102cc6dd3f7f1bcb90c7220fb1da4970b5"}
\ No newline at end of file
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/.gitignore
@@ -0,0 +1,2 @@
+Cargo.lock
+/target/
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/.travis.yml
@@ -0,0 +1,19 @@
+language: rust
+
+notifications:
+  webhooks: http://build.servo.org:54856/travis
+
+matrix:
+  include:
+    - rust: stable
+      env: FEATURES=""
+    - rust: beta
+      env: FEATURES=""
+    - rust: nightly
+      env: FEATURES=""
+    - rust: nightly
+      env: FEATURES="unstable"
+
+script:
+  - cargo build --verbose --features "$FEATURES"
+  - cargo test --verbose --features "$FEATURES"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/COPYRIGHT
@@ -0,0 +1,5 @@
+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. All files in the project carrying such notice may not be
+copied, modified, or distributed except according to those terms.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name = "euclid"
+version = "0.11.3"
+authors = ["The Servo Project Developers"]
+description = "Geometry primitives"
+documentation = "https://docs.rs/euclid/"
+repository = "https://github.com/servo/euclid"
+license = "MIT / Apache-2.0"
+
+[features]
+unstable = []
+
+[dependencies]
+heapsize = "0.3"
+rustc-serialize = "0.3.2"
+num-traits = {version = "0.1.32", default-features = false}
+log = "0.3.1"
+serde = "0.9"
+
+[dev-dependencies]
+rand = "0.3.7"
+serde_test = "0.9"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2012-2013 Mozilla Foundation
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/README.md
@@ -0,0 +1,5 @@
+# euclid
+
+This is a small library for geometric types.
+
+[Documentation](https://docs.rs/euclid/)
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/approxeq.rs
@@ -0,0 +1,47 @@
+// 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.
+
+
+/// Trait for testing approximate equality
+pub trait ApproxEq<Eps> {
+    fn approx_epsilon() -> Eps;
+    fn approx_eq(&self, other: &Self) -> bool;
+    fn approx_eq_eps(&self, other: &Self, approx_epsilon: &Eps) -> bool;
+}
+
+impl ApproxEq<f32> for f32 {
+    #[inline]
+    fn approx_epsilon() -> f32 { 1.0e-6 }
+
+    #[inline]
+    fn approx_eq(&self, other: &f32) -> bool {
+       self.approx_eq_eps(other, &1.0e-6)
+    }
+
+    #[inline]
+    fn approx_eq_eps(&self, other: &f32, approx_epsilon: &f32) -> bool {
+       (*self - *other).abs() < *approx_epsilon
+    }
+}
+
+
+impl ApproxEq<f64> for f64 {
+    #[inline]
+    fn approx_epsilon() -> f64 { 1.0e-6 }
+
+    #[inline]
+    fn approx_eq(&self, other: &f64) -> bool {
+        self.approx_eq_eps(other, &1.0e-6)
+    }
+
+    #[inline]
+    fn approx_eq_eps(&self, other: &f64, approx_epsilon: &f64) -> bool {
+        (*self - *other).abs() < *approx_epsilon
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/length.rs
@@ -0,0 +1,449 @@
+// Copyright 2014 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.
+//! A one-dimensional length, tagged with its units.
+
+use scale_factor::ScaleFactor;
+use num::Zero;
+
+use heapsize::HeapSizeOf;
+use num_traits::{NumCast, Saturating};
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use std::cmp::Ordering;
+use std::ops::{Add, Sub, Mul, Div, Neg};
+use std::ops::{AddAssign, SubAssign};
+use std::marker::PhantomData;
+use std::fmt;
+
+/// A one-dimensional distance, with value represented by `T` and unit of measurement `Unit`.
+///
+/// `T` can be any numeric type, for example a primitive type like `u64` or `f32`.
+///
+/// `Unit` is not used in the representation of a `Length` value. It is used only at compile time
+/// to ensure that a `Length` stored with one unit is converted explicitly before being used in an
+/// expression that requires a different unit.  It may be a type without values, such as an empty
+/// enum.
+///
+/// You can multiply a `Length` by a `scale_factor::ScaleFactor` to convert it from one unit to
+/// another. See the `ScaleFactor` docs for an example.
+// Uncomment the derive, and remove the macro call, once heapsize gets
+// PhantomData<T> support.
+#[repr(C)]
+#[derive(RustcDecodable, RustcEncodable)]
+pub struct Length<T, Unit>(pub T, PhantomData<Unit>);
+
+impl<T: Clone, Unit> Clone for Length<T, Unit> {
+    fn clone(&self) -> Self {
+        Length(self.0.clone(), PhantomData)
+    }
+}
+
+impl<T: Copy, Unit> Copy for Length<T, Unit> {}
+
+impl<Unit, T: HeapSizeOf> HeapSizeOf for Length<T, Unit> {
+    fn heap_size_of_children(&self) -> usize {
+        self.0.heap_size_of_children()
+    }
+}
+
+impl<Unit, T> Deserialize for Length<T, Unit> where T: Deserialize {
+    fn deserialize<D>(deserializer: D) -> Result<Length<T, Unit>,D::Error>
+                      where D: Deserializer {
+        Ok(Length(try!(Deserialize::deserialize(deserializer)), PhantomData))
+    }
+}
+
+impl<T, Unit> Serialize for Length<T, Unit> where T: Serialize {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
+        self.0.serialize(serializer)
+    }
+}
+
+impl<T, Unit> Length<T, Unit> {
+    pub fn new(x: T) -> Length<T, Unit> {
+        Length(x, PhantomData)
+    }
+}
+
+impl<Unit, T: Clone> Length<T, Unit> {
+    pub fn get(&self) -> T {
+        self.0.clone()
+    }
+}
+
+impl<T: fmt::Debug + Clone, U> fmt::Debug for Length<T, U> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.get().fmt(f)
+    }
+}
+
+impl<T: fmt::Display + Clone, U> fmt::Display for Length<T, U> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.get().fmt(f)
+    }
+}
+
+// length + length
+impl<U, T: Clone + Add<T, Output=T>> Add for Length<T, U> {
+    type Output = Length<T, U>;
+    fn add(self, other: Length<T, U>) -> Length<T, U> {
+        Length::new(self.get() + other.get())
+    }
+}
+
+// length += length
+impl<U, T: Clone + AddAssign<T>> AddAssign for Length<T, U> {
+    fn add_assign(&mut self, other: Length<T, U>) {
+        self.0 += other.get();
+    }
+}
+
+// length - length
+impl<U, T: Clone + Sub<T, Output=T>> Sub<Length<T, U>> for Length<T, U> {
+    type Output = Length<T, U>;
+    fn sub(self, other: Length<T, U>) -> <Self as Sub>::Output {
+        Length::new(self.get() - other.get())
+    }
+}
+
+// length -= length
+impl<U, T: Clone + SubAssign<T>> SubAssign for Length<T, U> {
+    fn sub_assign(&mut self, other: Length<T, U>) {
+        self.0 -= other.get();
+    }
+}
+
+// Saturating length + length and length - length.
+impl<U, T: Clone + Saturating> Saturating for Length<T, U> {
+    fn saturating_add(self, other: Length<T, U>) -> Length<T, U> {
+        Length::new(self.get().saturating_add(other.get()))
+    }
+
+    fn saturating_sub(self, other: Length<T, U>) -> Length<T, U> {
+        Length::new(self.get().saturating_sub(other.get()))
+    }
+}
+
+// length / length
+impl<Src, Dst, T: Clone + Div<T, Output=T>> Div<Length<T, Src>> for Length<T, Dst> {
+    type Output = ScaleFactor<T, Src, Dst>;
+    #[inline]
+    fn div(self, other: Length<T, Src>) -> ScaleFactor<T, Src, Dst> {
+        ScaleFactor::new(self.get() / other.get())
+    }
+}
+
+// length * scaleFactor
+impl<Src, Dst, T: Clone + Mul<T, Output=T>> Mul<ScaleFactor<T, Src, Dst>> for Length<T, Src> {
+    type Output = Length<T, Dst>;
+    #[inline]
+    fn mul(self, scale: ScaleFactor<T, Src, Dst>) -> Length<T, Dst> {
+        Length::new(self.get() * scale.get())
+    }
+}
+
+// length / scaleFactor
+impl<Src, Dst, T: Clone + Div<T, Output=T>> Div<ScaleFactor<T, Src, Dst>> for Length<T, Dst> {
+    type Output = Length<T, Src>;
+    #[inline]
+    fn div(self, scale: ScaleFactor<T, Src, Dst>) -> Length<T, Src> {
+        Length::new(self.get() / scale.get())
+    }
+}
+
+// -length
+impl <U, T:Clone + Neg<Output=T>> Neg for Length<T, U> {
+    type Output = Length<T, U>;
+    #[inline]
+    fn neg(self) -> Length<T, U> {
+        Length::new(-self.get())
+    }
+}
+
+impl<Unit, T0: NumCast + Clone> Length<T0, Unit> {
+    /// Cast from one numeric representation to another, preserving the units.
+    pub fn cast<T1: NumCast + Clone>(&self) -> Option<Length<T1, Unit>> {
+        NumCast::from(self.get()).map(Length::new)
+    }
+}
+
+impl<Unit, T: Clone + PartialEq> PartialEq for Length<T, Unit> {
+    fn eq(&self, other: &Length<T, Unit>) -> bool { self.get().eq(&other.get()) }
+}
+
+impl<Unit, T: Clone + PartialOrd> PartialOrd for Length<T, Unit> {
+    fn partial_cmp(&self, other: &Length<T, Unit>) -> Option<Ordering> {
+        self.get().partial_cmp(&other.get())
+    }
+}
+
+impl<Unit, T: Clone + Eq> Eq for Length<T, Unit> {}
+
+impl<Unit, T: Clone + Ord> Ord for Length<T, Unit> {
+    fn cmp(&self, other: &Length<T, Unit>) -> Ordering { self.get().cmp(&other.get()) }
+}
+
+impl<Unit, T: Zero> Zero for Length<T, Unit> {
+    fn zero() -> Length<T, Unit> {
+        Length::new(Zero::zero())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::Length;
+    use num::Zero;
+
+    use heapsize::HeapSizeOf;
+    use num_traits::Saturating;
+    use scale_factor::ScaleFactor;
+    use std::f32::INFINITY;
+
+    extern crate serde_test;
+    use self::serde_test::Token;
+    use self::serde_test::assert_tokens;
+
+    enum Inch {}
+    enum Mm {}
+    enum Cm {}
+    enum Second {}
+
+    #[test]
+    fn test_clone() {
+        // A cloned Length is a separate length with the state matching the
+        // original Length at the point it was cloned.
+        let mut variable_length: Length<f32, Inch> = Length::new(12.0);
+
+        let one_foot = variable_length.clone();
+        variable_length.0 = 24.0;
+
+        assert_eq!(one_foot.get(), 12.0);
+        assert_eq!(variable_length.get(), 24.0);
+    }
+
+    #[test]
+    fn test_heapsizeof_builtins() {
+        // Heap size of built-ins is zero by default.
+        let one_foot: Length<f32, Inch> = Length::new(12.0);
+
+        let heap_size_length_f32 = one_foot.heap_size_of_children();
+
+        assert_eq!(heap_size_length_f32, 0);
+    }
+
+    #[test]
+    fn test_heapsizeof_length_vector() {
+        // Heap size of any Length is just the heap size of the length value.
+        for n in 0..5 {
+            let length: Length<Vec<f32>, Inch> = Length::new(Vec::with_capacity(n));
+
+            assert_eq!(length.heap_size_of_children(), length.0.heap_size_of_children());
+        }
+    }
+
+    #[test]
+    fn test_length_serde() {
+        let one_cm: Length<f32, Mm> = Length::new(10.0);
+
+        assert_tokens(&one_cm, &[Token::F32(10.0)]);
+    }
+
+    #[test]
+    fn test_get_clones_length_value() {
+        // Calling get returns a clone of the Length's value.
+        // To test this, we need something clone-able - hence a vector.
+        let mut length: Length<Vec<i32>, Inch> = Length::new(vec![1, 2, 3]);
+
+        let value = length.get();
+        length.0.push(4);
+
+        assert_eq!(value, vec![1, 2, 3]);
+        assert_eq!(length.get(), vec![1, 2, 3, 4]);
+    }
+
+    #[test]
+    fn test_fmt_debug() {
+        // Debug and display format the value only.
+        let one_cm: Length<f32, Mm> = Length::new(10.0);
+
+        let result = format!("{:?}", one_cm);
+
+        assert_eq!(result, "10");
+    }
+
+    #[test]
+    fn test_fmt_display() {
+        // Debug and display format the value only.
+        let one_cm: Length<f32, Mm> = Length::new(10.0);
+
+        let result = format!("{}", one_cm);
+
+        assert_eq!(result, "10");
+    }
+
+    #[test]
+    fn test_add() {
+        let length1: Length<u8, Mm> = Length::new(250);
+        let length2: Length<u8, Mm> = Length::new(5);
+
+        let result = length1 + length2;
+
+        assert_eq!(result.get(), 255);
+    }
+
+    #[test]
+    fn test_addassign() {
+        let one_cm: Length<f32, Mm> = Length::new(10.0);
+        let mut measurement: Length<f32, Mm> = Length::new(5.0);
+
+        measurement += one_cm;
+
+        assert_eq!(measurement.get(), 15.0);
+    }
+
+    #[test]
+    fn test_sub() {
+        let length1: Length<u8, Mm> = Length::new(250);
+        let length2: Length<u8, Mm> = Length::new(5);
+
+        let result = length1 - length2;
+
+        assert_eq!(result.get(), 245);
+    }
+
+    #[test]
+    fn test_subassign() {
+        let one_cm: Length<f32, Mm> = Length::new(10.0);
+        let mut measurement: Length<f32, Mm> = Length::new(5.0);
+
+        measurement -= one_cm;
+
+        assert_eq!(measurement.get(), -5.0);
+    }
+
+    #[test]
+    fn test_saturating_add() {
+        let length1: Length<u8, Mm> = Length::new(250);
+        let length2: Length<u8, Mm> = Length::new(6);
+
+        let result = length1.saturating_add(length2);
+
+        assert_eq!(result.get(), 255);
+    }
+
+    #[test]
+    fn test_saturating_sub() {
+        let length1: Length<u8, Mm> = Length::new(5);
+        let length2: Length<u8, Mm> = Length::new(10);
+
+        let result = length1.saturating_sub(length2);
+
+        assert_eq!(result.get(), 0);
+    }
+
+    #[test]
+    fn test_division_by_length() {
+        // Division results in a ScaleFactor from denominator units
+        // to numerator units.
+        let length: Length<f32, Cm> = Length::new(5.0);
+        let duration: Length<f32, Second> = Length::new(10.0);
+
+        let result = length / duration;
+
+        let expected: ScaleFactor<f32, Second, Cm> = ScaleFactor::new(0.5);
+        assert_eq!(result, expected);
+    }
+
+    #[test]
+    fn test_multiplication() {
+        let length_mm: Length<f32, Mm> = Length::new(10.0);
+        let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
+
+        let result = length_mm * cm_per_mm;
+
+        let expected: Length<f32, Cm> = Length::new(1.0);
+        assert_eq!(result, expected);
+    }
+
+    #[test]
+    fn test_division_by_scalefactor() {
+        let length: Length<f32, Cm> = Length::new(5.0);
+        let cm_per_second: ScaleFactor<f32, Second, Cm> = ScaleFactor::new(10.0);
+
+        let result = length / cm_per_second;
+
+        let expected: Length<f32, Second> = Length::new(0.5);
+        assert_eq!(result, expected);
+    }
+
+    #[test]
+    fn test_negation() {
+        let length: Length<f32, Cm> = Length::new(5.0);
+
+        let result = -length;
+
+        let expected: Length<f32, Cm> = Length::new(-5.0);
+        assert_eq!(result, expected);
+    }
+
+    #[test]
+    fn test_cast() {
+        let length_as_i32: Length<i32, Cm> = Length::new(5);
+
+        let result: Length<f32, Cm> = length_as_i32.cast().unwrap();
+
+        let length_as_f32: Length<f32, Cm> = Length::new(5.0);
+        assert_eq!(result, length_as_f32);
+    }
+
+    #[test]
+    fn test_equality() {
+        let length_5_point_0: Length<f32, Cm> = Length::new(5.0);
+        let length_5_point_1: Length<f32, Cm> = Length::new(5.1);
+        let length_0_point_1: Length<f32, Cm> = Length::new(0.1);
+
+        assert!(length_5_point_0 == length_5_point_1 - length_0_point_1);
+        assert!(length_5_point_0 != length_5_point_1);
+    }
+
+    #[test]
+    fn test_order() {
+        let length_5_point_0: Length<f32, Cm> = Length::new(5.0);
+        let length_5_point_1: Length<f32, Cm> = Length::new(5.1);
+        let length_0_point_1: Length<f32, Cm> = Length::new(0.1);
+
+        assert!(length_5_point_0 < length_5_point_1);
+        assert!(length_5_point_0 <= length_5_point_1);
+        assert!(length_5_point_0 <= length_5_point_1 - length_0_point_1);
+        assert!(length_5_point_1 > length_5_point_0);
+        assert!(length_5_point_1 >= length_5_point_0);
+        assert!(length_5_point_0 >= length_5_point_1 - length_0_point_1);
+    }
+
+    #[test]
+    fn test_zero_add() {
+        type LengthCm = Length<f32, Cm>;
+        let length: LengthCm = Length::new(5.0);
+
+        let result = length - LengthCm::zero();
+
+        assert_eq!(result, length);
+    }
+
+    #[test]
+    fn test_zero_division() {
+        type LengthCm = Length<f32, Cm>;
+        let length: LengthCm = Length::new(5.0);
+        let length_zero: LengthCm = Length::zero();
+
+        let result = length / length_zero;
+
+        let expected: ScaleFactor<f32, Cm, Cm> = ScaleFactor::new(INFINITY);
+        assert_eq!(result, expected);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/lib.rs
@@ -0,0 +1,113 @@
+// 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.
+
+#![cfg_attr(feature = "unstable", feature(asm, repr_simd, test))]
+
+//! 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
+//! the generic Unit parameter.
+//!
+//! This unit system is not mandatory and all Typed* structures have an alias
+//! with the default unit: `UnknownUnit`.
+//! for example ```Point2D<T>``` is equivalent to ```TypedPoint2D<T, UnknownUnit>```.
+//! Client code typically creates a set of aliases for each type and doesn't need
+//! to deal with the specifics of typed units further. For example:
+//!
+//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
+//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
+//!
+//! ```rust
+//! use euclid::*;
+//! pub struct ScreenSpace;
+//! pub type ScreenPoint = TypedPoint2D<f32, ScreenSpace>;
+//! pub type ScreenSize = TypedSize2D<f32, ScreenSpace>;
+//! pub struct WorldSpace;
+//! pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
+//! pub type ProjectionMatrix = TypedMatrix4D<f32, WorldSpace, ScreenSpace>;
+//! // etc...
+//! ```
+//!
+//! Components are accessed in their scalar form by default for convenience, and most
+//! types additionally implement strongly typed accessors which return typed ```Length``` wrappers.
+//! For example:
+//!
+//! ```rust
+//! # use euclid::*;
+//! # pub struct WorldSpace;
+//! # pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
+//! let p = WorldPoint::new(0.0, 1.0, 1.0);
+//! // p.x is an f32.
+//! println!("p.x = {:?} ", p.x);
+//! // p.x is a Length<f32, WorldSpace>.
+//! println!("p.x_typed() = {:?} ", p.x_typed());
+//! // Length::get returns the scalar value (f32).
+//! assert_eq!(p.x, p.x_typed().get());
+//! ```
+
+extern crate heapsize;
+
+#[cfg_attr(test, macro_use)]
+extern crate log;
+extern crate rustc_serialize;
+extern crate serde;
+
+#[cfg(test)]
+extern crate rand;
+#[cfg(feature = "unstable")]
+extern crate test;
+extern crate num_traits;
+
+pub use length::Length;
+pub use scale_factor::ScaleFactor;
+pub use matrix2d::{Matrix2D, TypedMatrix2D};
+pub use matrix4d::{Matrix4D, TypedMatrix4D};
+pub use point::{
+    Point2D, TypedPoint2D,
+    Point3D, TypedPoint3D,
+    Point4D, TypedPoint4D,
+};
+pub use rect::{Rect, TypedRect};
+pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
+#[cfg(feature = "unstable")] pub use side_offsets::SideOffsets2DSimdI32;
+pub use size::{Size2D, TypedSize2D};
+
+pub mod approxeq;
+pub mod length;
+#[macro_use]
+mod macros;
+pub mod matrix2d;
+pub mod matrix4d;
+pub mod num;
+pub mod point;
+pub mod rect;
+pub mod scale_factor;
+pub mod side_offsets;
+pub mod size;
+pub mod trig;
+
+/// The default unit.
+#[derive(Clone, Copy, RustcDecodable, RustcEncodable)]
+pub struct UnknownUnit;
+
+/// Unit for angles in radians.
+pub struct Rad;
+
+/// Unit for angles in degrees.
+pub struct Deg;
+
+/// A value in radians.
+pub type Radians<T> = Length<T, Rad>;
+
+/// A value in Degrees.
+pub type Degrees<T> = Length<T, Deg>;
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/macros.rs
@@ -0,0 +1,87 @@
+// 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.
+
+macro_rules! define_matrix {
+    (
+        $(#[$attr:meta])*
+        pub struct $name:ident<T, $($phantom:ident),+> {
+            $(pub $field:ident: T,)+
+        }
+    ) => (
+        #[repr(C)]
+        $(#[$attr])*
+        pub struct $name<T, $($phantom),+> {
+            $(pub $field: T,)+
+            _unit: PhantomData<($($phantom),+)>
+        }
+
+        impl<T: Clone, $($phantom),+> Clone for $name<T, $($phantom),+> {
+            fn clone(&self) -> Self {
+                $name {
+                    $($field: self.$field.clone(),)+
+                    _unit: PhantomData,
+                }
+            }
+        }
+
+        impl<T: Copy, $($phantom),+> Copy for $name<T, $($phantom),+> {}
+
+        impl<T, $($phantom),+> ::heapsize::HeapSizeOf for $name<T, $($phantom),+>
+            where T: ::heapsize::HeapSizeOf
+        {
+            fn heap_size_of_children(&self) -> usize {
+                $(self.$field.heap_size_of_children() +)+ 0
+            }
+        }
+
+        impl<T, $($phantom),+> ::serde::Deserialize for $name<T, $($phantom),+>
+            where T: ::serde::Deserialize
+        {
+            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+                where D: ::serde::Deserializer
+            {
+                let ($($field,)+) =
+                    try!(::serde::Deserialize::deserialize(deserializer));
+                Ok($name {
+                    $($field: $field,)+
+                    _unit: PhantomData,
+                })
+            }
+        }
+
+        impl<T, $($phantom),+> ::serde::Serialize for $name<T, $($phantom),+>
+            where T: ::serde::Serialize
+        {
+            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+                where S: ::serde::Serializer
+            {
+                ($(&self.$field,)+).serialize(serializer)
+            }
+        }
+
+        impl<T, $($phantom),+> ::std::cmp::Eq for $name<T, $($phantom),+>
+            where T: ::std::cmp::Eq {}
+
+        impl<T, $($phantom),+> ::std::cmp::PartialEq for $name<T, $($phantom),+>
+            where T: ::std::cmp::PartialEq
+        {
+            fn eq(&self, other: &Self) -> bool {
+                true $(&& self.$field == other.$field)+
+            }
+        }
+
+        impl<T, $($phantom),+> ::std::hash::Hash for $name<T, $($phantom),+>
+            where T: ::std::hash::Hash
+        {
+            fn hash<H: ::std::hash::Hasher>(&self, h: &mut H) {
+                $(self.$field.hash(h);)+
+            }
+        }
+    )
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/matrix2d.rs
@@ -0,0 +1,431 @@
+// 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 super::{UnknownUnit, Radians};
+use num::{One, Zero};
+use point::TypedPoint2D;
+use rect::TypedRect;
+use std::ops::{Add, Mul, Div, Sub};
+use std::marker::PhantomData;
+use approxeq::ApproxEq;
+use trig::Trig;
+use std::fmt;
+
+define_matrix! {
+    /// A 2d transform stored as a 2 by 3 matrix in row-major order in memory,
+    /// useful to represent 2d transformations.
+    ///
+    /// Matrices can be parametrized over the source and destination units, to describe a
+    /// transformation from a space to another.
+    /// For example, `TypedMatrix2D<f32, WordSpace, ScreenSpace>::transform_point4d`
+    /// takes a `TypedPoint2D<f32, WordSpace>` and returns a `TypedPoint2D<f32, ScreenSpace>`.
+    ///
+    /// Matrices expose a set of convenience methods for pre- and post-transformations.
+    /// A pre-transformation corresponds to adding an operation that is applied before
+    /// the rest of the transformation, while a post-transformation adds an operation
+    /// that is applied after.
+    pub struct TypedMatrix2D<T, Src, Dst> {
+        pub m11: T, pub m12: T,
+        pub m21: T, pub m22: T,
+        pub m31: T, pub m32: T,
+    }
+}
+
+/// The default 2d matrix type with no units.
+pub type Matrix2D<T> = TypedMatrix2D<T, UnknownUnit, UnknownUnit>;
+
+impl<T: Copy, Src, Dst> TypedMatrix2D<T, Src, Dst> {
+    /// Create a matrix specifying its components in row-major order.
+    pub fn row_major(m11: T, m12: T, m21: T, m22: T, m31: T, m32: T) -> TypedMatrix2D<T, Src, Dst> {
+        TypedMatrix2D {
+            m11: m11, m12: m12,
+            m21: m21, m22: m22,
+            m31: m31, m32: m32,
+            _unit: PhantomData,
+        }
+    }
+
+    /// Create a matrix specifying its components in column-major order.
+    pub fn column_major(m11: T, m21: T, m31: T, m12: T, m22: T, m32: T) -> TypedMatrix2D<T, Src, Dst> {
+        TypedMatrix2D {
+            m11: m11, m12: m12,
+            m21: m21, m22: m22,
+            m31: m31, m32: m32,
+            _unit: PhantomData,
+        }
+    }
+
+    /// Returns an array containing this matrix's terms in row-major order (the order
+    /// in which the matrix is actually laid out in memory).
+    pub fn to_row_major_array(&self) -> [T; 6] {
+        [
+            self.m11, self.m12,
+            self.m21, self.m22,
+            self.m31, self.m32
+        ]
+    }
+
+    /// Returns an array containing this matrix's terms in column-major order.
+    pub fn to_column_major_array(&self) -> [T; 6] {
+        [
+            self.m11, self.m21, self.m31,
+            self.m12, self.m22, self.m32
+        ]
+    }
+
+    /// Drop the units, preserving only the numeric value.
+    pub fn to_untyped(&self) -> Matrix2D<T> {
+        Matrix2D::row_major(
+            self.m11, self.m12,
+            self.m21, self.m22,
+            self.m31, self.m32
+        )
+    }
+
+    /// Tag a unitless value with units.
+    pub fn from_untyped(p: &Matrix2D<T>) -> TypedMatrix2D<T, Src, Dst> {
+        TypedMatrix2D::row_major(
+            p.m11, p.m12,
+            p.m21, p.m22,
+            p.m31, p.m32
+        )
+    }
+}
+
+impl<T, Src, Dst> TypedMatrix2D<T, Src, Dst>
+where T: Copy +
+         PartialEq +
+         One + Zero {
+    pub fn identity() -> TypedMatrix2D<T, Src, Dst> {
+        let (_0, _1) = (Zero::zero(), One::one());
+        TypedMatrix2D::row_major(
+           _1, _0,
+           _0, _1,
+           _0, _0
+        )
+    }
+
+    // Intentional not public, because it checks for exact equivalence
+    // while most consumers will probably want some sort of approximate
+    // equivalence to deal with floating-point errors.
+    fn is_identity(&self) -> bool {
+        *self == TypedMatrix2D::identity()
+    }
+}
+
+impl<T, Src, Dst> TypedMatrix2D<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 multiplication of the two matrices such that mat's transformation
+    /// applies after self's transformation.
+    pub fn post_mul<NewDst>(&self, mat: &TypedMatrix2D<T, Dst, NewDst>) -> TypedMatrix2D<T, Src, NewDst> {
+        TypedMatrix2D::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.
+    pub fn pre_mul<NewSrc>(&self, mat: &TypedMatrix2D<T, NewSrc, Src>) -> TypedMatrix2D<T, NewSrc, Dst> {
+        mat.post_mul(self)
+    }
+
+    /// Returns a translation matrix.
+    pub fn create_translation(x: T, y: T) -> TypedMatrix2D<T, Src, Dst> {
+         let (_0, _1): (T, T) = (Zero::zero(), One::one());
+         TypedMatrix2D::row_major(
+            _1, _0,
+            _0, _1,
+             x,  y
+        )
+    }
+
+    /// Applies a translation after self's transformation and returns the resulting matrix.
+    pub fn post_translated(&self, x: T, y: T) -> TypedMatrix2D<T, Src, Dst> {
+        self.post_mul(&TypedMatrix2D::create_translation(x, y))
+    }
+
+    /// Applies a translation before self's transformation and returns the resulting matrix.
+    pub fn pre_translated(&self, x: T, y: T) -> TypedMatrix2D<T, Src, Dst> {
+        self.pre_mul(&TypedMatrix2D::create_translation(x, y))
+    }
+
+    /// Returns a scale matrix.
+    pub fn create_scale(x: T, y: T) -> TypedMatrix2D<T, Src, Dst> {
+        let _0 = Zero::zero();
+        TypedMatrix2D::row_major(
+             x, _0,
+            _0,  y,
+            _0, _0
+        )
+    }
+
+    /// Applies a scale after self's transformation and returns the resulting matrix.
+    pub fn post_scaled(&self, x: T, y: T) -> TypedMatrix2D<T, Src, Dst> {
+        self.post_mul(&TypedMatrix2D::create_scale(x, y))
+    }
+
+    /// Applies a scale before self's transformation and returns the resulting matrix.
+    pub fn pre_scaled(&self, x: T, y: T) -> TypedMatrix2D<T, Src, Dst> {
+        TypedMatrix2D::row_major(
+            self.m11 * x, self.m12,
+            self.m21,     self.m22 * y,
+            self.m31,     self.m32
+        )
+    }
+
+    /// Returns a rotation matrix.
+    pub fn create_rotation(theta: Radians<T>) -> TypedMatrix2D<T, Src, Dst> {
+        let _0 = Zero::zero();
+        let cos = theta.get().cos();
+        let sin = theta.get().sin();
+        TypedMatrix2D::row_major(
+            cos, _0 - sin,
+            sin, cos,
+             _0, _0
+        )
+    }
+
+    /// Applies a rotation after self's transformation and returns the resulting matrix.
+    pub fn post_rotated(&self, theta: Radians<T>) -> TypedMatrix2D<T, Src, Dst> {
+        self.post_mul(&TypedMatrix2D::create_rotation(theta))
+    }
+
+    /// Applies a rotation after self's transformation and returns the resulting matrix.
+    pub fn pre_rotated(&self, theta: Radians<T>) -> TypedMatrix2D<T, Src, Dst> {
+        self.pre_mul(&TypedMatrix2D::create_rotation(theta))
+    }
+
+    /// Returns the given point transformed by this matrix.
+    #[inline]
+    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 a rectangle that encompasses the result of transforming the given rectangle by this
+    /// matrix.
+    #[inline]
+    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 matrix.
+    pub fn determinant(&self) -> T {
+        self.m11 * self.m22 - self.m12 * self.m21
+    }
+
+    /// Returns the inverse matrix if possible.
+    pub fn inverse(&self) -> Option<TypedMatrix2D<T, Dst, Src>> {
+        let det = self.determinant();
+
+        let _0: T = Zero::zero();
+        let _1: T = One::one();
+
+        if det == _0 {
+          return None;
+        }
+
+        let inv_det = _1 / det;
+        Some(TypedMatrix2D::row_major(
+            inv_det * self.m22,
+            inv_det * (_0 - self.m12),
+            inv_det * (_0 - self.m21),
+            inv_det * self.m11,
+            inv_det * (self.m21 * self.m32 - self.m22 * self.m31),
+            inv_det * (self.m31 * self.m12 - self.m11 * self.m32),
+        ))
+    }
+
+    /// Returns the same matrix with a different destination unit.
+    #[inline]
+    pub fn with_destination<NewDst>(&self) -> TypedMatrix2D<T, Src, NewDst> {
+        TypedMatrix2D::row_major(
+            self.m11, self.m12,
+            self.m21, self.m22,
+            self.m31, self.m32,
+        )
+    }
+
+    /// Returns the same matrix with a different source unit.
+    #[inline]
+    pub fn with_source<NewSrc>(&self) -> TypedMatrix2D<T, NewSrc, Dst> {
+        TypedMatrix2D::row_major(
+            self.m11, self.m12,
+            self.m21, self.m22,
+            self.m31, self.m32,
+        )
+    }
+}
+
+impl<T: ApproxEq<T>, Src, Dst> TypedMatrix2D<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)
+    }
+}
+
+impl<T: Copy + fmt::Debug, Src, Dst> fmt::Debug for TypedMatrix2D<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 {
+            self.to_row_major_array().fmt(f)
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use approxeq::ApproxEq;
+    use point::Point2D;
+    use Radians;
+
+    use std::f32::consts::FRAC_PI_2;
+
+    type Mat = Matrix2D<f32>;
+
+    fn rad(v: f32) -> Radians<f32> { Radians::new(v) }
+
+    #[test]
+    pub fn test_translation() {
+        let t1 = Mat::create_translation(1.0, 2.0);
+        let t2 = Mat::identity().pre_translated(1.0, 2.0);
+        let t3 = Mat::identity().post_translated(1.0, 2.0);
+        assert_eq!(t1, t2);
+        assert_eq!(t1, t3);
+
+        assert_eq!(t1.transform_point(&Point2D::new(1.0, 1.0)), Point2D::new(2.0, 3.0));
+
+        assert_eq!(t1.post_mul(&t1), Mat::create_translation(2.0, 4.0));
+    }
+
+    #[test]
+    pub fn test_rotation() {
+        let r1 = Mat::create_rotation(rad(FRAC_PI_2));
+        let r2 = Mat::identity().pre_rotated(rad(FRAC_PI_2));
+        let r3 = Mat::identity().post_rotated(rad(FRAC_PI_2));
+        assert_eq!(r1, r2);
+        assert_eq!(r1, r3);
+
+        assert!(r1.transform_point(&Point2D::new(1.0, 2.0)).approx_eq(&Point2D::new(2.0, -1.0)));
+
+        assert!(r1.post_mul(&r1).approx_eq(&Mat::create_rotation(rad(FRAC_PI_2*2.0))));
+    }
+
+    #[test]
+    pub fn test_scale() {
+        let s1 = Mat::create_scale(2.0, 3.0);
+        let s2 = Mat::identity().pre_scaled(2.0, 3.0);
+        let s3 = Mat::identity().post_scaled(2.0, 3.0);
+        assert_eq!(s1, s2);
+        assert_eq!(s1, s3);
+
+        assert!(s1.transform_point(&Point2D::new(2.0, 2.0)).approx_eq(&Point2D::new(4.0, 6.0)));
+    }
+
+    #[test]
+    fn test_column_major() {
+        assert_eq!(
+            Mat::row_major(
+                1.0,  2.0,
+                3.0,  4.0,
+                5.0,  6.0
+            ),
+            Mat::column_major(
+                1.0,  3.0,  5.0,
+                2.0,  4.0,  6.0,
+            )
+        );
+    }
+
+    #[test]
+    pub fn test_inverse_simple() {
+        let m1 = Mat::identity();
+        let m2 = m1.inverse().unwrap();
+        assert!(m1.approx_eq(&m2));
+    }
+
+    #[test]
+    pub fn test_inverse_scale() {
+        let m1 = Mat::create_scale(1.5, 0.3);
+        let m2 = m1.inverse().unwrap();
+        assert!(m1.pre_mul(&m2).approx_eq(&Mat::identity()));
+    }
+
+    #[test]
+    pub fn test_inverse_translate() {
+        let m1 = Mat::create_translation(-132.0, 0.3);
+        let m2 = m1.inverse().unwrap();
+        assert!(m1.pre_mul(&m2).approx_eq(&Mat::identity()));
+    }
+
+    #[test]
+    fn test_inverse_none() {
+        assert!(Mat::create_scale(2.0, 0.0).inverse().is_none());
+        assert!(Mat::create_scale(2.0, 2.0).inverse().is_some());
+    }
+
+    #[test]
+    pub fn test_pre_post() {
+        let m1 = Matrix2D::identity().post_scaled(1.0, 2.0).post_translated(1.0, 2.0);
+        let m2 = Matrix2D::identity().pre_translated(1.0, 2.0).pre_scaled(1.0, 2.0);
+        assert!(m1.approx_eq(&m2));
+
+        let r = Mat::create_rotation(rad(FRAC_PI_2));
+        let t = Mat::create_translation(2.0, 3.0);
+
+        let a = Point2D::new(1.0, 1.0);
+
+        assert!(r.post_mul(&t).transform_point(&a).approx_eq(&Point2D::new(3.0, 2.0)));
+        assert!(t.post_mul(&r).transform_point(&a).approx_eq(&Point2D::new(4.0, -3.0)));
+        assert!(t.post_mul(&r).transform_point(&a).approx_eq(&r.transform_point(&t.transform_point(&a))));
+
+        assert!(r.pre_mul(&t).transform_point(&a).approx_eq(&Point2D::new(4.0, -3.0)));
+        assert!(t.pre_mul(&r).transform_point(&a).approx_eq(&Point2D::new(3.0, 2.0)));
+        assert!(t.pre_mul(&r).transform_point(&a).approx_eq(&t.transform_point(&r.transform_point(&a))));
+    }
+
+    #[test]
+    fn test_size_of() {
+        use std::mem::size_of;
+        assert_eq!(size_of::<Matrix2D<f32>>(), 6*size_of::<f32>());
+        assert_eq!(size_of::<Matrix2D<f64>>(), 6*size_of::<f64>());
+    }
+
+    #[test]
+    pub fn test_is_identity() {
+        let m1 = Matrix2D::identity();
+        assert!(m1.is_identity());
+        let m2 = m1.post_translated(0.1, 0.0);
+        assert!(!m2.is_identity());
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/matrix4d.rs
@@ -0,0 +1,825 @@
+// 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 super::{UnknownUnit, Radians};
+use approxeq::ApproxEq;
+use trig::Trig;
+use point::{TypedPoint2D, TypedPoint3D, TypedPoint4D};
+use rect::TypedRect;
+use matrix2d::TypedMatrix2D;
+use scale_factor::ScaleFactor;
+use num::{One, Zero};
+use std::ops::{Add, Mul, Sub, Div, Neg};
+use std::marker::PhantomData;
+use std::fmt;
+
+define_matrix! {
+    /// A 4 by 4 matrix stored in row-major order in memory, useful to represent
+    /// 3d transformations.
+    ///
+    /// Matrices can be parametrized over the source and destination units, to describe a
+    /// transformation from a space to another.
+    /// For example, `TypedMatrix4D<f32, WordSpace, ScreenSpace>::transform_point4d`
+    /// takes a `TypedPoint4D<f32, WordSpace>` and returns a `TypedPoint4D<f32, ScreenSpace>`.
+    ///
+    /// Matrices expose a set of convenience methods for pre- and post-transformations.
+    /// A pre-transformation corresponds to adding an operation that is applied before
+    /// the rest of the transformation, while a post-transformation adds an operation
+    /// that is applied after.
+    pub struct TypedMatrix4D<T, Src, Dst> {
+        pub m11: T, pub m12: T, pub m13: T, pub m14: T,
+        pub m21: T, pub m22: T, pub m23: T, pub m24: T,
+        pub m31: T, pub m32: T, pub m33: T, pub m34: T,
+        pub m41: T, pub m42: T, pub m43: T, pub m44: T,
+    }
+}
+
+/// The default 4d matrix type with no units.
+pub type Matrix4D<T> = TypedMatrix4D<T, UnknownUnit, UnknownUnit>;
+
+impl<T, Src, Dst> TypedMatrix4D<T, Src, Dst> {
+    /// Create a matrix specifying its components in row-major order.
+    ///
+    /// For example, the translation terms m41, m42, m43 on the last row with the
+    /// row-major convention) are the 13rd, 14th and 15th parameters.
+    #[inline]
+    pub fn row_major(
+            m11: T, m12: T, m13: T, m14: T,
+            m21: T, m22: T, m23: T, m24: T,
+            m31: T, m32: T, m33: T, m34: T,
+            m41: T, m42: T, m43: T, m44: T)
+         -> TypedMatrix4D<T, Src, Dst> {
+        TypedMatrix4D {
+            m11: m11, m12: m12, m13: m13, m14: m14,
+            m21: m21, m22: m22, m23: m23, m24: m24,
+            m31: m31, m32: m32, m33: m33, m34: m34,
+            m41: m41, m42: m42, m43: m43, m44: m44,
+            _unit: PhantomData,
+        }
+    }
+
+    /// Create a matrix specifying its components in column-major order.
+    ///
+    /// For example, the translation terms m41, m42, m43 on the last column with the
+    /// column-major convention) are the 4th, 8th and 12nd parameters.
+    #[inline]
+    pub fn column_major(
+            m11: T, m21: T, m31: T, m41: T,
+            m12: T, m22: T, m32: T, m42: T,
+            m13: T, m23: T, m33: T, m43: T,
+            m14: T, m24: T, m34: T, m44: T)
+         -> TypedMatrix4D<T, Src, Dst> {
+        TypedMatrix4D {
+            m11: m11, m12: m12, m13: m13, m14: m14,
+            m21: m21, m22: m22, m23: m23, m24: m24,
+            m31: m31, m32: m32, m33: m33, m34: m34,
+            m41: m41, m42: m42, m43: m43, m44: m44,
+            _unit: PhantomData,
+        }
+    }
+}
+
+impl <T, Src, Dst> TypedMatrix4D<T, Src, Dst>
+where T: Copy + Clone +
+         PartialEq +
+         One + Zero {
+    #[inline]
+    pub fn identity() -> TypedMatrix4D<T, Src, Dst> {
+        let (_0, _1): (T, T) = (Zero::zero(), One::one());
+        TypedMatrix4D::row_major(
+            _1, _0, _0, _0,
+            _0, _1, _0, _0,
+            _0, _0, _1, _0,
+            _0, _0, _0, _1
+        )
+    }
+
+    // Intentional not public, because it checks for exact equivalence
+    // while most consumers will probably want some sort of approximate
+    // equivalence to deal with floating-point errors.
+    #[inline]
+    fn is_identity(&self) -> bool {
+        *self == TypedMatrix4D::identity()
+    }
+}
+
+impl <T, Src, Dst> TypedMatrix4D<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 4 by 4 matrix representing a 2d transformation, specifying its components
+    /// in row-major order.
+    #[inline]
+    pub fn row_major_2d(m11: T, m12: T, m21: T, m22: T, m41: T, m42: T) -> TypedMatrix4D<T, Src, Dst> {
+        let (_0, _1): (T, T) = (Zero::zero(), One::one());
+        TypedMatrix4D::row_major(
+            m11, m12, _0, _0,
+            m21, m22, _0, _0,
+             _0,  _0, _1, _0,
+            m41, m42, _0, _1
+       )
+    }
+
+    /// Create an orthogonal projection matrix.
+    pub fn ortho(left: T, right: T,
+                 bottom: T, top: T,
+                 near: T, far: T) -> TypedMatrix4D<T, Src, Dst> {
+        let tx = -((right + left) / (right - left));
+        let ty = -((top + bottom) / (top - bottom));
+        let tz = -((far + near) / (far - near));
+
+        let (_0, _1): (T, T) = (Zero::zero(), One::one());
+        let _2 = _1 + _1;
+        TypedMatrix4D::row_major(
+            _2 / (right - left), _0                 , _0                , _0,
+            _0                 , _2 / (top - bottom), _0                , _0,
+            _0                 , _0                 , -_2 / (far - near), _0,
+            tx                 , ty                 , tz                , _1
+        )
+    }
+
+    /// Returns true if this matrix can be represented with a TypedMatrix2D.
+    ///
+    /// See https://drafts.csswg.org/css-transforms/#2d-matrix
+    #[inline]
+    pub fn is_2d(&self) -> bool {
+        let (_0, _1): (T, T) = (Zero::zero(), One::one());
+        self.m31 == _0 && self.m32 == _0 &&
+        self.m13 == _0 && self.m23 == _0 &&
+        self.m43 == _0 && self.m14 == _0 &&
+        self.m24 == _0 && self.m34 == _0 &&
+        self.m33 == _1 && self.m44 == _1
+    }
+
+    /// Create a 2D matrix picking the relevent terms from this matrix.
+    ///
+    /// This method assumes that self represents a 2d transformation, callers
+    /// should check that self.is_2d() returns true beforehand.
+    pub fn to_2d(&self) -> TypedMatrix2D<T, Src, Dst> {
+        TypedMatrix2D::row_major(
+            self.m11, self.m12,
+            self.m21, self.m22,
+            self.m41, self.m42
+        )
+    }
+
+    pub fn approx_eq(&self, other: &TypedMatrix4D<T, Src, Dst>) -> bool {
+        self.m11.approx_eq(&other.m11) && self.m12.approx_eq(&other.m12) &&
+        self.m13.approx_eq(&other.m13) && self.m14.approx_eq(&other.m14) &&
+        self.m21.approx_eq(&other.m21) && self.m22.approx_eq(&other.m22) &&
+        self.m23.approx_eq(&other.m23) && self.m24.approx_eq(&other.m24) &&
+        self.m31.approx_eq(&other.m31) && self.m32.approx_eq(&other.m32) &&
+        self.m33.approx_eq(&other.m33) && self.m34.approx_eq(&other.m34) &&
+        self.m41.approx_eq(&other.m41) && self.m42.approx_eq(&other.m42) &&
+        self.m43.approx_eq(&other.m43) && self.m44.approx_eq(&other.m44)
+    }
+
+    /// Returns the same matrix with a different destination unit.
+    #[inline]
+    pub fn with_destination<NewDst>(&self) -> TypedMatrix4D<T, Src, NewDst> {
+        TypedMatrix4D::row_major(
+            self.m11, self.m12, self.m13, self.m14,
+            self.m21, self.m22, self.m23, self.m24,
+            self.m31, self.m32, self.m33, self.m34,
+            self.m41, self.m42, self.m43, self.m44,
+        )
+    }
+
+    /// Returns the same matrix with a different source unit.
+    #[inline]
+    pub fn with_source<NewSrc>(&self) -> TypedMatrix4D<T, NewSrc, Dst> {
+        TypedMatrix4D::row_major(
+            self.m11, self.m12, self.m13, self.m14,
+            self.m21, self.m22, self.m23, self.m24,
+            self.m31, self.m32, self.m33, self.m34,
+            self.m41, self.m42, self.m43, self.m44,
+        )
+    }
+
+    /// Drop the units, preserving only the numeric value.
+    #[inline]
+    pub fn to_untyped(&self) -> Matrix4D<T> {
+        Matrix4D::row_major(
+            self.m11, self.m12, self.m13, self.m14,
+            self.m21, self.m22, self.m23, self.m24,
+            self.m31, self.m32, self.m33, self.m34,
+            self.m41, self.m42, self.m43, self.m44,
+        )
+    }
+
+    /// Tag a unitless value with units.
+    #[inline]
+    pub fn from_untyped(m: &Matrix4D<T>) -> Self {
+        TypedMatrix4D::row_major(
+            m.m11, m.m12, m.m13, m.m14,
+            m.m21, m.m22, m.m23, m.m24,
+            m.m31, m.m32, m.m33, m.m34,
+            m.m41, m.m42, m.m43, m.m44,
+        )
+    }
+
+    /// Returns the multiplication of the two matrices such that mat's transformation
+    /// applies after self's transformation.
+    pub fn post_mul<NewDst>(&self, mat: &TypedMatrix4D<T, Dst, NewDst>) -> TypedMatrix4D<T, Src, NewDst> {
+        TypedMatrix4D::row_major(
+            self.m11 * mat.m11  +  self.m12 * mat.m21  +  self.m13 * mat.m31  +  self.m14 * mat.m41,
+            self.m11 * mat.m12  +  self.m12 * mat.m22  +  self.m13 * mat.m32  +  self.m14 * mat.m42,
+            self.m11 * mat.m13  +  self.m12 * mat.m23  +  self.m13 * mat.m33  +  self.m14 * mat.m43,
+            self.m11 * mat.m14  +  self.m12 * mat.m24  +  self.m13 * mat.m34  +  self.m14 * mat.m44,
+            self.m21 * mat.m11  +  self.m22 * mat.m21  +  self.m23 * mat.m31  +  self.m24 * mat.m41,
+            self.m21 * mat.m12  +  self.m22 * mat.m22  +  self.m23 * mat.m32  +  self.m24 * mat.m42,
+            self.m21 * mat.m13  +  self.m22 * mat.m23  +  self.m23 * mat.m33  +  self.m24 * mat.m43,
+            self.m21 * mat.m14  +  self.m22 * mat.m24  +  self.m23 * mat.m34  +  self.m24 * mat.m44,
+            self.m31 * mat.m11  +  self.m32 * mat.m21  +  self.m33 * mat.m31  +  self.m34 * mat.m41,
+            self.m31 * mat.m12  +  self.m32 * mat.m22  +  self.m33 * mat.m32  +  self.m34 * mat.m42,
+            self.m31 * mat.m13  +  self.m32 * mat.m23  +  self.m33 * mat.m33  +  self.m34 * mat.m43,
+            self.m31 * mat.m14  +  self.m32 * mat.m24  +  self.m33 * mat.m34  +  self.m34 * mat.m44,
+            self.m41 * mat.m11  +  self.m42 * mat.m21  +  self.m43 * mat.m31  +  self.m44 * mat.m41,
+            self.m41 * mat.m12  +  self.m42 * mat.m22  +  self.m43 * mat.m32  +  self.m44 * mat.m42,
+            self.m41 * mat.m13  +  self.m42 * mat.m23  +  self.m43 * mat.m33  +  self.m44 * mat.m43,
+            self.m41 * mat.m14  +  self.m42 * mat.m24  +  self.m43 * mat.m34  +  self.m44 * mat.m44,
+        )
+    }
+
+    /// Returns the multiplication of the two matrices such that mat's transformation
+    /// applies before self's transformation.
+    pub fn pre_mul<NewSrc>(&self, mat: &TypedMatrix4D<T, NewSrc, Src>) -> TypedMatrix4D<T, NewSrc, Dst> {
+        mat.post_mul(self)
+    }
+
+    /// Returns the inverse matrix if possible.
+    pub fn inverse(&self) -> Option<TypedMatrix4D<T, Dst, Src>> {
+        let det = self.determinant();
+
+        if det == Zero::zero() {
+            return None;
+        }
+
+        // todo(gw): this could be made faster by special casing
+        // for simpler matrix types.
+        let m = TypedMatrix4D::row_major(
+            self.m23*self.m34*self.m42 - self.m24*self.m33*self.m42 +
+            self.m24*self.m32*self.m43 - self.m22*self.m34*self.m43 -
+            self.m23*self.m32*self.m44 + self.m22*self.m33*self.m44,
+
+            self.m14*self.m33*self.m42 - self.m13*self.m34*self.m42 -
+            self.m14*self.m32*self.m43 + self.m12*self.m34*self.m43 +
+            self.m13*self.m32*self.m44 - self.m12*self.m33*self.m44,
+
+            self.m13*self.m24*self.m42 - self.m14*self.m23*self.m42 +
+            self.m14*self.m22*self.m43 - self.m12*self.m24*self.m43 -
+            self.m13*self.m22*self.m44 + self.m12*self.m23*self.m44,
+
+            self.m14*self.m23*self.m32 - self.m13*self.m24*self.m32 -
+            self.m14*self.m22*self.m33 + self.m12*self.m24*self.m33 +
+            self.m13*self.m22*self.m34 - self.m12*self.m23*self.m34,
+
+            self.m24*self.m33*self.m41 - self.m23*self.m34*self.m41 -
+            self.m24*self.m31*self.m43 + self.m21*self.m34*self.m43 +
+            self.m23*self.m31*self.m44 - self.m21*self.m33*self.m44,
+
+            self.m13*self.m34*self.m41 - self.m14*self.m33*self.m41 +
+            self.m14*self.m31*self.m43 - self.m11*self.m34*self.m43 -
+            self.m13*self.m31*self.m44 + self.m11*self.m33*self.m44,
+
+            self.m14*self.m23*self.m41 - self.m13*self.m24*self.m41 -
+            self.m14*self.m21*self.m43 + self.m11*self.m24*self.m43 +
+            self.m13*self.m21*self.m44 - self.m11*self.m23*self.m44,
+
+            self.m13*self.m24*self.m31 - self.m14*self.m23*self.m31 +
+            self.m14*self.m21*self.m33 - self.m11*self.m24*self.m33 -
+            self.m13*self.m21*self.m34 + self.m11*self.m23*self.m34,
+
+            self.m22*self.m34*self.m41 - self.m24*self.m32*self.m41 +
+            self.m24*self.m31*self.m42 - self.m21*self.m34*self.m42 -
+            self.m22*self.m31*self.m44 + self.m21*self.m32*self.m44,
+
+            self.m14*self.m32*self.m41 - self.m12*self.m34*self.m41 -
+            self.m14*self.m31*self.m42 + self.m11*self.m34*self.m42 +
+            self.m12*self.m31*self.m44 - self.m11*self.m32*self.m44,
+
+            self.m12*self.m24*self.m41 - self.m14*self.m22*self.m41 +
+            self.m14*self.m21*self.m42 - self.m11*self.m24*self.m42 -
+            self.m12*self.m21*self.m44 + self.m11*self.m22*self.m44,
+
+            self.m14*self.m22*self.m31 - self.m12*self.m24*self.m31 -
+            self.m14*self.m21*self.m32 + self.m11*self.m24*self.m32 +
+            self.m12*self.m21*self.m34 - self.m11*self.m22*self.m34,
+
+            self.m23*self.m32*self.m41 - self.m22*self.m33*self.m41 -
+            self.m23*self.m31*self.m42 + self.m21*self.m33*self.m42 +
+            self.m22*self.m31*self.m43 - self.m21*self.m32*self.m43,
+
+            self.m12*self.m33*self.m41 - self.m13*self.m32*self.m41 +
+            self.m13*self.m31*self.m42 - self.m11*self.m33*self.m42 -
+            self.m12*self.m31*self.m43 + self.m11*self.m32*self.m43,
+
+            self.m13*self.m22*self.m41 - self.m12*self.m23*self.m41 -
+            self.m13*self.m21*self.m42 + self.m11*self.m23*self.m42 +
+            self.m12*self.m21*self.m43 - self.m11*self.m22*self.m43,
+
+            self.m12*self.m23*self.m31 - self.m13*self.m22*self.m31 +
+            self.m13*self.m21*self.m32 - self.m11*self.m23*self.m32 -
+            self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33
+        );
+
+        let _1: T = One::one();
+        Some(m.mul_s(_1 / det))
+    }
+
+    /// Compute the determinant of the matrix.
+    pub fn determinant(&self) -> T {
+        self.m14 * self.m23 * self.m32 * self.m41 -
+        self.m13 * self.m24 * self.m32 * self.m41 -
+        self.m14 * self.m22 * self.m33 * self.m41 +
+        self.m12 * self.m24 * self.m33 * self.m41 +
+        self.m13 * self.m22 * self.m34 * self.m41 -
+        self.m12 * self.m23 * self.m34 * self.m41 -
+        self.m14 * self.m23 * self.m31 * self.m42 +
+        self.m13 * self.m24 * self.m31 * self.m42 +
+        self.m14 * self.m21 * self.m33 * self.m42 -
+        self.m11 * self.m24 * self.m33 * self.m42 -
+        self.m13 * self.m21 * self.m34 * self.m42 +
+        self.m11 * self.m23 * self.m34 * self.m42 +
+        self.m14 * self.m22 * self.m31 * self.m43 -
+        self.m12 * self.m24 * self.m31 * self.m43 -
+        self.m14 * self.m21 * self.m32 * self.m43 +
+        self.m11 * self.m24 * self.m32 * self.m43 +
+        self.m12 * self.m21 * self.m34 * self.m43 -
+        self.m11 * self.m22 * self.m34 * self.m43 -
+        self.m13 * self.m22 * self.m31 * self.m44 +
+        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 matrix's component by a scalar and returns the result.
+    pub fn mul_s(&self, x: T) -> TypedMatrix4D<T, Src, Dst> {
+        TypedMatrix4D::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
+        )
+    }
+
+    /// Convenience function to create a scale matrix from a ScaleFactor.
+    pub fn from_scale_factor(scale: ScaleFactor<T, Src, Dst>) -> TypedMatrix4D<T, Src, Dst> {
+        TypedMatrix4D::create_scale(scale.get(), scale.get(), scale.get())
+    }
+
+    /// Returns the given 2d point transformed by this matrix.
+    ///
+    /// The input point must be use the unit Src, and the returned point has the unit Dst.
+    #[inline]
+    pub fn transform_point(&self, p: &TypedPoint2D<T, Src>) -> TypedPoint2D<T, Dst> {
+        self.transform_point4d(&TypedPoint4D::new(p.x, p.y, Zero::zero(), One::one())).to_2d()
+    }
+
+    /// Returns the given 3d point transformed by this matrix.
+    ///
+    /// The input point must be use the unit Src, and the returned point has the unit Dst.
+    #[inline]
+    pub fn transform_point3d(&self, p: &TypedPoint3D<T, Src>) -> TypedPoint3D<T, Dst> {
+        self.transform_point4d(&TypedPoint4D::new(p.x, p.y, p.z, One::one())).to_3d()
+    }
+
+    /// Returns the given 4d point transformed by this matrix.
+    ///
+    /// The input point must be use the unit Src, and the returned point has the unit Dst.
+    #[inline]
+    pub fn transform_point4d(&self, p: &TypedPoint4D<T, Src>) -> TypedPoint4D<T, Dst> {
+        let x = p.x * self.m11 + p.y * self.m21 + p.z * self.m31 + p.w * self.m41;
+        let y = p.x * self.m12 + p.y * self.m22 + p.z * self.m32 + p.w * self.m42;
+        let z = p.x * self.m13 + p.y * self.m23 + p.z * self.m33 + p.w * self.m43;
+        let w = p.x * self.m14 + p.y * self.m24 + p.z * self.m34 + p.w * self.m44;
+        TypedPoint4D::new(x, y, z, w)
+    }
+
+    /// Returns a rectangle that encompasses the result of transforming the given rectangle by this
+    /// matrix.
+    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()),
+        ])
+    }
+
+    /// Create a 3d translation matrix
+    pub fn create_translation(x: T, y: T, z: T) -> TypedMatrix4D<T, Src, Dst> {
+        let (_0, _1): (T, T) = (Zero::zero(), One::one());
+        TypedMatrix4D::row_major(
+            _1, _0, _0, _0,
+            _0, _1, _0, _0,
+            _0, _0, _1, _0,
+             x,  y,  z, _1
+        )
+    }
+
+    /// Returns a matrix with a translation applied before self's transformation.
+    pub fn pre_translated(&self, x: T, y: T, z: T) -> TypedMatrix4D<T, Src, Dst> {
+        self.pre_mul(&TypedMatrix4D::create_translation(x, y, z))
+    }
+
+    /// Returns a matrix with a translation applied after self's transformation.
+    pub fn post_translated(&self, x: T, y: T, z: T) -> TypedMatrix4D<T, Src, Dst> {
+        self.post_mul(&TypedMatrix4D::create_translation(x, y, z))
+    }
+
+    /// Create a 3d scale matrix
+    pub fn create_scale(x: T, y: T, z: T) -> TypedMatrix4D<T, Src, Dst> {
+        let (_0, _1): (T, T) = (Zero::zero(), One::one());
+        TypedMatrix4D::row_major(
+             x, _0, _0, _0,
+            _0,  y, _0, _0,
+            _0, _0,  z, _0,
+            _0, _0, _0, _1
+        )
+    }
+
+    /// Returns a matrix with a scale applied before self's transformation.
+    pub fn pre_scaled(&self, x: T, y: T, z: T) -> TypedMatrix4D<T, Src, Dst> {
+        TypedMatrix4D::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 matrix with a scale applied after self's transformation.
+    pub fn post_scaled(&self, x: T, y: T, z: T) -> TypedMatrix4D<T, Src, Dst> {
+        self.post_mul(&TypedMatrix4D::create_scale(x, y, z))
+    }
+
+    /// Create a 3d rotation matrix from an angle / axis.
+    /// The supplied axis must be normalized.
+    pub fn create_rotation(x: T, y: T, z: T, theta: Radians<T>) -> TypedMatrix4D<T, Src, Dst> {
+        let (_0, _1): (T, T) = (Zero::zero(), One::one());
+        let _2 = _1 + _1;
+
+        let xx = x * x;
+        let yy = y * y;
+        let zz = z * z;
+
+        let half_theta = theta.get() / _2;
+        let sc = half_theta.sin() * half_theta.cos();
+        let sq = half_theta.sin() * half_theta.sin();
+
+        TypedMatrix4D::row_major(
+            _1 - _2 * (yy + zz) * sq,
+            _2 * (x * y * sq - z * sc),
+            _2 * (x * z * sq + y * sc),
+            _0,
+
+            _2 * (x * y * sq + z * sc),
+            _1 - _2 * (xx + zz) * sq,
+            _2 * (y * z * sq - x * sc),
+            _0,
+
+            _2 * (x * z * sq - y * sc),
+            _2 * (y * z * sq + x * sc),
+            _1 - _2 * (xx + yy) * sq,
+            _0,
+
+            _0,
+            _0,
+            _0,
+            _1
+        )
+    }
+
+    /// Returns a matrix with a rotation applied after self's transformation.
+    pub fn post_rotated(&self, x: T, y: T, z: T, theta: Radians<T>) -> TypedMatrix4D<T, Src, Dst> {
+        self.post_mul(&TypedMatrix4D::create_rotation(x, y, z, theta))
+    }
+
+    /// Returns a matrix with a rotation applied before self's transformation.
+    pub fn pre_rotated(&self, x: T, y: T, z: T, theta: Radians<T>) -> TypedMatrix4D<T, Src, Dst> {
+        self.pre_mul(&TypedMatrix4D::create_rotation(x, y, z, theta))
+    }
+
+    /// Create a 2d skew matrix.
+    ///
+    /// See https://drafts.csswg.org/css-transforms/#funcdef-skew
+    pub fn create_skew(alpha: Radians<T>, beta: Radians<T>) -> TypedMatrix4D<T, Src, Dst> {
+        let (_0, _1): (T, T) = (Zero::zero(), One::one());
+        let (sx, sy) = (beta.get().tan(), alpha.get().tan());
+        TypedMatrix4D::row_major(
+            _1, sx, _0, _0,
+            sy, _1, _0, _0,
+            _0, _0, _1, _0,
+            _0, _0, _0, _1
+        )
+    }
+
+    /// Create a simple perspective projection matrix
+    pub fn create_perspective(d: T) -> TypedMatrix4D<T, Src, Dst> {
+        let (_0, _1): (T, T) = (Zero::zero(), One::one());
+        TypedMatrix4D::row_major(
+            _1, _0, _0, _0,
+            _0, _1, _0, _0,
+            _0, _0, _1, -_1 / d,
+            _0, _0, _0, _1
+        )
+    }
+}
+
+impl<T: Copy, Src, Dst> TypedMatrix4D<T, Src, Dst> {
+    /// Returns an array containing this matrix's terms in row-major order (the order
+    /// in which the matrix is actually laid out in memory).
+    pub fn to_row_major_array(&self) -> [T; 16] {
+        [
+            self.m11, self.m12, self.m13, self.m14,
+            self.m21, self.m22, self.m23, self.m24,
+            self.m31, self.m32, self.m33, self.m34,
+            self.m41, self.m42, self.m43, self.m44
+        ]
+    }
+
+    /// Returns an array containing this matrix's terms in column-major order.
+    pub fn to_column_major_array(&self) -> [T; 16] {
+        [
+            self.m11, self.m21, self.m31, self.m41,
+            self.m12, self.m22, self.m32, self.m42,
+            self.m13, self.m23, self.m33, self.m43,
+            self.m14, self.m24, self.m34, self.m44
+        ]
+    }
+
+    /// Returns an array containing this matrix's 4 rows in (in row-major order)
+    /// as arrays.
+    ///
+    /// This is a convenience method to interface with other libraries like glium.
+    pub fn to_row_arrays(&self) -> [[T; 4];4] {
+        [
+            [self.m11, self.m12, self.m13, self.m14],
+            [self.m21, self.m22, self.m23, self.m24],
+            [self.m31, self.m32, self.m33, self.m34],
+            [self.m41, self.m42, self.m43, self.m44]
+        ]
+    }
+
+    /// Returns an array containing this matrix's 4 columns in (in row-major order,
+    /// or 4 rows in column-major order) as arrays.
+    ///
+    /// This is a convenience method to interface with other libraries like glium.
+    pub fn to_column_arrays(&self) -> [[T; 4]; 4] {
+        [
+            [self.m11, self.m21, self.m31, self.m41],
+            [self.m12, self.m22, self.m32, self.m42],
+            [self.m13, self.m23, self.m33, self.m43],
+            [self.m14, self.m24, self.m34, self.m44]
+        ]
+    }
+}
+
+impl<T, Src, Dst> fmt::Debug for TypedMatrix4D<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 {
+            self.to_row_major_array().fmt(f)
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use approxeq::ApproxEq;
+    use matrix2d::Matrix2D;
+    use point::{Point2D, Point3D, Point4D};
+    use Radians;
+    use super::*;
+
+    use std::f32::consts::FRAC_PI_2;
+
+    type Mf32 = Matrix4D<f32>;
+
+    // For convenience.
+    fn rad(v: f32) -> Radians<f32> { Radians::new(v) }
+
+    #[test]
+    pub fn test_translation() {
+        let t1 = Mf32::create_translation(1.0, 2.0, 3.0);
+        let t2 = Mf32::identity().pre_translated(1.0, 2.0, 3.0);
+        let t3 = Mf32::identity().post_translated(1.0, 2.0, 3.0);
+        assert_eq!(t1, t2);
+        assert_eq!(t1, t3);
+
+        assert_eq!(t1.transform_point3d(&Point3D::new(1.0, 1.0, 1.0)), Point3D::new(2.0, 3.0, 4.0));
+        assert_eq!(t1.transform_point(&Point2D::new(1.0, 1.0)), Point2D::new(2.0, 3.0));
+
+        assert_eq!(t1.post_mul(&t1), Mf32::create_translation(2.0, 4.0, 6.0));
+
+        assert!(!t1.is_2d());
+        assert_eq!(Mf32::create_translation(1.0, 2.0, 3.0).to_2d(), Matrix2D::create_translation(1.0, 2.0));
+    }
+
+    #[test]
+    pub fn test_rotation() {
+        let r1 = Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2));
+        let r2 = Mf32::identity().pre_rotated(0.0, 0.0, 1.0, rad(FRAC_PI_2));
+        let r3 = Mf32::identity().post_rotated(0.0, 0.0, 1.0, rad(FRAC_PI_2));
+        assert_eq!(r1, r2);
+        assert_eq!(r1, r3);
+
+        assert!(r1.transform_point3d(&Point3D::new(1.0, 2.0, 3.0)).approx_eq(&Point3D::new(2.0, -1.0, 3.0)));
+        assert!(r1.transform_point(&Point2D::new(1.0, 2.0)).approx_eq(&Point2D::new(2.0, -1.0)));
+
+        assert!(r1.post_mul(&r1).approx_eq(&Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2*2.0))));
+
+        assert!(r1.is_2d());
+        assert!(r1.to_2d().approx_eq(&Matrix2D::create_rotation(rad(FRAC_PI_2))));
+    }
+
+    #[test]
+    pub fn test_scale() {
+        let s1 = Mf32::create_scale(2.0, 3.0, 4.0);
+        let s2 = Mf32::identity().pre_scaled(2.0, 3.0, 4.0);
+        let s3 = Mf32::identity().post_scaled(2.0, 3.0, 4.0);
+        assert_eq!(s1, s2);
+        assert_eq!(s1, s3);
+
+        assert!(s1.transform_point3d(&Point3D::new(2.0, 2.0, 2.0)).approx_eq(&Point3D::new(4.0, 6.0, 8.0)));
+        assert!(s1.transform_point(&Point2D::new(2.0, 2.0)).approx_eq(&Point2D::new(4.0, 6.0)));
+
+        assert_eq!(s1.post_mul(&s1), Mf32::create_scale(4.0, 9.0, 16.0));
+
+        assert!(!s1.is_2d());
+        assert_eq!(Mf32::create_scale(2.0, 3.0, 0.0).to_2d(), Matrix2D::create_scale(2.0, 3.0));
+    }
+
+    #[test]
+    pub fn test_ortho() {
+        let (left, right, bottom, top) = (0.0f32, 1.0f32, 0.1f32, 1.0f32);
+        let (near, far) = (-1.0f32, 1.0f32);
+        let result = Mf32::ortho(left, right, bottom, top, near, far);
+        let expected = Mf32::row_major(
+             2.0,  0.0,         0.0, 0.0,
+             0.0,  2.22222222,  0.0, 0.0,
+             0.0,  0.0,        -1.0, 0.0,
+            -1.0, -1.22222222, -0.0, 1.0
+        );
+        debug!("result={:?} expected={:?}", result, expected);
+        assert!(result.approx_eq(&expected));
+    }
+
+    #[test]
+    pub fn test_is_2d() {
+        assert!(Mf32::identity().is_2d());
+        assert!(Mf32::create_rotation(0.0, 0.0, 1.0, rad(0.7854)).is_2d());
+        assert!(!Mf32::create_rotation(0.0, 1.0, 0.0, rad(0.7854)).is_2d());
+    }
+
+    #[test]
+    pub fn test_row_major_2d() {
+        let m1 = Mf32::row_major_2d(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
+        let m2 = Mf32::row_major(
+            1.0, 2.0, 0.0, 0.0,
+            3.0, 4.0, 0.0, 0.0,
+            0.0, 0.0, 1.0, 0.0,
+            5.0, 6.0, 0.0, 1.0
+        );
+        assert_eq!(m1, m2);
+    }
+
+    #[test]
+    fn test_column_major() {
+        assert_eq!(
+            Mf32::row_major(
+                1.0,  2.0,  3.0,  4.0,
+                5.0,  6.0,  7.0,  8.0,
+                9.0,  10.0, 11.0, 12.0,
+                13.0, 14.0, 15.0, 16.0,
+            ),
+            Mf32::column_major(
+                1.0,  5.0,  9.0,  13.0,
+                2.0,  6.0,  10.0, 14.0,
+                3.0,  7.0,  11.0, 15.0,
+                4.0,  8.0,  12.0, 16.0,
+            )
+        );
+    }
+
+    #[test]
+    pub fn test_inverse_simple() {
+        let m1 = Mf32::identity();
+        let m2 = m1.inverse().unwrap();
+        assert!(m1.approx_eq(&m2));
+    }
+
+    #[test]
+    pub fn test_inverse_scale() {
+        let m1 = Mf32::create_scale(1.5, 0.3, 2.1);
+        let m2 = m1.inverse().unwrap();
+        assert!(m1.pre_mul(&m2).approx_eq(&Mf32::identity()));
+    }
+
+    #[test]
+    pub fn test_inverse_translate() {
+        let m1 = Mf32::create_translation(-132.0, 0.3, 493.0);
+        let m2 = m1.inverse().unwrap();
+        assert!(m1.pre_mul(&m2).approx_eq(&Mf32::identity()));
+    }
+
+    #[test]
+    pub fn test_inverse_rotate() {
+        let m1 = Mf32::create_rotation(0.0, 1.0, 0.0, rad(1.57));
+        let m2 = m1.inverse().unwrap();
+        assert!(m1.pre_mul(&m2).approx_eq(&Mf32::identity()));
+    }
+
+    #[test]
+    pub fn test_inverse_transform_point_2d() {
+        let m1 = Mf32::create_translation(100.0, 200.0, 0.0);
+        let m2 = m1.inverse().unwrap();
+        assert!(m1.pre_mul(&m2).approx_eq(&Mf32::identity()));
+
+        let p1 = Point2D::new(1000.0, 2000.0);
+        let p2 = m1.transform_point(&p1);
+        assert!(p2.eq(&Point2D::new(1100.0, 2200.0)));
+
+        let p3 = m2.transform_point(&p2);
+        assert!(p3.eq(&p1));
+    }
+
+    #[test]
+    fn test_inverse_none() {
+        assert!(Mf32::create_scale(2.0, 0.0, 2.0).inverse().is_none());
+        assert!(Mf32::create_scale(2.0, 2.0, 2.0).inverse().is_some());
+    }
+
+    #[test]
+    pub fn test_pre_post() {
+        let m1 = Matrix4D::identity().post_scaled(1.0, 2.0, 3.0).post_translated(1.0, 2.0, 3.0);
+        let m2 = Matrix4D::identity().pre_translated(1.0, 2.0, 3.0).pre_scaled(1.0, 2.0, 3.0);
+        assert!(m1.approx_eq(&m2));
+
+        let r = Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2));
+        let t = Mf32::create_translation(2.0, 3.0, 0.0);
+
+        let a = Point3D::new(1.0, 1.0, 1.0);
+
+        assert!(r.post_mul(&t).transform_point3d(&a).approx_eq(&Point3D::new(3.0, 2.0, 1.0)));
+        assert!(t.post_mul(&r).transform_point3d(&a).approx_eq(&Point3D::new(4.0, -3.0, 1.0)));
+        assert!(t.post_mul(&r).transform_point3d(&a).approx_eq(&r.transform_point3d(&t.transform_point3d(&a))));
+
+        assert!(r.pre_mul(&t).transform_point3d(&a).approx_eq(&Point3D::new(4.0, -3.0, 1.0)));
+        assert!(t.pre_mul(&r).transform_point3d(&a).approx_eq(&Point3D::new(3.0, 2.0, 1.0)));
+        assert!(t.pre_mul(&r).transform_point3d(&a).approx_eq(&t.transform_point3d(&r.transform_point3d(&a))));
+    }
+
+    #[test]
+    fn test_size_of() {
+        use std::mem::size_of;
+        assert_eq!(size_of::<Matrix4D<f32>>(), 16*size_of::<f32>());
+        assert_eq!(size_of::<Matrix4D<f64>>(), 16*size_of::<f64>());
+    }
+
+    #[test]
+    pub fn test_transform_associativity() {
+        let m1 = Mf32::row_major(3.0, 2.0, 1.5, 1.0,
+                                 0.0, 4.5, -1.0, -4.0,
+                                 0.0, 3.5, 2.5, 40.0,
+                                 0.0, 3.0, 0.0, 1.0);
+        let m2 = Mf32::row_major(1.0, -1.0, 3.0, 0.0,
+                                 -1.0, 0.5, 0.0, 2.0,
+                                 1.5, -2.0, 6.0, 0.0,
+                                 -2.5, 6.0, 1.0, 1.0);
+
+        let p = Point4D::new(1.0, 3.0, 5.0, 1.0);
+        let p1 = m2.pre_mul(&m1).transform_point4d(&p);
+        let p2 = m2.transform_point4d(&m1.transform_point4d(&p));
+        assert!(p1.approx_eq(&p2));
+    }
+
+    #[test]
+    pub fn test_is_identity() {
+        let m1 = Matrix4D::identity();
+        assert!(m1.is_identity());
+        let m2 = m1.post_translated(0.1, 0.0, 0.0);
+        assert!(!m2.is_identity());
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/num.rs
@@ -0,0 +1,66 @@
+// Copyright 2014 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.
+//! A one-dimensional length, tagged with its units.
+
+use num_traits;
+
+
+pub trait Zero {
+    fn zero() -> Self;
+}
+
+impl<T: num_traits::Zero> Zero for T {
+    fn zero() -> T { num_traits::Zero::zero() }
+}
+
+pub trait One {
+    fn one() -> Self;
+}
+
+impl<T: num_traits::One> One for T {
+    fn one() -> T { num_traits::One::one() }
+}
+
+pub trait Round : Copy { fn round(self) -> Self; }
+pub trait Floor : Copy { fn floor(self) -> Self; }
+pub trait Ceil : Copy { fn ceil(self) -> Self; }
+
+impl Round for f32 { fn round(self) -> Self { self.round() } }
+impl Round for f64 { fn round(self) -> Self { self.round() } }
+impl Round for i16 { fn round(self) -> Self { self } }
+impl Round for u16 { fn round(self) -> Self { self } }
+impl Round for i32 { fn round(self) -> Self { self } }
+impl Round for i64 { fn round(self) -> Self { self } }
+impl Round for u32 { fn round(self) -> Self { self } }
+impl Round for u64 { fn round(self) -> Self { self } }
+impl Round for usize { fn round(self) -> Self { self } }
+impl Round for isize { fn round(self) -> Self { self } }
+
+impl Floor for f32 { fn floor(self) -> Self { self.floor() } }
+impl Floor for f64 { fn floor(self) -> Self { self.floor() } }
+impl Floor for i16 { fn floor(self) -> Self { self } }
+impl Floor for u16 { fn floor(self) -> Self { self } }
+impl Floor for i32 { fn floor(self) -> Self { self } }
+impl Floor for i64 { fn floor(self) -> Self { self } }
+impl Floor for u32 { fn floor(self) -> Self { self } }
+impl Floor for u64 { fn floor(self) -> Self { self } }
+impl Floor for usize { fn floor(self) -> Self { self } }
+impl Floor for isize { fn floor(self) -> Self { self } }
+
+impl Ceil for f32 { fn ceil(self) -> Self { self.ceil() } }
+impl Ceil for f64 { fn ceil(self) -> Self { self.ceil() } }
+impl Ceil for i16 { fn ceil(self) -> Self { self } }
+impl Ceil for u16 { fn ceil(self) -> Self { self } }
+impl Ceil for i32 { fn ceil(self) -> Self { self } }
+impl Ceil for i64 { fn ceil(self) -> Self { self } }
+impl Ceil for u32 { fn ceil(self) -> Self { self } }
+impl Ceil for u64 { fn ceil(self) -> Self { self } }
+impl Ceil for usize { fn ceil(self) -> Self { self } }
+impl Ceil for isize { fn ceil(self) -> Self { self } }
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/point.rs
@@ -0,0 +1,995 @@
+// 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 super::UnknownUnit;
+use approxeq::ApproxEq;
+use length::Length;
+use scale_factor::ScaleFactor;
+use size::TypedSize2D;
+use num::*;
+use num_traits::{Float, NumCast};
+use std::fmt;
+use std::ops::{Add, Neg, Mul, Sub, Div};
+use std::marker::PhantomData;
+
+define_matrix! {
+    /// A 2d Point tagged with a unit.
+    #[derive(RustcDecodable, RustcEncodable)]
+    pub struct TypedPoint2D<T, U> {
+        pub x: T,
+        pub y: T,
+    }
+}
+
+/// Default 2d point type with no unit.
+///
+/// `Point2D` provides the same methods as `TypedPoint2D`.
+pub type Point2D<T> = TypedPoint2D<T, UnknownUnit>;
+
+impl<T: Copy + Zero, U> TypedPoint2D<T, U> {
+    /// Constructor, setting all components to zero.
+    #[inline]
+    pub fn zero() -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(Zero::zero(), Zero::zero())
+    }
+
+    /// Convert into a 3d point.
+    #[inline]
+    pub fn to_3d(&self) -> TypedPoint3D<T, U> {
+        TypedPoint3D::new(self.x, self.y, Zero::zero())
+    }
+}
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedPoint2D<T, U> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "({:?},{:?})", self.x, self.y)
+    }
+}
+
+impl<T: fmt::Display, U> fmt::Display for TypedPoint2D<T, U> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        write!(formatter, "({},{})", self.x, self.y)
+    }
+}
+
+impl<T: Copy, U> TypedPoint2D<T, U> {
+    /// Constructor taking scalar values directly.
+    #[inline]
+    pub fn new(x: T, y: T) -> TypedPoint2D<T, U> {
+        TypedPoint2D { x: x, y: y, _unit: PhantomData }
+    }
+
+    /// Constructor taking properly typed Lengths instead of scalar values.
+    #[inline]
+    pub fn from_lengths(x: Length<T, U>, y: Length<T, U>) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(x.0, y.0)
+    }
+
+    /// Returns self.x as a Length carrying the unit.
+    #[inline]
+    pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
+
+    /// Returns self.y as a Length carrying the unit.
+    #[inline]
+    pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
+
+    /// Drop the units, preserving only the numeric value.
+    #[inline]
+    pub fn to_untyped(&self) -> Point2D<T> {
+        TypedPoint2D::new(self.x, self.y)
+    }
+
+    /// Tag a unitless value with units.
+    #[inline]
+    pub fn from_untyped(p: &Point2D<T>) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(p.x, p.y)
+    }
+
+    #[inline]
+    pub fn to_array(&self) -> [T; 2] {
+        [self.x, self.y]
+    }
+}
+
+impl<T, U> TypedPoint2D<T, U>
+where T: Copy + Mul<T, Output=T> + Add<T, Output=T> + Sub<T, Output=T> {
+    /// Dot product.
+    #[inline]
+    pub fn dot(self, other: TypedPoint2D<T, U>) -> T {
+        self.x * other.x + self.y * other.y
+    }
+
+    /// Returns the norm of the cross product [self.x, self.y, 0] x [other.x, other.y, 0]..
+    #[inline]
+    pub fn cross(self, other: TypedPoint2D<T, U>) -> T {
+        self.x * other.y - self.y * other.x
+    }
+
+    #[inline]
+    pub fn normalize(self) -> Self where T: Float + ApproxEq<T> {
+        let dot = self.dot(self);
+        if dot.approx_eq(&T::zero()) {
+            self
+        } else {
+            self / dot.sqrt()
+        }
+    }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add for TypedPoint2D<T, U> {
+    type Output = TypedPoint2D<T, U>;
+    fn add(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(self.x + other.x, self.y + other.y)
+    }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add<TypedSize2D<T, U>> for TypedPoint2D<T, U> {
+    type Output = TypedPoint2D<T, U>;
+    fn add(self, other: TypedSize2D<T, U>) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(self.x + other.width, self.y + other.height)
+    }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> TypedPoint2D<T, U> {
+    pub fn add_size(&self, other: &TypedSize2D<T, U>) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(self.x + other.width, self.y + other.height)
+    }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedPoint2D<T, U> {
+    type Output = TypedPoint2D<T, U>;
+    fn sub(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(self.x - other.x, self.y - other.y)
+    }
+}
+
+impl <T: Copy + Neg<Output=T>, U> Neg for TypedPoint2D<T, U> {
+    type Output = TypedPoint2D<T, U>;
+    #[inline]
+    fn neg(self) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(-self.x, -self.y)
+    }
+}
+
+impl<T: Float, U> TypedPoint2D<T, U> {
+    pub fn min(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
+         TypedPoint2D::new(self.x.min(other.x), self.y.min(other.y))
+    }
+
+    pub fn max(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(self.x.max(other.x), self.y.max(other.y))
+    }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedPoint2D<T, U> {
+    type Output = TypedPoint2D<T, U>;
+    #[inline]
+    fn mul(self, scale: T) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(self.x * scale, self.y * scale)
+    }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedPoint2D<T, U> {
+    type Output = TypedPoint2D<T, U>;
+    #[inline]
+    fn div(self, scale: T) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(self.x / scale, self.y / scale)
+    }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedPoint2D<T, U1> {
+    type Output = TypedPoint2D<T, U2>;
+    #[inline]
+    fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedPoint2D<T, U2> {
+        TypedPoint2D::new(self.x * scale.get(), self.y * scale.get())
+    }
+}
+
+impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedPoint2D<T, U2> {
+    type Output = TypedPoint2D<T, U1>;
+    #[inline]
+    fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedPoint2D<T, U1> {
+        TypedPoint2D::new(self.x / scale.get(), self.y / scale.get())
+    }
+}
+
+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 }`.
+    pub fn round(&self) -> Self {
+        TypedPoint2D::new(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 }`.
+    pub fn ceil(&self) -> Self {
+        TypedPoint2D::new(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 }`.
+    pub fn floor(&self) -> Self {
+        TypedPoint2D::new(self.x.floor(), self.y.floor())
+    }
+}
+
+impl<T: NumCast + Copy, U> TypedPoint2D<T, U> {
+    /// Cast from one numeric representation to another, preserving the units.
+    ///
+    /// When casting from floating point to integer coordinates, the decimals are truncated
+    /// as one would expect from a simple cast, but this behavior does not always make sense
+    /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
+    pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedPoint2D<NewT, U>> {
+        match (NumCast::from(self.x), NumCast::from(self.y)) {
+            (Some(x), Some(y)) => Some(TypedPoint2D::new(x, y)),
+            _ => None
+        }
+    }
+
+    // Convenience functions for common casts
+
+    /// Cast into an `f32` point.
+    pub fn to_f32(&self) -> TypedPoint2D<f32, U> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `usize` point, truncating decimals if any.
+    ///
+    /// When casting from floating point points, it is worth considering whether
+    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+    /// the desired conversion behavior.
+    pub fn to_uint(&self) -> TypedPoint2D<usize, U> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an i32 point, truncating decimals if any.
+    ///
+    /// When casting from floating point points, it is worth considering whether
+    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+    /// the desired conversion behavior.
+    pub fn to_i32(&self) -> TypedPoint2D<i32, U> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an i64 point, truncating decimals if any.
+    ///
+    /// When casting from floating point points, 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) -> TypedPoint2D<i64, U> {
+        self.cast().unwrap()
+    }
+}
+
+impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedPoint2D<T, U>> for TypedPoint2D<T, U> {
+    #[inline]
+    fn approx_epsilon() -> Self {
+        TypedPoint2D::new(T::approx_epsilon(), T::approx_epsilon())
+    }
+
+    #[inline]
+    fn approx_eq(&self, other: &Self) -> bool {
+        self.x.approx_eq(&other.x) && self.y.approx_eq(&other.y)
+    }
+
+    #[inline]
+    fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
+        self.x.approx_eq_eps(&other.x, &eps.x) && self.y.approx_eq_eps(&other.y, &eps.y)
+    }
+}
+
+define_matrix! {
+    /// A 3d Point tagged with a unit.
+    #[derive(RustcDecodable, RustcEncodable)]
+    pub struct TypedPoint3D<T, U> {
+        pub x: T,
+        pub y: T,
+        pub z: T,
+    }
+}
+
+/// Default 3d point type with no unit.
+///
+/// `Point3D` provides the same methods as `TypedPoint3D`.
+pub type Point3D<T> = TypedPoint3D<T, UnknownUnit>;
+
+impl<T: Copy + Zero, U> TypedPoint3D<T, U> {
+    /// Constructor, setting all copmonents to zero.
+    #[inline]
+    pub fn zero() -> TypedPoint3D<T, U> {
+        TypedPoint3D::new(Zero::zero(), Zero::zero(), Zero::zero())
+    }
+}
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedPoint3D<T, U> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "({:?},{:?},{:?})", self.x, self.y, self.z)
+    }
+}
+
+impl<T: fmt::Display, U> fmt::Display for TypedPoint3D<T, U> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "({},{},{})", self.x, self.y, self.z)
+    }
+}
+
+impl<T: Copy, U> TypedPoint3D<T, U> {
+    /// Constructor taking scalar values directly.
+    #[inline]
+    pub fn new(x: T, y: T, z: T) -> TypedPoint3D<T, U> {
+        TypedPoint3D { x: x, y: y, z: z, _unit: PhantomData }
+    }
+
+    /// 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>) -> TypedPoint3D<T, U> {
+        TypedPoint3D::new(x.0, y.0, z.0)
+    }
+
+    /// Returns self.x as a Length carrying the unit.
+    #[inline]
+    pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
+
+    /// Returns self.y as a Length carrying the unit.
+    #[inline]
+    pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
+
+    /// Returns self.z as a Length carrying the unit.
+    #[inline]
+    pub fn z_typed(&self) -> Length<T, U> { Length::new(self.z) }
+
+    #[inline]
+    pub fn to_array(&self) -> [T; 3] { [self.x, self.y, self.z] }
+
+    /// Drop the units, preserving only the numeric value.
+    #[inline]
+    pub fn to_untyped(&self) -> Point3D<T> {
+        TypedPoint3D::new(self.x, self.y, self.z)
+    }
+
+    /// Tag a unitless value with units.
+    #[inline]
+    pub fn from_untyped(p: &Point3D<T>) -> TypedPoint3D<T, U> {
+        TypedPoint3D::new(p.x, p.y, p.z)
+    }
+
+    /// Convert into a 2d point.
+    #[inline]
+    pub fn to_2d(&self) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(self.x, self.y)
+    }
+}
+
+impl<T: Mul<T, Output=T> +
+        Add<T, Output=T> +
+        Sub<T, Output=T> +
+        Copy, U> TypedPoint3D<T, U> {
+
+    // Dot product.
+    #[inline]
+    pub fn dot(self, other: TypedPoint3D<T, U>) -> T {
+        self.x * other.x +
+        self.y * other.y +
+        self.z * other.z
+    }
+
+    // Cross product.
+    #[inline]
+    pub fn cross(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
+        TypedPoint3D::new(self.y * other.z - self.z * other.y,
+                          self.z * other.x - self.x * other.z,
+                          self.x * other.y - self.y * other.x)
+    }
+
+    #[inline]
+    pub fn normalize(self) -> Self where T: Float + ApproxEq<T> {
+        let dot = self.dot(self);
+        if dot.approx_eq(&T::zero()) {
+            self
+        } else {
+            self / dot.sqrt()
+        }
+    }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add for TypedPoint3D<T, U> {
+    type Output = TypedPoint3D<T, U>;
+    fn add(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
+        TypedPoint3D::new(self.x + other.x,
+                          self.y + other.y,
+                          self.z + other.z)
+    }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedPoint3D<T, U> {
+    type Output = TypedPoint3D<T, U>;
+    fn sub(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
+        TypedPoint3D::new(self.x - other.x,
+                          self.y - other.y,
+                          self.z - other.z)
+    }
+}
+
+impl <T: Copy + Neg<Output=T>, U> Neg for TypedPoint3D<T, U> {
+    type Output = TypedPoint3D<T, U>;
+    #[inline]
+    fn neg(self) -> TypedPoint3D<T, U> {
+        TypedPoint3D::new(-self.x, -self.y, -self.z)
+    }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedPoint3D<T, U> {
+    type Output = Self;
+    #[inline]
+    fn mul(self, scale: T) -> Self {
+        Self::new(self.x * scale, self.y * scale, self.z * scale)
+    }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedPoint3D<T, U> {
+    type Output = Self;
+    #[inline]
+    fn div(self, scale: T) -> Self {
+        Self::new(self.x / scale, self.y / scale, self.z / scale)
+    }
+}
+
+impl<T: Float, U> TypedPoint3D<T, U> {
+    pub fn min(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
+         TypedPoint3D::new(self.x.min(other.x),
+                           self.y.min(other.y),
+                           self.z.min(other.z))
+    }
+
+    pub fn max(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
+        TypedPoint3D::new(self.x.max(other.x), self.y.max(other.y),
+                     self.z.max(other.z))
+    }
+}
+
+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).
+    pub fn round(&self) -> Self {
+        TypedPoint3D::new(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).
+    pub fn ceil(&self) -> Self {
+        TypedPoint3D::new(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).
+    pub fn floor(&self) -> Self {
+        TypedPoint3D::new(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.
+    ///
+    /// When casting from floating point to integer coordinates, the decimals are truncated
+    /// as one would expect from a simple cast, but this behavior does not always make sense
+    /// geometrically. Consider using round(), ceil or floor() before casting.
+    pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedPoint3D<NewT, U>> {
+        match (NumCast::from(self.x),
+               NumCast::from(self.y),
+               NumCast::from(self.z)) {
+            (Some(x), Some(y), Some(z)) => Some(TypedPoint3D::new(x, y, z)),
+            _ => None
+        }
+    }
+
+    // Convenience functions for common casts
+
+    /// Cast into an `f32` point.
+    pub fn to_f32(&self) -> TypedPoint3D<f32, U> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `usize` point, truncating decimals if any.
+    ///
+    /// When casting from floating point points, it is worth considering whether
+    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+    /// the desired conversion behavior.
+    pub fn to_uint(&self) -> TypedPoint3D<usize, U> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `i32` point, truncating decimals if any.
+    ///
+    /// When casting from floating point points, it is worth considering whether
+    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+    /// the desired conversion behavior.
+    pub fn to_i32(&self) -> TypedPoint3D<i32, U> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `i64` point, truncating decimals if any.
+    ///
+    /// When casting from floating point points, 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) -> TypedPoint3D<i64, U> {
+        self.cast().unwrap()
+    }
+}
+
+impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedPoint3D<T, U>> for TypedPoint3D<T, U> {
+    #[inline]
+    fn approx_epsilon() -> Self {
+        TypedPoint3D::new(T::approx_epsilon(), T::approx_epsilon(), T::approx_epsilon())
+    }
+
+    #[inline]
+    fn approx_eq(&self, other: &Self) -> bool {
+        self.x.approx_eq(&other.x)
+            && self.y.approx_eq(&other.y)
+            && self.z.approx_eq(&other.z)
+    }
+
+    #[inline]
+    fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
+        self.x.approx_eq_eps(&other.x, &eps.x)
+            && self.y.approx_eq_eps(&other.y, &eps.y)
+            && self.z.approx_eq_eps(&other.z, &eps.z)
+    }
+}
+
+define_matrix! {
+    /// A 4d Point tagged with a unit.
+    #[derive(RustcDecodable, RustcEncodable)]
+    pub struct TypedPoint4D<T, U> {
+        pub x: T,
+        pub y: T,
+        pub z: T,
+        pub w: T,
+    }
+}
+
+/// Default 4d point with no unit.
+///
+/// `Point4D` provides the same methods as `TypedPoint4D`.
+pub type Point4D<T> = TypedPoint4D<T, UnknownUnit>;
+
+impl<T: Copy + Zero, U> TypedPoint4D<T, U> {
+    /// Constructor, setting all copmonents to zero.
+    #[inline]
+    pub fn zero() -> TypedPoint4D<T, U> {
+        TypedPoint4D::new(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero())
+    }
+}
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedPoint4D<T, U> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "({:?},{:?},{:?},{:?})", self.x, self.y, self.z, self.w)
+    }
+}
+
+impl<T: fmt::Display, U> fmt::Display for TypedPoint4D<T, U> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        write!(formatter, "({},{},{},{})", self.x, self.y, self.z, self.w)
+    }
+}
+
+impl<T: Copy, U> TypedPoint4D<T, U> {
+    /// Constructor taking scalar values directly.
+    #[inline]
+    pub fn new(x: T, y: T, z: T, w: T) -> TypedPoint4D<T, U> {
+        TypedPoint4D { x: x, y: y, z: z, w: w, _unit: PhantomData }
+    }
+
+    /// 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>,
+                        w: Length<T, U>) -> TypedPoint4D<T, U> {
+        TypedPoint4D::new(x.0, y.0, z.0, w.0)
+    }
+
+    /// Returns self.x as a Length carrying the unit.
+    #[inline]
+    pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
+
+    /// Returns self.y as a Length carrying the unit.
+    #[inline]
+    pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
+
+    /// Returns self.z as a Length carrying the unit.
+    #[inline]
+    pub fn z_typed(&self) -> Length<T, U> { Length::new(self.z) }
+
+    /// Returns self.w as a Length carrying the unit.
+    #[inline]
+    pub fn w_typed(&self) -> Length<T, U> { Length::new(self.w) }
+
+    /// Drop the units, preserving only the numeric value.
+    #[inline]
+    pub fn to_untyped(&self) -> Point4D<T> {
+        TypedPoint4D::new(self.x, self.y, self.z, self.w)
+    }
+
+    /// Tag a unitless value with units.
+    #[inline]
+    pub fn from_untyped(p: &Point4D<T>) -> TypedPoint4D<T, U> {
+        TypedPoint4D::new(p.x, p.y, p.z, p.w)
+    }
+
+    #[inline]
+    pub fn to_array(&self) -> [T; 4] {
+        [self.x, self.y, self.z, self.w]
+    }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> TypedPoint4D<T, U> {
+    /// Convert into a 2d point.
+    #[inline]
+    pub fn to_2d(self) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(self.x / self.w, self.y / self.w)
+    }
+
+    /// Convert into a 3d point.
+    #[inline]
+    pub fn to_3d(self) -> TypedPoint3D<T, U> {
+        TypedPoint3D::new(self.x / self.w, self.y / self.w, self.z / self.w)
+    }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add for TypedPoint4D<T, U> {
+    type Output = TypedPoint4D<T, U>;
+    fn add(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
+        TypedPoint4D::new(self.x + other.x,
+                          self.y + other.y,
+                          self.z + other.z,
+                          self.w + other.w)
+    }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedPoint4D<T, U> {
+    type Output = TypedPoint4D<T, U>;
+    fn sub(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
+        TypedPoint4D::new(self.x - other.x,
+                          self.y - other.y,
+                          self.z - other.z,
+                          self.w - other.w)
+    }
+}
+
+impl <T: Copy + Neg<Output=T>, U> Neg for TypedPoint4D<T, U> {
+    type Output = TypedPoint4D<T, U>;
+    #[inline]
+    fn neg(self) -> TypedPoint4D<T, U> {
+        TypedPoint4D::new(-self.x, -self.y, -self.z, -self.w)
+    }
+}
+
+impl<T: Float, U> TypedPoint4D<T, U> {
+    pub fn min(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
+         TypedPoint4D::new(self.x.min(other.x), self.y.min(other.y),
+                           self.z.min(other.z), self.w.min(other.w))
+    }
+
+    pub fn max(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
+        TypedPoint4D::new(self.x.max(other.x), self.y.max(other.y),
+                          self.z.max(other.z), self.w.max(other.w))
+    }
+}
+
+impl<T: Round, U> TypedPoint4D<T, U> {
+    /// Rounds each component to the nearest integer value.
+    ///
+    /// This behavior is preserved for negative values (unlike the basic cast).
+    pub fn round(&self) -> Self {
+        TypedPoint4D::new(self.x.round(), self.y.round(), self.z.round(), self.w.round())
+    }
+}
+
+impl<T: Ceil, U> TypedPoint4D<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).
+    pub fn ceil(&self) -> Self {
+        TypedPoint4D::new(self.x.ceil(), self.y.ceil(), self.z.ceil(), self.w.ceil())
+    }
+}
+
+impl<T: Floor, U> TypedPoint4D<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).
+    pub fn floor(&self) -> Self {
+        TypedPoint4D::new(self.x.floor(), self.y.floor(), self.z.floor(), self.w.floor())
+    }
+}
+
+impl<T: NumCast + Copy, U> TypedPoint4D<T, U> {
+    /// Cast from one numeric representation to another, preserving the units.
+    ///
+    /// When casting from floating point to integer coordinates, the decimals are truncated
+    /// as one would expect from a simple cast, but this behavior does not always make sense
+    /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
+    pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedPoint4D<NewT, U>> {
+        match (NumCast::from(self.x),
+               NumCast::from(self.y),
+               NumCast::from(self.z),
+               NumCast::from(self.w)) {
+            (Some(x), Some(y), Some(z), Some(w)) => Some(TypedPoint4D::new(x, y, z, w)),
+            _ => None
+        }
+    }
+
+    // Convenience functions for common casts
+
+    /// Cast into an `f32` point.
+    pub fn to_f32(&self) -> TypedPoint4D<f32, U> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `usize` point, truncating decimals if any.
+    ///
+    /// When casting from floating point points, it is worth considering whether
+    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+    /// the desired conversion behavior.
+    pub fn to_uint(&self) -> TypedPoint4D<usize, U> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `i32` point, truncating decimals if any.
+    ///
+    /// When casting from floating point points, it is worth considering whether
+    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
+    /// the desired conversion behavior.
+    pub fn to_i32(&self) -> TypedPoint4D<i32, U> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `i64` point, truncating decimals if any.
+    ///
+    /// When casting from floating point points, 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) -> TypedPoint4D<i64, U> {
+        self.cast().unwrap()
+    }
+}
+
+impl<T: ApproxEq<T>, U> ApproxEq<T> for TypedPoint4D<T, U> {
+    fn approx_epsilon() -> T {
+        T::approx_epsilon()
+    }
+
+    fn approx_eq_eps(&self, other: &Self, approx_epsilon: &T) -> bool {
+        self.x.approx_eq_eps(&other.x, approx_epsilon)
+        && self.y.approx_eq_eps(&other.y, approx_epsilon)
+        && self.z.approx_eq_eps(&other.z, approx_epsilon)
+        && self.w.approx_eq_eps(&other.w, approx_epsilon)
+    }
+
+    fn approx_eq(&self, other: &Self) -> bool {
+        self.approx_eq_eps(&other, &Self::approx_epsilon())
+    }
+}
+
+pub fn point2<T: Copy, U>(x: T, y: T) -> TypedPoint2D<T, U> {
+    TypedPoint2D::new(x, y)
+}
+
+pub fn point3<T: Copy, U>(x: T, y: T, z: T) -> TypedPoint3D<T, U> {
+    TypedPoint3D::new(x, y, z)
+}
+
+pub fn point4<T: Copy, U>(x: T, y: T, z: T, w: T) -> TypedPoint4D<T, U> {
+    TypedPoint4D::new(x, y, z, w)
+}
+
+#[cfg(test)]
+mod point2d {
+    use super::Point2D;
+
+    #[test]
+    pub fn test_scalar_mul() {
+        let p1: Point2D<f32> = Point2D::new(3.0, 5.0);
+
+        let result = p1 * 5.0;
+
+        assert_eq!(result, Point2D::new(15.0, 25.0));
+    }
+
+    #[test]
+    pub fn test_dot() {
+        let p1: Point2D<f32> = Point2D::new(2.0, 7.0);
+        let p2: Point2D<f32> = Point2D::new(13.0, 11.0);
+        assert_eq!(p1.dot(p2), 103.0);
+    }
+
+    #[test]
+    pub fn test_cross() {
+        let p1: Point2D<f32> = Point2D::new(4.0, 7.0);
+        let p2: Point2D<f32> = Point2D::new(13.0, 8.0);
+        let r = p1.cross(p2);
+        assert_eq!(r, -59.0);
+    }
+
+    #[test]
+    pub fn test_normalize() {
+        let p0: Point2D<f32> = Point2D::zero();
+        let p1: Point2D<f32> = Point2D::new(4.0, 0.0);
+        let p2: Point2D<f32> = Point2D::new(3.0, -4.0);
+        assert_eq!(p0.normalize(), p0);
+        assert_eq!(p1.normalize(), Point2D::new(1.0, 0.0));
+        assert_eq!(p2.normalize(), Point2D::new(0.6, -0.8));
+    }
+
+    #[test]
+    pub fn test_min() {
+        let p1 = Point2D::new(1.0, 3.0);
+        let p2 = Point2D::new(2.0, 2.0);
+
+        let result = p1.min(p2);
+
+        assert_eq!(result, Point2D::new(1.0, 2.0));
+    }
+
+    #[test]
+    pub fn test_max() {
+        let p1 = Point2D::new(1.0, 3.0);
+        let p2 = Point2D::new(2.0, 2.0);
+
+        let result = p1.max(p2);
+
+        assert_eq!(result, Point2D::new(2.0, 3.0));
+    }
+}
+
+#[cfg(test)]
+mod typedpoint2d {
+    use super::TypedPoint2D;
+    use scale_factor::ScaleFactor;
+
+    pub enum Mm {}
+    pub enum Cm {}
+
+    pub type Point2DMm<T> = TypedPoint2D<T, Mm>;
+    pub type Point2DCm<T> = TypedPoint2D<T, Cm>;
+
+    #[test]
+    pub fn test_add() {
+        let p1 = Point2DMm::new(1.0, 2.0);
+        let p2 = Point2DMm::new(3.0, 4.0);
+
+        let result = p1 + p2;
+
+        assert_eq!(result, Point2DMm::new(4.0, 6.0));
+    }
+
+    #[test]
+    pub fn test_scalar_mul() {
+        let p1 = Point2DMm::new(1.0, 2.0);
+        let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
+
+        let result = p1 * cm_per_mm;
+
+        assert_eq!(result, Point2DCm::new(0.1, 0.2));
+    }
+}
+
+#[cfg(test)]
+mod point3d {
+    use super::Point3D;
+
+    #[test]
+    pub fn test_dot() {
+        let p1 = Point3D::new(7.0, 21.0, 32.0);
+        let p2 = Point3D::new(43.0, 5.0, 16.0);
+        assert_eq!(p1.dot(p2), 918.0);
+    }
+
+    #[test]
+    pub fn test_cross() {
+        let p1 = Point3D::new(4.0, 7.0, 9.0);
+        let p2 = Point3D::new(13.0, 8.0, 3.0);
+        let p3 = p1.cross(p2);
+        assert_eq!(p3, Point3D::new(-51.0, 105.0, -59.0));
+    }
+
+    #[test]
+    pub fn test_normalize() {
+        let p0: Point3D<f32> = Point3D::zero();
+        let p1: Point3D<f32> = Point3D::new(0.0, -6.0, 0.0);
+        let p2: Point3D<f32> = Point3D::new(1.0, 2.0, -2.0);
+        assert_eq!(p0.normalize(), p0);
+        assert_eq!(p1.normalize(), Point3D::new(0.0, -1.0, 0.0));
+        assert_eq!(p2.normalize(), Point3D::new(1.0/3.0, 2.0/3.0, -2.0/3.0));
+    }
+
+    #[test]
+    pub fn test_min() {
+        let p1 = Point3D::new(1.0, 3.0, 5.0);
+        let p2 = Point3D::new(2.0, 2.0, -1.0);
+
+        let result = p1.min(p2);
+
+        assert_eq!(result, Point3D::new(1.0, 2.0, -1.0));
+    }
+
+    #[test]
+    pub fn test_max() {
+        let p1 = Point3D::new(1.0, 3.0, 5.0);
+        let p2 = Point3D::new(2.0, 2.0, -1.0);
+
+        let result = p1.max(p2);
+
+        assert_eq!(result, Point3D::new(2.0, 3.0, 5.0));
+    }
+}
+
+#[cfg(test)]
+mod point4d {
+    use super::Point4D;
+
+    #[test]
+    pub fn test_add() {
+        let p1 = Point4D::new(7.0, 21.0, 32.0, 1.0);
+        let p2 = Point4D::new(43.0, 5.0, 16.0, 2.0);
+
+        let result = p1 + p2;
+
+        assert_eq!(result, Point4D::new(50.0, 26.0, 48.0, 3.0));
+    }
+
+    #[test]
+    pub fn test_sub() {
+        let p1 = Point4D::new(7.0, 21.0, 32.0, 1.0);
+        let p2 = Point4D::new(43.0, 5.0, 16.0, 2.0);
+
+        let result = p1 - p2;
+
+        assert_eq!(result, Point4D::new(-36.0, 16.0, 16.0, -1.0));
+    }
+
+    #[test]
+    pub fn test_min() {
+        let p1 = Point4D::new(1.0, 3.0, 5.0, 7.0);
+        let p2 = Point4D::new(2.0, 2.0, -1.0, 10.0);
+
+        let result = p1.min(p2);
+
+        assert_eq!(result, Point4D::new(1.0, 2.0, -1.0, 7.0));
+    }
+
+    #[test]
+    pub fn test_max() {
+        let p1 = Point4D::new(1.0, 3.0, 5.0, 7.0);
+        let p2 = Point4D::new(2.0, 2.0, -1.0, 10.0);
+
+        let result = p1.max(p2);
+
+        assert_eq!(result, Point4D::new(2.0, 3.0, 5.0, 10.0));
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/rect.rs
@@ -0,0 +1,671 @@
+// 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 super::UnknownUnit;
+use length::Length;
+use scale_factor::ScaleFactor;
+use num::*;
+use point::TypedPoint2D;
+use size::TypedSize2D;
+
+use heapsize::HeapSizeOf;
+use num_traits::NumCast;
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use std::cmp::PartialOrd;
+use std::fmt;
+use std::ops::{Add, Sub, Mul, Div};
+
+/// A 2d Rectangle optionally tagged with a unit.
+#[derive(RustcDecodable, RustcEncodable)]
+pub struct TypedRect<T, U = UnknownUnit> {
+    pub origin: TypedPoint2D<T, U>,
+    pub size: TypedSize2D<T, U>,
+}
+
+/// The default rectangle type with no unit.
+pub type Rect<T> = TypedRect<T, UnknownUnit>;
+
+impl<T: HeapSizeOf, U> HeapSizeOf for TypedRect<T, U> {
+    fn heap_size_of_children(&self) -> usize {
+        self.origin.heap_size_of_children() + self.size.heap_size_of_children()
+    }
+}
+
+impl<T: Copy + Deserialize, U> Deserialize for TypedRect<T, U> {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+        where D: Deserializer
+    {
+        let (origin, size) = try!(Deserialize::deserialize(deserializer));
+        Ok(TypedRect::new(origin, size))
+    }
+}
+
+impl<T: Serialize, U> Serialize for TypedRect<T, U> {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+        where S: Serializer
+    {
+        (&self.origin, &self.size).serialize(serializer)
+    }
+}
+
+impl<T: Copy, U> Copy for TypedRect<T, U> {}
+
+impl<T: Copy, U> Clone for TypedRect<T, U> {
+    fn clone(&self) -> TypedRect<T, U> { *self }
+}
+
+impl<T: PartialEq, U> PartialEq<TypedRect<T, U>> for TypedRect<T, U> {
+    fn eq(&self, other: &TypedRect<T, U>) -> bool {
+        self.origin.eq(&other.origin) && self.size.eq(&other.size)
+    }
+}
+
+impl<T: Eq, U> Eq for TypedRect<T, U> {}
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedRect<T, U> {
+   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "TypedRect({:?} at {:?})", self.size, self.origin)
+    }
+}
+
+impl<T: fmt::Display, U> fmt::Display for TypedRect<T, U> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        write!(formatter, "Rect({} at {})", self.size, self.origin)
+    }
+}
+
+impl<T, U> TypedRect<T, U> {
+    /// Constructor.
+    pub fn new(origin: TypedPoint2D<T, U>, size: TypedSize2D<T, U>) -> TypedRect<T, U> {
+        TypedRect {
+            origin: origin,
+            size: size,
+        }
+    }
+}
+
+impl<T, U> TypedRect<T, U>
+where T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output=T> + Sub<T, Output=T> {
+    #[inline]
+    pub fn intersects(&self, other: &TypedRect<T, U>) -> bool {
+        self.origin.x < other.origin.x + other.size.width &&
+       other.origin.x <  self.origin.x + self.size.width &&
+        self.origin.y < other.origin.y + other.size.height &&
+       other.origin.y <  self.origin.y + self.size.height
+    }
+
+    #[inline]
+    pub fn max_x(&self) -> T {
+        self.origin.x + self.size.width
+    }
+
+    #[inline]
+    pub fn min_x(&self) -> T {
+        self.origin.x
+    }
+
+    #[inline]
+    pub fn max_y(&self) -> T {
+        self.origin.y + self.size.height
+    }
+
+    #[inline]
+    pub fn min_y(&self) -> T {
+        self.origin.y
+    }
+
+    #[inline]
+    pub fn max_x_typed(&self) -> Length<T, U> {
+        Length::new(self.max_x())
+    }
+
+    #[inline]
+    pub fn min_x_typed(&self) -> Length<T, U> {
+        Length::new(self.min_x())
+    }
+
+    #[inline]
+    pub fn max_y_typed(&self) -> Length<T, U> {
+        Length::new(self.max_y())
+    }
+
+    #[inline]
+    pub fn min_y_typed(&self) -> Length<T, U> {
+        Length::new(self.min_y())
+    }
+
+    #[inline]
+    pub fn intersection(&self, other: &TypedRect<T, U>) -> Option<TypedRect<T, U>> {
+        if !self.intersects(other) {
+            return None;
+        }
+
+        let upper_left = TypedPoint2D::new(max(self.min_x(), other.min_x()),
+                                      max(self.min_y(), other.min_y()));
+        let lower_right_x = min(self.max_x(), other.max_x());
+        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)))
+    }
+
+    /// Translates the rect by a vector.
+    #[inline]
+    pub fn translate(&self, other: &TypedPoint2D<T, U>) -> TypedRect<T, U> {
+        TypedRect::new(
+            TypedPoint2D::new(self.origin.x + other.x, self.origin.y + other.y),
+            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]
+    pub fn contains(&self, other: &TypedPoint2D<T, U>) -> bool {
+        self.origin.x <= other.x && other.x < self.origin.x + self.size.width &&
+        self.origin.y <= other.y && other.y < self.origin.y + self.size.height
+    }
+
+    /// Returns true if this rectangle contains the interior of rect. Always
+    /// returns true if rect is empty, and always returns false if rect is
+    /// nonempty but this rectangle is empty.
+    #[inline]
+    pub fn contains_rect(&self, rect: &TypedRect<T, U>) -> 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]
+    pub fn inflate(&self, width: T, height: T) -> TypedRect<T, U> {
+        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]
+    pub fn inflate_typed(&self, width: Length<T, U>, height: Length<T, U>) -> TypedRect<T, U> {
+        self.inflate(width.get(), height.get())
+    }
+
+    #[inline]
+    pub fn top_right(&self) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(self.max_x(), self.origin.y)
+    }
+
+    #[inline]
+    pub fn bottom_left(&self) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(self.origin.x, self.max_y())
+    }
+
+    #[inline]
+    pub fn bottom_right(&self) -> TypedPoint2D<T, U> {
+        TypedPoint2D::new(self.max_x(), self.max_y())
+    }
+
+    #[inline]
+    pub fn translate_by_size(&self, size: &TypedSize2D<T, U>) -> TypedRect<T, U> {
+        self.translate(&TypedPoint2D::new(size.width, size.height))
+    }
+
+    /// Returns the smallest rectangle containing the four points.
+    pub fn from_points(points: &[TypedPoint2D<T, U>]) -> Self {
+        if points.len() == 0 {
+            return TypedRect::zero();
+        }
+        let (mut min_x, mut min_y) = (points[0].x, points[0].y);
+        let (mut max_x, mut max_y) = (min_x, min_y);
+        for point in &points[1..] {
+            if point.x < min_x {
+                min_x = point.x
+            }
+            if point.x > max_x {
+                max_x = point.x
+            }
+            if point.y < min_y {
+                min_y = point.y
+            }
+            if point.y > max_y {
+                max_y = point.y
+            }
+        }
+        TypedRect::new(TypedPoint2D::new(min_x, min_y),
+                       TypedSize2D::new(max_x - min_x, max_y - min_y))
+    }
+}
+
+impl<T, U> TypedRect<T, U>
+where T: Copy + Clone + PartialOrd + Add<T, Output=T> + Sub<T, Output=T> + Zero {
+    #[inline]
+    pub fn union(&self, other: &TypedRect<T, U>) -> TypedRect<T, U> {
+        if self.size == Zero::zero() {
+            return *other;
+        }
+        if other.size == Zero::zero() {
+            return *self;
+        }
+
+        let upper_left = TypedPoint2D::new(min(self.min_x(), other.min_x()),
+                                      min(self.min_y(), other.min_y()));
+
+        let lower_right_x = max(self.max_x(), other.max_x());
+        let lower_right_y = max(self.max_y(), other.max_y());
+
+        TypedRect::new(
+            upper_left,
+            TypedSize2D::new(lower_right_x - upper_left.x, lower_right_y - upper_left.y)
+        )
+    }
+}
+
+impl<T, U> TypedRect<T, U> {
+    #[inline]
+    pub fn scale<Scale: Copy>(&self, x: Scale, y: Scale) -> TypedRect<T, U>
+        where T: Copy + Clone + Mul<Scale, Output=T> {
+        TypedRect::new(
+            TypedPoint2D::new(self.origin.x * x, self.origin.y * y),
+            TypedSize2D::new(self.size.width * x, self.size.height * y)
+        )
+    }
+}
+
+impl<T: Copy + PartialEq + Zero, U> TypedRect<T, U> {
+    /// Constructor, setting all sides to zero.
+    pub fn zero() -> TypedRect<T, U> {
+        TypedRect::new(
+            TypedPoint2D::zero(),
+            TypedSize2D::zero(),
+        )
+    }
+
+    /// Returns true if the size is zero, regardless of the origin's value.
+    pub fn is_empty(&self) -> bool {
+        self.size.width == Zero::zero() || self.size.height == Zero::zero()
+    }
+}
+
+
+pub fn min<T: Clone + PartialOrd>(x: T, y: T) -> T {
+    if x <= y { x } else { y }
+}
+
+pub fn max<T: Clone + PartialOrd>(x: T, y: T) -> T {
+    if x >= y { x } else { y }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedRect<T, U> {
+    type Output = TypedRect<T, U>;
+    #[inline]
+    fn mul(self, scale: T) -> TypedRect<T, U> {
+        TypedRect::new(self.origin * scale, self.size * scale)
+    }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedRect<T, U> {
+    type Output = TypedRect<T, U>;
+    #[inline]
+    fn div(self, scale: T) -> TypedRect<T, U> {
+        TypedRect::new(self.origin / scale, self.size / scale)
+    }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedRect<T, U1> {
+    type Output = TypedRect<T, U2>;
+    #[inline]
+    fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedRect<T, U2> {
+        TypedRect::new(self.origin * scale, self.size * scale)
+    }
+}
+
+impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedRect<T, U2> {
+    type Output = TypedRect<T, U1>;
+    #[inline]
+    fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedRect<T, U1> {
+        TypedRect::new(self.origin / scale, self.size / scale)
+    }
+}
+
+impl<T: Copy, Unit> TypedRect<T, Unit> {
+    /// Drop the units, preserving only the numeric value.
+    pub fn to_untyped(&self) -> Rect<T> {
+        TypedRect::new(self.origin.to_untyped(), self.size.to_untyped())
+    }
+
+    /// Tag a unitless value with units.
+    pub fn from_untyped(r: &Rect<T>) -> TypedRect<T, Unit> {
+        TypedRect::new(TypedPoint2D::from_untyped(&r.origin), TypedSize2D::from_untyped(&r.size))
+    }
+}
+
+impl<T0: NumCast + Copy, Unit> TypedRect<T0, Unit> {
+    /// Cast from one numeric representation to another, preserving the units.
+    ///
+    /// When casting from floating point to integer coordinates, the decimals are truncated
+    /// as one would expect from a simple cast, but this behavior does not always make sense
+    /// geometrically. Consider using round(), round_in or round_out() before casting.
+    pub fn cast<T1: NumCast + Copy>(&self) -> Option<TypedRect<T1, Unit>> {
+        match (self.origin.cast(), self.size.cast()) {
+            (Some(origin), Some(size)) => Some(TypedRect::new(origin, size)),
+            _ => None
+        }
+    }
+}
+
+impl<T: Floor + Ceil + Round + Add<T, Output=T> + Sub<T, Output=T>, U> TypedRect<T, U> {
+    /// Return a rectangle with edges rounded to integer coordinates, such that
+    /// 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).
+    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.
+    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.
+    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
+impl<T: NumCast + Copy, Unit> TypedRect<T, Unit> {
+    /// Cast into an `f32` rectangle.
+    pub fn to_f32(&self) -> TypedRect<f32, Unit> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `usize` rectangle, truncating decimals if any.
+    ///
+    /// When casting from floating point rectangles, it is worth considering whether
+    /// to `round()`, `round_in()` or `round_out()` before the cast in order to
+    /// obtain the desired conversion behavior.
+    pub fn to_uint(&self) -> TypedRect<usize, Unit> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `i32` rectangle, truncating decimals if any.
+    ///
+    /// When casting from floating point rectangles, it is worth considering whether
+    /// to `round()`, `round_in()` or `round_out()` before the cast in order to
+    /// obtain the desired conversion behavior.
+    pub fn to_i32(&self) -> TypedRect<i32, Unit> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `i64` rectangle, truncating decimals if any.
+    ///
+    /// When casting from floating point rectangles, it is worth considering whether
+    /// to `round()`, `round_in()` or `round_out()` before the cast in order to
+    /// obtain the desired conversion behavior.
+    pub fn to_i64(&self) -> TypedRect<i64, Unit> {
+        self.cast().unwrap()
+    }
+}
+
+/// Shorthand for `TypedRect::new(TypedPoint2D::new(x, y), TypedSize2D::new(w, h))`.
+pub fn rect<T: Copy, U>(x: T, y: T, w: T, h: T) -> TypedRect<T, U> {
+    TypedRect::new(TypedPoint2D::new(x, y), TypedSize2D::new(w, h))
+}
+
+#[cfg(test)]
+mod tests {
+    use point::Point2D;
+    use size::Size2D;
+    use super::*;
+
+    #[test]
+    fn test_min_max() {
+        assert!(min(0u32, 1u32) == 0u32);
+        assert!(min(-1.0f32, 0.0f32) == -1.0f32);
+
+        assert!(max(0u32, 1u32) == 1u32);
+        assert!(max(-1.0f32, 0.0f32) == 0.0f32);
+    }
+
+    #[test]
+    fn test_translate() {
+        let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
+        let pp = p.translate(&Point2D::new(10,15));
+
+        assert!(pp.size.width == 50);
+        assert!(pp.size.height == 40);
+        assert!(pp.origin.x == 10);
+        assert!(pp.origin.y == 15);
+
+
+        let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
+        let rr = r.translate(&Point2D::new(0,-10));
+
+        assert!(rr.size.width == 50);
+        assert!(rr.size.height == 40);
+        assert!(rr.origin.x == -10);
+        assert!(rr.origin.y == -15);
+    }
+
+    #[test]
+    fn test_translate_by_size() {
+        let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
+        let pp = p.translate_by_size(&Size2D::new(10,15));
+
+        assert!(pp.size.width == 50);
+        assert!(pp.size.height == 40);
+        assert!(pp.origin.x == 10);
+        assert!(pp.origin.y == 15);
+
+
+        let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
+        let rr = r.translate_by_size(&Size2D::new(0,-10));
+
+        assert!(rr.size.width == 50);
+        assert!(rr.size.height == 40);
+        assert!(rr.origin.x == -10);
+        assert!(rr.origin.y == -15);
+    }
+
+    #[test]
+    fn test_union() {
+        let p = Rect::new(Point2D::new(0, 0), Size2D::new(50, 40));
+        let q = Rect::new(Point2D::new(20,20), Size2D::new(5, 5));
+        let r = Rect::new(Point2D::new(-15, -30), Size2D::new(200, 15));
+        let s = Rect::new(Point2D::new(20, -15), Size2D::new(250, 200));
+
+        let pq = p.union(&q);
+        assert!(pq.origin == Point2D::new(0, 0));
+        assert!(pq.size == Size2D::new(50, 40));
+
+        let pr = p.union(&r);
+        assert!(pr.origin == Point2D::new(-15, -30));
+        assert!(pr.size == Size2D::new(200, 70));
+
+        let ps = p.union(&s);
+        assert!(ps.origin == Point2D::new(0, -15));
+        assert!(ps.size == Size2D::new(270, 200));
+
+    }
+
+    #[test]
+    fn test_intersection() {
+        let p = Rect::new(Point2D::new(0, 0), Size2D::new(10, 20));
+        let q = Rect::new(Point2D::new(5, 15), Size2D::new(10, 10));
+        let r = Rect::new(Point2D::new(-5, -5), Size2D::new(8, 8));
+
+        let pq = p.intersection(&q);
+        assert!(pq.is_some());
+        let pq = pq.unwrap();
+        assert!(pq.origin == Point2D::new(5, 15));
+        assert!(pq.size == Size2D::new(5, 5));
+
+        let pr = p.intersection(&r);
+        assert!(pr.is_some());
+        let pr = pr.unwrap();
+        assert!(pr.origin == Point2D::new(0, 0));
+        assert!(pr.size == Size2D::new(3, 3));
+
+        let qr = q.intersection(&r);
+        assert!(qr.is_none());
+    }
+
+    #[test]
+    fn test_contains() {
+        let r = Rect::new(Point2D::new(-20, 15), Size2D::new(100, 200));
+
+        assert!(r.contains(&Point2D::new(0, 50)));
+        assert!(r.contains(&Point2D::new(-10, 200)));
+
+        // The `contains` method is inclusive of the top/left edges, but not the
+        // bottom/right edges.
+        assert!(r.contains(&Point2D::new(-20, 15)));
+        assert!(!r.contains(&Point2D::new(80, 15)));
+        assert!(!r.contains(&Point2D::new(80, 215)));
+        assert!(!r.contains(&Point2D::new(-20, 215)));
+
+        // Points beyond the top-left corner.
+        assert!(!r.contains(&Point2D::new(-25, 15)));
+        assert!(!r.contains(&Point2D::new(-15, 10)));
+
+        // Points beyond the top-right corner.
+        assert!(!r.contains(&Point2D::new(85, 20)));
+        assert!(!r.contains(&Point2D::new(75, 10)));
+
+        // Points beyond the bottom-right corner.
+        assert!(!r.contains(&Point2D::new(85, 210)));
+        assert!(!r.contains(&Point2D::new(75, 220)));
+
+        // Points beyond the bottom-left corner.
+        assert!(!r.contains(&Point2D::new(-25, 210)));
+        assert!(!r.contains(&Point2D::new(-15, 220)));
+
+        let r = Rect::new(Point2D::new(-20.0, 15.0), Size2D::new(100.0, 200.0));
+        assert!(r.contains_rect(&r));
+        assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.1,  0.0))));
+        assert!(!r.contains_rect(&r.translate(&Point2D::new(-0.1,  0.0))));
+        assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.0,  0.1))));
+        assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.0, -0.1))));
+        // Empty rectangles are always considered as contained in other rectangles,
+        // even if their origin is not.
+        let p = Point2D::new(1.0, 1.0);
+        assert!(!r.contains(&p));
+        assert!(r.contains_rect(&Rect::new(p, Size2D::zero())));
+    }
+
+    #[test]
+    fn test_scale() {
+        let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
+        let pp = p.scale(10, 15);
+
+        assert!(pp.size.width == 500);
+        assert!(pp.size.height == 600);
+        assert!(pp.origin.x == 0);
+        assert!(pp.origin.y == 0);
+
+        let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
+        let rr = r.scale(1, 20);
+
+        assert!(rr.size.width == 50);
+        assert!(rr.size.height == 800);
+        assert!(rr.origin.x == -10);
+        assert!(rr.origin.y == -100);
+    }
+
+    #[test]
+    fn test_inflate() {
+        let p = Rect::new(Point2D::new(0, 0), Size2D::new(10, 10));
+        let pp = p.inflate(10, 20);
+
+        assert!(pp.size.width == 30);
+        assert!(pp.size.height == 50);
+        assert!(pp.origin.x == -10);
+        assert!(pp.origin.y == -20);
+
+        let r = Rect::new(Point2D::new(0, 0), Size2D::new(10, 20));
+        let rr = r.inflate(-2, -5);
+
+        assert!(rr.size.width == 6);
+        assert!(rr.size.height == 10);
+        assert!(rr.origin.x == 2);
+        assert!(rr.origin.y == 5);
+    }
+
+    #[test]
+    fn test_min_max_x_y() {
+        let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
+        assert!(p.max_y() == 40);
+        assert!(p.min_y() == 0);
+        assert!(p.max_x() == 50);
+        assert!(p.min_x() == 0);
+
+        let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
+        assert!(r.max_y() == 35);
+        assert!(r.min_y() == -5);
+        assert!(r.max_x() == 40);
+        assert!(r.min_x() == -10);
+    }
+
+    #[test]
+    fn test_is_empty() {
+        assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(0u32, 0u32)).is_empty());
+        assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(10u32, 0u32)).is_empty());
+        assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(0u32, 10u32)).is_empty());
+        assert!(!Rect::new(Point2D::new(0u32, 0u32), Size2D::new(1u32, 1u32)).is_empty());
+        assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(0u32, 0u32)).is_empty());
+        assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(10u32, 0u32)).is_empty());
+        assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(0u32, 10u32)).is_empty());
+        assert!(!Rect::new(Point2D::new(10u32, 10u32), Size2D::new(1u32, 1u32)).is_empty());
+    }
+
+    #[test]
+    fn test_round() {
+        let mut x = -2.0;
+        let mut y = -2.0;
+        let mut w = -2.0;
+        let mut h = -2.0;
+        while x < 2.0 {
+            while y < 2.0 {
+                while w < 2.0 {
+                    while h < 2.0 {
+                        let rect = Rect::new(Point2D::new(x, y), Size2D::new(w, h));
+
+                        assert!(rect.contains_rect(&rect.round_in()));
+                        assert!(rect.round_in().inflate(1.0, 1.0).contains_rect(&rect));
+
+                        assert!(rect.round_out().contains_rect(&rect));
+                        assert!(rect.inflate(1.0, 1.0).contains_rect(&rect.round_out()));
+
+                        assert!(rect.inflate(1.0, 1.0).contains_rect(&rect.round()));
+                        assert!(rect.round().inflate(1.0, 1.0).contains_rect(&rect));
+
+                        h += 0.1;
+                    }
+                    w += 0.1;
+                }
+                y += 0.1;
+            }
+            x += 0.1
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/scale_factor.rs
@@ -0,0 +1,172 @@
+// Copyright 2014 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.
+//! A type-checked scaling factor between units.
+
+use num::One;
+
+use heapsize::HeapSizeOf;
+use num_traits::NumCast;
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use std::fmt;
+use std::ops::{Add, Mul, Sub, Div};
+use std::marker::PhantomData;
+
+/// A scaling factor between two different units of measurement.
+///
+/// This is effectively a type-safe float, intended to be used in combination with other types like
+/// `length::Length` to enforce conversion between systems of measurement at compile time.
+///
+/// `Src` and `Dst` represent the units before and after multiplying a value by a `ScaleFactor`. They
+/// may be types without values, such as empty enums.  For example:
+///
+/// ```rust
+/// use euclid::scale_factor::ScaleFactor;
+/// use euclid::length::Length;
+/// enum Mm {};
+/// enum Inch {};
+///
+/// let mm_per_inch: ScaleFactor<f32, Inch, Mm> = ScaleFactor::new(25.4);
+///
+/// let one_foot: Length<f32, Inch> = Length::new(12.0);
+/// let one_foot_in_mm: Length<f32, Mm> = one_foot * mm_per_inch;
+/// ```
+#[repr(C)]
+#[derive(RustcDecodable, RustcEncodable)]
+pub struct ScaleFactor<T, Src, Dst>(pub T, PhantomData<(Src, Dst)>);
+
+impl<T: HeapSizeOf, Src, Dst> HeapSizeOf for ScaleFactor<T, Src, Dst> {
+    fn heap_size_of_children(&self) -> usize {
+        self.0.heap_size_of_children()
+    }
+}
+
+impl<T, Src, Dst> Deserialize for ScaleFactor<T, Src, Dst> where T: Deserialize {
+    fn deserialize<D>(deserializer: D) -> Result<ScaleFactor<T, Src, Dst>, D::Error>
+                      where D: Deserializer {
+        Ok(ScaleFactor(try!(Deserialize::deserialize(deserializer)), PhantomData))
+    }
+}
+
+impl<T, Src, Dst> Serialize for ScaleFactor<T, Src, Dst> where T: Serialize {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
+        self.0.serialize(serializer)
+    }
+}
+
+impl<T, Src, Dst> ScaleFactor<T, Src, Dst> {
+    pub fn new(x: T) -> ScaleFactor<T, Src, Dst> {
+        ScaleFactor(x, PhantomData)
+    }
+}
+
+impl<T: Clone, Src, Dst> ScaleFactor<T, Src, Dst> {
+    pub fn get(&self) -> T {
+        self.0.clone()
+    }
+}
+
+impl<T: Clone + One + Div<T, Output=T>, Src, Dst> ScaleFactor<T, Src, Dst> {
+    /// The inverse ScaleFactor (1.0 / self).
+    pub fn inv(&self) -> ScaleFactor<T, Dst, Src> {
+        let one: T = One::one();
+        ScaleFactor::new(one / self.get())
+    }
+}
+
+// scale0 * scale1
+impl<T: Clone + Mul<T, Output=T>, A, B, C>
+Mul<ScaleFactor<T, B, C>> for ScaleFactor<T, A, B> {
+    type Output = ScaleFactor<T, A, C>;
+    #[inline]
+    fn mul(self, other: ScaleFactor<T, B, C>) -> ScaleFactor<T, A, C> {
+        ScaleFactor::new(self.get() * other.get())
+    }
+}
+
+// scale0 + scale1
+impl<T: Clone + Add<T, Output=T>, Src, Dst> Add for ScaleFactor<T, Src, Dst> {
+    type Output = ScaleFactor<T, Src, Dst>;
+    #[inline]
+    fn add(self, other: ScaleFactor<T, Src, Dst>) -> ScaleFactor<T, Src, Dst> {
+        ScaleFactor::new(self.get() + other.get())
+    }
+}
+
+// scale0 - scale1
+impl<T: Clone + Sub<T, Output=T>, Src, Dst> Sub for ScaleFactor<T, Src, Dst> {
+    type Output = ScaleFactor<T, Src, Dst>;
+    #[inline]
+    fn sub(self, other: ScaleFactor<T, Src, Dst>) -> ScaleFactor<T, Src, Dst> {
+        ScaleFactor::new(self.get() - other.get())
+    }
+}
+
+impl<T: NumCast + Clone, Src, Dst0> ScaleFactor<T, Src, Dst0> {
+    /// Cast from one numeric representation to another, preserving the units.
+    pub fn cast<T1: NumCast + Clone>(&self) -> Option<ScaleFactor<T1, Src, Dst0>> {
+        NumCast::from(self.get()).map(ScaleFactor::new)
+    }
+}
+
+// FIXME: Switch to `derive(PartialEq, Clone)` after this Rust issue is fixed:
+// https://github.com/mozilla/rust/issues/7671
+
+impl<T: PartialEq, Src, Dst> PartialEq for ScaleFactor<T, Src, Dst> {
+    fn eq(&self, other: &ScaleFactor<T, Src, Dst>) -> bool {
+        self.0 == other.0
+    }
+}
+
+impl<T: Clone, Src, Dst> Clone for ScaleFactor<T, Src, Dst> {
+    fn clone(&self) -> ScaleFactor<T, Src, Dst> {
+        ScaleFactor::new(self.get())
+    }
+}
+
+impl<T: Copy, Src, Dst> Copy for ScaleFactor<T, Src, Dst> {}
+
+impl<T: fmt::Debug, Src, Dst> fmt::Debug for ScaleFactor<T, Src, Dst> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl<T: fmt::Display, Src, Dst> fmt::Display for ScaleFactor<T, Src, Dst> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::ScaleFactor;
+
+    enum Inch {}
+    enum Cm {}
+    enum Mm {}
+
+    #[test]
+    fn test_scale_factor() {
+        let mm_per_inch: ScaleFactor<f32, Inch, Mm> = ScaleFactor::new(25.4);
+        let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
+
+        let mm_per_cm: ScaleFactor<f32, Cm, Mm> = cm_per_mm.inv();
+        assert_eq!(mm_per_cm.get(), 10.0);
+
+        let cm_per_inch: ScaleFactor<f32, Inch, Cm> = mm_per_inch * cm_per_mm;
+        assert_eq!(cm_per_inch, ScaleFactor::new(2.54));
+
+        let a: ScaleFactor<isize, Inch, Inch> = ScaleFactor::new(2);
+        let b: ScaleFactor<isize, Inch, Inch> = ScaleFactor::new(3);
+        assert!(a != b);
+        assert_eq!(a, a.clone());
+        assert_eq!(a.clone() + b.clone(), ScaleFactor::new(5));
+        assert_eq!(a - b, ScaleFactor::new(-1));
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/side_offsets.rs
@@ -0,0 +1,283 @@
+// 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.
+
+//! A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
+//! and margins in CSS.
+
+use super::UnknownUnit;
+use length::Length;
+use num::Zero;
+use std::fmt;
+use std::ops::Add;
+use std::marker::PhantomData;
+
+#[cfg(feature = "unstable")]
+use heapsize::HeapSizeOf;
+
+/// A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
+/// and margins in CSS, optionally tagged with a unit.
+define_matrix! {
+    pub struct TypedSideOffsets2D<T, U> {
+        pub top: T,
+        pub right: T,
+        pub bottom: T,
+        pub left: T,
+    }
+}
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedSideOffsets2D<T, U> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "({:?},{:?},{:?},{:?})",
+               self.top, self.right, self.bottom, self.left)
+    }
+}
+
+/// The default side offset type with no unit.
+pub type SideOffsets2D<T> = TypedSideOffsets2D<T, UnknownUnit>;
+
+impl<T: Copy, U> TypedSideOffsets2D<T, U> {
+    /// Constructor taking a scalar for each side.
+    pub fn new(top: T, right: T, bottom: T, left: T) -> TypedSideOffsets2D<T, U> {
+        TypedSideOffsets2D {
+            top: top,
+            right: right,
+            bottom: bottom,
+            left: left,
+            _unit: PhantomData,
+        }
+    }
+
+    /// Constructor taking a typed Length for each side.
+    pub fn from_lengths(top: Length<T, U>,
+                        right: Length<T, U>,
+                        bottom: Length<T, U>,
+                        left: Length<T, U>) -> TypedSideOffsets2D<T, U> {
+        TypedSideOffsets2D::new(top.0, right.0, bottom.0, left.0)
+    }
+
+    /// Access self.top as a typed Length instead of a scalar value.
+    pub fn top_typed(&self) -> Length<T, U> { Length::new(self.top) }
+
+    /// Access self.right as a typed Length instead of a scalar value.
+    pub fn right_typed(&self) -> Length<T, U> { Length::new(self.right) }
+
+    /// Access self.bottom as a typed Length instead of a scalar value.
+    pub fn bottom_typed(&self) -> Length<T, U> { Length::new(self.bottom) }
+
+    /// Access self.left as a typed Length instead of a scalar value.
+    pub fn left_typed(&self) -> Length<T, U> { Length::new(self.left) }
+
+    /// Constructor setting the same value to all sides, taking a scalar value directly.
+    pub fn new_all_same(all: T) -> TypedSideOffsets2D<T, U> {
+        TypedSideOffsets2D::new(all, all, all, all)
+    }
+
+    /// Constructor setting the same value to all sides, taking a typed Length.
+    pub fn from_length_all_same(all: Length<T, U>) -> TypedSideOffsets2D<T, U> {
+        TypedSideOffsets2D::new_all_same(all.0)
+    }
+}
+
+impl<T, U> TypedSideOffsets2D<T, U> where T: Add<T, Output=T> + Copy {
+    pub fn horizontal(&self) -> T {
+        self.left + self.right
+    }
+
+    pub fn vertical(&self) -> T {
+        self.top + self.bottom
+    }
+
+    pub fn horizontal_typed(&self) -> Length<T, U> {
+        Length::new(self.horizontal())
+    }
+
+    pub fn vertical_typed(&self) -> Length<T, U> {
+        Length::new(self.vertical())
+    }
+}
+
+impl<T, U> Add for TypedSideOffsets2D<T, U> where T : Copy + Add<T, Output=T> {
+    type Output = TypedSideOffsets2D<T, U>;
+    fn add(self, other: TypedSideOffsets2D<T, U>) -> TypedSideOffsets2D<T, U> {
+        TypedSideOffsets2D::new(
+            self.top + other.top,
+            self.right + other.right,
+            self.bottom + other.bottom,
+            self.left + other.left,
+        )
+    }
+}
+
+impl<T: Copy + Zero, U> TypedSideOffsets2D<T, U> {
+    /// Constructor, setting all sides to zero.
+    pub fn zero() -> TypedSideOffsets2D<T, U> {
+        TypedSideOffsets2D::new(
+            Zero::zero(),
+            Zero::zero(),
+            Zero::zero(),
+            Zero::zero(),
+        )
+    }
+}
+
+/// A SIMD enabled version of TypedSideOffsets2D specialized for i32.
+#[cfg(feature = "unstable")]
+#[derive(Clone, Copy, PartialEq)]
+#[repr(simd)]
+pub struct SideOffsets2DSimdI32 {
+    pub top: i32,
+    pub bottom: i32,
+    pub right: i32,
+    pub left: i32,
+}
+
+#[cfg(feature = "unstable")]
+impl HeapSizeOf for SideOffsets2DSimdI32 {
+    fn heap_size_of_children(&self) -> usize { 0 }
+}
+
+#[cfg(feature = "unstable")]
+impl SideOffsets2DSimdI32 {
+    #[inline]
+    pub fn new(top: i32, right: i32, bottom: i32, left: i32) -> SideOffsets2DSimdI32 {
+        SideOffsets2DSimdI32 {
+            top: top,
+            bottom: bottom,
+            right: right,
+            left: left,
+        }
+    }
+}
+
+#[cfg(feature = "unstable")]
+impl SideOffsets2DSimdI32 {
+    #[inline]
+    pub fn new_all_same(all: i32) -> SideOffsets2DSimdI32 {
+        SideOffsets2DSimdI32::new(all.clone(), all.clone(), all.clone(), all.clone())
+    }
+}
+
+#[cfg(feature = "unstable")]
+impl SideOffsets2DSimdI32 {
+    #[inline]
+    pub fn horizontal(&self) -> i32 {
+        self.left + self.right
+    }
+
+    #[inline]
+    pub fn vertical(&self) -> i32 {
+        self.top + self.bottom
+    }
+}
+
+/*impl Add for SideOffsets2DSimdI32 {
+    type Output = SideOffsets2DSimdI32;
+    #[inline]
+    fn add(self, other: SideOffsets2DSimdI32) -> SideOffsets2DSimdI32 {
+        self + other // Use SIMD addition
+    }
+}*/
+
+#[cfg(feature = "unstable")]
+impl SideOffsets2DSimdI32 {
+    #[inline]
+    pub fn zero() -> SideOffsets2DSimdI32 {
+        SideOffsets2DSimdI32 {
+            top: 0,
+            bottom: 0,
+            right: 0,
+            left: 0,
+        }
+    }
+
+    #[cfg(not(target_arch = "x86_64"))]
+    #[inline]
+    pub fn is_zero(&self) -> bool {
+        self.top == 0 && self.right == 0 && self.bottom == 0 && self.left == 0
+    }
+
+    #[cfg(target_arch = "x86_64")]
+    #[inline]
+    pub fn is_zero(&self) -> bool {
+        let is_zero: bool;
+        unsafe {
+            asm! {
+                "ptest $1, $1
+                 setz $0"
+                : "=r"(is_zero)
+                : "x"(*self)
+                :
+                : "intel"
+            };
+        }
+        is_zero
+    }
+}
+
+#[cfg(feature = "unstable")]
+#[cfg(test)]
+mod tests {
+    use super::SideOffsets2DSimdI32;
+
+    #[test]
+    fn test_is_zero() {
+        assert!(SideOffsets2DSimdI32::new_all_same(0).is_zero());
+        assert!(!SideOffsets2DSimdI32::new_all_same(1).is_zero());
+        assert!(!SideOffsets2DSimdI32::new(1, 0, 0, 0).is_zero());
+        assert!(!SideOffsets2DSimdI32::new(0, 1, 0, 0).is_zero());
+        assert!(!SideOffsets2DSimdI32::new(0, 0, 1, 0).is_zero());
+        assert!(!SideOffsets2DSimdI32::new(0, 0, 0, 1).is_zero());
+    }
+}
+
+#[cfg(feature = "unstable")]
+#[cfg(bench)]
+mod bench {
+    use test::BenchHarness;
+    use std::num::Zero;
+    use rand::{XorShiftRng, Rng};
+    use super::SideOffsets2DSimdI32;
+
+    #[cfg(target_arch = "x86")]
+    #[cfg(target_arch = "x86_64")]
+    #[bench]
+    fn bench_naive_is_zero(bh: &mut BenchHarness) {
+        fn is_zero(x: &SideOffsets2DSimdI32) -> bool {
+            x.top.is_zero() && x.right.is_zero() && x.bottom.is_zero() && x.left.is_zero()
+        }
+        let mut rng = XorShiftRng::new().unwrap();
+        bh.iter(|| is_zero(&rng.gen::<SideOffsets2DSimdI32>()))
+    }
+
+    #[bench]
+    fn bench_is_zero(bh: &mut BenchHarness) {
+        let mut rng = XorShiftRng::new().unwrap();
+        bh.iter(|| rng.gen::<SideOffsets2DSimdI32>().is_zero())
+    }
+
+    #[bench]
+    fn bench_naive_add(bh: &mut BenchHarness) {
+        fn add(x: &SideOffsets2DSimdI32, y: &SideOffsets2DSimdI32) -> SideOffsets2DSimdI32 {
+            SideOffsets2DSimdI32 {
+                top: x.top + y.top,
+                right: x.right + y.right,
+                bottom: x.bottom + y.bottom,
+                left: x.left + y.left,
+            }
+        }
+        let mut rng = XorShiftRng::new().unwrap();
+        bh.iter(|| add(&rng.gen::<SideOffsets2DSimdI32>(), &rng.gen::<SideOffsets2DSimdI32>()))
+    }
+
+    #[bench]
+    fn bench_add(bh: &mut BenchHarness) {
+        let mut rng = XorShiftRng::new().unwrap();
+        bh.iter(|| rng.gen::<SideOffsets2DSimdI32>() + rng.gen::<SideOffsets2DSimdI32>())
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/size.rs
@@ -0,0 +1,276 @@
+// 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 super::UnknownUnit;
+use length::Length;
+use scale_factor::ScaleFactor;
+use num::*;
+
+use num_traits::NumCast;
+use std::fmt;
+use std::ops::{Add, Div, Mul, Sub};
+use std::marker::PhantomData;
+
+/// A 2d size tagged with a unit.
+define_matrix! {
+    #[derive(RustcDecodable, RustcEncodable)]
+    pub struct TypedSize2D<T, U> {
+        pub width: T,
+        pub height: T,
+    }
+}
+
+/// Default 2d size type with no unit.
+///
+/// `Size2D` provides the same methods as `TypedSize2D`.
+pub type Size2D<T> = TypedSize2D<T, UnknownUnit>;
+
+impl<T: fmt::Debug, U> fmt::Debug for TypedSize2D<T, U> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{:?}×{:?}", self.width, self.height)
+    }
+}
+
+impl<T: fmt::Display, U> fmt::Display for TypedSize2D<T, U> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        write!(formatter, "({}x{})", self.width, self.height)
+    }
+}
+
+impl<T, U> TypedSize2D<T, U> {
+    /// Constructor taking scalar values.
+    pub fn new(width: T, height: T) -> TypedSize2D<T, U> {
+        TypedSize2D {
+            width: width,
+            height: height,
+            _unit: PhantomData,
+        }
+    }
+}
+
+impl<T: Clone, U> TypedSize2D<T, U> {
+    /// Constructor taking scalar strongly typed lengths.
+    pub fn from_lengths(width: Length<T, U>, height: Length<T, U>) -> TypedSize2D<T, U> {
+        TypedSize2D::new(width.get(), height.get())
+    }
+}
+
+impl<T: Round, U> TypedSize2D<T, U> {
+    /// Rounds each component to the nearest integer value.
+    ///
+    /// This behavior is preserved for negative values (unlike the basic cast).
+    pub fn round(&self) -> Self {
+        TypedSize2D::new(self.width.round(), self.height.round())
+    }
+}
+
+impl<T: Ceil, U> TypedSize2D<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).
+    pub fn ceil(&self) -> Self {
+        TypedSize2D::new(self.width.ceil(), self.height.ceil())
+    }
+}
+
+impl<T: Floor, U> TypedSize2D<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).
+    pub fn floor(&self) -> Self {
+        TypedSize2D::new(self.width.floor(), self.height.floor())
+    }
+}
+
+impl<T: Copy + Add<T, Output=T>, U> Add for TypedSize2D<T, U> {
+    type Output = TypedSize2D<T, U>;
+    fn add(self, other: TypedSize2D<T, U>) -> TypedSize2D<T, U> {
+        TypedSize2D::new(self.width + other.width, self.height + other.height)
+    }
+}
+
+impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedSize2D<T, U> {
+    type Output = TypedSize2D<T, U>;
+    fn sub(self, other: TypedSize2D<T, U>) -> TypedSize2D<T, U> {
+        TypedSize2D::new(self.width - other.width, self.height - other.height)
+    }
+}
+
+impl<T: Copy + Clone + Mul<T, Output=U>, U> TypedSize2D<T, U> {
+    pub fn area(&self) -> U { self.width * self.height }
+}
+
+impl<T: Zero, U> TypedSize2D<T, U> {
+    pub fn zero() -> TypedSize2D<T, U> {
+        TypedSize2D::new(
+            Zero::zero(),
+            Zero::zero(),
+        )
+    }
+}
+
+impl<T: Zero, U> Zero for TypedSize2D<T, U> {
+    fn zero() -> TypedSize2D<T, U> {
+        TypedSize2D::new(
+            Zero::zero(),
+            Zero::zero(),
+        )
+    }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedSize2D<T, U> {
+    type Output = TypedSize2D<T, U>;
+    #[inline]
+    fn mul(self, scale: T) -> TypedSize2D<T, U> {
+        TypedSize2D::new(self.width * scale, self.height * scale)
+    }
+}
+
+impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedSize2D<T, U> {
+    type Output = TypedSize2D<T, U>;
+    #[inline]
+    fn div(self, scale: T) -> TypedSize2D<T, U> {
+        TypedSize2D::new(self.width / scale, self.height / scale)
+    }
+}
+
+impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedSize2D<T, U1> {
+    type Output = TypedSize2D<T, U2>;
+    #[inline]
+    fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedSize2D<T, U2> {
+        TypedSize2D::new(self.width * scale.get(), self.height * scale.get())
+    }
+}
+
+impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedSize2D<T, U2> {
+    type Output = TypedSize2D<T, U1>;
+    #[inline]
+    fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedSize2D<T, U1> {
+        TypedSize2D::new(self.width / scale.get(), self.height / scale.get())
+    }
+}
+
+impl<T: Copy, U> TypedSize2D<T, U> {
+    /// Returns self.width as a Length carrying the unit.
+    #[inline]
+    pub fn width_typed(&self) -> Length<T, U> { Length::new(self.width) }
+
+    /// Returns self.height as a Length carrying the unit.
+    #[inline]
+    pub fn height_typed(&self) -> Length<T, U> { Length::new(self.height) }
+
+    #[inline]
+    pub fn to_array(&self) -> [T; 2] { [self.width, self.height] }
+
+    /// Drop the units, preserving only the numeric value.
+    pub fn to_untyped(&self) -> Size2D<T> {
+        TypedSize2D::new(self.width, self.height)
+    }
+
+    /// Tag a unitless value with units.
+    pub fn from_untyped(p: &Size2D<T>) -> TypedSize2D<T, U> {
+        TypedSize2D::new(p.width, p.height)
+    }
+}
+
+impl<T: NumCast + Copy, Unit> TypedSize2D<T, Unit> {
+    /// Cast from one numeric representation to another, preserving the units.
+    ///
+    /// When casting from floating point to integer coordinates, the decimals are truncated
+    /// as one would expect from a simple cast, but this behavior does not always make sense
+    /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
+    pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedSize2D<NewT, Unit>> {
+        match (NumCast::from(self.width), NumCast::from(self.height)) {
+            (Some(w), Some(h)) => Some(TypedSize2D::new(w, h)),
+            _ => None
+        }
+    }
+
+    // Convenience functions for common casts
+
+    /// Cast into an `f32` size.
+    pub fn to_f32(&self) -> TypedSize2D<f32, Unit> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `uint` size, truncating decimals if any.
+    ///
+    /// 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_uint(&self) -> TypedSize2D<usize, Unit> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `i32` size, truncating decimals if any.
+    ///
+    /// 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_i32(&self) -> TypedSize2D<i32, Unit> {
+        self.cast().unwrap()
+    }
+
+    /// Cast into an `i64` size, truncating decimals if any.
+    ///
+    /// 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()
+    }
+}
+
+/// 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;
+
+    #[test]
+    pub fn test_add() {
+        let p1 = Size2D::new(1.0, 2.0);
+        let p2 = Size2D::new(3.0, 4.0);
+        assert_eq!(p1 + p2, Size2D::new(4.0, 6.0));
+
+        let p1 = Size2D::new(1.0, 2.0);
+        let p2 = Size2D::new(0.0, 0.0);
+        assert_eq!(p1 + p2, Size2D::new(1.0, 2.0));
+
+        let p1 = Size2D::new(1.0, 2.0);
+        let p2 = Size2D::new(-3.0, -4.0);
+        assert_eq!(p1 + p2, Size2D::new(-2.0, -2.0));
+
+        let p1 = Size2D::new(0.0, 0.0);
+        let p2 = Size2D::new(0.0, 0.0);
+        assert_eq!(p1 + p2, Size2D::new(0.0, 0.0));
+    }
+
+    #[test]
+    pub fn test_sub() {
+        let p1 = Size2D::new(1.0, 2.0);
+        let p2 = Size2D::new(3.0, 4.0);
+        assert_eq!(p1 - p2, Size2D::new(-2.0, -2.0));
+
+        let p1 = Size2D::new(1.0, 2.0);
+        let p2 = Size2D::new(0.0, 0.0);
+        assert_eq!(p1 - p2, Size2D::new(1.0, 2.0));
+
+        let p1 = Size2D::new(1.0, 2.0);
+        let p2 = Size2D::new(-3.0, -4.0);
+        assert_eq!(p1 - p2, Size2D::new(4.0, 6.0));
+
+        let p1 = Size2D::new(0.0, 0.0);
+        let p2 = Size2D::new(0.0, 0.0);
+        assert_eq!(p1 - p2, Size2D::new(0.0, 0.0));
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/euclid-0.11.3/src/trig.rs
@@ -0,0 +1,50 @@
+// 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.
+
+
+/// Trait for basic trigonometry functions, so they can be used on generic numeric types
+pub trait Trig {
+    fn sin(self) -> Self;
+    fn cos(self) -> Self;
+    fn tan(self) -> Self;
+}
+
+impl Trig for f32 {
+    #[inline]
+    fn sin(self) -> f32 {
+        self.sin()
+    }
+
+    #[inline]
+    fn cos(self) -> f32 {
+       self.cos()
+    }
+
+    #[inline]
+    fn tan(self) -> f32 {
+       self.tan()
+    }
+}
+
+impl Trig for f64 {
+    #[inline]
+    fn sin(self) -> f64 {
+        self.sin()
+    }
+
+    #[inline]
+    fn cos(self) -> f64 {
+       self.cos()
+    }
+
+    #[inline]
+    fn tan(self) -> f64 {
+       self.tan()
+    }
+}
--- a/third_party/rust/euclid/.cargo-checksum.json
+++ b/third_party/rust/euclid/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"118514fd9c4958df0d25584cda4917186c46011569f55ef350530c1ad3fbdb48",".travis.yml":"13d3e5a7bf83b04c8e8cfa14f0297bd8366d68391d977dd547f64707dffc275a","COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"10cfe5580ee83ae883a60d96f504dda8ae7885ae5fd3a3faf95c2a2b8b38fad0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"52f974f01c1e15182413e4321c8817d5e66fe4d92c5ec223c857dd0440f5c229","src/approxeq.rs":"2987e046c90d948b6c7d7ddba52d10c8b7520d71dc0a50dbe7665de128d7410e","src/length.rs":"d7c6369f2fe2a17c845b57749bd48c471159f0571a7314d3bf90737d53f697d3","src/lib.rs":"e2e621f05304278d020429d0349acf7a4e7c7a9a72bd23fc0e55680267472ee9","src/macros.rs":"b63dabdb52df84ea170dc1dab5fe8d7a78c054562d1566bab416124708d2d7af","src/matrix2d.rs":"2361338f59813adf4eebaab76e4dd82be0fbfb9ff2461da8dd9ac9d43583b322","src/matrix4d.rs":"b8547bed6108b037192021c97169c00ad456120b849e9b7ac7bec40363edaec1","src/num.rs":"62286aa642ce3afa7ebd950f50bf2197d8722907f2e23a2e2ea6690484d8b250","src/point.rs":"53f3c9018c822e0a6dc5018005e153775479f41fe55c082d0be10f331fda773f","src/rect.rs":"db62b3af8939529509ae21b3bf6ae498d73a95b4ff3a6eba4db614be08e95f8b","src/scale_factor.rs":"df6dbd1f0f9f63210b92809f84a383dad982a74f09789cf22c7d8f9b62199d39","src/side_offsets.rs":"f85526a421ffda63ff01a3478d4162c8717eef68e942acfa2fd9a1adee02ebb2","src/size.rs":"19d1c08f678d793c6eff49a44f69e5b7179e574aa9b81fb4e73210733af38718","src/trig.rs":"6b207980052d13c625272f2a70a22f7741b59513c2a4882385926f497c763a63"},"package":"f5517462c626a893f3b027615e88d7102cc6dd3f7f1bcb90c7220fb1da4970b5"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"118514fd9c4958df0d25584cda4917186c46011569f55ef350530c1ad3fbdb48",".travis.yml":"13d3e5a7bf83b04c8e8cfa14f0297bd8366d68391d977dd547f64707dffc275a","COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"c91c98dc9510ef29a7ce0d7c78294f15cb139c9afecca38e5fda56b0a6984954","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6cf810ad389c73a27141a7a67454ed12d4b01c3c16605b9a7414b389bc0615dd","src/length.rs":"d7c6369f2fe2a17c845b57749bd48c471159f0571a7314d3bf90737d53f697d3","src/lib.rs":"e2e621f05304278d020429d0349acf7a4e7c7a9a72bd23fc0e55680267472ee9","src/macros.rs":"b63dabdb52df84ea170dc1dab5fe8d7a78c054562d1566bab416124708d2d7af","src/matrix2d.rs":"2361338f59813adf4eebaab76e4dd82be0fbfb9ff2461da8dd9ac9d43583b322","src/matrix4d.rs":"b8547bed6108b037192021c97169c00ad456120b849e9b7ac7bec40363edaec1","src/num.rs":"749b201289fc6663199160a2f9204e17925fd3053f8ab7779e7bfb377ad06227","src/point.rs":"dbf12a3ad35dc2502b7f2637856d8ee40f5a96e37ed00f3ee3272bf5752c060c","src/rect.rs":"0a255046dd11a6093d9a77e327e1df31802808536b4d87e4e3b80ff6b208de0f","src/scale_factor.rs":"df6dbd1f0f9f63210b92809f84a383dad982a74f09789cf22c7d8f9b62199d39","src/side_offsets.rs":"f85526a421ffda63ff01a3478d4162c8717eef68e942acfa2fd9a1adee02ebb2","src/size.rs":"ae1b647e300600b50a21dba8c1d915801782ebae82baeb5e49017e6d68a49b28","src/trig.rs":"ef290927af252ca90a29ba9f17158b591ed591604e66cb9df045dd47b9cfdca5"},"package":"6083f113c422ff9cd855a1cf6cc8ec0903606c0eb43a0c6a0ced3bdc9731e4c1"}
\ No newline at end of file
--- a/third_party/rust/euclid/Cargo.toml
+++ b/third_party/rust/euclid/Cargo.toml
@@ -1,22 +1,24 @@
 [package]
 name = "euclid"
-version = "0.11.3"
+version = "0.13.0"
 authors = ["The Servo Project Developers"]
 description = "Geometry primitives"
 documentation = "https://docs.rs/euclid/"
 repository = "https://github.com/servo/euclid"
+keywords = ["matrix", "vector", "linear-algebra", "geometry"]
+categories = ["science"]
 license = "MIT / Apache-2.0"
 
 [features]
 unstable = []
 
 [dependencies]
-heapsize = "0.3"
+heapsize = "0.4"
 rustc-serialize = "0.3.2"
 num-traits = {version = "0.1.32", default-features = false}
 log = "0.3.1"
 serde = "0.9"
 
 [dev-dependencies]
 rand = "0.3.7"
 serde_test = "0.9"
--- a/third_party/rust/euclid/README.md
+++ b/third_party/rust/euclid/README.md
@@ -1,5 +1,8 @@
 # euclid
 
-This is a small library for geometric types.
+This is a small library for geometric types with a focus on 2d graphics and
+layout.
 
-[Documentation](https://docs.rs/euclid/)
+* [Documentation](https://docs.rs/euclid/)
+* [Release notes](https://github.com/servo/euclid/releases)
+* [crates.io](https://crates.io/crates/euclid)
--- a/third_party/rust/euclid/src/approxeq.rs
+++ b/third_party/rust/euclid/src/approxeq.rs
@@ -10,38 +10,27 @@
 
 /// Trait for testing approximate equality
 pub trait ApproxEq<Eps> {
     fn approx_epsilon() -> Eps;
     fn approx_eq(&self, other: &Self) -> bool;
     fn approx_eq_eps(&self, other: &Self, approx_epsilon: &Eps) -> bool;
 }
 
-impl ApproxEq<f32> for f32 {
-    #[inline]
-    fn approx_epsilon() -> f32 { 1.0e-6 }
-
-    #[inline]
-    fn approx_eq(&self, other: &f32) -> bool {
-       self.approx_eq_eps(other, &1.0e-6)
-    }
-
-    #[inline]
-    fn approx_eq_eps(&self, other: &f32, approx_epsilon: &f32) -> bool {
-       (*self - *other).abs() < *approx_epsilon
-    }
+macro_rules! approx_eq {
+    ($ty:ty, $eps:expr) => (
+        impl ApproxEq<$ty> for $ty {
+            #[inline]
+            fn approx_epsilon() -> $ty { $eps }
+            #[inline]
+            fn approx_eq(&self, other: &$ty) -> bool {
+                self.approx_eq_eps(other, &$eps)
+            }
+            #[inline]
+            fn approx_eq_eps(&self, other: &$ty, approx_epsilon: &$ty) -> bool {
+                (*self - *other).abs() < *approx_epsilon
+            }
+        }
+    )
 }
 
-
-impl ApproxEq<f64> for f64 {
-    #[inline]
-    fn approx_epsilon() -> f64 { 1.0e-6 }
-
-    #[inline]
-    fn approx_eq(&self, other: &f64) -> bool {
-        self.approx_eq_eps(other, &1.0e-6)
-    }
-
-    #[inline]
-    fn approx_eq_eps(&self, other: &f64, approx_epsilon: &f64) -> bool {
-        (*self - *other).abs() < *approx_epsilon
-    }
-}
+approx_eq!(f32, 1.0e-6);
+approx_eq!(f64, 1.0e-6);
--- a/third_party/rust/euclid/src/num.rs
+++ b/third_party/rust/euclid/src/num.rs
@@ -22,45 +22,56 @@ impl<T: num_traits::Zero> Zero for T {
 pub trait One {
     fn one() -> Self;
 }
 
 impl<T: num_traits::One> One for T {
     fn one() -> T { num_traits::One::one() }
 }
 
+
 pub trait Round : Copy { fn round(self) -> Self; }
 pub trait Floor : Copy { fn floor(self) -> Self; }
 pub trait Ceil : Copy { fn ceil(self) -> Self; }
 
-impl Round for f32 { fn round(self) -> Self { self.round() } }
-impl Round for f64 { fn round(self) -> Self { self.round() } }
-impl Round for i16 { fn round(self) -> Self { self } }
-impl Round for u16 { fn round(self) -> Self { self } }
-impl Round for i32 { fn round(self) -> Self { self } }
-impl Round for i64 { fn round(self) -> Self { self } }
-impl Round for u32 { fn round(self) -> Self { self } }
-impl Round for u64 { fn round(self) -> Self { self } }
-impl Round for usize { fn round(self) -> Self { self } }
-impl Round for isize { fn round(self) -> Self { self } }
+macro_rules! num_int {
+    ($ty:ty) => (
+        impl Round for $ty {
+            #[inline]
+            fn round(self) -> $ty { self }
+        }
+        impl Floor for $ty {
+            #[inline]
+            fn floor(self) -> $ty { self }
+        }
+        impl Ceil for $ty {
+            #[inline]
+            fn ceil(self) -> $ty { self }
+        }
+    )
+}
+macro_rules! num_float {
+    ($ty:ty) => (
+        impl Round for $ty {
+            #[inline]
+            fn round(self) -> $ty { self.round() }
+        }
+        impl Floor for $ty {
+            #[inline]
+            fn floor(self) -> $ty { self.floor() }
+        }
+        impl Ceil for $ty {
+            #[inline]
+            fn ceil(self) -> $ty { self.ceil() }
+        }
+    )
+}
 
-impl Floor for f32 { fn floor(self) -> Self { self.floor() } }
-impl Floor for f64 { fn floor(self) -> Self { self.floor() } }
-impl Floor for i16 { fn floor(self) -> Self { self } }
-impl Floor for u16 { fn floor(self) -> Self { self } }
-impl Floor for i32 { fn floor(self) -> Self { self } }
-impl Floor for i64 { fn floor(self) -> Self { self } }
-impl Floor for u32 { fn floor(self) -> Self { self } }
-impl Floor for u64 { fn floor(self) -> Self { self } }
-impl Floor for usize { fn floor(self) -> Self { self } }
-impl Floor for isize { fn floor(self) -> Self { self } }
-
-impl Ceil for f32 { fn ceil(self) -> Self { self.ceil() } }
-impl Ceil for f64 { fn ceil(self) -> Self { self.ceil() } }
-impl Ceil for i16 { fn ceil(self) -> Self { self } }
-impl Ceil for u16 { fn ceil(self) -> Self { self } }
-impl Ceil for i32 { fn ceil(self) -> Self { self } }
-impl Ceil for i64 { fn ceil(self) -> Self { self } }
-impl Ceil for u32 { fn ceil(self) -> Self { self } }
-impl Ceil for u64 { fn ceil(self) -> Self { self } }
-impl Ceil for usize { fn ceil(self) -> Self { self } }
-impl Ceil for isize { fn ceil(self) -> Self { self } }
-
+num_int!(i16);
+num_int!(u16);
+num_int!(i32);
+num_int!(u32);
+num_int!(i64);
+num_int!(u64);
+num_int!(isize);
+num_int!(usize);
+num_float!(f32);
+num_float!(f64);
--- a/third_party/rust/euclid/src/point.rs
+++ b/third_party/rust/euclid/src/point.rs
@@ -249,17 +249,17 @@ impl<T: NumCast + Copy, U> TypedPoint2D<
         self.cast().unwrap()
     }
 
     /// Cast into an `usize` point, truncating decimals if any.
     ///
     /// When casting from floating point points, it is worth considering whether
     /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
     /// the desired conversion behavior.
-    pub fn to_uint(&self) -> TypedPoint2D<usize, U> {
+    pub fn to_usize(&self) -> TypedPoint2D<usize, U> {
         self.cast().unwrap()
     }
 
     /// Cast into an i32 point, truncating decimals if any.
     ///
     /// When casting from floating point points, it is worth considering whether
     /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
     /// the desired conversion behavior.
@@ -512,17 +512,17 @@ impl<T: NumCast + Copy, U> TypedPoint3D<
         self.cast().unwrap()
     }
 
     /// Cast into an `usize` point, truncating decimals if any.
     ///
     /// When casting from floating point points, it is worth considering whether
     /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
     /// the desired conversion behavior.
-    pub fn to_uint(&self) -> TypedPoint3D<usize, U> {
+    pub fn to_usize(&self) -> TypedPoint3D<usize, U> {
         self.cast().unwrap()
     }
 
     /// Cast into an `i32` point, truncating decimals if any.
     ///
     /// When casting from floating point points, it is worth considering whether
     /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
     /// the desired conversion behavior.
@@ -751,17 +751,17 @@ impl<T: NumCast + Copy, U> TypedPoint4D<
         self.cast().unwrap()
     }
 
     /// Cast into an `usize` point, truncating decimals if any.
     ///
     /// When casting from floating point points, it is worth considering whether
     /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
     /// the desired conversion behavior.
-    pub fn to_uint(&self) -> TypedPoint4D<usize, U> {
+    pub fn to_usize(&self) -> TypedPoint4D<usize, U> {
         self.cast().unwrap()
     }
 
     /// Cast into an `i32` point, truncating decimals if any.
     ///
     /// When casting from floating point points, it is worth considering whether
     /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
     /// the desired conversion behavior.
--- a/third_party/rust/euclid/src/rect.rs
+++ b/third_party/rust/euclid/src/rect.rs
@@ -399,17 +399,17 @@ impl<T: NumCast + Copy, Unit> TypedRect<
         self.cast().unwrap()
     }
 
     /// Cast into an `usize` rectangle, truncating decimals if any.
     ///
     /// When casting from floating point rectangles, it is worth considering whether
     /// to `round()`, `round_in()` or `round_out()` before the cast in order to
     /// obtain the desired conversion behavior.
-    pub fn to_uint(&self) -> TypedRect<usize, Unit> {
+    pub fn to_usize(&self) -> TypedRect<usize, Unit> {
         self.cast().unwrap()
     }
 
     /// Cast into an `i32` rectangle, truncating decimals if any.
     ///
     /// When casting from floating point rectangles, it is worth considering whether
     /// to `round()`, `round_in()` or `round_out()` before the cast in order to
     /// obtain the desired conversion behavior.
--- a/third_party/rust/euclid/src/size.rs
+++ b/third_party/rust/euclid/src/size.rs
@@ -199,17 +199,17 @@ impl<T: NumCast + Copy, Unit> TypedSize2
         self.cast().unwrap()
     }
 
     /// Cast into an `uint` size, truncating decimals if any.
     ///
     /// 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_uint(&self) -> TypedSize2D<usize, Unit> {
+    pub fn to_usize(&self) -> TypedSize2D<usize, Unit> {
         self.cast().unwrap()
     }
 
     /// Cast into an `i32` size, truncating decimals if any.
     ///
     /// 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.
--- a/third_party/rust/euclid/src/trig.rs
+++ b/third_party/rust/euclid/src/trig.rs
@@ -10,41 +10,23 @@
 
 /// Trait for basic trigonometry functions, so they can be used on generic numeric types
 pub trait Trig {
     fn sin(self) -> Self;
     fn cos(self) -> Self;
     fn tan(self) -> Self;
 }
 
-impl Trig for f32 {
-    #[inline]
-    fn sin(self) -> f32 {
-        self.sin()
-    }
-
-    #[inline]
-    fn cos(self) -> f32 {
-       self.cos()
-    }
-
-    #[inline]
-    fn tan(self) -> f32 {
-       self.tan()
-    }
+macro_rules! trig {
+    ($ty:ty) => (
+        impl Trig for $ty {
+            #[inline]
+            fn sin(self) -> $ty { self.sin() }
+            #[inline]
+            fn cos(self) -> $ty { self.cos() }
+            #[inline]
+            fn tan(self) -> $ty { self.tan() }
+        }
+    )
 }
 
-impl Trig for f64 {
-    #[inline]
-    fn sin(self) -> f64 {
-        self.sin()
-    }
-
-    #[inline]
-    fn cos(self) -> f64 {
-       self.cos()
-    }
-
-    #[inline]
-    fn tan(self) -> f64 {
-       self.tan()
-    }
-}
+trig!(f32);
+trig!(f64);
new file mode 100644
--- /dev/null
+++ b/third_party/rust/heapsize-0.3.8/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"97503c8cf1fc53fd41e237662402477c0ab257225d25fe21470494a0b1bbec3c",".travis.yml":"1108708721703f4562646e1e7c6f6c924fa997835714bcc6a3ff8a58382134f1","Cargo.toml":"723e5918946fdb518ed1ad3e03ae9104b980cbe85bbee1989dc4197570ba6d73","README.md":"9a38b16bccde5db28c34d79134f02d2cdcbbab224b9a68ace93c5b85b5ef38f2","appveyor.yml":"130e820ab60abf8d08f3a91d4b0158e6a581c180385e12850113adb362eb158c","build.rs":"e13e88ed285a829256d3c6987563a663c37e335457d090125a3e19b1a97fec8e","src/lib.rs":"ab4e0a2e6d0ac700df5dbb7a2c83542cb82c94d4e46c632a4114fec93d6aba0a","tests/tests.rs":"f642da7b54b6cde55cf25fe84b2e6b27356d26b351d42a38e944b93e0c1fa24f"},"package":"5a376f7402b85be6e0ba504243ecbc0709c48019ecc6286d0540c2e359050c88"}
\ No newline at end of file
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/third_party/rust/heapsize-0.3.8/.gitignore
@@ -0,0 +1,3 @@
+target
+Cargo.lock
+*.swp
new file mode 100644
--- /dev/null
+++ b/third_party/rust/heapsize-0.3.8/.travis.yml
@@ -0,0 +1,19 @@
+language: rust
+rust:
+ - 1.8.0
+ - nightly
+ - beta
+ - stable
+
+os:
+  - linux
+  - osx
+
+notifications:
+  webhooks: http://build.servo.org:54856/travis
+
+script:
+ - cargo test
+ - "[ $TRAVIS_RUST_VERSION != nightly ] || cargo test --features unstable"
+ - "[ $TRAVIS_RUST_VERSION != nightly ] || cargo test --manifest-path derive/Cargo.toml"
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/heapsize-0.3.8/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "heapsize"
+version = "0.3.8"
+authors = [ "The Servo Project Developers" ]
+description = "Infrastructure for measuring the total runtime size of an object on the heap"
+license = "MPL-2.0"
+repository = "https://github.com/servo/heapsize"
+build = "build.rs"
+
+[target.'cfg(windows)'.dependencies]
+kernel32-sys = "0.2.1"
+
+[features]
+unstable = []
new file mode 100644
--- /dev/null
+++ b/third_party/rust/heapsize-0.3.8/README.md
@@ -0,0 +1,5 @@
+# heapsize
+
+In support of measuring heap allocations in Rust programs.
+
+[API Documentation](https://doc.servo.org/heapsize/)
new file mode 100644
--- /dev/null
+++ b/third_party/rust/heapsize-0.3.8/appveyor.yml
@@ -0,0 +1,23 @@
+environment:
+  matrix:
+  - FEATURES: ""
+  - FEATURES: "unstable"
+
+platform:
+  - i686-pc-windows-gnu
+  - i686-pc-windows-msvc
+  - x86_64-pc-windows-gnu
+  - x86_64-pc-windows-msvc
+
+install:
+  - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:PLATFORM}.exe"
+  - rust-nightly-%PLATFORM%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
+  - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
+  - rustc -V
+  - cargo -V
+
+build_script:
+  - cargo build --verbose --features "%FEATURES%"
+
+test_script:
+  - cargo test --verbose --features "%FEATURES%"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/heapsize-0.3.8/build.rs
@@ -0,0 +1,37 @@
+use std::env::var;
+use std::process::Command;
+use std::str;
+
+fn main() {
+    let verbose = Command::new(var("RUSTC").unwrap_or("rustc".into()))
+        .arg("--version")
+        .arg("--verbose")
+        .output()
+        .unwrap()
+        .stdout;
+    let verbose = str::from_utf8(&verbose).unwrap();
+    let mut commit_date = None;
+    let mut release = None;
+    for line in verbose.lines() {
+        let mut parts = line.split(':');
+        match parts.next().unwrap().trim() {
+            "commit-date" => commit_date = Some(parts.next().unwrap().trim()),
+            "release" => release = Some(parts.next().unwrap().trim()),
+            _ => {}
+        }
+    }
+    let version = release.unwrap().split('-').next().unwrap();;
+    let mut version_components = version.split('.').map(|s| s.parse::<u32>().unwrap());
+    let version = (
+        version_components.next().unwrap(),
+        version_components.next().unwrap(),
+        version_components.next().unwrap(),
+        // "unknown" sorts after "2016-02-14", which is what we want to defaut to unprefixed
+        // https://github.com/servo/heapsize/pull/44#issuecomment-187935883
+        commit_date.unwrap()
+    );
+    assert_eq!(version_components.next(), None);
+    if version < (1, 8, 0, "2016-02-14") {
+        println!("cargo:rustc-cfg=prefixed_jemalloc");
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/heapsize-0.3.8/src/lib.rs
@@ -0,0 +1,323 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//! Data structure measurement.
+
+#[cfg(target_os = "windows")]
+extern crate kernel32;
+
+#[cfg(target_os = "windows")]
+use kernel32::{GetProcessHeap, HeapSize, HeapValidate};
+use std::borrow::Cow;
+use std::cell::{Cell, RefCell};
+use std::collections::{BTreeMap, HashSet, HashMap, LinkedList, VecDeque};
+use std::hash::BuildHasher;
+use std::hash::Hash;
+use std::marker::PhantomData;
+use std::mem::size_of;
+use std::net::{Ipv4Addr, Ipv6Addr};
+use std::os::raw::c_void;
+use std::sync::Arc;
+use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize};
+use std::rc::Rc;
+
+/// Get the size of a heap block.
+///
+/// Ideally Rust would expose a function like this in std::rt::heap.
+///
+/// `unsafe` because the caller must ensure that the pointer is from jemalloc.
+/// FIXME: This probably interacts badly with custom allocators:
+/// https://doc.rust-lang.org/book/custom-allocators.html
+pub unsafe fn heap_size_of(ptr: *const c_void) -> usize {
+    if ptr == 0x01 as *const c_void {
+        0
+    } else {
+        heap_size_of_impl(ptr)
+    }
+}
+
+#[cfg(not(target_os = "windows"))]
+unsafe fn heap_size_of_impl(ptr: *const c_void) -> usize {
+    // The C prototype is `je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr)`. On some
+    // platforms `JEMALLOC_USABLE_SIZE_CONST` is `const` and on some it is empty. But in practice
+    // this function doesn't modify the contents of the block that `ptr` points to, so we use
+    // `*const c_void` here.
+    extern "C" {
+		#[cfg_attr(any(prefixed_jemalloc, target_os = "macos", target_os = "android"), link_name = "je_malloc_usable_size")]
+        fn malloc_usable_size(ptr: *const c_void) -> usize;
+    }
+    malloc_usable_size(ptr)
+}
+
+#[cfg(target_os = "windows")]
+pub unsafe fn heap_size_of_impl(mut ptr: *const c_void) -> usize {
+    let heap = GetProcessHeap();
+
+    if HeapValidate(heap, 0, ptr) == 0 {
+        ptr = *(ptr as *const *const c_void).offset(-1);
+    }
+
+    HeapSize(heap, 0, ptr) as usize
+}
+
+// The simplest trait for measuring the size of heap data structures. More complex traits that
+// return multiple measurements -- e.g. measure text separately from images -- are also possible,
+// and should be used when appropriate.
+//
+pub trait HeapSizeOf {
+    /// Measure the size of any heap-allocated structures that hang off this value, but not the
+    /// space taken up by the value itself (i.e. what size_of::<T> measures, more or less); that
+    /// space is handled by the implementation of HeapSizeOf for Box<T> below.
+    fn heap_size_of_children(&self) -> usize;
+}
+
+// There are two possible ways to measure the size of `self` when it's on the heap: compute it
+// (with `::std::rt::heap::usable_size(::std::mem::size_of::<T>(), 0)`) or measure it directly
+// using the heap allocator (with `heap_size_of`). We do the latter, for the following reasons.
+//
+// * The heap allocator is the true authority for the sizes of heap blocks; its measurement is
+//   guaranteed to be correct. In comparison, size computations are error-prone. (For example, the
+//   `rt::heap::usable_size` function used in some of Rust's non-default allocator implementations
+//   underestimate the true usable size of heap blocks, which is safe in general but would cause
+//   under-measurement here.)
+//
+// * If we measure something that isn't a heap block, we'll get a crash. This keeps us honest,
+//   which is important because unsafe code is involved and this can be gotten wrong.
+//
+// However, in the best case, the two approaches should give the same results.
+//
+impl<T: HeapSizeOf + ?Sized> HeapSizeOf for Box<T> {
+    fn heap_size_of_children(&self) -> usize {
+        // Measure size of `self`.
+        unsafe {
+            heap_size_of(&**self as *const T as *const c_void) + (**self).heap_size_of_children()
+        }
+    }
+}
+
+impl<T: HeapSizeOf> HeapSizeOf for [T] {
+    fn heap_size_of_children(&self) -> usize {
+        self.iter().fold(0, |size, item| size + item.heap_size_of_children())
+    }
+}
+
+impl HeapSizeOf for String {
+    fn heap_size_of_children(&self) -> usize {
+        unsafe {
+            heap_size_of(self.as_ptr() as *const c_void)
+        }
+    }
+}
+
+impl<'a, T: ?Sized> HeapSizeOf for &'a T {
+    fn heap_size_of_children(&self) -> usize {
+        0
+    }
+}
+
+impl<T: HeapSizeOf> HeapSizeOf for Option<T> {
+    fn heap_size_of_children(&self) -> usize {
+        match *self {
+            None => 0,
+            Some(ref x) => x.heap_size_of_children()
+        }
+    }
+}
+
+impl<T: HeapSizeOf, E: HeapSizeOf> HeapSizeOf for Result<T, E> {
+    fn heap_size_of_children(&self) -> usize {
+        match *self {
+            Ok(ref x) => x.heap_size_of_children(),
+            Err(ref e) => e.heap_size_of_children(),
+        }
+    }
+}
+
+impl<'a, B: ?Sized + ToOwned> HeapSizeOf for Cow<'a, B> where B::Owned: HeapSizeOf {
+    fn heap_size_of_children(&self) -> usize {
+        match *self {
+            Cow::Borrowed(_) => 0,
+            Cow::Owned(ref b) => b.heap_size_of_children(),
+        }
+    }
+}
+
+impl HeapSizeOf for () {
+    fn heap_size_of_children(&self) -> usize {
+        0
+    }
+}
+
+impl<T1, T2> HeapSizeOf for (T1, T2)
+    where T1: HeapSizeOf, T2 :HeapSizeOf
+{
+    fn heap_size_of_children(&self) -> usize {
+        self.0.heap_size_of_children() +
+            self.1.heap_size_of_children()
+    }
+}
+
+impl<T1, T2, T3> HeapSizeOf for (T1, T2, T3)
+    where T1: HeapSizeOf, T2 :HeapSizeOf, T3: HeapSizeOf
+{
+    fn heap_size_of_children(&self) -> usize {
+        self.0.heap_size_of_children() +
+            self.1.heap_size_of_children() +
+            self.2.heap_size_of_children()
+    }
+}
+
+impl<T1, T2, T3, T4> HeapSizeOf for (T1, T2, T3, T4)
+    where T1: HeapSizeOf, T2 :HeapSizeOf, T3: HeapSizeOf, T4: HeapSizeOf
+{
+    fn heap_size_of_children(&self) -> usize {
+        self.0.heap_size_of_children() +
+            self.1.heap_size_of_children() +
+            self.2.heap_size_of_children() +
+            self.3.heap_size_of_children()
+  }
+}
+
+impl<T1, T2, T3, T4, T5> HeapSizeOf for (T1, T2, T3, T4, T5)
+    where T1: HeapSizeOf, T2 :HeapSizeOf, T3: HeapSizeOf, T4: HeapSizeOf, T5: HeapSizeOf
+{
+    fn heap_size_of_children(&self) -> usize {
+        self.0.heap_size_of_children() +
+            self.1.heap_size_of_children() +
+            self.2.heap_size_of_children() +
+            self.3.heap_size_of_children() +
+            self.4.heap_size_of_children()
+  }
+}
+
+impl<T: HeapSizeOf> HeapSizeOf for Arc<T> {
+    fn heap_size_of_children(&self) -> usize {
+        (**self).heap_size_of_children()
+    }
+}
+
+impl<T: HeapSizeOf> HeapSizeOf for RefCell<T> {
+    fn heap_size_of_children(&self) -> usize {
+        self.borrow().heap_size_of_children()
+    }
+}
+
+impl<T: HeapSizeOf + Copy> HeapSizeOf for Cell<T> {
+    fn heap_size_of_children(&self) -> usize {
+        self.get().heap_size_of_children()
+    }
+}
+
+impl<T: HeapSizeOf> HeapSizeOf for Vec<T> {
+    fn heap_size_of_children(&self) -> usize {
+        self.iter().fold(
+            unsafe { heap_size_of(self.as_ptr() as *const c_void) },
+            |n, elem| n + elem.heap_size_of_children())
+    }
+}
+
+impl<T: HeapSizeOf> HeapSizeOf for VecDeque<T> {
+    fn heap_size_of_children(&self) -> usize {
+        self.iter().fold(
+            // FIXME: get the buffer pointer for heap_size_of(), capacity() is a lower bound:
+            self.capacity() * size_of::<T>(),
+            |n, elem| n + elem.heap_size_of_children())
+    }
+}
+
+impl<T> HeapSizeOf for Vec<Rc<T>> {
+    fn heap_size_of_children(&self) -> usize {
+        // The fate of measuring Rc<T> is still undecided, but we still want to measure
+        // the space used for storing them.
+        unsafe {
+            heap_size_of(self.as_ptr() as *const c_void)
+        }
+    }
+}
+
+impl<T: HeapSizeOf, S> HeapSizeOf for HashSet<T, S>
+    where T: Eq + Hash, S: BuildHasher {
+    fn heap_size_of_children(&self) -> usize {
+        //TODO(#6908) measure actual bucket memory usage instead of approximating
+        let size = self.capacity() * (size_of::<T>() + size_of::<usize>());
+        self.iter().fold(size, |n, value| {
+            n + value.heap_size_of_children()
+        })
+    }
+}
+
+impl<K: HeapSizeOf, V: HeapSizeOf, S> HeapSizeOf for HashMap<K, V, S>
+    where K: Eq + Hash, S: BuildHasher {
+    fn heap_size_of_children(&self) -> usize {
+        //TODO(#6908) measure actual bucket memory usage instead of approximating
+        let size = self.capacity() * (size_of::<V>() + size_of::<K>() + size_of::<usize>());
+        self.iter().fold(size, |n, (key, value)| {
+            n + key.heap_size_of_children() + value.heap_size_of_children()
+        })
+    }
+}
+
+// PhantomData is always 0.
+impl<T> HeapSizeOf for PhantomData<T> {
+    fn heap_size_of_children(&self) -> usize {
+        0
+    }
+}
+
+// A linked list has an overhead of two words per item.
+impl<T: HeapSizeOf> HeapSizeOf for LinkedList<T> {
+    fn heap_size_of_children(&self) -> usize {
+        let mut size = 0;
+        for item in self {
+            size += 2 * size_of::<usize>() + size_of::<T>() + item.heap_size_of_children();
+        }
+        size
+    }
+}
+
+// FIXME: Overhead for the BTreeMap nodes is not accounted for.
+impl<K: HeapSizeOf, V: HeapSizeOf> HeapSizeOf for BTreeMap<K, V> {
+    fn heap_size_of_children(&self) -> usize {
+        let mut size = 0;
+        for (key, value) in self.iter() {
+            size += size_of::<(K, V)>() +
+                    key.heap_size_of_children() +
+                    value.heap_size_of_children();
+        }
+        size
+    }
+}
+
+/// For use on types defined in external crates
+/// with known heap sizes.
+#[macro_export]
+macro_rules! known_heap_size(
+    ($size:expr, $($ty:ty),+) => (
+        $(
+            impl $crate::HeapSizeOf for $ty {
+                #[inline(always)]
+                fn heap_size_of_children(&self) -> usize {
+                    $size
+                }
+            }
+        )+
+    );
+    ($size: expr, $($ty:ident<$($gen:ident),+>),+) => (
+        $(
+        impl<$($gen: $crate::HeapSizeOf),+> $crate::HeapSizeOf for $ty<$($gen),+> {
+            #[inline(always)]
+            fn heap_size_of_children(&self) -> usize {
+                $size
+            }
+        }
+        )+
+    );
+);
+
+known_heap_size!(0, char, str);
+known_heap_size!(0, u8, u16, u32, u64, usize);
+known_heap_size!(0, i8, i16, i32, i64, isize);
+known_heap_size!(0, bool, f32, f64);
+known_heap_size!(0, AtomicBool, AtomicIsize, AtomicUsize);
+known_heap_size!(0, Ipv4Addr, Ipv6Addr);
new file mode 100644
--- /dev/null
+++ b/third_party/rust/heapsize-0.3.8/tests/tests.rs
@@ -0,0 +1,171 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#![cfg_attr(feature= "unstable", feature(alloc, heap_api, repr_simd))]
+
+extern crate heapsize;
+
+use heapsize::{HeapSizeOf, heap_size_of};
+use std::os::raw::c_void;
+
+pub const EMPTY: *mut () = 0x1 as *mut ();
+
+#[cfg(feature = "unstable")]
+mod unstable {
+    extern crate alloc;
+
+    use heapsize::{HeapSizeOf, heap_size_of};
+    use std::os::raw::c_void;
+
+    #[repr(C, simd)]
+    struct OverAligned(u64, u64, u64, u64);
+
+    #[test]
+    fn check_empty() {
+        assert_eq!(::EMPTY, alloc::heap::EMPTY);
+    }
+
+    #[cfg(not(target_os = "windows"))]
+    #[test]
+    fn test_alloc() {
+        unsafe {
+            // A 64 byte request is allocated exactly.
+            let x = alloc::heap::allocate(64, 0);
+            assert_eq!(heap_size_of(x as *const c_void), 64);
+            alloc::heap::deallocate(x, 64, 0);
+
+            // A 255 byte request is rounded up to 256 bytes.
+            let x = alloc::heap::allocate(255, 0);
+            assert_eq!(heap_size_of(x as *const c_void), 256);
+            alloc::heap::deallocate(x, 255, 0);
+
+            // A 1MiB request is allocated exactly.
+            let x = alloc::heap::allocate(1024 * 1024, 0);
+            assert_eq!(heap_size_of(x as *const c_void), 1024 * 1024);
+            alloc::heap::deallocate(x, 1024 * 1024, 0);
+
+            // An overaligned 1MiB request is allocated exactly.
+            let x = alloc::heap::allocate(1024 * 1024, 32);
+            assert_eq!(heap_size_of(x as *const c_void), 1024 * 1024);
+            alloc::heap::deallocate(x, 1024 * 1024, 32);
+        }
+    }
+
+    #[cfg(target_os = "windows")]
+    #[test]
+    fn test_alloc() {
+        unsafe {
+            // A 64 byte request is allocated exactly.
+            let x = alloc::heap::allocate(64, 0);
+            assert_eq!(heap_size_of(x as *const c_void), 64);
+            alloc::heap::deallocate(x, 64, 0);
+
+            // A 255 byte request is allocated exactly.
+            let x = alloc::heap::allocate(255, 0);
+            assert_eq!(heap_size_of(x as *const c_void), 255);
+            alloc::heap::deallocate(x, 255, 0);
+
+            // A 1MiB request is allocated exactly.
+            let x = alloc::heap::allocate(1024 * 1024, 0);
+            assert_eq!(heap_size_of(x as *const c_void), 1024 * 1024);
+            alloc::heap::deallocate(x, 1024 * 1024, 0);
+
+            // An overaligned 1MiB request is over-allocated.
+            let x = alloc::heap::allocate(1024 * 1024, 32);
+            assert_eq!(heap_size_of(x as *const c_void), 1024 * 1024 + 32);
+            alloc::heap::deallocate(x, 1024 * 1024, 32);
+        }
+    }
+
+    #[cfg(not(target_os = "windows"))]
+    #[test]
+    fn test_simd() {
+        let x = Box::new(OverAligned(0, 0, 0, 0));
+        assert_eq!(unsafe { heap_size_of(&*x as *const _ as *const c_void) }, 32);
+    }
+
+    #[cfg(target_os = "windows")]
+    #[test]
+    fn test_simd() {
+        let x = Box::new(OverAligned(0, 0, 0, 0));
+        assert_eq!(unsafe { heap_size_of(&*x as *const _ as *const c_void) }, 32 + 32);
+    }
+
+    #[test]
+    fn test_boxed_str() {
+        let x = "raclette".to_owned().into_boxed_str();
+        assert_eq!(x.heap_size_of_children(), 8);
+    }
+}
+
+#[test]
+fn test_heap_size() {
+
+    // Note: jemalloc often rounds up request sizes. However, it does not round up for request
+    // sizes of 8 and higher that are powers of two. We take advantage of knowledge here to make
+    // the sizes of various heap-allocated blocks predictable.
+
+    //-----------------------------------------------------------------------
+    // Start with basic heap block measurement.
+
+    unsafe {
+        // EMPTY is the special non-null address used to represent zero-size allocations.
+        assert_eq!(heap_size_of(EMPTY as *const c_void), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // Test HeapSizeOf implementations for various built-in types.
+
+    // Not on the heap; 0 bytes.
+    let x = 0i64;
+    assert_eq!(x.heap_size_of_children(), 0);
+
+    // An i64 is 8 bytes.
+    let x = Box::new(0i64);
+    assert_eq!(x.heap_size_of_children(), 8);
+
+    // An ascii string with 16 chars is 16 bytes in UTF-8.
+    let string = String::from("0123456789abcdef");
+    assert_eq!(string.heap_size_of_children(), 16);
+
+    let string_ref: (&String, ()) = (&string, ());
+    assert_eq!(string_ref.heap_size_of_children(), 0);
+
+    let slice: &str = &*string;
+    assert_eq!(slice.heap_size_of_children(), 0);
+
+    // Not on the heap.
+    let x: Option<i32> = None;
+    assert_eq!(x.heap_size_of_children(), 0);
+
+    // Not on the heap.
+    let x = Some(0i64);
+    assert_eq!(x.heap_size_of_children(), 0);
+
+    // The `Some` is not on the heap, but the Box is.
+    let x = Some(Box::new(0i64));
+    assert_eq!(x.heap_size_of_children(), 8);
+
+    // Not on the heap.
+    let x = ::std::sync::Arc::new(0i64);
+    assert_eq!(x.heap_size_of_children(), 0);
+
+    // The `Arc` is not on the heap, but the Box is.
+    let x = ::std::sync::Arc::new(Box::new(0i64));
+    assert_eq!(x.heap_size_of_children(), 8);
+
+    // Zero elements, no heap storage.
+    let x: Vec<i64> = vec![];
+    assert_eq!(x.heap_size_of_children(), 0);
+
+    // Four elements, 8 bytes per element.
+    let x = vec![0i64, 1i64, 2i64, 3i64];
+    assert_eq!(x.heap_size_of_children(), 32);
+}
+
+#[test]
+fn test_boxed_slice() {
+    let x = vec![1i64, 2i64].into_boxed_slice();
+    assert_eq!(x.heap_size_of_children(), 16)
+}
--- a/third_party/rust/heapsize/.cargo-checksum.json
+++ b/third_party/rust/heapsize/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"97503c8cf1fc53fd41e237662402477c0ab257225d25fe21470494a0b1bbec3c",".travis.yml":"1108708721703f4562646e1e7c6f6c924fa997835714bcc6a3ff8a58382134f1","Cargo.toml":"723e5918946fdb518ed1ad3e03ae9104b980cbe85bbee1989dc4197570ba6d73","README.md":"9a38b16bccde5db28c34d79134f02d2cdcbbab224b9a68ace93c5b85b5ef38f2","appveyor.yml":"130e820ab60abf8d08f3a91d4b0158e6a581c180385e12850113adb362eb158c","build.rs":"e13e88ed285a829256d3c6987563a663c37e335457d090125a3e19b1a97fec8e","src/lib.rs":"ab4e0a2e6d0ac700df5dbb7a2c83542cb82c94d4e46c632a4114fec93d6aba0a","tests/tests.rs":"f642da7b54b6cde55cf25fe84b2e6b27356d26b351d42a38e944b93e0c1fa24f"},"package":"5a376f7402b85be6e0ba504243ecbc0709c48019ecc6286d0540c2e359050c88"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"97503c8cf1fc53fd41e237662402477c0ab257225d25fe21470494a0b1bbec3c",".travis.yml":"ff4b4eeea4c3d6636633496f884b85e83e3613ad2bb84358b357f0cb8b8b1618","Cargo.toml":"f3a8db502210ebefe0565223738d41e1f6327bc283545789bea68fc93a599393","README.md":"9a38b16bccde5db28c34d79134f02d2cdcbbab224b9a68ace93c5b85b5ef38f2","appveyor.yml":"130e820ab60abf8d08f3a91d4b0158e6a581c180385e12850113adb362eb158c","build.rs":"e13e88ed285a829256d3c6987563a663c37e335457d090125a3e19b1a97fec8e","src/lib.rs":"024183eb6acfd9ebaa0b4bdc31aecd39dcb8bf92ab22228921f154b450b628a3","tests/tests.rs":"28ec35b89867f04be2b1a43116ee82b6f45e34efa53938e29c6727ad4da46ead"},"package":"4c7593b1522161003928c959c20a2ca421c68e940d63d75573316a009e48a6d4"}
\ No newline at end of file
--- a/third_party/rust/heapsize/.travis.yml
+++ b/third_party/rust/heapsize/.travis.yml
@@ -10,10 +10,10 @@ os:
   - osx
 
 notifications:
   webhooks: http://build.servo.org:54856/travis
 
 script:
  - cargo test
  - "[ $TRAVIS_RUST_VERSION != nightly ] || cargo test --features unstable"
- - "[ $TRAVIS_RUST_VERSION != nightly ] || cargo test --manifest-path derive/Cargo.toml"
+ - "[[ $TRAVIS_RUST_VERSION != nightly && $TRAVIS_RUST_VERSION != beta ]] || cargo test --manifest-path derive/Cargo.toml"
 
--- a/third_party/rust/heapsize/Cargo.toml
+++ b/third_party/rust/heapsize/Cargo.toml
@@ -1,14 +1,17 @@
 [package]
 name = "heapsize"
-version = "0.3.8"
+version = "0.4.0"
 authors = [ "The Servo Project Developers" ]
 description = "Infrastructure for measuring the total runtime size of an object on the heap"
 license = "MPL-2.0"
 repository = "https://github.com/servo/heapsize"
 build = "build.rs"
 
 [target.'cfg(windows)'.dependencies]
 kernel32-sys = "0.2.1"
 
 [features]
 unstable = []
+
+# https://github.com/servo/heapsize/issues/74
+flexible-tests = []
--- a/third_party/rust/heapsize/src/lib.rs
+++ b/third_party/rust/heapsize/src/lib.rs
@@ -10,35 +10,35 @@ extern crate kernel32;
 #[cfg(target_os = "windows")]
 use kernel32::{GetProcessHeap, HeapSize, HeapValidate};
 use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
 use std::collections::{BTreeMap, HashSet, HashMap, LinkedList, VecDeque};
 use std::hash::BuildHasher;
 use std::hash::Hash;
 use std::marker::PhantomData;
-use std::mem::size_of;
+use std::mem::{size_of, align_of};
 use std::net::{Ipv4Addr, Ipv6Addr};
 use std::os::raw::c_void;
 use std::sync::Arc;
 use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize};
 use std::rc::Rc;
 
 /// Get the size of a heap block.
 ///
 /// Ideally Rust would expose a function like this in std::rt::heap.
 ///
 /// `unsafe` because the caller must ensure that the pointer is from jemalloc.
 /// FIXME: This probably interacts badly with custom allocators:
 /// https://doc.rust-lang.org/book/custom-allocators.html
-pub unsafe fn heap_size_of(ptr: *const c_void) -> usize {
-    if ptr == 0x01 as *const c_void {
+pub unsafe fn heap_size_of<T>(ptr: *const T) -> usize {
+    if ptr as usize <= align_of::<T>() {
         0
     } else {
-        heap_size_of_impl(ptr)
+        heap_size_of_impl(ptr as *const c_void)
     }
 }
 
 #[cfg(not(target_os = "windows"))]
 unsafe fn heap_size_of_impl(ptr: *const c_void) -> usize {
     // The C prototype is `je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr)`. On some
     // platforms `JEMALLOC_USABLE_SIZE_CONST` is `const` and on some it is empty. But in practice
     // this function doesn't modify the contents of the block that `ptr` points to, so we use
@@ -46,17 +46,17 @@ unsafe fn heap_size_of_impl(ptr: *const 
     extern "C" {
 		#[cfg_attr(any(prefixed_jemalloc, target_os = "macos", target_os = "android"), link_name = "je_malloc_usable_size")]
         fn malloc_usable_size(ptr: *const c_void) -> usize;
     }
     malloc_usable_size(ptr)
 }
 
 #[cfg(target_os = "windows")]
-pub unsafe fn heap_size_of_impl(mut ptr: *const c_void) -> usize {
+unsafe fn heap_size_of_impl(mut ptr: *const c_void) -> usize {
     let heap = GetProcessHeap();
 
     if HeapValidate(heap, 0, ptr) == 0 {
         ptr = *(ptr as *const *const c_void).offset(-1);
     }
 
     HeapSize(heap, 0, ptr) as usize
 }
@@ -100,27 +100,46 @@ impl<T: HeapSizeOf> HeapSizeOf for [T] {
     fn heap_size_of_children(&self) -> usize {
         self.iter().fold(0, |size, item| size + item.heap_size_of_children())
     }
 }
 
 impl HeapSizeOf for String {
     fn heap_size_of_children(&self) -> usize {
         unsafe {
-            heap_size_of(self.as_ptr() as *const c_void)
+            heap_size_of(self.as_ptr())
         }
     }
 }
 
 impl<'a, T: ?Sized> HeapSizeOf for &'a T {
     fn heap_size_of_children(&self) -> usize {
         0
     }
 }
 
+// The implementations for *mut T and *const T are designed for use cases like LinkedHashMap where
+// you have a data structure which internally maintains an e.g. HashMap parameterized with raw
+// pointers. We want to be able to rely on the standard HeapSizeOf implementation for `HashMap`,
+// and can handle the contribution of the raw pointers manually.
+//
+// These have to return 0 since we don't know if the pointer is pointing to a heap allocation or
+// even valid memory.
+impl<T: ?Sized> HeapSizeOf for *mut T {
+    fn heap_size_of_children(&self) -> usize {
+        0
+    }
+}
+
+impl<T: ?Sized> HeapSizeOf for *const T {
+    fn heap_size_of_children(&self) -> usize {
+        0
+    }
+}
+
 impl<T: HeapSizeOf> HeapSizeOf for Option<T> {
     fn heap_size_of_children(&self) -> usize {
         match *self {
             None => 0,
             Some(ref x) => x.heap_size_of_children()
         }
     }
 }
@@ -207,17 +226,17 @@ impl<T: HeapSizeOf + Copy> HeapSizeOf fo
     fn heap_size_of_children(&self) -> usize {
         self.get().heap_size_of_children()
     }
 }
 
 impl<T: HeapSizeOf> HeapSizeOf for Vec<T> {
     fn heap_size_of_children(&self) -> usize {
         self.iter().fold(
-            unsafe { heap_size_of(self.as_ptr() as *const c_void) },
+            unsafe { heap_size_of(self.as_ptr()) },
             |n, elem| n + elem.heap_size_of_children())
     }
 }
 
 impl<T: HeapSizeOf> HeapSizeOf for VecDeque<T> {
     fn heap_size_of_children(&self) -> usize {
         self.iter().fold(
             // FIXME: get the buffer pointer for heap_size_of(), capacity() is a lower bound:
@@ -226,17 +245,17 @@ impl<T: HeapSizeOf> HeapSizeOf for VecDe
     }
 }
 
 impl<T> HeapSizeOf for Vec<Rc<T>> {
     fn heap_size_of_children(&self) -> usize {
         // The fate of measuring Rc<T> is still undecided, but we still want to measure
         // the space used for storing them.
         unsafe {
-            heap_size_of(self.as_ptr() as *const c_void)
+            heap_size_of(self.as_ptr())
         }
     }
 }
 
 impl<T: HeapSizeOf, S> HeapSizeOf for HashSet<T, S>
     where T: Eq + Hash, S: BuildHasher {
     fn heap_size_of_children(&self) -> usize {
         //TODO(#6908) measure actual bucket memory usage instead of approximating
--- a/third_party/rust/heapsize/tests/tests.rs
+++ b/third_party/rust/heapsize/tests/tests.rs
@@ -4,168 +4,187 @@
 
 #![cfg_attr(feature= "unstable", feature(alloc, heap_api, repr_simd))]
 
 extern crate heapsize;
 
 use heapsize::{HeapSizeOf, heap_size_of};
 use std::os::raw::c_void;
 
-pub const EMPTY: *mut () = 0x1 as *mut ();
+const EMPTY: *mut () = 0x1 as *mut ();
+
+/// https://github.com/servo/heapsize/issues/74
+#[cfg(feature = "flexible-tests")]
+macro_rules! assert_size {
+    ($actual: expr, $expected: expr) => {
+        {
+            let actual = $actual;
+            let expected = $expected;
+            assert!(actual >= expected, "expected {:?} >= {:?}", actual, expected)
+        }
+    }
+}
+
+#[cfg(not(feature = "flexible-tests"))]
+macro_rules! assert_size {
+    ($actual: expr, $expected: expr) => {
+        assert_eq!($actual, $expected)
+    }
+}
 
 #[cfg(feature = "unstable")]
 mod unstable {
     extern crate alloc;
 
-    use heapsize::{HeapSizeOf, heap_size_of};
+    use heapsize::heap_size_of;
     use std::os::raw::c_void;
 
     #[repr(C, simd)]
     struct OverAligned(u64, u64, u64, u64);
 
     #[test]
     fn check_empty() {
         assert_eq!(::EMPTY, alloc::heap::EMPTY);
     }
 
     #[cfg(not(target_os = "windows"))]
     #[test]
     fn test_alloc() {
         unsafe {
             // A 64 byte request is allocated exactly.
             let x = alloc::heap::allocate(64, 0);
-            assert_eq!(heap_size_of(x as *const c_void), 64);
+            assert_size!(heap_size_of(x as *const c_void), 64);
             alloc::heap::deallocate(x, 64, 0);
 
             // A 255 byte request is rounded up to 256 bytes.
             let x = alloc::heap::allocate(255, 0);
-            assert_eq!(heap_size_of(x as *const c_void), 256);
+            assert_size!(heap_size_of(x as *const c_void), 256);
             alloc::heap::deallocate(x, 255, 0);
 
             // A 1MiB request is allocated exactly.
             let x = alloc::heap::allocate(1024 * 1024, 0);
-            assert_eq!(heap_size_of(x as *const c_void), 1024 * 1024);
+            assert_size!(heap_size_of(x as *const c_void), 1024 * 1024);
             alloc::heap::deallocate(x, 1024 * 1024, 0);
 
             // An overaligned 1MiB request is allocated exactly.
             let x = alloc::heap::allocate(1024 * 1024, 32);
-            assert_eq!(heap_size_of(x as *const c_void), 1024 * 1024);
+            assert_size!(heap_size_of(x as *const c_void), 1024 * 1024);
             alloc::heap::deallocate(x, 1024 * 1024, 32);
         }
     }
 
     #[cfg(target_os = "windows")]
     #[test]
     fn test_alloc() {
         unsafe {
             // A 64 byte request is allocated exactly.
             let x = alloc::heap::allocate(64, 0);
-            assert_eq!(heap_size_of(x as *const c_void), 64);
+            assert_size!(heap_size_of(x as *const c_void), 64);
             alloc::heap::deallocate(x, 64, 0);
 
             // A 255 byte request is allocated exactly.
             let x = alloc::heap::allocate(255, 0);
-            assert_eq!(heap_size_of(x as *const c_void), 255);
+            assert_size!(heap_size_of(x as *const c_void), 255);
             alloc::heap::deallocate(x, 255, 0);
 
             // A 1MiB request is allocated exactly.
             let x = alloc::heap::allocate(1024 * 1024, 0);
-            assert_eq!(heap_size_of(x as *const c_void), 1024 * 1024);
+            assert_size!(heap_size_of(x as *const c_void), 1024 * 1024);
             alloc::heap::deallocate(x, 1024 * 1024, 0);
 
             // An overaligned 1MiB request is over-allocated.
             let x = alloc::heap::allocate(1024 * 1024, 32);
-            assert_eq!(heap_size_of(x as *const c_void), 1024 * 1024 + 32);
+            assert_size!(heap_size_of(x as *const c_void), 1024 * 1024 + 32);
             alloc::heap::deallocate(x, 1024 * 1024, 32);
         }
     }
 
     #[cfg(not(target_os = "windows"))]
     #[test]
     fn test_simd() {
         let x = Box::new(OverAligned(0, 0, 0, 0));
-        assert_eq!(unsafe { heap_size_of(&*x as *const _ as *const c_void) }, 32);
+        assert_size!(unsafe { heap_size_of(&*x as *const _ as *const c_void) }, 32);
     }
 
     #[cfg(target_os = "windows")]
     #[test]
     fn test_simd() {
         let x = Box::new(OverAligned(0, 0, 0, 0));
-        assert_eq!(unsafe { heap_size_of(&*x as *const _ as *const c_void) }, 32 + 32);
+        assert_size!(unsafe { heap_size_of(&*x as *const _ as *const c_void) }, 32 + 32);
     }
+}
 
-    #[test]
-    fn test_boxed_str() {
-        let x = "raclette".to_owned().into_boxed_str();
-        assert_eq!(x.heap_size_of_children(), 8);
-    }
+#[test]
+fn test_boxed_str() {
+    let x = "raclette".to_owned().into_boxed_str();
+    assert_size!(x.heap_size_of_children(), 8);
 }
 
 #[test]
 fn test_heap_size() {
 
     // Note: jemalloc often rounds up request sizes. However, it does not round up for request
     // sizes of 8 and higher that are powers of two. We take advantage of knowledge here to make
     // the sizes of various heap-allocated blocks predictable.
 
     //-----------------------------------------------------------------------
     // Start with basic heap block measurement.
 
     unsafe {
         // EMPTY is the special non-null address used to represent zero-size allocations.
-        assert_eq!(heap_size_of(EMPTY as *const c_void), 0);
+        assert_size!(heap_size_of(EMPTY as *const c_void), 0);
     }
 
     //-----------------------------------------------------------------------
     // Test HeapSizeOf implementations for various built-in types.
 
     // Not on the heap; 0 bytes.
     let x = 0i64;
-    assert_eq!(x.heap_size_of_children(), 0);
+    assert_size!(x.heap_size_of_children(), 0);
 
     // An i64 is 8 bytes.
     let x = Box::new(0i64);
-    assert_eq!(x.heap_size_of_children(), 8);
+    assert_size!(x.heap_size_of_children(), 8);
 
     // An ascii string with 16 chars is 16 bytes in UTF-8.
     let string = String::from("0123456789abcdef");
-    assert_eq!(string.heap_size_of_children(), 16);
+    assert_size!(string.heap_size_of_children(), 16);
 
     let string_ref: (&String, ()) = (&string, ());
-    assert_eq!(string_ref.heap_size_of_children(), 0);
+    assert_size!(string_ref.heap_size_of_children(), 0);
 
     let slice: &str = &*string;
-    assert_eq!(slice.heap_size_of_children(), 0);
+    assert_size!(slice.heap_size_of_children(), 0);
 
     // Not on the heap.
     let x: Option<i32> = None;
-    assert_eq!(x.heap_size_of_children(), 0);
+    assert_size!(x.heap_size_of_children(), 0);
 
     // Not on the heap.
     let x = Some(0i64);
-    assert_eq!(x.heap_size_of_children(), 0);
+    assert_size!(x.heap_size_of_children(), 0);
 
     // The `Some` is not on the heap, but the Box is.
     let x = Some(Box::new(0i64));
-    assert_eq!(x.heap_size_of_children(), 8);
+    assert_size!(x.heap_size_of_children(), 8);
 
     // Not on the heap.
     let x = ::std::sync::Arc::new(0i64);
-    assert_eq!(x.heap_size_of_children(), 0);
+    assert_size!(x.heap_size_of_children(), 0);
 
     // The `Arc` is not on the heap, but the Box is.
     let x = ::std::sync::Arc::new(Box::new(0i64));
-    assert_eq!(x.heap_size_of_children(), 8);
+    assert_size!(x.heap_size_of_children(), 8);
 
     // Zero elements, no heap storage.
     let x: Vec<i64> = vec![];
-    assert_eq!(x.heap_size_of_children(), 0);
+    assert_size!(x.heap_size_of_children(), 0);
 
     // Four elements, 8 bytes per element.
     let x = vec![0i64, 1i64, 2i64, 3i64];
-    assert_eq!(x.heap_size_of_children(), 32);
+    assert_size!(x.heap_size_of_children(), 32);
 }
 
 #[test]
 fn test_boxed_slice() {
     let x = vec![1i64, 2i64].into_boxed_slice();
-    assert_eq!(x.heap_size_of_children(), 16)
+    assert_size!(x.heap_size_of_children(), 16)
 }
--- a/third_party/rust/plane-split/.cargo-checksum.json
+++ b/third_party/rust/plane-split/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"b76d49f66f842c652d40825c67791352364a6b6bbb7d8d1009f2ac79eb413e66","Cargo.toml":"3100d538a6cd25f84ae7d502f37ec09603f4a7fb902e46583df5bdbb50b73538","LICENSE":"b946744aeda89b467929585fe8eeb5461847695220c1b168fb375d8abd4ea3d0","README.md":"62f99334c17b451342fcea70eb1cc27b26612616b7c1a58fab50dd493f766f32","benches/split.rs":"49befe22321f34280106fdea53d93644b7757873407376247f86f9d55d09b4ab","src/bsp.rs":"83f1a84b4dda5668727eb27070f22676d1f77ab9eaff0c777b32651f75ecf5b6","src/lib.rs":"c6bdf6ac6db519b79b3dbf0d4805bbba3e761e0d5cf19b4ae5388a5b93ff7454","src/naive.rs":"c7e50de094d24b609f03e3dc9599bb040a6baef84bce93ffab7af7f049fb805b","tests/main.rs":"915d915c5ca82befef82f1604cc974b072238a8d69043341589d8dd569d412d3","tests/split.rs":"a4681a788f9a9a515d4084d97ba33406a54bc0725711ade9fc955348d1703368"},"package":"8b3624c9e5e728dcc6347bde5762406b0f0707bea527d585e8f7b6ac44fdd33a"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"b76d49f66f842c652d40825c67791352364a6b6bbb7d8d1009f2ac79eb413e66","Cargo.toml":"6a8c18281f4854b2f184e335d2efb7702ed920f3e66adbe84ce2013215215068","LICENSE":"b946744aeda89b467929585fe8eeb5461847695220c1b168fb375d8abd4ea3d0","README.md":"62f99334c17b451342fcea70eb1cc27b26612616b7c1a58fab50dd493f766f32","benches/split.rs":"49befe22321f34280106fdea53d93644b7757873407376247f86f9d55d09b4ab","src/bsp.rs":"1bc961e97b47f6d918384858310c60a20f9490e11404a89f379a2ad6c5705071","src/lib.rs":"c7f52a46d9ebdb9c1346b39312110aaba75821297e5f446c81a8a25706d850f5","src/naive.rs":"c7e50de094d24b609f03e3dc9599bb040a6baef84bce93ffab7af7f049fb805b","tests/main.rs":"915d915c5ca82befef82f1604cc974b072238a8d69043341589d8dd569d412d3","tests/split.rs":"a4681a788f9a9a515d4084d97ba33406a54bc0725711ade9fc955348d1703368"},"package":"f00d5b0bef85e7e218329cde2f9b75784967c62c0cc9b7faa491d81c2d35eb2a"}
\ No newline at end of file
--- a/third_party/rust/plane-split/Cargo.toml
+++ b/third_party/rust/plane-split/Cargo.toml
@@ -1,15 +1,15 @@
 [package]
 name = "plane-split"
-version = "0.3.0"
+version = "0.4.1"
 description = "Plane splitting"
 authors = ["Dzmitry Malyshau <kvark@mozilla.com>"]
 license = "MPL-2.0"
 repository = "https://github.com/kvark/plane-split"
 keywords = ["geometry", "math"]
 documentation = "https://docs.rs/plane-split"
 
 [dependencies]
 binary-space-partition = "0.1.2"
-euclid = "0.11.2"
+euclid = "0.13"
 log = "0.3"
 num-traits = {version = "0.1.37", default-features = false}
--- a/third_party/rust/plane-split/src/bsp.rs
+++ b/third_party/rust/plane-split/src/bsp.rs
@@ -14,21 +14,21 @@ impl<T, U> Plane for Polygon<T, U> where
     U: fmt::Debug,
 {
     fn cut(&self, mut plane: Self) -> PlaneCut<Self> {
         debug!("\tCutting anchor {}", plane.anchor);
         let dist = self.signed_distance_sum_to(&plane);
 
         match self.intersect(&plane) {
             Intersection::Coplanar if dist.approx_eq(&T::zero()) => {
-                debug!("\t\tcoplanar and matching");
+                debug!("\t\tCoplanar and matching");
                 PlaneCut::Sibling(plane)
             }
             Intersection::Coplanar | Intersection::Outside => {
-                debug!("\t\tcoplanar at {:?}", dist);
+                debug!("\t\tCoplanar at {:?}", dist);
                 if dist > T::zero() {
                     PlaneCut::Cut {
                         front: vec![plane],
                         back: vec![],
                     }
                 } else {
                     PlaneCut::Cut {
                         front: vec![],
@@ -43,17 +43,17 @@ impl<T, U> Plane for Polygon<T, U> where
 
                 for sub in Some(plane).into_iter().chain(res_add1).chain(res_add2) {
                     if self.signed_distance_sum_to(&sub) > T::zero() {
                         front.push(sub)
                     } else {
                         back.push(sub)
                     }
                 }
-                debug!("\t\tcut across {:?} by {} in front and {} in back",
+                debug!("\t\tCut across {:?} by {} in front and {} in back",
                     line, front.len(), back.len());
 
                 PlaneCut::Cut {
                     front: front,
                     back: back,
                 }
             },
         }
--- a/third_party/rust/plane-split/src/lib.rs
+++ b/third_party/rust/plane-split/src/lib.rs
@@ -293,30 +293,30 @@ impl<T, U> Polygon<T, U> where
             ],
         }
     }
 
     /// Compute the line of intersection with another polygon.
     pub fn intersect(&self, other: &Self) -> Intersection<Line<T, U>> {
         if self.are_outside(&other.points) || other.are_outside(&self.points) {
             // one is completely outside the other
-            debug!("\t\toutside");
+            debug!("\t\tOutside");
             return Intersection::Outside
         }
         let cross_dir = self.normal.cross(other.normal);
         if cross_dir.dot(cross_dir) < T::approx_epsilon() {
             // polygons are co-planar
-            debug!("\t\tcoplanar");
+            debug!("\t\tCoplanar");
             return Intersection::Coplanar
         }
         let self_proj = self.project_on(&cross_dir);
         let other_proj = other.project_on(&cross_dir);
         if !self_proj.intersect(&other_proj) {
             // projections on the line don't intersect
-            debug!("\t\tprojection outside");
+            debug!("\t\tProjection outside");
             return Intersection::Outside
         }
         // compute any point on the intersection between planes
         // (n1, v) + d1 = 0
         // (n2, v) + d2 = 0
         // v = a*n1/w + b*n2/w; w = (n1, n2)
         // v = (d2*w - d1) / (1 - w*w) * n1 - (d2 - d1*w) / (1 - w*w) * n2
         let w = self.normal.dot(other.normal);