Bug 1498460 - Backport an upstream Skia patch. r=lsalzman
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 15 Oct 2018 14:25:06 -0400
changeset 489813 86f5694c6c50995d0e3cd19be96d9db27240ab10
parent 489812 bd4c433b0e5000a35f1b8f1694038d6f48f5abfe
child 489814 a1fb2da7388b017c761e0c0c6116e3ea7c3fac71
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewerslsalzman
bugs1498460
milestone64.0a1
Bug 1498460 - Backport an upstream Skia patch. r=lsalzman Backport of: https://skia.googlesource.com/skia/+/d5b4593024544c3405615066aa5b4f94352eb3cb
gfx/skia/skia/src/gpu/GrTessellator.cpp
gfx/skia/skia/src/gpu/ops/GrAAConvexPathRenderer.cpp
gfx/skia/skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.cpp
--- a/gfx/skia/skia/src/gpu/GrTessellator.cpp
+++ b/gfx/skia/skia/src/gpu/GrTessellator.cpp
@@ -2269,28 +2269,28 @@ int get_contour_count(const SkPath& path
     }
     if (maxPts > ((int)SK_MaxU16 + 1)) {
         SkDebugf("Path not rendered, too many verts (%d)\n", maxPts);
         return 0;
     }
     return contourCnt;
 }
 
-int count_points(Poly* polys, SkPath::FillType fillType) {
-    int count = 0;
+int64_t count_points(Poly* polys, SkPath::FillType fillType) {
+    int64_t count = 0;
     for (Poly* poly = polys; poly; poly = poly->fNext) {
         if (apply_fill_type(fillType, poly) && poly->fCount >= 3) {
             count += (poly->fCount - 2) * (TESSELLATOR_WIREFRAME ? 6 : 3);
         }
     }
     return count;
 }
 
-int count_outer_mesh_points(const VertexList& outerMesh) {
-    int count = 0;
+int64_t count_outer_mesh_points(const VertexList& outerMesh) {
+    int64_t count = 0;
     for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
         for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
             count += TESSELLATOR_WIREFRAME ? 12 : 6;
         }
     }
     return count;
 }
 
@@ -2322,23 +2322,24 @@ int PathToTriangles(const SkPath& path, 
         *isLinear = true;
         return 0;
     }
     SkArenaAlloc alloc(kArenaChunkSize);
     VertexList outerMesh;
     Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, antialias,
                                 isLinear, &outerMesh);
     SkPath::FillType fillType = antialias ? SkPath::kWinding_FillType : path.getFillType();
-    int count = count_points(polys, fillType);
+    int64_t count64 = count_points(polys, fillType);
     if (antialias) {
-        count += count_outer_mesh_points(outerMesh);
+        count64 += count_outer_mesh_points(outerMesh);
     }
-    if (0 == count) {
+    if (0 == count64 || count64 > SK_MaxS32) {
         return 0;
     }
+    int count = count64;
 
     void* verts = vertexAllocator->lock(count);
     if (!verts) {
         SkDebugf("Could not allocate vertices\n");
         return 0;
     }
 
     LOG("emitting %d verts\n", count);
@@ -2362,21 +2363,22 @@ int PathToVertices(const SkPath& path, S
         *verts = nullptr;
         return 0;
     }
     SkArenaAlloc alloc(kArenaChunkSize);
     bool isLinear;
     Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, false, &isLinear,
                                 nullptr);
     SkPath::FillType fillType = path.getFillType();
