From ffa1da7545820b102e5c443ab17743caeb8af07c Mon Sep 17 00:00:00 2001 From: Boris Chiou Date: Thu, 5 Jul 2018 15:40:39 -0700 Subject: [PATCH] Bug 1467277 - Avoid getting zero normalized vector of rotate3d when setting a rotate matrix. r=nical For example, if we set a transform to rotate3d(0, 0, 1e50, 45deg), the expected normalized rotate axis is (0, 0, 1). However, the length is larger than the maximum of float, so the actual value is (0/inf, 0/inf, 1e50/inf) == (0, 0, 0). Therefore, we scale the vector before doing normalization to avoid getting a zero vector. MozReview-Commit-ID: 5LUDWD4RuNj --HG-- extra : rebase_source : eb82f0b3979bf6ea3cd11b643ebb30a49edc24f8 --- gfx/2d/BasePoint3D.h | 32 ++++++++++++++------- gfx/2d/Matrix.h | 2 +- layout/reftests/transform-3d/1467277-1.html | 9 ++++++ layout/reftests/transform-3d/reftest.list | 1 + 4 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 layout/reftests/transform-3d/1467277-1.html diff --git a/gfx/2d/BasePoint3D.h b/gfx/2d/BasePoint3D.h index 466986228dbd..39345b5f68ef 100644 --- a/gfx/2d/BasePoint3D.h +++ b/gfx/2d/BasePoint3D.h @@ -87,10 +87,10 @@ struct BasePoint3D { } Sub& operator/=(T aScale) { - x /= aScale; - y /= aScale; - z /= aScale; - return *static_cast(this); + x /= aScale; + y /= aScale; + z /= aScale; + return *static_cast(this); } Sub operator-() const { @@ -98,22 +98,34 @@ struct BasePoint3D { } Sub CrossProduct(const Sub& aPoint) const { - return Sub(y * aPoint.z - aPoint.y * z, - z * aPoint.x - aPoint.z * x, - x * aPoint.y - aPoint.x * y); + return Sub(y * aPoint.z - aPoint.y * z, + z * aPoint.x - aPoint.z * x, + x * aPoint.y - aPoint.x * y); } T DotProduct(const Sub& aPoint) const { - return x * aPoint.x + y * aPoint.y + z * aPoint.z; + return x * aPoint.x + y * aPoint.y + z * aPoint.z; } T Length() const { - return sqrt(x*x + y*y + z*z); + return sqrt(x*x + y*y + z*z); } // Invalid for points with distance from origin of 0. void Normalize() { - *this /= Length(); + *this /= Length(); + } + + void RobustNormalize() { + // If the distance is infinite, we scale it by 1/(the maximum value of T) + // before doing normalization, so we can avoid getting a zero point. + T length = Length(); + if (mozilla::IsInfinite(length)) { + *this /= std::numeric_limits::max(); + length = Length(); + } + + *this /= length; } friend std::ostream& operator<<(std::ostream& stream, const BasePoint3D& aPoint) { diff --git a/gfx/2d/Matrix.h b/gfx/2d/Matrix.h index 5fcfa0b02199..c9e8ef67b2ee 100644 --- a/gfx/2d/Matrix.h +++ b/gfx/2d/Matrix.h @@ -1650,7 +1650,7 @@ public: if (!vector.Length()) { return; } - vector.Normalize(); + vector.RobustNormalize(); double x = vector.x; double y = vector.y; diff --git a/layout/reftests/transform-3d/1467277-1.html b/layout/reftests/transform-3d/1467277-1.html new file mode 100644 index 000000000000..ae6c4ccc3324 --- /dev/null +++ b/layout/reftests/transform-3d/1467277-1.html @@ -0,0 +1,9 @@ + + + + +
+ Test Text +
+ + diff --git a/layout/reftests/transform-3d/reftest.list b/layout/reftests/transform-3d/reftest.list index 972347d57170..f06d130e30d4 100644 --- a/layout/reftests/transform-3d/reftest.list +++ b/layout/reftests/transform-3d/reftest.list @@ -32,6 +32,7 @@ fuzzy-if(winWidget,143,689) fuzzy-if(OSX,224,924) fuzzy-if(winWidget,154,644) ra fuzzy-if(skiaContent,1,4) == matrix3d-1a.html matrix3d-1-ref.html == matrix3d-2a.html matrix3d-2-ref.html == rotate3d-1a.html rotatex-1-ref.html +== 1467277-1.html rotatex-1-ref.html fuzzy-if(webrender,0-1,0-6) == rotate3d-2a.html rotatey-1-ref.html != backface-visibility-1a.html about:blank == backface-visibility-1b.html about:blank