Bug 1488887. Update Cargo lockfiles and revendor dependencies.
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Wed, 05 Sep 2018 21:21:57 -0400
changeset 435037 f471c397a043fc454277234b6182f6ef62aabaab
parent 435036 ef1988b6f9b8a85dfff8ceaeccbedbf02bca81ce
child 435038 c666a3d42de4702b9db3a7bd5f585f30a21f0c65
push id34588
push userebalazs@mozilla.com
push dateThu, 06 Sep 2018 09:54:17 +0000
treeherdermozilla-central@0c947d96e8f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1488887
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1488887. Update Cargo lockfiles and revendor dependencies. * * * Re-vendor rust dependencies
Cargo.lock
third_party/rust/plane-split/.cargo-checksum.json
third_party/rust/plane-split/Cargo.toml
third_party/rust/plane-split/src/clip.rs
third_party/rust/plane-split/src/lib.rs
third_party/rust/plane-split/src/polygon.rs
third_party/rust/plane-split/tests/clip.rs
third_party/rust/plane-split/tests/main.rs
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1667,17 +1667,17 @@ dependencies = [
 
 [[package]]
 name = "pkg-config"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "plane-split"
-version = "0.12.1"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -2656,17 +2656,17 @@ dependencies = [
  "dwrote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "plane-split 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "plane-split 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_api 0.57.2",
 ]
@@ -2980,17 +2980,17 @@ dependencies = [
 "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
 "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
 "checksum petgraph 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "7a7e5234c228fbfa874c86a77f685886127f82e0aef602ad1d48333fcac6ad61"
 "checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
 "checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
 "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
 "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
 "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
-"checksum plane-split 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3a4fc9e31d70eb6828e9a2d7a401a824d9f281686a39a8fc06f08796edb1bb"
+"checksum plane-split 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "64d766f38b15fe1337bdddfc869ef5c50437323f857aaaadc6490197db80a1b8"
 "checksum podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e5422a1ee1bc57cc47ae717b0137314258138f38fd5f3cea083f43a9725383a0"
 "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 "checksum proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "77997c53ae6edd6d187fec07ec41b207063b5ee6f33680e9fa86d405cdd313d4"
 "checksum proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "cccdc7557a98fe98453030f077df7f3a042052fae465bb61d2c2c41435cfd9b6"
 "checksum procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f566249236c6ca4340f7ca78968271f0ed2b0f234007a61b66f9ecd0af09260"
 "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
 "checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
--- a/third_party/rust/plane-split/.cargo-checksum.json
+++ b/third_party/rust/plane-split/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".travis.yml":"b76d49f66f842c652d40825c67791352364a6b6bbb7d8d1009f2ac79eb413e66","Cargo.toml":"9bffe8481e8672f72a85e3844627b35874b2f357ea7e7d91856268ce03f898a7","LICENSE":"b946744aeda89b467929585fe8eeb5461847695220c1b168fb375d8abd4ea3d0","README.md":"a65ed5c817c867fe23bc2029f34baea4a645a07dd5d101a0027e796d2923be58","benches/split.rs":"632a011dfc6d8235dea853785061b7bbfe0362eb85b91b3b01fbf77a7f1c7f26","src/bsp.rs":"60a306ecb7032a57bc5a7b7f094cb9669f7cd112894f85e6e2fc501a608a9404","src/clip.rs":"d1171933bea98c68440869d341d6f2ecdd672b2acb0a4408a011b7ef1c44b266","src/lib.rs":"3e9fb055066623b08be1abc06d0fd30f838d840ad13a6acab76d117f0c8bf5ff","src/polygon.rs":"c30e17aa88714b490f1cc9b7a9a388b37bc9af919ce1983e42f8b94555847118","tests/clip.rs":"0745faa4cb679c5eef4103a26a8714d6feb37ffd00b6c3dafad5937ec5392f10","tests/main.rs":"e299b33390fc486b45685eaef3af4fc67793b114dc0e63c873022dc1530ab672","tests/split.rs":"0eb1afb1f26cdecd5fffbf32d57e889f8f69254c0a57eecb8ccbbdf38efcdf27"},"package":"ff3a4fc9e31d70eb6828e9a2d7a401a824d9f281686a39a8fc06f08796edb1bb"}
\ No newline at end of file
+{"files":{".travis.yml":"b76d49f66f842c652d40825c67791352364a6b6bbb7d8d1009f2ac79eb413e66","Cargo.toml":"91ca8efc8aeb123545f2dace7bebe3cd2d14bfba3d7f09a242cf88fdd04ee951","LICENSE":"b946744aeda89b467929585fe8eeb5461847695220c1b168fb375d8abd4ea3d0","README.md":"a65ed5c817c867fe23bc2029f34baea4a645a07dd5d101a0027e796d2923be58","benches/split.rs":"632a011dfc6d8235dea853785061b7bbfe0362eb85b91b3b01fbf77a7f1c7f26","src/bsp.rs":"60a306ecb7032a57bc5a7b7f094cb9669f7cd112894f85e6e2fc501a608a9404","src/clip.rs":"838cee6106d240581d1cfcba5d47b67f99a1360748ce7c56531dc4582121fc34","src/lib.rs":"a9ce93011a0b0702a1df2a342aeeb9982a3c8a819b20fefa284686ee0fa04d08","src/polygon.rs":"8c2509698441582d66ca86c35ca6fa924aeaf891a2bb1fc6b08bb311d11ae738","tests/clip.rs":"3335364fd6849697d3919084be5dce6c49acb31d8c53adc93a4cd05ee2ea93a9","tests/main.rs":"ed807b036c475ab99973124c31a9932da51e77e7e580cdc182e98a96af6be941","tests/split.rs":"0eb1afb1f26cdecd5fffbf32d57e889f8f69254c0a57eecb8ccbbdf38efcdf27"},"package":"64d766f38b15fe1337bdddfc869ef5c50437323f857aaaadc6490197db80a1b8"}
\ No newline at end of file
--- a/third_party/rust/plane-split/Cargo.toml
+++ b/third_party/rust/plane-split/Cargo.toml
@@ -7,17 +7,17 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "plane-split"
-version = "0.12.1"
+version = "0.13.0"
 authors = ["Dzmitry Malyshau <kvark@mozilla.com>"]
 description = "Plane splitting"
 documentation = "https://docs.rs/plane-split"
 keywords = ["geometry", "math"]
 license = "MPL-2.0"
 repository = "https://github.com/servo/plane-split"
 [dependencies.binary-space-partition]
 version = "0.1.2"
