| Index: src/gpu/GrDefaultPathRenderer.cpp
 | 
| diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp
 | 
| deleted file mode 100644
 | 
| index f4ce7c85a52bfc9ca818dad8f87e477e35033f2e..0000000000000000000000000000000000000000
 | 
| --- a/src/gpu/GrDefaultPathRenderer.cpp
 | 
| +++ /dev/null
 | 
| @@ -1,761 +0,0 @@
 | 
| -/*
 | 
| - * Copyright 2011 Google Inc.
 | 
| - *
 | 
| - * Use of this source code is governed by a BSD-style license that can be
 | 
| - * found in the LICENSE file.
 | 
| - */
 | 
| -
 | 
| -#include "GrDefaultPathRenderer.h"
 | 
| -
 | 
| -#include "GrBatchFlushState.h"
 | 
| -#include "GrBatchTest.h"
 | 
| -#include "GrContext.h"
 | 
| -#include "GrDefaultGeoProcFactory.h"
 | 
| -#include "GrPathUtils.h"
 | 
| -#include "GrPipelineBuilder.h"
 | 
| -#include "GrVertices.h"
 | 
| -#include "SkGeometry.h"
 | 
| -#include "SkString.h"
 | 
| -#include "SkStrokeRec.h"
 | 
| -#include "SkTLazy.h"
 | 
| -#include "SkTraceEvent.h"
 | 
| -
 | 
| -#include "batches/GrVertexBatch.h"
 | 
| -
 | 
| -GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
 | 
| -                                             bool stencilWrapOpsSupport)
 | 
| -    : fSeparateStencil(separateStencilSupport)
 | 
| -    , fStencilWrapOps(stencilWrapOpsSupport) {
 | 
| -}
 | 
| -
 | 
| -
 | 
| -////////////////////////////////////////////////////////////////////////////////
 | 
| -// Stencil rules for paths
 | 
| -
 | 
| -////// Even/Odd
 | 
| -
 | 
| -GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
 | 
| -    kInvert_StencilOp,
 | 
| -    kKeep_StencilOp,
 | 
| -    kAlwaysIfInClip_StencilFunc,
 | 
| -    0xffff,
 | 
| -    0xffff,
 | 
| -    0xffff);
 | 
| -
 | 
| -// ok not to check clip b/c stencil pass only wrote inside clip
 | 
| -GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
 | 
| -    kZero_StencilOp,
 | 
| -    kZero_StencilOp,
 | 
| -    kNotEqual_StencilFunc,
 | 
| -    0xffff,
 | 
| -    0x0000,
 | 
| -    0xffff);
 | 
| -
 | 
| -// have to check clip b/c outside clip will always be zero.
 | 
| -GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
 | 
| -    kZero_StencilOp,
 | 
| -    kZero_StencilOp,
 | 
| -    kEqualIfInClip_StencilFunc,
 | 
| -    0xffff,
 | 
| -    0x0000,
 | 
| -    0xffff);
 | 
| -
 | 
| -////// Winding
 | 
| -
 | 
| -// when we have separate stencil we increment front faces / decrement back faces
 | 
| -// when we don't have wrap incr and decr we use the stencil test to simulate
 | 
| -// them.
 | 
| -
 | 
| -GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
 | 
| -    kIncWrap_StencilOp,             kDecWrap_StencilOp,
 | 
| -    kKeep_StencilOp,                kKeep_StencilOp,
 | 
| -    kAlwaysIfInClip_StencilFunc,    kAlwaysIfInClip_StencilFunc,
 | 
| -    0xffff,                         0xffff,
 | 
| -    0xffff,                         0xffff,
 | 
| -    0xffff,                         0xffff);
 | 
| -
 | 
| -// if inc'ing the max value, invert to make 0
 | 
| -// if dec'ing zero invert to make all ones.
 | 
| -// we can't avoid touching the stencil on both passing and
 | 
| -// failing, so we can't resctrict ourselves to the clip.
 | 
| -GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
 | 
| -    kInvert_StencilOp,              kInvert_StencilOp,
 | 
| -    kIncClamp_StencilOp,            kDecClamp_StencilOp,
 | 
| -    kEqual_StencilFunc,             kEqual_StencilFunc,
 | 
| -    0xffff,                         0xffff,
 | 
| -    0xffff,                         0x0000,
 | 
| -    0xffff,                         0xffff);
 | 
| -
 | 
