Make onPrepareDraws const

BUG=skia:

Review URL: https://codereview.chromium.org/1483103003
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp
index ba163a3..5167b77 100644
--- a/gm/beziereffects.cpp
+++ b/gm/beziereffects.cpp
@@ -70,7 +70,7 @@
         return &fGeometry;
     }
 
-    void generateGeometry(Target* target) override {
+    void generateGeometry(Target* target) const override {
         QuadHelper helper;
         size_t vertexStride = this->geometryProcessor()->getVertexStride();
         SkASSERT(vertexStride == sizeof(Vertex));
@@ -470,7 +470,7 @@
         return &fGeometry;
     }
 
-    void generateGeometry(Target* target) override {
+    void generateGeometry(Target* target) const override {
         QuadHelper helper;
         size_t vertexStride = this->geometryProcessor()->getVertexStride();
         SkASSERT(vertexStride == sizeof(Vertex));
diff --git a/gm/convexpolyeffect.cpp b/gm/convexpolyeffect.cpp
index f040b90..fb767dd 100644
--- a/gm/convexpolyeffect.cpp
+++ b/gm/convexpolyeffect.cpp
@@ -45,6 +45,9 @@
     ConvexPolyTestBatch(const GrGeometryProcessor* gp, const Geometry& geo)
         : INHERITED(ClassID(), gp, geo.fBounds)
         , fGeometry(geo) {
+        // Make sure any artifacts around the exterior of path are visible by using overly
+        // conservative bounding geometry.
+        fGeometry.fBounds.outset(5.f, 5.f);
     }
 
     Geometry* geoData(int index) override {
@@ -57,7 +60,7 @@
         return &fGeometry;
     }
 
-    void generateGeometry(Target* target) override {
+    void generateGeometry(Target* target) const override {
         size_t vertexStride = this->geometryProcessor()->getVertexStride();
         SkASSERT(vertexStride == sizeof(SkPoint));
         QuadHelper helper;
@@ -66,9 +69,6 @@
             return;
         }
 
-        // Make sure any artifacts around the exterior of path are visible by using overly
-        // conservative bounding geometry.
-        fGeometry.fBounds.outset(5.f, 5.f);
         fGeometry.fBounds.toQuad(verts);
 
         helper.recordDraw(target);
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 6aba34b..e13c0d1 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -692,7 +692,7 @@
         fBatch.fCoverageIgnored = !overrides.readsCoverage();
     }
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         SkMatrix invert;
         if (!this->viewMatrix().invert(&invert)) {
             return;
@@ -717,7 +717,7 @@
         }
 
         for (int i = 0; i < instanceCount; i++) {
-            Geometry& geom = fGeoData[i];
+            const Geometry& geom = fGeoData[i];
 
             SkScalar innerRadius = geom.fInnerRadius;
             SkScalar outerRadius = geom.fOuterRadius;
@@ -912,7 +912,7 @@
         fBatch.fCoverageIgnored = !overrides.readsCoverage();
     }
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         SkMatrix invert;
         if (!this->viewMatrix().invert(&invert)) {
             return;
@@ -937,7 +937,7 @@
         }
 
         for (int i = 0; i < instanceCount; i++) {
-            Geometry& geom = fGeoData[i];
+            const Geometry& geom = fGeoData[i];
 
             SkScalar xRadius = geom.fXRadius;
             SkScalar yRadius = geom.fYRadius;
@@ -1185,7 +1185,7 @@
         fBatch.fCoverageIgnored = !overrides.readsCoverage();
     }
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         // Setup geometry processor
         SkAutoTUnref<GrGeometryProcessor> gp(DIEllipseEdgeEffect::Create(this->color(),
                                                                          this->viewMatrix(),
@@ -1205,7 +1205,7 @@
         }
 
         for (int i = 0; i < instanceCount; i++) {
-            Geometry& geom = fGeoData[i];
+            const Geometry& geom = fGeoData[i];
 
             SkScalar xRadius = geom.fXRadius;
             SkScalar yRadius = geom.fYRadius;
@@ -1540,7 +1540,7 @@
         fBatch.fCoverageIgnored = !overrides.readsCoverage();
     }
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         // reset to device coordinates
         SkMatrix invert;
         if (!this->viewMatrix().invert(&invert)) {
@@ -1575,7 +1575,7 @@
         }
 
         for (int i = 0; i < instanceCount; i++) {
-            Geometry& args = fGeoData[i];
+            const Geometry& args = fGeoData[i];
 
             SkScalar outerRadius = args.fOuterRadius;
 
@@ -1720,7 +1720,7 @@
         fBatch.fCoverageIgnored = !overrides.readsCoverage();
     }
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         // reset to device coordinates
         SkMatrix invert;
         if (!this->viewMatrix().invert(&invert)) {
@@ -1755,7 +1755,7 @@
         }
 
         for (int i = 0; i < instanceCount; i++) {
-            Geometry& args = fGeoData[i];
+            const Geometry& args = fGeoData[i];
 
             // Compute the reciprocals of the radii here to save time in the shader
             SkScalar xRadRecip = SkScalarInvert(args.fXRadius);
diff --git a/src/gpu/GrPathUtils.h b/src/gpu/GrPathUtils.h
index 385cc0e..4874fa2 100644
--- a/src/gpu/GrPathUtils.h
+++ b/src/gpu/GrPathUtils.h
@@ -74,7 +74,7 @@
          * vertices is a pointer to the first vertex.
          */
         template <int N, size_t STRIDE, size_t UV_OFFSET>
-        void apply(const void* vertices) {
+        void apply(const void* vertices) const {
             intptr_t xyPtr = reinterpret_cast<intptr_t>(vertices);
             intptr_t uvPtr = reinterpret_cast<intptr_t>(vertices) + UV_OFFSET;
             float sx = fM[0];
diff --git a/src/gpu/batches/GrAAConvexPathRenderer.cpp b/src/gpu/batches/GrAAConvexPathRenderer.cpp
index 79296e3..c5b7c57 100644
--- a/src/gpu/batches/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/batches/GrAAConvexPathRenderer.cpp
@@ -778,7 +778,7 @@
         fBatch.fCanTweakAlphaForCoverage = overrides.canTweakAlphaForCoverage();
     }
 
-    void prepareLinesOnlyDraws(Target* target) {
+    void prepareLinesOnlyDraws(Target* target) const {
         bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
 
         // Setup GrGeometryProcessor
@@ -806,7 +806,7 @@
         for (int i = 0; i < instanceCount; i++) {
             tess.rewind();
 
-            Geometry& args = fGeoData[i];
+            const Geometry& args = fGeoData[i];
 
             if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
                 continue;
@@ -842,7 +842,7 @@
         }
     }
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
 #ifndef SK_IGNORE_LINEONLY_AA_CONVEX_PATH_OPTS
         if (this->linesOnly()) {
             this->prepareLinesOnlyDraws(target);
@@ -866,15 +866,22 @@
 
         // TODO generate all segments for all paths and use one vertex buffer
         for (int i = 0; i < instanceCount; i++) {
-            Geometry& args = fGeoData[i];
+            const Geometry& args = fGeoData[i];
 
             // We use the fact that SkPath::transform path does subdivision based on
             // perspective. Otherwise, we apply the view matrix when copying to the
             // segment representation.
             const SkMatrix* viewMatrix = &args.fViewMatrix;
+
+            // We avoid initializing the path unless we have to
+            const SkPath* pathPtr = &args.fPath;
+            SkTLazy<SkPath> tmpPath;
             if (viewMatrix->hasPerspective()) {
-                args.fPath.transform(*viewMatrix);
+                SkPath* tmpPathPtr = tmpPath.init(*pathPtr);
+                tmpPathPtr->setIsVolatile(true);
+                tmpPathPtr->transform(*viewMatrix);
                 viewMatrix = &SkMatrix::I();
+                pathPtr = tmpPathPtr;
             }
 
             int vertexCount;
@@ -886,7 +893,7 @@
             SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
             SkPoint fanPt;
 
-            if (!get_segments(args.fPath, *viewMatrix, &segments, &fanPt, &vertexCount,
+            if (!get_segments(*pathPtr, *viewMatrix, &segments, &fanPt, &vertexCount,
                               &indexCount)) {
                 continue;
             }
diff --git a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
index 80fd542..0b14e4d 100644
--- a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
+++ b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
@@ -143,7 +143,6 @@
         uint32_t fGenID;
         SkStrokeRec fStroke;
         bool fAntiAlias;
-        PathData* fPathData;
     };
 
     static GrDrawBatch* Create(const Geometry& geometry, GrColor color, const SkMatrix& viewMatrix,
@@ -183,7 +182,7 @@
         int fInstancesToFlush;
     };
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         int instanceCount = fGeoData.count();
 
         SkMatrix invert;
@@ -229,7 +228,7 @@
 
         flushInfo.fInstancesToFlush = 0;
         for (int i = 0; i < instanceCount; i++) {
-            Geometry& args = fGeoData[i];
+            const Geometry& args = fGeoData[i];
 
             // get mip level
             SkScalar maxScale = this->viewMatrix().getMaxScale();
@@ -247,22 +246,22 @@
 
             // check to see if path is cached
             PathData::Key key(args.fGenID, desiredDimension, args.fStroke);
-            args.fPathData = fPathCache->find(key);
-            if (nullptr == args.fPathData || !atlas->hasID(args.fPathData->fID)) {
+            PathData* pathData = fPathCache->find(key);
+            if (nullptr == pathData || !atlas->hasID(pathData->fID)) {
                 // Remove the stale cache entry
-                if (args.fPathData) {
-                    fPathCache->remove(args.fPathData->fKey);
-                    fPathList->remove(args.fPathData);
-                    delete args.fPathData;
+                if (pathData) {
+                    fPathCache->remove(pathData->fKey);
+                    fPathList->remove(pathData);
+                    delete pathData;
                 }
                 SkScalar scale = desiredDimension/maxDim;
-                args.fPathData = new PathData;
+                pathData = new PathData;
                 if (!this->addPathToAtlas(target,
                                           dfProcessor,
                                           this->pipeline(),
                                           &flushInfo,
                                           atlas,
-                                          args.fPathData,
+                                          pathData,
                                           args.fPath,
                                           args.fGenID,
                                           args.fStroke,
@@ -274,7 +273,7 @@
                 }
             }
 
-            atlas->setLastUseToken(args.fPathData->fID, target->currentToken());
+            atlas->setLastUseToken(pathData->fID, target->currentToken());
 
             // Now set vertices
             intptr_t offset = reinterpret_cast<intptr_t>(vertices);
@@ -288,7 +287,7 @@
                                     vertexStride,
                                     this->viewMatrix(),
                                     args.fPath,
-                                    args.fPathData);
+                                    pathData);
             flushInfo.fInstancesToFlush++;
         }
 
@@ -304,7 +303,6 @@
         fBatch.fColor = color;
         fBatch.fViewMatrix = viewMatrix;
         fGeoData.push_back(geometry);
-        fGeoData.back().fPathData = nullptr;
 
         fAtlas = atlas;
         fPathCache = pathCache;
@@ -326,7 +324,7 @@
                         const SkStrokeRec& stroke,
                         bool antiAlias,
                         uint32_t dimension,
-                        SkScalar scale) {
+                        SkScalar scale) const {
         const SkRect& bounds = path.getBounds();
 
         // generate bounding rect for bitmap draw
@@ -443,7 +441,7 @@
                            size_t vertexStride,
                            const SkMatrix& viewMatrix,
                            const SkPath& path,
-                           const PathData* pathData) {
+                           const PathData* pathData) const {
         GrTexture* texture = atlas->getTexture();
 
         SkScalar dx = pathData->fBounds.fLeft;
@@ -476,7 +474,7 @@
                                   vertexStride);
     }
 
-    void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) {
+    void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const {
         GrVertices vertices;
         int maxInstancesPerDraw = flushInfo->fIndexBuffer->maxQuads();
         vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer,
diff --git a/src/gpu/batches/GrAAHairLinePathRenderer.cpp b/src/gpu/batches/GrAAHairLinePathRenderer.cpp
index fd579f2..94abe1c 100644
--- a/src/gpu/batches/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/batches/GrAAHairLinePathRenderer.cpp
@@ -713,7 +713,7 @@
 
     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 
-    void onPrepareDraws(Target*) override;
+    void onPrepareDraws(Target*) const override;
 
     typedef SkTArray<SkPoint, true> PtArray;
     typedef SkTArray<int, true> IntArray;
@@ -791,7 +791,7 @@
     typedef GrVertexBatch INHERITED;
 };
 
-void AAHairlineBatch::onPrepareDraws(Target* target) {
+void AAHairlineBatch::onPrepareDraws(Target* target) const {
     // Setup the viewmatrix and localmatrix for the GrGeometryProcessor.
     SkMatrix invert;
     if (!this->viewMatrix().invert(&invert)) {
diff --git a/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
index 295bcb1..4b03c5a 100644
--- a/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
+++ b/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
@@ -162,7 +162,7 @@
     }
 
     void draw(GrVertexBatch::Target* target, const GrPipeline* pipeline, int vertexCount,
-            size_t vertexStride, void* vertices, int indexCount, uint16_t* indices) {
+              size_t vertexStride, void* vertices, int indexCount, uint16_t* indices) const {
         if (vertexCount == 0 || indexCount == 0) {
             return;
         }
@@ -190,7 +190,7 @@
         target->draw(info);
     }
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
 
         // Setup GrGeometryProcessor
@@ -220,7 +220,7 @@
         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++) {
-            Geometry& args = fGeoData[i];
+            const Geometry& args = fGeoData[i];
             GrAAConvexTessellator tess(args.fStrokeWidth, args.fJoin, args.fMiterLimit);
 
             if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
@@ -232,8 +232,8 @@
             if (indexCount + currentIndices > 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.
-                draw(target, this->pipeline(), vertexCount, vertexStride, vertices, indexCount,
-                     indices);
+                this->draw(target, this->pipeline(), vertexCount, vertexStride, vertices,
+                           indexCount, indices);
                 vertexCount = 0;
                 indexCount = 0;
             }
@@ -252,8 +252,8 @@
             vertexCount += currentVertices;
             indexCount += currentIndices;
         }
-        draw(target, this->pipeline(), vertexCount, vertexStride, vertices, indexCount,
-             indices);
+        this->draw(target, this->pipeline(), vertexCount, vertexStride, vertices, indexCount,
+                   indices);
         sk_free(vertices);
         sk_free(indices);
     }
diff --git a/src/gpu/batches/GrAAStrokeRectBatch.cpp b/src/gpu/batches/GrAAStrokeRectBatch.cpp
index 419964f..21c55f6 100644
--- a/src/gpu/batches/GrAAStrokeRectBatch.cpp
+++ b/src/gpu/batches/GrAAStrokeRectBatch.cpp
@@ -107,7 +107,7 @@
         bounds->join(geo.fDevOutsideAssist);
     }
 
-    void onPrepareDraws(Target*) override;
+    void onPrepareDraws(Target*) const override;
     void initBatchTracker(const GrXPOverridesForBatch&) override;
 
     AAStrokeRectBatch(const SkMatrix& viewMatrix,bool miterStroke)
@@ -182,7 +182,7 @@
     fBatch.fCanTweakAlphaForCoverage = overrides.canTweakAlphaForCoverage();
 }
 
-void AAStrokeRectBatch::onPrepareDraws(Target* target) {
+void AAStrokeRectBatch::onPrepareDraws(Target* target) const {
     bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
 
     SkAutoTUnref<const GrGeometryProcessor> gp(create_stroke_rect_gp(canTweakAlphaForCoverage,
diff --git a/src/gpu/batches/GrAtlasTextBatch.cpp b/src/gpu/batches/GrAtlasTextBatch.cpp
index ac5ec11..fa34036 100644
--- a/src/gpu/batches/GrAtlasTextBatch.cpp
+++ b/src/gpu/batches/GrAtlasTextBatch.cpp
@@ -131,7 +131,7 @@
                                         SkTypeface** typeface, GrFontScaler** scaler,
                                         const SkDescriptor** desc, const GrGeometryProcessor* gp,
                                         int glyphCount, size_t vertexStride,
-                                        GrColor color, SkScalar transX, SkScalar transY) {
+                                        GrColor color, SkScalar transX, SkScalar transY) const {
     static_assert(!regenGlyphs || regenTexCoords, "must regenTexCoords along regenGlyphs");
     GrBatchTextStrike* strike = nullptr;
     if (regenTexCoords) {
@@ -297,7 +297,7 @@
 #define REGEN_ARGS target, &flushInfo, blob, &run, &info, &cache, &typeface, &scaler, &desc, gp, \
                    glyphCount, vertexStride, args.fColor, args.fTransX, args.fTransY
 
-void GrAtlasTextBatch::onPrepareDraws(Target* target) {
+void GrAtlasTextBatch::onPrepareDraws(Target* target) const {
     // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
     // TODO actually only invert if we don't have RGBA
     SkMatrix localMatrix;
@@ -363,7 +363,7 @@
     SkTypeface* typeface = nullptr;
 
     for (int i = 0; i < fGeoCount; i++) {
-        Geometry& args = fGeoData[i];
+        const Geometry& args = fGeoData[i];
         Blob* blob = args.fBlob;
         Run& run = blob->fRuns[args.fRun];
         TextInfo& info = run.fSubRunInfo[args.fSubRun];
@@ -434,7 +434,7 @@
     this->flush(target, &flushInfo);
 }
 
-void GrAtlasTextBatch::flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) {
+void GrAtlasTextBatch::flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const {
     GrVertices vertices;
     int maxGlyphsPerDraw = flushInfo->fIndexBuffer->maxQuads();
     vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer,
@@ -518,7 +518,7 @@
 // TODO trying to figure out why lcd is so whack
 GrGeometryProcessor* GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatrix,
                                                         SkColor filteredColor,
-                                                        GrColor color, GrTexture* texture) {
+                                                        GrColor color, GrTexture* texture) const {
     GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode);
     bool isLCD = this->isLCD();
     // set up any flags
diff --git a/src/gpu/batches/GrAtlasTextBatch.h b/src/gpu/batches/GrAtlasTextBatch.h
index 1e6d953..65fd07d 100644
--- a/src/gpu/batches/GrAtlasTextBatch.h
+++ b/src/gpu/batches/GrAtlasTextBatch.h
@@ -138,7 +138,7 @@
         int fVertexOffset;
     };
 
-    void onPrepareDraws(Target* target) override;
+    void onPrepareDraws(Target* target) const override;
 
     GrAtlasTextBatch() : INHERITED(ClassID()) {} // initialized in factory functions.
 
@@ -177,9 +177,9 @@
                           TextInfo* info, SkGlyphCache** cache,
                           SkTypeface** typeface, GrFontScaler** scaler, const SkDescriptor** desc,
                           const GrGeometryProcessor* gp, int glyphCount, size_t vertexStride,
-                          GrColor color, SkScalar transX, SkScalar transY);
+                          GrColor color, SkScalar transX, SkScalar transY) const;
 
-    inline void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo);
+    inline void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const;
 
     GrColor color() const { return fBatch.fColor; }
     const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
@@ -191,7 +191,7 @@
     // TODO just use class params
     // TODO trying to figure out why lcd is so whack
     GrGeometryProcessor* setupDfProcessor(const SkMatrix& viewMatrix, SkColor filteredColor,
-                                          GrColor color, GrTexture* texture);
+                                          GrColor color, GrTexture* texture) const;
 
     struct BatchTracker {
         GrColor fColor;
diff --git a/src/gpu/batches/GrDefaultPathRenderer.cpp b/src/gpu/batches/GrDefaultPathRenderer.cpp
index 23f9fc8..c6ca1ca 100644
--- a/src/gpu/batches/GrDefaultPathRenderer.cpp
+++ b/src/gpu/batches/GrDefaultPathRenderer.cpp
@@ -251,7 +251,7 @@
         fBatch.fCoverageIgnored = !overrides.readsCoverage();
     }
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         SkAutoTUnref<const GrGeometryProcessor> gp;
         {
             using namespace GrDefaultGeoProcFactory;
@@ -279,7 +279,7 @@
         // We will use index buffers if we have multiple paths or one path with multiple contours
         bool isIndexed = instanceCount > 1;
         for (int i = 0; i < instanceCount; i++) {
-            Geometry& args = fGeoData[i];
+            const Geometry& args = fGeoData[i];
 
             int contourCount;
             maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contourCount,
@@ -341,7 +341,7 @@
         int vertexOffset = 0;
         int indexOffset = 0;
         for (int i = 0; i < instanceCount; i++) {
-            Geometry& args = fGeoData[i];
+            const Geometry& args = fGeoData[i];
 
             int vertexCnt = 0;
             int indexCnt = 0;
@@ -431,7 +431,7 @@
                     int* indexCnt,
                     const SkPath& path,
                     SkScalar srcSpaceTol,
-                    bool isIndexed)  {
+                    bool isIndexed) const {
         {
             SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
 
diff --git a/src/gpu/batches/GrDrawAtlasBatch.cpp b/src/gpu/batches/GrDrawAtlasBatch.cpp
index 3ee8f88..dab5b4f 100644
--- a/src/gpu/batches/GrDrawAtlasBatch.cpp
+++ b/src/gpu/batches/GrDrawAtlasBatch.cpp
@@ -51,7 +51,7 @@
     return GrDefaultGeoProcFactory::Create(gpColor, coverage, localCoords, viewMatrix);
 }
 
-void GrDrawAtlasBatch::onPrepareDraws(Target* target) {
+void GrDrawAtlasBatch::onPrepareDraws(Target* target) const {
     // Setup geometry processor
     SkAutoTUnref<const GrGeometryProcessor> gp(set_vertex_attributes(this->hasColors(),
                                                                      this->color(),
diff --git a/src/gpu/batches/GrDrawAtlasBatch.h b/src/gpu/batches/GrDrawAtlasBatch.h
index 3c0c348..4e89523 100644
--- a/src/gpu/batches/GrDrawAtlasBatch.h
+++ b/src/gpu/batches/GrDrawAtlasBatch.h
@@ -45,7 +45,7 @@
     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 
 private:
-    void onPrepareDraws(Target*) override;
+    void onPrepareDraws(Target*) const override;
 
     void initBatchTracker(const GrXPOverridesForBatch&) override;
 
diff --git a/src/gpu/batches/GrDrawVerticesBatch.cpp b/src/gpu/batches/GrDrawVerticesBatch.cpp
index cc5ccbd..cfbd24c 100644
--- a/src/gpu/batches/GrDrawVerticesBatch.cpp
+++ b/src/gpu/batches/GrDrawVerticesBatch.cpp
@@ -92,7 +92,7 @@
     }
 }
 
-void GrDrawVerticesBatch::onPrepareDraws(Target* target) {
+void GrDrawVerticesBatch::onPrepareDraws(Target* target) const {
     bool hasLocalCoords = !fGeoData[0].fLocalCoords.isEmpty();
     int colorOffset = -1, texOffset = -1;
     SkAutoTUnref<const GrGeometryProcessor> gp(
diff --git a/src/gpu/batches/GrDrawVerticesBatch.h b/src/gpu/batches/GrDrawVerticesBatch.h
index 33647df..9b2faf3 100644
--- a/src/gpu/batches/GrDrawVerticesBatch.h
+++ b/src/gpu/batches/GrDrawVerticesBatch.h
@@ -49,7 +49,7 @@
     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 
 private:
-    void onPrepareDraws(Target*) override;
+    void onPrepareDraws(Target*) const override;
     void initBatchTracker(const GrXPOverridesForBatch&) override;
 
     GrDrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
diff --git a/src/gpu/batches/GrNinePatch.cpp b/src/gpu/batches/GrNinePatch.cpp
index b438919..59040cb 100644
--- a/src/gpu/batches/GrNinePatch.cpp
+++ b/src/gpu/batches/GrNinePatch.cpp
@@ -85,7 +85,7 @@
     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 
 private:
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         SkAutoTUnref<const GrGeometryProcessor> gp(create_gp(fOverrides.readsCoverage()));
         if (!gp) {
             SkDebugf("Couldn't create GrGeometryProcessor\n");
@@ -112,7 +112,7 @@
             intptr_t verts = reinterpret_cast<intptr_t>(vertices) +
                              i * kRectsPerInstance * kVertsPerRect * vertexStride;
 
-            Geometry& geo = fGeoData[i];
+            const Geometry& geo = fGeoData[i];
             SkNinePatchIter iter(fImageWidth, fImageHeight, geo.fCenter, geo.fDst);
 
             SkRect srcR, dstR;
diff --git a/src/gpu/batches/GrNonAAStrokeRectBatch.cpp b/src/gpu/batches/GrNonAAStrokeRectBatch.cpp
index 2f80884..d036b90 100644
--- a/src/gpu/batches/GrNonAAStrokeRectBatch.cpp
+++ b/src/gpu/batches/GrNonAAStrokeRectBatch.cpp
@@ -70,6 +70,9 @@
         geometry.fRect = rect;
         geometry.fStrokeWidth = strokeWidth;
         geometry.fColor = color;
+
+        // Sort the rect for hairlines
+        geometry.fRect.sort();
     }
 
     void appendAndUpdateBounds(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
@@ -102,7 +105,7 @@
         }
     }
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         SkAutoTUnref<const GrGeometryProcessor> gp;
         {
             using namespace GrDefaultGeoProcFactory;
@@ -121,7 +124,7 @@
 
         SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr));
 
-        Geometry& args = fGeoData[0];
+        const Geometry& args = fGeoData[0];
 
         int vertexCount = kVertsPerHairlineRect;
         if (args.fStrokeWidth > 0) {
@@ -142,10 +145,8 @@
         SkPoint* vertex = reinterpret_cast<SkPoint*>(verts);
 
         GrPrimitiveType primType;
-
         if (args.fStrokeWidth > 0) {;
             primType = kTriangleStrip_GrPrimitiveType;
-            args.fRect.sort();
             init_stroke_rect_strip(vertex, args.fRect, args.fStrokeWidth);
         } else {
             // hairline
diff --git a/src/gpu/batches/GrTInstanceBatch.h b/src/gpu/batches/GrTInstanceBatch.h
index d2d4d6c..bf37168 100644
--- a/src/gpu/batches/GrTInstanceBatch.h
+++ b/src/gpu/batches/GrTInstanceBatch.h
@@ -89,7 +89,7 @@
 private:
     GrTInstanceBatch() : INHERITED(ClassID()) {}
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         SkAutoTUnref<const GrGeometryProcessor> gp(Impl::CreateGP(this->seedGeometry(), 
                                                                   fOverrides));
         if (!gp) {
diff --git a/src/gpu/batches/GrTessellatingPathRenderer.cpp b/src/gpu/batches/GrTessellatingPathRenderer.cpp
index 8cd411a..082a8db 100644
--- a/src/gpu/batches/GrTessellatingPathRenderer.cpp
+++ b/src/gpu/batches/GrTessellatingPathRenderer.cpp
@@ -1418,7 +1418,7 @@
     int tessellate(GrUniqueKey* key,
                    GrResourceProvider* resourceProvider,
                    SkAutoTUnref<GrVertexBuffer>& vertexBuffer,
-                   bool canMapVB) {
+                   bool canMapVB) const {
         SkPath path;
         GrStrokeInfo stroke(fStroke);
         if (stroke.isDashed()) {
@@ -1521,7 +1521,7 @@
         return actualCount;
     }
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         // construct a cache key from the path's genID and the view matrix
         static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
         GrUniqueKey key;
@@ -1545,7 +1545,7 @@
             screenSpaceTol, fViewMatrix, fPath.getBounds());
         if (!cache_match(vertexBuffer.get(), tol, &actualCount)) {
             bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
-            actualCount = tessellate(&key, rp, vertexBuffer, canMapVB);
+            actualCount = this->tessellate(&key, rp, vertexBuffer, canMapVB);
         }
 
         if (actualCount == 0) {
diff --git a/src/gpu/batches/GrTestBatch.h b/src/gpu/batches/GrTestBatch.h
index b070bba..9427504 100644
--- a/src/gpu/batches/GrTestBatch.h
+++ b/src/gpu/batches/GrTestBatch.h
@@ -60,7 +60,7 @@
     const GrGeometryProcessor* geometryProcessor() const { return fGeometryProcessor; }
 
 private:
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         target->initDraw(fGeometryProcessor, this->pipeline());
         this->generateGeometry(target);
     }
@@ -72,7 +72,7 @@
         return false;
     }
 
-    virtual void generateGeometry(Target*) = 0;
+    virtual void generateGeometry(Target*) const = 0;
 
     struct BatchTracker {
         GrColor fColor;
diff --git a/src/gpu/batches/GrVertexBatch.h b/src/gpu/batches/GrVertexBatch.h
index ba899cc..d0daf59 100644
--- a/src/gpu/batches/GrVertexBatch.h
+++ b/src/gpu/batches/GrVertexBatch.h
@@ -65,7 +65,7 @@
     void onPrepare(GrBatchFlushState* state) final;
     void onDraw(GrBatchFlushState* state) final;
 
-    virtual void onPrepareDraws(Target*) = 0;
+    virtual void onPrepareDraws(Target*) const = 0;
 
     // A set of contiguous draws with no inline uploads between them that all use the same
     // primitive processor. All the draws in a DrawArray share a primitive processor and use the
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index 77d29cb..e62ede0 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -316,6 +316,14 @@
     }
 
     struct DashDraw {
+        DashDraw(const Geometry& geo) {
+            memcpy(fPtsRot, geo.fPtsRot, sizeof(geo.fPtsRot));
+            memcpy(fIntervals, geo.fIntervals, sizeof(geo.fIntervals));
+            fPhase = geo.fPhase;
+        }
+        SkPoint fPtsRot[2];
+        SkScalar fIntervals[2];
+        SkScalar fPhase;
         SkScalar fStartOffset;
         SkScalar fStrokeWidth;
         SkScalar fLineLength;
@@ -327,7 +335,7 @@
         bool fHasEndRect;
     };
 
-    void onPrepareDraws(Target* target) override {
+    void onPrepareDraws(Target* target) const override {
         int instanceCount = fGeoData.count();
         SkPaint::Cap cap = this->cap();
         bool isRoundCap = SkPaint::kRound_Cap == cap;
@@ -362,14 +370,17 @@
         // We do two passes over all of the dashes.  First we setup the start, end, and bounds,
         // rectangles.  We preserve all of this work in the rects / draws arrays below.  Then we
         // iterate again over these decomposed dashes to generate vertices
-        SkSTArray<128, SkRect, true> rects;
-        SkSTArray<128, DashDraw, true> draws;
+        static const int kNumStackDashes = 128;
+        SkSTArray<kNumStackDashes, SkRect, true> rects;
+        SkSTArray<kNumStackDashes, DashDraw, true> draws;
 
         int totalRectCount = 0;
         int rectOffset = 0;
         rects.push_back_n(3 * instanceCount);
         for (int i = 0; i < instanceCount; i++) {
-            Geometry& args = fGeoData[i];
+            const Geometry& args = fGeoData[i];
+
+            DashDraw& draw = draws.push_back(args);
 
             bool hasCap = SkPaint::kButt_Cap != cap && 0 != args.fSrcStrokeWidth;
 
@@ -399,32 +410,32 @@
             // If we are using AA, check to see if we are drawing a partial dash at the start. If so
             // draw it separately here and adjust our start point accordingly
             if (useAA) {
-                if (args.fPhase > 0 && args.fPhase < args.fIntervals[0]) {
+                if (draw.fPhase > 0 && draw.fPhase < draw.fIntervals[0]) {
                     SkPoint startPts[2];
-                    startPts[0] = args.fPtsRot[0];
+                    startPts[0] = draw.fPtsRot[0];
                     startPts[1].fY = startPts[0].fY;
-                    startPts[1].fX = SkMinScalar(startPts[0].fX + args.fIntervals[0] - args.fPhase,
-                                                 args.fPtsRot[1].fX);
+                    startPts[1].fX = SkMinScalar(startPts[0].fX + draw.fIntervals[0] - draw.fPhase,
+                                                 draw.fPtsRot[1].fX);
                     startRect.set(startPts, 2);
                     startRect.outset(strokeAdj, halfSrcStroke);
 
                     hasStartRect = true;
-                    startAdj = args.fIntervals[0] + args.fIntervals[1] - args.fPhase;
+                    startAdj = draw.fIntervals[0] + draw.fIntervals[1] - draw.fPhase;
                 }
             }
 
             // adjustments for start and end of bounding rect so we only draw dash intervals
             // contained in the original line segment.
-            startAdj += calc_start_adjustment(args.fIntervals, args.fPhase);
+            startAdj += calc_start_adjustment(draw.fIntervals, draw.fPhase);
             if (startAdj != 0) {
-                args.fPtsRot[0].fX += startAdj;
-                args.fPhase = 0;
+                draw.fPtsRot[0].fX += startAdj;
+                draw.fPhase = 0;
             }
             SkScalar endingInterval = 0;
-            SkScalar endAdj = calc_end_adjustment(args.fIntervals, args.fPtsRot, args.fPhase,
+            SkScalar endAdj = calc_end_adjustment(draw.fIntervals, draw.fPtsRot, draw.fPhase,
                                                   &endingInterval);
-            args.fPtsRot[1].fX -= endAdj;
-            if (args.fPtsRot[0].fX >= args.fPtsRot[1].fX) {
+            draw.fPtsRot[1].fX -= endAdj;
+            if (draw.fPtsRot[0].fX >= draw.fPtsRot[1].fX) {
                 lineDone = true;
             }
 
@@ -435,9 +446,9 @@
                 // If we adjusted the end then we will not be drawing a partial dash at the end.
                 // If we didn't adjust the end point then we just need to make sure the ending
                 // dash isn't a full dash
-                if (0 == endAdj && endingInterval != args.fIntervals[0]) {
+                if (0 == endAdj && endingInterval != draw.fIntervals[0]) {
                     SkPoint endPts[2];
-                    endPts[1] = args.fPtsRot[1];
+                    endPts[1] = draw.fPtsRot[1];
                     endPts[0].fY = endPts[1].fY;
                     endPts[0].fX = endPts[1].fX - endingInterval;
 
@@ -445,24 +456,24 @@
                     endRect.outset(strokeAdj, halfSrcStroke);
 
                     hasEndRect = true;
-                    endAdj = endingInterval + args.fIntervals[1];
+                    endAdj = endingInterval + draw.fIntervals[1];
 
-                    args.fPtsRot[1].fX -= endAdj;
-                    if (args.fPtsRot[0].fX >= args.fPtsRot[1].fX) {
+                    draw.fPtsRot[1].fX -= endAdj;
+                    if (draw.fPtsRot[0].fX >= draw.fPtsRot[1].fX) {
                         lineDone = true;
                     }
                 }
             }
 
             if (startAdj != 0) {
-                args.fPhase = 0;
+                draw.fPhase = 0;
             }
 
             // Change the dashing info from src space into device space
-            SkScalar* devIntervals = args.fIntervals;
-            devIntervals[0] = args.fIntervals[0] * args.fParallelScale;
-            devIntervals[1] = args.fIntervals[1] * args.fParallelScale;
-            SkScalar devPhase = args.fPhase * args.fParallelScale;
+            SkScalar* devIntervals = draw.fIntervals;
+            devIntervals[0] = draw.fIntervals[0] * args.fParallelScale;
+            devIntervals[1] = draw.fIntervals[1] * args.fParallelScale;
+            SkScalar devPhase = draw.fPhase * args.fParallelScale;
             SkScalar strokeWidth = args.fSrcStrokeWidth * args.fPerpendicularScale;
 
             if ((strokeWidth < 1.f && useAA) || 0.f == strokeWidth) {
@@ -492,16 +503,16 @@
                 // Reset the start rect to draw this single solid rect
                 // but it requires to upload a new intervals uniform so we can mimic
                 // one giant dash
-                args.fPtsRot[0].fX -= hasStartRect ? startAdj : 0;
-                args.fPtsRot[1].fX += hasEndRect ? endAdj : 0;
-                startRect.set(args.fPtsRot, 2);
+                draw.fPtsRot[0].fX -= hasStartRect ? startAdj : 0;
+                draw.fPtsRot[1].fX += hasEndRect ? endAdj : 0;
+                startRect.set(draw.fPtsRot, 2);
                 startRect.outset(strokeAdj, halfSrcStroke);
                 hasStartRect = true;
                 hasEndRect = false;
                 lineDone = true;
 
                 SkPoint devicePts[2];
-                args.fViewMatrix.mapPoints(devicePts, args.fPtsRot, 2);
+                args.fViewMatrix.mapPoints(devicePts, draw.fPtsRot, 2);
                 SkScalar lineLength = SkPoint::Distance(devicePts[0], devicePts[1]);
                 if (hasCap) {
                     lineLength += 2.f * halfDevStroke;
@@ -519,17 +530,16 @@
                 startOffset -= halfDevStroke;
             }
 
-            DashDraw& draw = draws.push_back();
             if (!lineDone) {
                 SkPoint devicePts[2];
-                args.fViewMatrix.mapPoints(devicePts, args.fPtsRot, 2);
+                args.fViewMatrix.mapPoints(devicePts, draw.fPtsRot, 2);
                 draw.fLineLength = SkPoint::Distance(devicePts[0], devicePts[1]);
                 if (hasCap) {
                     draw.fLineLength += 2.f * halfDevStroke;
                 }
 
-                bounds.set(args.fPtsRot[0].fX, args.fPtsRot[0].fY,
-                           args.fPtsRot[1].fX, args.fPtsRot[1].fY);
+                bounds.set(draw.fPtsRot[0].fX, draw.fPtsRot[0].fY,
+                           draw.fPtsRot[1].fX, draw.fPtsRot[1].fY);
                 bounds.outset(bloatX + strokeAdj, bloatY + halfSrcStroke);
             }
 
@@ -566,15 +576,15 @@
         int curVIdx = 0;
         int rectIndex = 0;
         for (int i = 0; i < instanceCount; i++) {
-            Geometry& geom = fGeoData[i];
+            const Geometry& geom = fGeoData[i];
 
             if (!draws[i].fLineDone) {
                 if (fullDash) {
                     setup_dashed_rect(rects[rectIndex], vertices, curVIdx, geom.fSrcRotInv,
                                       draws[i].fStartOffset, draws[i].fDevBloatX,
                                       draws[i].fDevBloatY, draws[i].fLineLength,
-                                      draws[i].fHalfDevStroke, geom.fIntervals[0],
-                                      geom.fIntervals[1], draws[i].fStrokeWidth,
+                                      draws[i].fHalfDevStroke, draws[i].fIntervals[0],
+                                      draws[i].fIntervals[1], draws[i].fStrokeWidth,
                                       capType, gp->getVertexStride());
                 } else {
                     SkPoint* verts = reinterpret_cast<SkPoint*>(vertices);
@@ -589,9 +599,9 @@
                 if (fullDash) {
                     setup_dashed_rect(rects[rectIndex], vertices, curVIdx, geom.fSrcRotInv,
                                       draws[i].fStartOffset, draws[i].fDevBloatX,
-                                      draws[i].fDevBloatY, geom.fIntervals[0],
-                                      draws[i].fHalfDevStroke, geom.fIntervals[0],
-                                      geom.fIntervals[1], draws[i].fStrokeWidth, capType,
+                                      draws[i].fDevBloatY, draws[i].fIntervals[0],
+                                      draws[i].fHalfDevStroke, draws[i].fIntervals[0],
+                                      draws[i].fIntervals[1], draws[i].fStrokeWidth, capType,
                                       gp->getVertexStride());
                 } else {
                     SkPoint* verts = reinterpret_cast<SkPoint*>(vertices);
@@ -606,9 +616,9 @@
                 if (fullDash) {
                     setup_dashed_rect(rects[rectIndex], vertices, curVIdx, geom.fSrcRotInv,
                                       draws[i].fStartOffset, draws[i].fDevBloatX,
-                                      draws[i].fDevBloatY, geom.fIntervals[0],
-                                      draws[i].fHalfDevStroke, geom.fIntervals[0],
-                                      geom.fIntervals[1], draws[i].fStrokeWidth, capType,
+                                      draws[i].fDevBloatY, draws[i].fIntervals[0],
+                                      draws[i].fHalfDevStroke, draws[i].fIntervals[0],
+                                      draws[i].fIntervals[1], draws[i].fStrokeWidth, capType,
                                       gp->getVertexStride());
                 } else {
                     SkPoint* verts = reinterpret_cast<SkPoint*>(vertices);
diff --git a/tests/GrPorterDuffTest.cpp b/tests/GrPorterDuffTest.cpp
index ca732a4..f1c1961 100644
--- a/tests/GrPorterDuffTest.cpp
+++ b/tests/GrPorterDuffTest.cpp
@@ -1118,7 +1118,7 @@
         const char* name() const override { return "Test LCD Text Batch"; }
         void initBatchTracker(const GrXPOverridesForBatch&) override {}
         bool onCombineIfPossible(GrBatch*, const GrCaps&) override  { return false; }
-        void onPrepareDraws(Target*) override {};
+        void onPrepareDraws(Target*) const override {};
 
         typedef GrVertexBatch INHERITED;
     } testLCDCoverageBatch;