-    int count = count_points(polys, fillType);
-    if (0 == count) {
+    int64_t count64 = count_points(polys, fillType);
+    if (0 == count64 || count64 > SK_MaxS32) {
         *verts = nullptr;
         return 0;
     }
+    int count = count64;
 
     *verts = new GrTessellator::WindingVertex[count];
     GrTessellator::WindingVertex* vertsEnd = *verts;
     SkPoint* points = new SkPoint[count];
     SkPoint* pointsEnd = points;
     for (Poly* poly = polys; poly; poly = poly->fNext) {
         if (apply_fill_type(fillType, poly)) {
             SkPoint* start = pointsEnd;
--- a/gfx/skia/skia/src/gpu/ops/GrAAConvexPathRenderer.cpp
+++ b/gfx/skia/skia/src/gpu/ops/GrAAConvexPathRenderer.cpp
@@ -17,16 +17,17 @@
 #include "GrPathUtils.h"
 #include "GrProcessor.h"
 #include "GrSimpleMeshDrawOpHelper.h"
 #include "SkGeometry.h"
 #include "SkPathPriv.h"
 #include "SkPointPriv.h"
 #include "SkString.h"
 #include "SkTraceEvent.h"
+#include "SkTypes.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "glsl/GrGLSLGeometryProcessor.h"
 #include "glsl/GrGLSLProgramDataManager.h"
 #include "glsl/GrGLSLUniformHandler.h"
 #include "glsl/GrGLSLVarying.h"
 #include "glsl/GrGLSLVertexGeoBuilder.h"
 #include "ops/GrMeshDrawOp.h"
 
@@ -125,53 +126,58 @@ static void compute_vectors(SegmentArray
     // Make the normals point towards the outside
     SkPointPriv::Side normSide;
     if (dir == SkPathPriv::kCCW_FirstDirection) {
         normSide = SkPointPriv::kRight_Side;
     } else {
         normSide = SkPointPriv::kLeft_Side;
     }
 
-    *vCount = 0;
-    *iCount = 0;
+    int64_t vCount64 = 0;
+    int64_t iCount64 = 0;
     // compute normals at all points
     for (int a = 0; a < count; ++a) {
         Segment& sega = (*segments)[a];
         int b = (a + 1) % count;
         Segment& segb = (*segments)[b];
 
         const SkPoint* prevPt = &sega.endPt();
         int n = segb.countPoints();
         for (int p = 0; p < n; ++p) {
             segb.fNorms[p] = segb.fPts[p] - *prevPt;
             segb.fNorms[p].normalize();
             SkPointPriv::SetOrthog(&segb.fNorms[p], segb.fNorms[p], normSide);
             prevPt = &segb.fPts[p];
         }
         if (Segment::kLine == segb.fType) {
-            *vCount += 5;
-            *iCount += 9;
+            vCount64 += 5;
+            iCount64 += 9;
         } else {
-            *vCount += 6;
-            *iCount += 12;
+            vCount64 += 6;
+            iCount64 += 12;
         }
     }
 
     // compute mid-vectors where segments meet. TODO: Detect shallow corners
     // and leave out the wedges and close gaps by stitching segments together.
     for (int a = 0; a < count; ++a) {
         const Segment& sega = (*segments)[a];
         int b = (a + 1) % count;
         Segment& segb = (*segments)[b];
         segb.fMid = segb.fNorms[0] + sega.endNorm();
         segb.fMid.normalize();
         // corner wedges
-        *vCount += 4;
-        *iCount += 6;
+        vCount64 += 4;
+        iCount64 += 6;
     }
+    if (vCount64 > SK_MaxS32 || iCount64 > SK_MaxS32) {
+        return;
+    }
+    *vCount = vCount64;
+    *iCount = iCount64;
 }
 
 struct DegenerateTestData {
     DegenerateTestData() { fStage = kInitial; }
     bool isDegenerate() const { return kNonDegenerate != fStage; }
     enum {
         kInitial,
         kPoint,
--- a/gfx/skia/skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
+++ b/gfx/skia/skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
@@ -250,58 +250,70 @@ private:
 
         SkASSERT(fHelper.compatibleWithAlphaAsCoverage()
                          ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)
                          : vertexStride ==
                                    sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
 
         int instanceCount = fPaths.count();
 
-        int vertexCount = 0;
-        int indexCount = 0;
-        int maxVertices = DEFAULT_BUFFER_SIZE;
-        int maxIndices = DEFAULT_BUFFER_SIZE;
+        int64_t vertexCount = 0;
+        int64_t indexCount = 0;
+        int64_t maxVertices = DEFAULT_BUFFER_SIZE;
+        int64_t maxIndices = DEFAULT_BUFFER_SIZE;
         uint8_t* vertices = (uint8_t*) sk_malloc_throw(maxVertices * vertexStride);
         uint16_t* indices = (uint16_t*) sk_malloc_throw(maxIndices * sizeof(uint16_t));
         for (int i = 0; i < instanceCount; i++) {
             const PathData& args = fPaths[i];
             GrAAConvexTessellator tess(args.fStyle, args.fStrokeWidth,
                                        args.fJoin, args.fMiterLimit);
 
             if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
                 continue;
             }
 
-            int currentIndices = tess.numIndices();
-            if (indexCount + currentIndices > UINT16_MAX) {
+            int currentVertices = tess.numPts();
+            if (vertexCount + currentVertices > static_cast<int>(UINT16_MAX)) {
                 // if we added the current instance, we would overflow the indices we can store in a
                 // uint16_t. Draw what we've got so far and reset.
                 this->draw(target, gp.get(), pipeline, vertexCount, vertexStride, vertices,
                            indexCount, indices);
                 vertexCount = 0;
                 indexCount = 0;
             }
-            int currentVertices = tess.numPts();
             if (vertexCount + currentVertices > maxVertices) {
                 maxVertices = SkTMax(vertexCount + currentVertices, maxVertices * 2);
+                if (maxVertices * vertexStride > SK_MaxS32) {
+                    sk_free(vertices);
+                    sk_free(indices);
+                    return;
+                }
                 vertices = (uint8_t*) sk_realloc_throw(vertices, maxVertices * vertexStride);
             }
+            int currentIndices = tess.numIndices();
             if (indexCount + currentIndices > maxIndices) {
                 maxIndices = SkTMax(indexCount + currentIndices, maxIndices * 2);
+                if (maxIndices * sizeof(uint16_t) > SK_MaxS32) {
+                    sk_free(vertices);
+                    sk_free(indices);
+                    return;
+                }
                 indices = (uint16_t*) sk_realloc_throw(indices, maxIndices * sizeof(uint16_t));
             }
 
             extract_verts(tess, vertices + vertexStride * vertexCount, vertexStride, args.fColor,
                           vertexCount, indices + indexCount,
                           fHelper.compatibleWithAlphaAsCoverage());
             vertexCount += currentVertices;
             indexCount += currentIndices;
         }
-        this->draw(target, gp.get(), pipeline, vertexCount, vertexStride, vertices, indexCount,
-                   indices);
+        if (vertexCount <= SK_MaxS32 && indexCount <= SK_MaxS32) {
+            this->draw(target, gp.get(), pipeline, vertexCount, vertexStride, vertices, indexCount,
+                       indices);
+        }
         sk_free(vertices);
         sk_free(indices);
     }
 
     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
         AAFlatteningConvexPathOp* that = t->cast<AAFlatteningConvexPathOp>();
         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
             return false;
--- a/gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -264,16 +264,22 @@ private:
                     kA8_GrMaskFormat, invert, fHelper.usesLocalCoords());
         }
 
         // allocate vertices
         size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride();
         SkASSERT(vertexStride == sizeof(SkPoint) + sizeof(GrColor) + 2*sizeof(uint16_t));
 
         const GrBuffer* vertexBuffer;
+
+        // We need to make sure we don't overflow a 32 bit int when we request space in the
+        // makeVertexSpace call below.
+        if (instanceCount > SK_MaxS32 / kVerticesPerQuad) {
+            return;
+        }
         void* vertices = target->makeVertexSpace(vertexStride,
                                                  kVerticesPerQuad * instanceCount,
                                                  &vertexBuffer,
                                                  &flushInfo.fVertexOffset);
         flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
         flushInfo.fIndexBuffer = target->resourceProvider()->refQuadIndexBuffer();
         if (!vertices || !flushInfo.fIndexBuffer) {
             SkDebugf("Could not allocate vertices\n");