| -// When there are no separate faces we do two passes to setup the winding rule
 | 
| -// stencil. First we draw the front faces and inc, then we draw the back faces
 | 
| -// and dec. These are same as the above two split into the incrementing and
 | 
| -// decrementing passes.
 | 
| -GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
 | 
| -    kIncWrap_StencilOp,
 | 
| -    kKeep_StencilOp,
 | 
| -    kAlwaysIfInClip_StencilFunc,
 | 
| -    0xffff,
 | 
| -    0xffff,
 | 
| -    0xffff);
 | 
| -
 | 
| -GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
 | 
| -    kDecWrap_StencilOp,
 | 
| -    kKeep_StencilOp,
 | 
| -    kAlwaysIfInClip_StencilFunc,
 | 
| -    0xffff,
 | 
| -    0xffff,
 | 
| -    0xffff);
 | 
| -
 | 
| -GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
 | 
| -    kInvert_StencilOp,
 | 
| -    kIncClamp_StencilOp,
 | 
| -    kEqual_StencilFunc,
 | 
| -    0xffff,
 | 
| -    0xffff,
 | 
| -    0xffff);
 | 
| -
 | 
| -GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
 | 
| -    kInvert_StencilOp,
 | 
| -    kDecClamp_StencilOp,
 | 
| -    kEqual_StencilFunc,
 | 
| -    0xffff,
 | 
| -    0x0000,
 | 
| -    0xffff);
 | 
| -
 | 
| -// Color passes are the same whether we use the two-sided stencil or two passes
 | 
| -
 | 
| -GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
 | 
| -    kZero_StencilOp,
 | 
| -    kZero_StencilOp,
 | 
| -    kNonZeroIfInClip_StencilFunc,
 | 
| -    0xffff,
 | 
| -    0x0000,
 | 
| -    0xffff);
 | 
| -
 | 
| -GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
 | 
| -    kZero_StencilOp,
 | 
| -    kZero_StencilOp,
 | 
| -    kEqualIfInClip_StencilFunc,
 | 
| -    0xffff,
 | 
| -    0x0000,
 | 
| -    0xffff);
 | 
| -
 | 
| -////// Normal render to stencil
 | 
| -
 | 
| -// Sometimes the default path renderer can draw a path directly to the stencil
 | 
| -// buffer without having to first resolve the interior / exterior.
 | 
| -GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
 | 
| -    kZero_StencilOp,
 | 
| -    kIncClamp_StencilOp,
 | 
| -    kAlwaysIfInClip_StencilFunc,
 | 
| -    0xffff,
 | 
| -    0x0000,
 | 
| -    0xffff);
 | 
| -
 | 
| -////////////////////////////////////////////////////////////////////////////////
 | 
| -// Helpers for drawPath
 | 
| -
 | 
| -#define STENCIL_OFF     0   // Always disable stencil (even when needed)
 | 
| -
 | 
| -static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) {
 | 
| -#if STENCIL_OFF
 | 
| -    return true;
 | 
| -#else
 | 
| -    if (!stroke.isHairlineStyle() && !path.isInverseFillType()) {
 | 
| -        return path.isConvex();
 | 
| -    }
 | 
| -    return false;
 | 
| -#endif
 | 
| -}
 | 
| -
 | 
| -GrPathRenderer::StencilSupport
 | 
