Bug 1331894 - Crash in InvalidArrayIndex_CRASH | mozilla::layers::BuildPathFromPolygon - Cull polygons with no area draft
authorMiko Mynttinen <mikokm@gmail.com>
Wed, 18 Jan 2017 12:10:12 +0100
changeset 463189 8210f471407372a1ab7236e58adaea9b12f13e4d
parent 463181 f94f1552ae0a2ef38684663552603595df863606
child 542589 b214c1d500f1087c1dbe3cbc66edf54546da45a5
push id41970
push userbmo:mikokm@gmail.com
push dateWed, 18 Jan 2017 15:55:58 +0000
bugs1331894
milestone53.0a1
Bug 1331894 - Crash in InvalidArrayIndex_CRASH | mozilla::layers::BuildPathFromPolygon - Cull polygons with no area MozReview-Commit-ID: KCkIA68vvgW
gfx/2d/Polygon.h
gfx/layers/Compositor.cpp
gfx/layers/basic/BasicCompositor.cpp
--- a/gfx/2d/Polygon.h
+++ b/gfx/2d/Polygon.h
@@ -179,20 +179,21 @@ public:
     for (size_t i = 0; i < pointCount; ++i) {
       const Point4DType p1 = points[(i + 1) % pointCount];
       const Point4DType p2 = points[i];
 
       const Point4DType normal(p2.y - p1.y, p1.x - p2.x, 0.0f, 0.0f);
       const PolygonTyped<Units> plane({p1, p2}, normal);
 
       ClipPolygonWithPlane(polygon, plane);
-    }
 
-    if (polygon.GetPoints().Length() < 3) {
-      return PolygonTyped<Units>();
+      if (polygon.IsEmpty()) {
+        // The clipping created a polygon with no area.
+        return PolygonTyped<Units>();
+      }
     }
 
     return polygon;
   }
 
   static PolygonTyped<Units> FromRect(const RectTyped<Units>& aRect)
   {
     return PolygonTyped<Units> {
@@ -214,16 +215,22 @@ public:
   }
 
   const Point4DType& operator[](size_t aIndex) const
   {
     MOZ_ASSERT(mPoints.Length() > aIndex);
     return mPoints[aIndex];
   }
 
+  bool IsEmpty() const
+  {
+    // If the polygon has less than three points, it has no visible area.
+    return mPoints.Length() < 3;
+  }
+
   void SplitPolygon(const Point4DType& aNormal,
                     const nsTArray<float>& aDots,
                     nsTArray<Point4DType>& aBackPoints,
                     nsTArray<Point4DType>& aFrontPoints) const
   {
     static const auto Sign = [](const float& f) {
       if (f > 0.0f) return 1;
       if (f < 0.0f) return -1;
@@ -265,17 +272,17 @@ public:
       }
     }
   }
 
   nsTArray<TriangleTyped<Units>> ToTriangles() const
   {
     nsTArray<TriangleTyped<Units>> triangles;
 
-    if (mPoints.Length() < 3) {
+    if (IsEmpty()) {
       return triangles;
     }
 
     for (size_t i = 1; i < mPoints.Length() - 1; ++i) {
       TriangleTyped<Units> triangle(Point(mPoints[0].x, mPoints[0].y),
                                     Point(mPoints[i].x, mPoints[i].y),
                                     Point(mPoints[i+1].x, mPoints[i+1].y));
       triangles.AppendElement(Move(triangle));
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -275,23 +275,28 @@ Compositor::DrawGeometry(const gfx::Rect
   }
 
   if (!aGeometry || !SupportsLayerGeometry()) {
     DrawQuad(aRect, aClipRect, aEffectChain,
              aOpacity, aTransform, aVisibleRect);
     return;
   }
 
-  // Cull invisible polygons.
+  // Cull completely invisible polygons.
   if (aRect.Intersect(aGeometry->BoundingBox()).IsEmpty()) {
     return;
   }
 
   const gfx::Polygon clipped = aGeometry->ClipPolygon(aRect);
 
+  // Cull polygons with no area.
+  if (clipped.IsEmpty()) {
+    return;
+  }
+
   DrawPolygon(clipped, aRect, aClipRect, aEffectChain,
               aOpacity, aTransform, aVisibleRect);
 }
 
 void
 Compositor::DrawTriangles(const nsTArray<gfx::TexturedTriangle>& aTriangles,
                           const gfx::Rect& aRect,
                           const gfx::IntRect& aClipRect,
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -361,16 +361,18 @@ BasicCompositor::SupportsLayerGeometry()
 {
   return gfxPrefs::BasicLayerGeometry();
 }
 
 static RefPtr<gfx::Path>
 BuildPathFromPolygon(const RefPtr<DrawTarget>& aDT,
                      const gfx::Polygon& aPolygon)
 {
+  MOZ_ASSERT(!aPolygon.IsEmpty());
+
   RefPtr<PathBuilder> pathBuilder = aDT->CreatePathBuilder();
   const nsTArray<Point4D>& points = aPolygon.GetPoints();
 
   pathBuilder->MoveTo(points[0].As2DPoint());
 
   for (size_t i = 1; i < points.Length(); ++i) {
     pathBuilder->LineTo(points[i].As2DPoint());
   }