--- a/third_party/rust/plane-split/src/clip.rs
+++ b/third_party/rust/plane-split/src/clip.rs
@@ -1,9 +1,9 @@
-use {Intersection, Plane, Polygon};
+use {Intersection, NegativeHemisphereError, Plane, Polygon};
 
 use euclid::{Trig, TypedRect, TypedScale, TypedTransform3D, TypedVector3D};
 use euclid::approxeq::ApproxEq;
 use num_traits::{Float, One, Zero};
 
 use std::{fmt, mem, ops};
 
 
@@ -31,52 +31,65 @@ impl<
         }
     }
 
     /// Reset the clipper internals, but preserve the allocation.
     pub fn reset(&mut self) {
         self.clips.clear();
     }
 
-    /// Add a set of planes that define the frustum for a given transformation.
-    pub fn add_frustum<V>(
-        &mut self,
+    /// Extract the clipping planes that define the frustum for a given transformation.
+    pub fn frustum_planes<V>(
         t: &TypedTransform3D<T, U, V>,
         bounds: Option<TypedRect<T, V>>,
-    ) {
-        //Note: this is not the near plane, but the positive hemisphere
-        // in homogeneous space.
+    ) -> Result<impl Iterator<Item = Plane<T, U>>, NegativeHemisphereError> {
         let mw = TypedVector3D::new(t.m14, t.m24, t.m34);
-        self.clips.extend(Plane::from_unnormalized(mw, t.m44));
+        let plane_positive = Plane::from_unnormalized(mw, t.m44)?;
+
+        let bounds_iter_maybe = match bounds {
+            Some(bounds) => {
+                let mx = TypedVector3D::new(t.m11, t.m21, t.m31);
+                let left = bounds.origin.x;
+                let plane_left = Plane::from_unnormalized(
+                    mx - mw * TypedScale::new(left),
+                    t.m41 - t.m44 * left,
+                )?;
+                let right = bounds.origin.x + bounds.size.width;
+                let plane_right = Plane::from_unnormalized(
+                    mw * TypedScale::new(right) - mx,
+                    t.m44 * right - t.m41,
+                )?;
 
-        if let Some(bounds) = bounds {
-            let mx = TypedVector3D::new(t.m11, t.m21, t.m31);
-            let left = bounds.origin.x;
-            self.clips.extend(Plane::from_unnormalized(
-                mx - mw * TypedScale::new(left),
-                t.m41 - t.m44 * left,
-            ));
-            let right = bounds.origin.x + bounds.size.width;
-            self.clips.extend(Plane::from_unnormalized(
-                mw * TypedScale::new(right) - mx,
-                t.m44 * right - t.m41,
-            ));
+                let my = TypedVector3D::new(t.m12, t.m22, t.m32);
+                let top = bounds.origin.y;
+                let plane_top = Plane::from_unnormalized(
+                    my - mw * TypedScale::new(top),
+                    t.m42 - t.m44 * top,
+                )?;
+                let bottom = bounds.origin.y + bounds.size.height;
+                let plane_bottom = Plane::from_unnormalized(
+                    mw * TypedScale::new(bottom) - my,
+                    t.m44 * bottom - t.m42,
+                )?;
 
-            let my = TypedVector3D::new(t.m12, t.m22, t.m32);
-            let top = bounds.origin.y;
-            self.clips.extend(Plane::from_unnormalized(
-                my - mw * TypedScale::new(top),
-                t.m42 - t.m44 * top,
-            ));
-            let bottom = bounds.origin.y + bounds.size.height;
-            self.clips.extend(Plane::from_unnormalized(
-                mw * TypedScale::new(bottom) - my,
-                t.m44 * bottom - t.m42,
-            ));
-        }
+                Some(plane_left
+                    .into_iter()
+                    .chain(plane_right)
+                    .chain(plane_top)
+                    .chain(plane_bottom)
+                )
+            }
+            None => None,
+        };
+
+        Ok(bounds_iter_maybe
+            .into_iter()
+            .flat_map(|pi| pi)
+            .chain(plane_positive)
+        )
     }
 
     /// Add a clipping plane to the list. The plane will clip everything behind it,
     /// where the direction is set by the plane normal.
     pub fn add(&mut self, plane: Plane<T, U>) {
         self.clips.push(plane);
     }
 
@@ -107,30 +120,35 @@ impl<
             }
         }
 
         &self.results
     }
 
     /// Clip the primitive with the frustum of the specified transformation,
     /// returning a sequence of polygons in the transformed space.