| -GrDefaultPathRenderer::onGetStencilSupport(const SkPath& path, const GrStrokeInfo& stroke) const {
 | 
| -    if (single_pass_path(path, stroke)) {
 | 
| -        return GrPathRenderer::kNoRestriction_StencilSupport;
 | 
| -    } else {
 | 
| -        return GrPathRenderer::kStencilOnly_StencilSupport;
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -static inline void append_countour_edge_indices(bool hairLine,
 | 
| -                                                uint16_t fanCenterIdx,
 | 
| -                                                uint16_t edgeV0Idx,
 | 
| -                                                uint16_t** indices) {
 | 
| -    // when drawing lines we're appending line segments along
 | 
| -    // the contour. When applying the other fill rules we're
 | 
| -    // drawing triangle fans around fanCenterIdx.
 | 
| -    if (!hairLine) {
 | 
| -        *((*indices)++) = fanCenterIdx;
 | 
| -    }
 | 
| -    *((*indices)++) = edgeV0Idx;
 | 
| -    *((*indices)++) = edgeV0Idx + 1;
 | 
| -}
 | 
| -
 | 
| -static inline void add_quad(SkPoint** vert, const SkPoint* base, const SkPoint pts[],
 | 
| -                            SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol, bool indexed,
 | 
| -                            bool isHairline, uint16_t subpathIdxStart, int offset, uint16_t** idx) {
 | 
| -    // first pt of quad is the pt we ended on in previous step
 | 
| -    uint16_t firstQPtIdx = (uint16_t)(*vert - base) - 1 + offset;
 | 
| -    uint16_t numPts =  (uint16_t)
 | 
| -        GrPathUtils::generateQuadraticPoints(
 | 
| -            pts[0], pts[1], pts[2],
 | 
| -            srcSpaceTolSqd, vert,
 | 
| -            GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
 | 
| -    if (indexed) {
 | 
| -        for (uint16_t i = 0; i < numPts; ++i) {
 | 
| -            append_countour_edge_indices(isHairline, subpathIdxStart,
 | 
| -                                         firstQPtIdx + i, idx);
 | 
| -        }
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -class DefaultPathBatch : public GrVertexBatch {
 | 
| -public:
 | 
| -    struct Geometry {
 | 
| -        GrColor fColor;
 | 
| -        SkPath fPath;
 | 
| -        SkScalar fTolerance;
 | 
| -    };
 | 
| -
 | 
| -    static GrDrawBatch* Create(const Geometry& geometry, uint8_t coverage,
 | 
| -                               const SkMatrix& viewMatrix, bool isHairline,
 | 
| -                               const SkRect& devBounds) {
 | 
| -        return new DefaultPathBatch(geometry, coverage, viewMatrix, isHairline, devBounds);
 | 
| -    }
 | 
| -
 | 
| -    const char* name() const override { return "DefaultPathBatch"; }
 | 
| -
 | 
| -    void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
 | 
| -        // When this is called on a batch, there is only one geometry bundle
 | 
| -        out->setKnownFourComponents(fGeoData[0].fColor);
 | 
| -    }
 | 
| -    void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
 | 
| -        out->setKnownSingleComponent(this->coverage());
 | 
| -    }
 | 
| -
 | 
| -private:
 | 
| -    void initBatchTracker(const GrPipelineOptimizations& opt) override {
 | 
| -        // Handle any color overrides
 | 
| -        if (!opt.readsColor()) {
 | 
| -            fGeoData[0].fColor = GrColor_ILLEGAL;
 | 
| -        }
 | 
| -        opt.getOverrideColorIfSet(&fGeoData[0].fColor);
 | 
| -
 | 
| -        // setup batch properties
 | 
| -        fBatch.fColorIgnored = !opt.readsColor();
 | 
| -        fBatch.fColor = fGeoData[0].fColor;
 | 
| -        fBatch.fUsesLocalCoords = opt.readsLocalCoords();
 | 
| -        fBatch.fCoverageIgnored = !opt.readsCoverage();
 | 
| -    }
 | 
| -
 | 
| -    void onPrepareDraws(Target* target) override {
 | 
| -        SkAutoTUnref<const GrGeometryProcessor> gp;
 | 
| -        {
 | 
| -            using namespace GrDefaultGeoProcFactory;
 | 
| -            Color color(this->color());
 | 
| -            Coverage coverage(this->coverage());
 | 
| -            if (this->coverageIgnored()) {
 | 
| -                coverage.fType = Coverage::kNone_Type;
 | 
| -            }
 | 
| -            LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type :
 | 
| -                                                              LocalCoords::kUnused_Type);
 | 
| -            gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords,
 | 
| -                                                     this->viewMatrix()));
 | 
| -        }
 | 
| -
 | 
| -        size_t vertexStride = gp->getVertexStride();
 | 
| -        SkASSERT(vertexStride == sizeof(SkPoint));
 | 
| -
 | 
| -        target->initDraw(gp, this->pipeline());
 | 
| -
 | 
| -        int instanceCount = fGeoData.count();
 | 
| -
 | 
| -        // compute number of vertices
 | 
| -        int maxVertices = 0;
 | 
| -
 | 
| -        // 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];
 | 
| -
 | 
| -            int contourCount;
 | 
| -            maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contourCount,
 | 
| -                                                            args.fTolerance);
 | 
| -
 | 
| -            isIndexed = isIndexed || contourCount > 1;
 | 
| -        }
 | 
| -
 | 
| -        if (maxVertices == 0 || maxVertices > ((int)SK_MaxU16 + 1)) {
 | 
| -            SkDebugf("Cannot render path (%d)\n", maxVertices);
 | 
| -            return;
 | 
| -        }
 | 
| -
 | 
| -        // determine primitiveType
 | 
| -        int maxIndices = 0;
 | 
| -        GrPrimitiveType primitiveType;
 | 
| -        if (this->isHairline()) {
 | 
| -            if (isIndexed) {
 | 
| -                maxIndices = 2 * maxVertices;
 | 
| -                primitiveType = kLines_GrPrimitiveType;
 | 
| -            } else {
 | 
| -                primitiveType = kLineStrip_GrPrimitiveType;
 | 
| -            }
 | 
| -        } else {
 | 
| -            if (isIndexed) {
 | 
| -                maxIndices = 3 * maxVertices;
 | 
| -                primitiveType = kTriangles_GrPrimitiveType;
 | 
| -            } else {
 | 
| -                primitiveType = kTriangleFan_GrPrimitiveType;
 | 
| -            }
 | 
| -        }
 | 
| -
 | 
| -        // allocate vertex / index buffers
 | 
| -        const GrVertexBuffer* vertexBuffer;
 | 
| -        int firstVertex;
 | 
| -
 | 
| -        void* verts = target->makeVertexSpace(vertexStride, maxVertices,
 | 
| -                                              &vertexBuffer, &firstVertex);
 | 
| -
 | 
| -        if (!verts) {
 | 
| -            SkDebugf("Could not allocate vertices\n");
 | 
| -            return;
 | 
| -        }
 | 
| -
 | 
| -        const GrIndexBuffer* indexBuffer = nullptr;
 | 
| -        int firstIndex = 0;
 | 
| -
 | 
| -        void* indices = nullptr;
 | 
| -        if (isIndexed) {
 | 
| -            indices = target->makeIndexSpace(maxIndices, &indexBuffer, &firstIndex);
 | 
| -
 | 
| -            if (!indices) {
 | 
| -                SkDebugf("Could not allocate indices\n");
 | 
| -                return;
 | 
| -            }
 | 
| -        }
 | 
| -
 | 
| -        // fill buffers
 | 
| -        int vertexOffset = 0;
 | 
| -        int indexOffset = 0;
 | 
| -        for (int i = 0; i < instanceCount; i++) {
 | 
| -            Geometry& args = fGeoData[i];
 | 
| -
 | 
| -            int vertexCnt = 0;
 | 
| -            int indexCnt = 0;
 | 
| -            if (!this->createGeom(verts,
 | 
| -                                  vertexOffset,
 | 
| -                                  indices,
 | 
| -                                  indexOffset,
 | 
| -                                  &vertexCnt,
 | 
| -                                  &indexCnt,
 | 
| -                                  args.fPath,
 | 
| -                                  args.fTolerance,
 | 
| -                                  isIndexed)) {
 | 
| -                return;
 | 
| -            }
 | 
| -
 | 
| -            vertexOffset += vertexCnt;
 | 
| -            indexOffset += indexCnt;
 | 
| -            SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices);
 | 
| -        }
 | 
| -
 | 
| -        GrVertices vertices;
 | 
| -        if (isIndexed) {
 | 
| -            vertices.initIndexed(primitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex,
 | 
| -                                 vertexOffset, indexOffset);
 | 
| -        } else {
 | 
| -            vertices.init(primitiveType, vertexBuffer, firstVertex, vertexOffset);
 | 
| -        }
 | 
| -        target->draw(vertices);
 | 
| -
 | 
| -        // put back reserves
 | 
| -        target->putBackIndices((size_t)(maxIndices - indexOffset));
 | 
| -        target->putBackVertices((size_t)(maxVertices - vertexOffset), (size_t)vertexStride);
 | 
| -    }
 | 
| -
 | 
| -    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 | 
| -
 | 
| -    DefaultPathBatch(const Geometry& geometry, uint8_t coverage, const SkMatrix& viewMatrix,
 | 
| -                     bool isHairline, const SkRect& devBounds) {
 | 
| -        this->initClassID<DefaultPathBatch>();
 | 
| -        fBatch.fCoverage = coverage;
 | 
| -        fBatch.fIsHairline = isHairline;
 | 
| -        fBatch.fViewMatrix = viewMatrix;
 | 
| -        fGeoData.push_back(geometry);
 | 
| -
 | 
| -        this->setBounds(devBounds);
 | 
| -    }
 | 