+    /// Returns None if the transformation can't be frustum clipped.
     pub fn clip_transformed<'a, V>(
         &'a mut self,
         polygon: Polygon<T, U>,
         transform: &'a TypedTransform3D<T, U, V>,
         bounds: Option<TypedRect<T, V>>,
-    ) -> impl 'a + Iterator<Item = Polygon<T, V>>
+    ) -> Result<impl 'a + Iterator<Item = Polygon<T, V>>, NegativeHemisphereError>
     where
         T: Trig,
         V: 'a + fmt::Debug,
     {
-        let num_planes = if bounds.is_some() {5} else {1};
-        self.add_frustum(transform, bounds);
+        let planes = Self::frustum_planes(transform, bounds)?;
+
+        let old_count = self.clips.len();
+        self.clips.extend(planes);
         self.clip(polygon);
         // remove the frustum planes
-        for _ in 0 .. num_planes {
+        while self.clips.len() > old_count {
             self.clips.pop();
         }
-        self.results
+
+        let polys = self.results
             .drain(..)
-            .flat_map(move |poly| poly.transform(transform))
+            .flat_map(move |poly| poly.transform(transform));
+        Ok(polys)
     }
 }
--- a/third_party/rust/plane-split/src/lib.rs
+++ b/third_party/rust/plane-split/src/lib.rs
@@ -87,33 +87,44 @@ impl<T: Clone, U> Clone for Plane<T, U> 
     fn clone(&self) -> Self {
         Plane {
             normal: self.normal.clone(),
             offset: self.offset.clone(),
         }
     }
 }
 