| -
 | 
| -    bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
 | 
| -        DefaultPathBatch* that = t->cast<DefaultPathBatch>();
 | 
| -        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
 | 
| -                                     that->bounds(), caps)) {
 | 
| -            return false;
 | 
| -        }
 | 
| -
 | 
| -        if (this->color() != that->color()) {
 | 
| -            return false;
 | 
| -        }
 | 
| -
 | 
| -        if (this->coverage() != that->coverage()) {
 | 
| -            return false;
 | 
| -        }
 | 
| -
 | 
| -        if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
 | 
| -            return false;
 | 
| -        }
 | 
| -
 | 
| -        if (this->isHairline() != that->isHairline()) {
 | 
| -            return false;
 | 
| -        }
 | 
| -
 | 
| -        fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
 | 
| -        this->joinBounds(that->bounds());
 | 
| -        return true;
 | 
| -    }
 | 
| -
 | 
| -    bool createGeom(void* vertices,
 | 
| -                    size_t vertexOffset,
 | 
| -                    void* indices,
 | 
| -                    size_t indexOffset,
 | 
| -                    int* vertexCnt,
 | 
| -                    int* indexCnt,
 | 
| -                    const SkPath& path,
 | 
| -                    SkScalar srcSpaceTol,
 | 
| -                    bool isIndexed)  {
 | 
| -        {
 | 
| -            SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
 | 
| -
 | 
| -            uint16_t indexOffsetU16 = (uint16_t)indexOffset;
 | 
| -            uint16_t vertexOffsetU16 = (uint16_t)vertexOffset;
 | 
| -
 | 
| -            uint16_t* idxBase = reinterpret_cast<uint16_t*>(indices) + indexOffsetU16;
 | 
| -            uint16_t* idx = idxBase;
 | 
| -            uint16_t subpathIdxStart = vertexOffsetU16;
 | 
| -
 | 
| -            SkPoint* base = reinterpret_cast<SkPoint*>(vertices) + vertexOffset;
 | 
| -            SkPoint* vert = base;
 | 
| -
 | 
| -            SkPoint pts[4];
 | 
| -
 | 
| -            bool first = true;
 | 
| -            int subpath = 0;
 | 
| -
 | 
| -            SkPath::Iter iter(path, false);
 | 
| -
 | 
| -            bool done = false;
 | 
| -            while (!done) {
 | 
| -                SkPath::Verb verb = iter.next(pts);
 | 
| -                switch (verb) {
 | 
| -                    case SkPath::kMove_Verb:
 | 
| -                        if (!first) {
 | 
| -                            uint16_t currIdx = (uint16_t) (vert - base) + vertexOffsetU16;
 | 
| -                            subpathIdxStart = currIdx;
 | 
| -                            ++subpath;
 | 
| -                        }
 | 
| -                        *vert = pts[0];
 | 
| -                        vert++;
 | 
| -                        break;
 | 
| -                    case SkPath::kLine_Verb:
 | 
| -                        if (isIndexed) {
 | 
| -                            uint16_t prevIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16;
 | 
| -                            append_countour_edge_indices(this->isHairline(), subpathIdxStart,
 | 
| -                                                         prevIdx, &idx);
 | 
| -                        }
 | 
| -                        *(vert++) = pts[1];
 | 
| -                        break;
 | 
| -                    case SkPath::kConic_Verb: {
 | 
| -                        SkScalar weight = iter.conicWeight();
 | 
| -                        SkAutoConicToQuads converter;
 | 
| -                        // Converting in src-space, hance the finer tolerance (0.25)
 | 
| -                        // TODO: find a way to do this in dev-space so the tolerance means something
 | 
| -                        const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f);
 | 
| -                        for (int i = 0; i < converter.countQuads(); ++i) {
 | 
| -                            add_quad(&vert, base, quadPts + i*2, srcSpaceTolSqd, srcSpaceTol,
 | 
| -                                     isIndexed, this->isHairline(), subpathIdxStart,
 | 
| -                                     (int)vertexOffset, &idx);
 | 
| -                        }
 | 
| -                        break;
 | 
| -                    }
 | 
| -                    case SkPath::kQuad_Verb:
 | 
| -                        add_quad(&vert, base, pts, srcSpaceTolSqd, srcSpaceTol, isIndexed,
 | 
| -                                 this->isHairline(), subpathIdxStart, (int)vertexOffset, &idx);
 | 
| -                        break;
 | 
| -                    case SkPath::kCubic_Verb: {
 | 
| -                        // first pt of cubic is the pt we ended on in previous step
 | 
| -                        uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16;
 | 
| -                        uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
 | 
| -                                        pts[0], pts[1], pts[2], pts[3],
 | 
| -                                        srcSpaceTolSqd, &vert,
 | 
| -                                        GrPathUtils::cubicPointCount(pts, srcSpaceTol));
 | 
| -                        if (isIndexed) {
 | 
| -                            for (uint16_t i = 0; i < numPts; ++i) {
 | 
| -                                append_countour_edge_indices(this->isHairline(), subpathIdxStart,
 | 
| -                                                             firstCPtIdx + i, &idx);
 | 
| -                            }
 | 
| -                        }
 | 
| -                        break;
 | 
| -                    }
 | 
| -                    case SkPath::kClose_Verb:
 | 
| -                        break;
 | 
| -                    case SkPath::kDone_Verb:
 | 
| -                        done = true;
 | 
| -                }
 | 
| -                first = false;
 | 
| -            }
 | 
| -
 | 
| -            *vertexCnt = static_cast<int>(vert - base);
 | 
| -            *indexCnt = static_cast<int>(idx - idxBase);
 | 
| -
 | 
| -        }
 | 
| -        return true;
 | 
| -    }
 | 
| -
 | 
| -    GrColor color() const { return fBatch.fColor; }
 | 
| -    uint8_t coverage() const { return fBatch.fCoverage; }
 | 
| -    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
 | 
| -    const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
 | 
| -    bool isHairline() const { return fBatch.fIsHairline; }
 | 
| -    bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
 | 
| -
 | 
| -    struct BatchTracker {
 | 
| -        GrColor fColor;
 | 
| -        uint8_t fCoverage;
 | 
| -        SkMatrix fViewMatrix;
 | 
| -        bool fUsesLocalCoords;
 | 
| -        bool fColorIgnored;
 | 
| -        bool fCoverageIgnored;
 | 
| -        bool fIsHairline;
 | 
| -    };
 | 
| -
 | 
| -    BatchTracker fBatch;
 | 
| -    SkSTArray<1, Geometry, true> fGeoData;
 | 
| -};
 | 
| -
 | 
| -bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
 | 
| -                                             GrPipelineBuilder* pipelineBuilder,
 | 
| -                                             GrColor color,
 | 
| -                                             const SkMatrix& viewMatrix,
 | 
| -                                             const SkPath& path,
 | 
| -                                             const GrStrokeInfo& origStroke,
 | 
| -                                             bool stencilOnly) {
 | 
| -    SkTCopyOnFirstWrite<GrStrokeInfo> stroke(origStroke);
 | 
| -
 | 
| -    SkScalar hairlineCoverage;
 | 
| -    uint8_t newCoverage = 0xff;
 | 
| -    if (IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, &hairlineCoverage)) {
 | 
| -        newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
 | 
| -
 | 
| -        if (!stroke->isHairlineStyle()) {
 | 
| -            stroke.writable()->setHairlineStyle();
 | 
| -        }
 | 
| -    }
 | 
| -
 | 
| -    const bool isHairline = stroke->isHairlineStyle();
 | 
| -
 | 
| -    // Save the current xp on the draw state so we can reset it if needed
 | 
| -    SkAutoTUnref<const GrXPFactory> backupXPFactory(SkRef(pipelineBuilder->getXPFactory()));
 | 
| -    // face culling doesn't make sense here
 | 
| -    SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace());
 | 
| -
 | 
| -    int                         passCount = 0;
 | 
| -    const GrStencilSettings*    passes[3];
 | 
| -    GrPipelineBuilder::DrawFace drawFace[3];
 | 
| -    bool                        reverse = false;
 | 
| -    bool                        lastPassIsBounds;
 | 
| -
 | 