+/// An error returned when everything would end up projected
+/// to the negative hemisphere (W <= 0.0);
+#[derive(Clone, Debug, Hash, PartialEq, PartialOrd)]
+pub struct NegativeHemisphereError;
+
 impl<
     T: Copy + Zero + One + Float + ApproxEq<T> +
         ops::Sub<T, Output=T> + ops::Add<T, Output=T> +
         ops::Mul<T, Output=T> + ops::Div<T, Output=T>,
     U,
 > Plane<T, U> {
     /// Construct a new plane from unnormalized equation.
-    pub fn from_unnormalized(normal: TypedVector3D<T, U>, offset: T) -> Option<Self> {
+    pub fn from_unnormalized(
+        normal: TypedVector3D<T, U>, offset: T
+    ) -> Result<Option<Self>, NegativeHemisphereError> {
         let square_len = normal.square_length();
-        if square_len < T::approx_epsilon() {
-            None
+        if square_len < T::approx_epsilon() * T::approx_epsilon() {
+            if offset > T::zero() {
+                Ok(None)
+            } else {
+                Err(NegativeHemisphereError)
+            }
         } else {
             let kf = T::one() / square_len.sqrt();
-            Some(Plane {
+            Ok(Some(Plane {
                 normal: normal * TypedScale::new(kf),
                 offset: offset * kf,
-            })
+            }))
         }
     }
 
     /// Check if this plane contains another one.
     pub fn contains(&self, other: &Self) -> bool {
         //TODO: actually check for inside/outside
         self.normal == other.normal && self.offset == other.offset
     }
--- a/third_party/rust/plane-split/src/polygon.rs
+++ b/third_party/rust/plane-split/src/polygon.rs
@@ -114,30 +114,20 @@ impl<T: Clone, U> Clone for Polygon<T, U
 impl<T, U> Polygon<T, U> where
     T: Copy + fmt::Debug + ApproxEq<T> +
         ops::Sub<T, Output=T> + ops::Add<T, Output=T> +
         ops::Mul<T, Output=T> + ops::Div<T, Output=T> +
         Zero + One + Float,
     U: fmt::Debug,
 {
     /// Construct a polygon from points that are already transformed.
-    #[deprecated(since = "0.12.1", note = "Use try_from_points instead")]
+    /// Return None if the polygon doesn't contain any space.
     pub fn from_points(
         points: [TypedPoint3D<T, U>; 4],
         anchor: usize,
-    ) -> Self {
-        Self::try_from_points(points, anchor).unwrap()
-    }
-
-    /// Construct a polygon from points that are already transformed.
-    /// Return None if the polygon doesn't contain any space.
-    /// This method will be removed in `from_points` in the next breaking release.
-    pub fn try_from_points(
-        points: [TypedPoint3D<T, U>; 4],
-        anchor: usize,
     ) -> Option<Self> {
         let edge1 = points[1] - points[0];
         let edge2 = points[2] - points[0];
         let edge3 = points[3] - points[0];
         let edge4 = points[3] - points[1];
 
         if edge2.square_length() < T::epsilon() || edge4.square_length() < T::epsilon() {
             return None
@@ -174,17 +164,17 @@ impl<T, U> Polygon<T, U> where
         Self::from_points(
             [
                 rect.origin.to_3d(),
                 rect.top_right().to_3d(),
                 rect.bottom_right().to_3d(),
                 rect.bottom_left().to_3d(),
             ],
             anchor,
-        )
+        ).unwrap()
     }
 
     /// Construct a polygon from a rectangle with 3D transform.
     pub fn from_transformed_rect<V>(
         rect: TypedRect<T, V>,
         transform: TypedTransform3D<T, V, U>,
         anchor: usize,
     ) -> Option<Self>
@@ -196,17 +186,17 @@ impl<T, U> Polygon<T, U> where
             transform.transform_point3d(&rect.top_right().to_3d())?,
             transform.transform_point3d(&rect.bottom_right().to_3d())?,
             transform.transform_point3d(&rect.bottom_left().to_3d())?,
         ];
 
         //Note: this code path could be more efficient if we had inverse-transpose
         //let n4 = transform.transform_point4d(&TypedPoint4D::new(T::zero(), T::zero(), T::one(), T::zero()));
         //let normal = TypedPoint3D::new(n4.x, n4.y, n4.z);
-        Self::try_from_points(points, anchor)
+        Self::from_points(points, anchor)
     }
 
     /// Bring a point into the local coordinate space, returning
     /// the 2D normalized coordinates.
     pub fn untransform_point(&self, point: TypedPoint3D<T, U>) -> Point2D<T> {
         //debug_assert!(self.contains(point));
         // get axises and target vector
         let a = self.points[1] - self.points[0];
@@ -238,17 +228,17 @@ impl<T, U> Polygon<T, U> where
             let mut homo = transform.transform_point3d_homogeneous(point);
             homo.w = homo.w.max(T::approx_epsilon());
             *out = homo.to_point3d()?;
         }
 
         //Note: this code path could be more efficient if we had inverse-transpose
         //let n4 = transform.transform_point4d(&TypedPoint4D::new(T::zero(), T::zero(), T::one(), T::zero()));
         //let normal = TypedPoint3D::new(n4.x, n4.y, n4.z);
-        Polygon::try_from_points(points, self.anchor)
+        Polygon::from_points(points, self.anchor)
     }
 
     /// Check if all the points are indeed placed on the plane defined by
     /// the normal and offset, and the winding order is consistent.
     pub fn is_valid(&self) -> bool {
         let is_planar = self.points
             .iter()
             .all(|p| is_zero(self.plane.signed_distance_to(p)));
--- a/third_party/rust/plane-split/tests/clip.rs
+++ b/third_party/rust/plane-split/tests/clip.rs
@@ -5,97 +5,120 @@ use euclid::{point3, rect, vec3};
 use euclid::{Angle, TypedRect, TypedTransform3D};
 use plane_split::{Clipper, Plane, Polygon};
 
 use std::f32::consts::FRAC_PI_4;
 
 
 #[test]
 fn clip_in() {
-    let plane: Plane<f32, ()> = Plane::from_unnormalized(vec3(1.0, 0.0, 1.0), 20.0).unwrap();
+    let plane: Plane<f32, ()> = Plane::from_unnormalized(vec3(1.0, 0.0, 1.0), 20.0).unwrap().unwrap();
     let mut clipper = Clipper::new();
     clipper.add(plane);
 
-    let poly = Polygon::from_points([
-        point3(-10.0, -10.0, 0.0),
-        point3(10.0, -10.0, 0.0),
-        point3(10.0, 10.0, 0.0),
-        point3(-10.0, 10.0, 0.0),
-    ], 0);
+    let poly = Polygon::from_points(
+        [
+            point3(-10.0, -10.0, 0.0),
+            point3(10.0, -10.0, 0.0),
+            point3(10.0, 10.0, 0.0),
+            point3(-10.0, 10.0, 0.0),
+        ],
+        0,
+    ).unwrap();
 
     let results = clipper.clip(poly.clone());
     assert_eq!(results[0], poly);
     assert_eq!(results.len(), 1);
 }
 
 #[test]
 fn clip_out() {
-    let plane: Plane<f32, ()> = Plane::from_unnormalized(vec3(1.0, 0.0, 1.0), -20.0).unwrap();
+    let plane: Plane<f32, ()> = Plane::from_unnormalized(vec3(1.0, 0.0, 1.0), -20.0).unwrap().unwrap();
     let mut clipper = Clipper::new();
     clipper.add(plane);
 
-    let poly = Polygon::from_points([
-        point3(-10.0, -10.0, 0.0),
-        point3(10.0, -10.0, 0.0),
-        point3(10.0, 10.0, 0.0),
-        point3(-10.0, 10.0, 0.0),
-    ], 0);
+    let poly = Polygon::from_points(
+        [
+            point3(-10.0, -10.0, 0.0),
+            point3(10.0, -10.0, 0.0),
+            point3(10.0, 10.0, 0.0),
+            point3(-10.0, 10.0, 0.0),
+        ],
+        0,
+    ).unwrap();
 
     let results = clipper.clip(poly);
     assert!(results.is_empty());
 }
 
 #[test]
 fn clip_parallel() {
     let plane: Plane<f32, ()> = Plane {
         normal: vec3(0.0, 0.0, 1.0),
         offset: 0.0,
     };
     let mut clipper = Clipper::new();
     clipper.add(plane);
 
-    let poly = Polygon::from_points([
-        point3(-10.0, -10.0, 0.0),
-        point3(10.0, -10.0, 0.0),
-        point3(10.0, 10.0, 0.0),
-        point3(-10.0, 10.0, 0.0),
-    ], 0);
+    let poly = Polygon::from_points(
+        [
+            point3(-10.0, -10.0, 0.0),
+            point3(10.0, -10.0, 0.0),
+            point3(10.0, 10.0, 0.0),
+            point3(-10.0, 10.0, 0.0),
+        ],
+        0,
+    ).unwrap();
 
     let results = clipper.clip(poly);
     assert!(results.is_empty());
 }
 
 #[test]
 fn clip_repeat() {
-    let plane: Plane<f32, ()> = Plane::from_unnormalized(vec3(1.0, 0.0, 1.0), 0.0).unwrap();
+    let plane: Plane<f32, ()> = Plane::from_unnormalized(vec3(1.0, 0.0, 1.0), 0.0).unwrap().unwrap();
     let mut clipper = Clipper::new();
     clipper.add(plane.clone());
     clipper.add(plane.clone());
 
-    let poly = Polygon::from_points([
-        point3(-10.0, -10.0, 0.0),
-        point3(10.0, -10.0, 0.0),
-        point3(10.0, 10.0, 0.0),
-        point3(-10.0, 10.0, 0.0),
-    ], 0);
+    let poly = Polygon::from_points(
+        [
+            point3(-10.0, -10.0, 0.0),
+            point3(10.0, -10.0, 0.0),
+            point3(10.0, 10.0, 0.0),
+            point3(-10.0, 10.0, 0.0),
+        ],
+        0,
+    ).unwrap();
 
     let results = clipper.clip(poly);
     assert_eq!(results.len(), 1);
     assert!(plane.signed_distance_sum_to(&results[0]) > 0.0);
 }
 
 #[test]
 fn clip_transformed() {
     let t_rot: TypedTransform3D<f32, (), ()> =
         TypedTransform3D::create_rotation(0.0, 1.0, 0.0, Angle::radians(-FRAC_PI_4));
     let t_div: TypedTransform3D<f32, (), ()> =
         TypedTransform3D::create_perspective(5.0);
     let transform = t_rot.post_mul(&t_div);
 
-    let poly_rect: TypedRect<f32, ()> = rect(-10.0, -10.0, 20.0, 20.0);
-    let polygon = Polygon::from_rect(poly_rect, 0);
+    let polygon = Polygon::from_rect(rect(-10.0, -10.0, 20.0, 20.0), 0);
     let bounds: TypedRect<f32, ()> = rect(-1.0, -1.0, 2.0, 2.0);
 
     let mut clipper = Clipper::new();
     let results = clipper.clip_transformed(polygon, &transform, Some(bounds));
     // iterating enforces the transformation checks/unwraps
-    assert_ne!(0, results.count());
+    assert_ne!(0, results.unwrap().count());
 }
+
+#[test]
+fn clip_badly_transformed() {
+    let mut tx = TypedTransform3D::<f32, (), ()>::identity();
+    tx.m14 = -0.0000001;
+    tx.m44 = 0.0;
+
+    let mut clipper = Clipper::new();
+    let polygon = Polygon::from_rect(rect(-10.0, -10.0, 20.0, 20.0), 0);
+    let results = clipper.clip_transformed(polygon, &tx, None);
+    assert!(results.is_err());
+}
--- a/third_party/rust/plane-split/tests/main.rs
+++ b/third_party/rust/plane-split/tests/main.rs
@@ -1,14 +1,14 @@
 extern crate euclid;
 extern crate plane_split;
 
 use euclid::{Angle, TypedRect, TypedSize2D, TypedTransform3D, point2, point3, vec3};
 use euclid::approxeq::ApproxEq;
-use plane_split::{Intersection, Line, LineProjection, Plane, Polygon};
+use plane_split::{Intersection, Line, LineProjection, NegativeHemisphereError, Plane, Polygon};
 
 
 #[test]
 fn line_proj_bounds() {
     assert_eq!((-5i8, 4), LineProjection { markers: [-5i8, 1, 4, 2] }.get_bounds());
     assert_eq!((1f32, 4.0), LineProjection { markers: [4f32, 3.0, 2.0, 1.0] }.get_bounds());
 }
 
@@ -55,17 +55,17 @@ fn valid() {
         },
         anchor: 0,
     };
     assert!(poly_c.is_valid());
 }
 
 #[test]
 fn empty() {
-    let poly = Polygon::<f32, ()>::try_from_points(
+    let poly = Polygon::<f32, ()>::from_points(
         [
             point3(0.0, 0.0, 1.0),
             point3(0.0, 0.0, 1.0),
             point3(0.0, 0.00001, 1.0),
             point3(1.0, 0.0, 0.0),
         ],
         1,
     );
@@ -257,16 +257,22 @@ fn split() {
     test_cut(&poly, 2, Line {
         origin: point3(0.5, 1.0, 0.0),
         dir: vec3(-0.5f32.sqrt(), 0.0, 0.5f32.sqrt()),
     });
 }
 
 #[test]
 fn plane_unnormalized() {
-    let mut plane: Option<Plane<f32, ()>> = Plane::from_unnormalized(vec3(0.0, 0.0, 0.0), 1.0);
-    assert_eq!(plane, None);
+    let zero_vec = vec3(0.0000001, 0.0, 0.0);
+    let mut plane: Result<Option<Plane<f32, ()>>, _> = Plane::from_unnormalized(zero_vec, 1.0);
+    assert_eq!(plane, Ok(None));
+    plane = Plane::from_unnormalized(zero_vec, 0.0);
+    assert_eq!(plane, Err(NegativeHemisphereError));
+    plane = Plane::from_unnormalized(zero_vec, -0.5);
+    assert_eq!(plane, Err(NegativeHemisphereError));
+
     plane = Plane::from_unnormalized(vec3(-3.0, 4.0, 0.0), 2.0);
-    assert_eq!(plane, Some(Plane {
+    assert_eq!(plane, Ok(Some(Plane {
         normal: vec3(-3.0/5.0, 4.0/5.0, 0.0),
         offset: 2.0/5.0,
-    }));
+    })));
 }