| -    if (isHairline) {
 | 
| -        passCount = 1;
 | 
| -        if (stencilOnly) {
 | 
| -            passes[0] = &gDirectToStencil;
 | 
| -        } else {
 | 
| -            passes[0] = nullptr;
 | 
| -        }
 | 
| -        lastPassIsBounds = false;
 | 
| -        drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
 | 
| -    } else {
 | 
| -        if (single_pass_path(path, *stroke)) {
 | 
| -            passCount = 1;
 | 
| -            if (stencilOnly) {
 | 
| -                passes[0] = &gDirectToStencil;
 | 
| -            } else {
 | 
| -                passes[0] = nullptr;
 | 
| -            }
 | 
| -            drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
 | 
| -            lastPassIsBounds = false;
 | 
| -        } else {
 | 
| -            switch (path.getFillType()) {
 | 
| -                case SkPath::kInverseEvenOdd_FillType:
 | 
| -                    reverse = true;
 | 
| -                    // fallthrough
 | 
| -                case SkPath::kEvenOdd_FillType:
 | 
| -                    passes[0] = &gEOStencilPass;
 | 
| -                    if (stencilOnly) {
 | 
| -                        passCount = 1;
 | 
| -                        lastPassIsBounds = false;
 | 
| -                    } else {
 | 
| -                        passCount = 2;
 | 
| -                        lastPassIsBounds = true;
 | 
| -                        if (reverse) {
 | 
| -                            passes[1] = &gInvEOColorPass;
 | 
| -                        } else {
 | 
| -                            passes[1] = &gEOColorPass;
 | 
| -                        }
 | 
| -                    }
 | 
| -                    drawFace[0] = drawFace[1] = GrPipelineBuilder::kBoth_DrawFace;
 | 
| -                    break;
 | 
| -
 | 
| -                case SkPath::kInverseWinding_FillType:
 | 
| -                    reverse = true;
 | 
| -                    // fallthrough
 | 
| -                case SkPath::kWinding_FillType:
 | 
| -                    if (fSeparateStencil) {
 | 
| -                        if (fStencilWrapOps) {
 | 
| -                            passes[0] = &gWindStencilSeparateWithWrap;
 | 
| -                        } else {
 | 
| -                            passes[0] = &gWindStencilSeparateNoWrap;
 | 
| -                        }
 | 
| -                        passCount = 2;
 | 
| -                        drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
 | 
| -                    } else {
 | 
| -                        if (fStencilWrapOps) {
 | 
| -                            passes[0] = &gWindSingleStencilWithWrapInc;
 | 
| -                            passes[1] = &gWindSingleStencilWithWrapDec;
 | 
| -                        } else {
 | 
| -                            passes[0] = &gWindSingleStencilNoWrapInc;
 | 
| -                            passes[1] = &gWindSingleStencilNoWrapDec;
 | 
| -                        }
 | 
| -                        // which is cw and which is ccw is arbitrary.
 | 
| -                        drawFace[0] = GrPipelineBuilder::kCW_DrawFace;
 | 
| -                        drawFace[1] = GrPipelineBuilder::kCCW_DrawFace;
 | 
| -                        passCount = 3;
 | 
| -                    }
 | 
| -                    if (stencilOnly) {
 | 
| -                        lastPassIsBounds = false;
 | 
| -                        --passCount;
 | 
| -                    } else {
 | 
| -                        lastPassIsBounds = true;
 | 
| -                        drawFace[passCount-1] = GrPipelineBuilder::kBoth_DrawFace;
 | 
| -                        if (reverse) {
 | 
| -                            passes[passCount-1] = &gInvWindColorPass;
 | 
| -                        } else {
 | 
| -                            passes[passCount-1] = &gWindColorPass;
 | 
| -                        }
 | 
| -                    }
 | 
| -                    break;
 | 
| -                default:
 | 
| -                    SkDEBUGFAIL("Unknown path fFill!");
 | 
| -                    return false;
 | 
| -            }
 | 
| -        }
 | 
| -    }
 | 
| -
 | 
| -    SkScalar tol = GrPathUtils::kDefaultTolerance;
 | 
| -    SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds());
 | 
| -
 | 
| -    SkRect devBounds;
 | 
| -    GetPathDevBounds(path, pipelineBuilder->getRenderTarget(), viewMatrix, &devBounds);
 | 
| -
 | 
| -    for (int p = 0; p < passCount; ++p) {
 | 
| -        pipelineBuilder->setDrawFace(drawFace[p]);
 | 
| -        if (passes[p]) {
 | 
| -            *pipelineBuilder->stencil() = *passes[p];
 | 
| -        }
 | 
| -
 | 
| -        if (lastPassIsBounds && (p == passCount-1)) {
 | 
| -            // Reset the XP Factory on pipelineBuilder
 | 
| -            pipelineBuilder->setXPFactory(backupXPFactory);
 | 
| -            SkRect bounds;
 | 
| -            SkMatrix localMatrix = SkMatrix::I();
 | 
| -            if (reverse) {
 | 
| -                SkASSERT(pipelineBuilder->getRenderTarget());
 | 
| -                // draw over the dev bounds (which will be the whole dst surface for inv fill).
 | 
| -                bounds = devBounds;
 | 
| -                SkMatrix vmi;
 | 
| -                // mapRect through persp matrix may not be correct
 | 
| -                if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
 | 
| -                    vmi.mapRect(&bounds);
 | 
| -                } else {
 | 
| -                    if (!viewMatrix.invert(&localMatrix)) {
 | 
| -                        return false;
 | 
| -                    }
 | 
| -                }
 | 
| -            } else {
 | 
| -                bounds = path.getBounds();
 | 
| -            }
 | 
| -            const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
 | 
| -                                                                               viewMatrix;
 | 
| -            target->drawNonAARect(*pipelineBuilder, color, viewM, bounds, localMatrix);
 | 
| -        } else {
 | 
| -            if (passCount > 1) {
 | 
| -                pipelineBuilder->setDisableColorXPFactory();
 | 
| -            }
 | 
| -
 | 
| -            DefaultPathBatch::Geometry geometry;
 | 
| -            geometry.fColor = color;
 | 
| -            geometry.fPath = path;
 | 
| -            geometry.fTolerance = srcSpaceTol;
 | 
| -
 | 
| -            SkAutoTUnref<GrDrawBatch> batch(DefaultPathBatch::Create(geometry, newCoverage,
 | 
| -                                                                     viewMatrix, isHairline,
 | 
| -                                                                     devBounds));
 | 
| -
 | 
| -            target->drawBatch(*pipelineBuilder, batch);
 | 
| -        }
 | 
| -    }
 | 
| -    return true;
 | 
| -}
 | 
| -
 | 
| -bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
 | 
| -    // this class can draw any path with any fill but doesn't do any anti-aliasing.
 | 
| -    return !args.fAntiAlias && (args.fStroke->isFillStyle() ||
 | 
| -                                IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix,
 | 
| -                                                             nullptr));
 | 
| -}
 | 
| -
 | 
| -bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
 | 
| -    return this->internalDrawPath(args.fTarget,
 | 
| -                                  args.fPipelineBuilder,
 | 
| -                                  args.fColor,
 | 
| -                                  *args.fViewMatrix,
 | 
| -                                  *args.fPath,
 | 
| -                                  *args.fStroke,
 | 
| -                                  false);
 | 
| -}
 | 
| -
 | 
| -void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
 | 
| -    SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType());
 | 
| -    SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType());
 | 
| -    this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix,
 | 
| -                           *args.fPath, *args.fStroke, true);
 | 
| -}
 | 
| -
 | 
| -///////////////////////////////////////////////////////////////////////////////////////////////////
 | 
| -
 | 
| -#ifdef GR_TEST_UTILS
 | 
| -
 | 
| -DRAW_BATCH_TEST_DEFINE(DefaultPathBatch) {
 | 
| -    GrColor color = GrRandomColor(random);
 | 
| -    SkMatrix viewMatrix = GrTest::TestMatrix(random);
 | 
| -
 | 
| -    // For now just hairlines because the other types of draws require two batches.
 | 
| -    // TODO we should figure out a way to combine the stencil and cover steps into one batch
 | 
| -    GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle);
 | 
| -    SkPath path = GrTest::TestPath(random);
 | 
| -
 | 
| -    // Compute srcSpaceTol
 | 
| -    SkRect bounds = path.getBounds();
 | 
| -    SkScalar tol = GrPathUtils::kDefaultTolerance;
 | 
| -    SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds);
 | 
| -
 | 
| -    DefaultPathBatch::Geometry geometry;
 | 
| -    geometry.fColor = color;
 | 
| -    geometry.fPath = path;
 | 
| -    geometry.fTolerance = srcSpaceTol;
 | 
| -
 | 
| -    viewMatrix.mapRect(&bounds);
 | 
| -    uint8_t coverage = GrRandomCoverage(random);
 | 
| -    return DefaultPathBatch::Create(geometry, coverage, viewMatrix, true, bounds);
 | 
| -}
 | 
| -
 | 
| -#endif
 | 
| 
 |