| Index: src/gpu/batches/GrPLSPathRenderer.cpp
 | 
| diff --git a/src/gpu/batches/GrPLSPathRenderer.cpp b/src/gpu/batches/GrPLSPathRenderer.cpp
 | 
| deleted file mode 100644
 | 
| index 7f8eaa4da94ca006bba8c5c2e6df23aa9a8e2ba1..0000000000000000000000000000000000000000
 | 
| --- a/src/gpu/batches/GrPLSPathRenderer.cpp
 | 
| +++ /dev/null
 | 
| @@ -1,1011 +0,0 @@
 | 
| -/*
 | 
| - * Copyright 2015 Google Inc.
 | 
| - *
 | 
| - * Use of this source code is governed by a BSD-style license that can be
 | 
| - * found in the LICENSE file.
 | 
| - */
 | 
| -
 | 
| -#include "GrPLSPathRenderer.h"
 | 
| -
 | 
| -#include "SkChunkAlloc.h"
 | 
| -#include "SkGeometry.h"
 | 
| -#include "SkPathPriv.h"
 | 
| -#include "SkString.h"
 | 
| -#include "SkTSort.h"
 | 
| -#include "SkTraceEvent.h"
 | 
| -#include "GrBatchFlushState.h"
 | 
| -#include "GrBatchTest.h"
 | 
| -#include "GrCaps.h"
 | 
| -#include "GrContext.h"
 | 
| -#include "GrDefaultGeoProcFactory.h"
 | 
| -#include "GrPLSGeometryProcessor.h"
 | 
| -#include "GrInvariantOutput.h"
 | 
| -#include "GrPathUtils.h"
 | 
| -#include "GrProcessor.h"
 | 
| -#include "GrPipelineBuilder.h"
 | 
| -#include "GrStrokeInfo.h"
 | 
| -#include "GrTessellator.h"
 | 
| -#include "batches/GrVertexBatch.h"
 | 
| -#include "glsl/GrGLSLGeometryProcessor.h"
 | 
| -#include "gl/builders/GrGLProgramBuilder.h"
 | 
| -#include "glsl/GrGLSLPLSPathRendering.h"
 | 
| -
 | 
| -GrPLSPathRenderer::GrPLSPathRenderer() {
 | 
| -}
 | 
| -
 | 
| -struct PLSVertex {
 | 
| -    SkPoint  fPos;
 | 
| -    // for triangles, these are the three triangle vertices
 | 
| -    // for quads, vert1 is the texture UV coords, and vert2 and vert3 are the line segment 
 | 
| -    // comprising the flat edge of the quad
 | 
| -    SkPoint  fVert1;
 | 
| -    SkPoint  fVert2;
 | 
| -    SkPoint  fVert3;
 | 
| -    int fWinding;
 | 
| -};
 | 
| -typedef SkTArray<PLSVertex, true> PLSVertices;
 | 
| -
 | 
| -typedef SkTArray<SkPoint, true> FinishVertices;
 | 
| -
 | 
| -static const float kCubicTolerance = 0.5f;
 | 
| -static const float kConicTolerance = 0.5f;
 | 
| -
 | 
| -static const float kBloatSize = 1.0f;
 | 
| -
 | 
| -static const float kBloatLimit = 640000.0f;
 | 
| -
 | 
| -#define kQuadNumVertices 5
 | 
| -static void add_quad(SkPoint pts[3], PLSVertices& vertices) {
 | 
| -    SkPoint normal = SkPoint::Make(pts[0].fY - pts[2].fY, 
 | 
| -                                   pts[2].fX - pts[0].fX);
 | 
| -    normal.setLength(kBloatSize);
 | 
| -    SkScalar cross = (pts[1] - pts[0]).cross(pts[2] - pts[0]);
 | 
| -    if (cross < 0) {
 | 
| -        normal = -normal;
 | 
| -    }
 | 
| -    PLSVertex quad[kQuadNumVertices];
 | 
| -    quad[0].fPos = pts[0] + normal;
 | 
| -    quad[1].fPos = pts[0] - normal;
 | 
| -    quad[2].fPos = pts[1] - normal;
 | 
| -    quad[3].fPos = pts[2] - normal;
 | 
| -    quad[4].fPos = pts[2] + normal;
 | 
| -    for (int i = 0; i < kQuadNumVertices; i++) {
 | 
| -        quad[i].fWinding = cross < 0 ? 1 : -1;
 | 
| -        if (cross > 0.0) {
 | 
| -            quad[i].fVert2 = pts[0];
 | 
| -            quad[i].fVert3 = pts[2];
 | 
| -        }
 | 
| -        else {
 | 
| -            quad[i].fVert2 = pts[2];
 | 
| -            quad[i].fVert3 = pts[0];
 | 
| -        }
 | 
| -    }
 | 
| -    GrPathUtils::QuadUVMatrix DevToUV(pts);
 | 
| -    DevToUV.apply<kQuadNumVertices, sizeof(PLSVertex), sizeof(SkPoint)>(quad);
 | 
| -    for (int i = 2; i < kQuadNumVertices; i++) {
 | 
| -        vertices.push_back(quad[0]);
 | 
| -        vertices.push_back(quad[i - 1]);
 | 
| -        vertices.push_back(quad[i]);
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/* Used by bloat_tri; outsets a single point. */
 | 
| -static bool outset(SkPoint* p1, SkPoint line1, SkPoint line2) {
 | 
| -    // rotate the two line vectors 90 degrees to form the normals, and compute
 | 
| -    // the dot product of the normals
 | 
| -    SkScalar dotProd = line1.fY * line2.fY + line1.fX * line2.fX;
 | 
| -    SkScalar lengthSq = 1.0f / ((1.0f - dotProd) / 2.0f);
 | 
| -    if (lengthSq > kBloatLimit) {
 | 
| -        return false;
 | 
| -    }
 | 
| -    SkPoint bisector = line1 + line2;
 | 
| -    bisector.setLength(SkScalarSqrt(lengthSq) * kBloatSize);
 | 
| -    *p1 += bisector;
 | 
| -    return true;
 | 
| -}
 | 
| -
 | 
| -/* Bloats a triangle so as to create a border kBloatSize pixels wide all around it. */
 | 
| -static bool bloat_tri(SkPoint pts[3]) {
 | 
| -    SkPoint line1 = pts[0] - pts[1];
 | 
| -    line1.normalize();
 | 
| -    SkPoint line2 = pts[0] - pts[2];
 | 
| -    line2.normalize();
 | 
| -    SkPoint line3 = pts[1] - pts[2];
 | 
| -    line3.normalize();
 | 
| -
 | 
| -    SkPoint result[3];
 | 
| -    result[0] = pts[0];
 | 
| -    if (!outset(&result[0], line1, line2)) {
 | 
| -        return false;
 | 
| -    }
 | 
| -    result[1] = pts[1];
 | 
| -    if (!outset(&result[1], -line1, line3)) {
 | 
| -        return false;
 | 
| -    }
 | 
| -    result[2] = pts[2];
 | 
| -    if (!outset(&result[2], -line3, -line2)) {
 | 
| -        return false;
 | 
| -    }
 | 
| -    pts[0] = result[0];
 | 
| -    pts[1] = result[1];
 | 
| -    pts[2] = result[2];
 | 
| -    return true;
 | 
| -}
 | 
| -
 | 
| -static bool get_geometry(const SkPath& path, const SkMatrix& m, PLSVertices& triVertices, 
 | 
| -                         PLSVertices& quadVertices, GrResourceProvider* resourceProvider,
 | 
| -                         SkRect bounds) {
 | 
| -    SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance;
 | 
| -    SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, m, bounds);
 | 
| -    int contourCnt;
 | 
| -    int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol);
 | 
| -    if (maxPts <= 0) {
 | 
| -        return 0;
 | 
| -    }
 | 
| -    SkPath linesOnlyPath;
 | 
| -    linesOnlyPath.setFillType(path.getFillType());
 | 
| -    SkSTArray<15, SkPoint, true> quadPoints;
 | 
| -    SkPathPriv::FirstDirection dir = SkPathPriv::FirstDirection::kUnknown_FirstDirection;
 | 
| -    SkPath::Iter iter(path, true);
 | 
| -    bool done = false;
 | 
| -    while (!done) {
 | 
| -        SkPoint pts[4];
 | 
| -        SkPath::Verb verb = iter.next(pts);
 | 
| -        switch (verb) {
 | 
| -            case SkPath::kMove_Verb:
 | 
| -                SkASSERT(quadPoints.count() % 3 == 0);
 | 
| -                for (int i = 0; i < quadPoints.count(); i += 3) {
 | 
| -                    add_quad(&quadPoints[i], quadVertices);
 | 
| -                }
 | 
| -                quadPoints.reset();
 | 
| -                m.mapPoints(&pts[0], 1);
 | 
| -                linesOnlyPath.moveTo(pts[0]);
 | 
| -                break;
 | 
| -            case SkPath::kLine_Verb:
 | 
| -                m.mapPoints(&pts[1], 1);
 | 
| -                linesOnlyPath.lineTo(pts[1]);
 | 
| -                break;
 | 
| -            case SkPath::kQuad_Verb:
 | 
| -                m.mapPoints(pts, 3);
 | 
| -                linesOnlyPath.lineTo(pts[2]);
 | 
| -                quadPoints.push_back(pts[0]);
 | 
| -                quadPoints.push_back(pts[1]);
 | 
| -                quadPoints.push_back(pts[2]);
 | 
| -                break;
 | 
| -            case SkPath::kCubic_Verb: {
 | 
| -                m.mapPoints(pts, 4);
 | 
| -                SkSTArray<15, SkPoint, true> quads;
 | 
| -                GrPathUtils::convertCubicToQuads(pts, kCubicTolerance, false, dir, &quads);
 | 
| -                int count = quads.count();
 | 
| -                for (int q = 0; q < count; q += 3) {
 | 
| -                    linesOnlyPath.lineTo(quads[q + 2]);
 | 
| -                    quadPoints.push_back(quads[q]);
 | 
| -                    quadPoints.push_back(quads[q + 1]);
 | 
| -                    quadPoints.push_back(quads[q + 2]);
 | 
| -                }
 | 
| -                break;
 | 
| -            }
 | 
| -            case SkPath::kConic_Verb: {
 | 
| -                m.mapPoints(pts, 3);
 | 
| -                SkScalar weight = iter.conicWeight();
 | 
| -                SkAutoConicToQuads converter;
 | 
| -                const SkPoint* quads = converter.computeQuads(pts, weight, kConicTolerance);
 | 
| -                int count = converter.countQuads();
 | 
| -                for (int i = 0; i < count; ++i) {
 | 
| -                    linesOnlyPath.lineTo(quads[2 * i + 2]);
 | 
| -                    quadPoints.push_back(quads[2 * i]);
 | 
| -                    quadPoints.push_back(quads[2 * i + 1]);
 | 
| -                    quadPoints.push_back(quads[2 * i + 2]);
 | 
| -                }
 | 
| -                break;
 | 
| -            }
 | 
| -            case SkPath::kClose_Verb:
 | 
| -                linesOnlyPath.close();
 | 
| -                break;
 | 
| -            case SkPath::kDone_Verb:
 | 
| -                done = true;
 | 
| -                break;
 | 
| -            default: SkASSERT(false);
 | 
| -        }
 | 
| -    }
 | 
| -    SkASSERT(quadPoints.count() % 3 == 0);
 | 
| -    for (int i = 0; i < quadPoints.count(); i += 3) {
 | 
| -        add_quad(&quadPoints[i], quadVertices);
 | 
| -    }
 | 
| -
 | 
| -    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
 | 
| -    GrUniqueKey key;
 | 
| -    GrUniqueKey::Builder builder(&key, kDomain, 2);
 | 
| -    builder[0] = path.getGenerationID();
 | 
| -    builder[1] = path.getFillType();
 | 
| -    builder.finish();
 | 
| -    GrTessellator::WindingVertex* windingVertices;
 | 
| -    int triVertexCount = GrTessellator::PathToVertices(linesOnlyPath, 0, bounds, &windingVertices);
 | 
| -    if (triVertexCount > 0) {
 | 
| -        for (int i = 0; i < triVertexCount; i += 3) {
 | 
| -            SkPoint p1 = windingVertices[i].fPos;
 | 
| -            SkPoint p2 = windingVertices[i + 1].fPos;
 | 
| -            SkPoint p3 = windingVertices[i + 2].fPos;
 | 
| -            int winding = windingVertices[i].fWinding;
 | 
| -            SkASSERT(windingVertices[i + 1].fWinding == winding);
 | 
| -            SkASSERT(windingVertices[i + 2].fWinding == winding);
 | 
| -            SkScalar cross = (p2 - p1).cross(p3 - p1);
 | 
| -            SkPoint bloated[3] = { p1, p2, p3 };
 | 
| -            if (cross < 0.0f) {
 | 
| -                SkTSwap(p1, p3);
 | 
| -            }
 | 
| -            if (bloat_tri(bloated)) {
 | 
| -                triVertices.push_back({ bloated[0], p1, p2, p3, winding });
 | 
| -                triVertices.push_back({ bloated[1], p1, p2, p3, winding });
 | 
| -                triVertices.push_back({ bloated[2], p1, p2, p3, winding });
 | 
| -            }
 | 
| -            else {
 | 
| -                SkScalar minX = SkTMin(p1.fX, SkTMin(p2.fX, p3.fX)) - 1.0f;
 | 
| -                SkScalar minY = SkTMin(p1.fY, SkTMin(p2.fY, p3.fY)) - 1.0f;
 | 
| -                SkScalar maxX = SkTMax(p1.fX, SkTMax(p2.fX, p3.fX)) + 1.0f;
 | 
| -                SkScalar maxY = SkTMax(p1.fY, SkTMax(p2.fY, p3.fY)) + 1.0f;
 | 
| -                triVertices.push_back({ { minX, minY }, p1, p2, p3, winding });
 | 
| -                triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding });
 | 
| -                triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding });
 | 
| -                triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding });
 | 
| -                triVertices.push_back({ { maxX, maxY }, p1, p2, p3, winding });
 | 
| -                triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding });
 | 
| -            }
 | 
| -        }
 | 
| -        delete[] windingVertices;
 | 
| -    }
 | 
| -    return triVertexCount > 0 || quadVertices.count() > 0;
 | 
| -}
 | 
| -
 | 
| -class PLSAATriangleEffect : public GrPLSGeometryProcessor {
 | 
| -public:
 | 
| -
 | 
| -    static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix,
 | 
| -                                          bool usesLocalCoords) {
 | 
| -        return new PLSAATriangleEffect(localMatrix, usesLocalCoords);
 | 
| -    }
 | 
| -
 | 
| -    virtual ~PLSAATriangleEffect() {}
 | 
| -
 | 
| -    const char* name() const override { return "PLSAATriangle"; }
 | 
| -
 | 
| -    const Attribute* inPosition() const { return fInPosition; }
 | 
| -    const Attribute* inVertex1() const { return fInVertex1; }
 | 
| -    const Attribute* inVertex2() const { return fInVertex2; }
 | 
| -    const Attribute* inVertex3() const { return fInVertex3; }
 | 
| -    const Attribute* inWindings() const { return fInWindings; }
 | 
| -    const SkMatrix& localMatrix() const { return fLocalMatrix; }
 | 
| -    bool usesLocalCoords() const { return fUsesLocalCoords; }
 | 
| -
 | 
| -    class GLSLProcessor : public GrGLSLGeometryProcessor {
 | 
| -    public:
 | 
| -        GLSLProcessor(const GrGeometryProcessor&) {}
 | 
| -
 | 
| -        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
 | 
| -            const PLSAATriangleEffect& te = args.fGP.cast<PLSAATriangleEffect>();
 | 
| -            GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
 | 
| -            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 | 
| -            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
 | 
| -
 | 
| -            varyingHandler->emitAttributes(te);
 | 
| -
 | 
| -            this->setupPosition(vsBuilder, gpArgs, te.inPosition()->fName);
 | 
| -
 | 
| -            GrGLSLVertToFrag v1(kVec2f_GrSLType);
 | 
| -            varyingHandler->addVarying("Vertex1", &v1, kHigh_GrSLPrecision);
 | 
| -            vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", 
 | 
| -                                   v1.vsOut(),
 | 
| -                                   te.inVertex1()->fName, 
 | 
| -                                   te.inVertex1()->fName);
 | 
| -
 | 
| -            GrGLSLVertToFrag v2(kVec2f_GrSLType);
 | 
| -            varyingHandler->addVarying("Vertex2", &v2, kHigh_GrSLPrecision);
 | 
| -            vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", 
 | 
| -                                   v2.vsOut(),
 | 
| -                                   te.inVertex2()->fName, 
 | 
| -                                   te.inVertex2()->fName);
 | 
| -
 | 
| -            GrGLSLVertToFrag v3(kVec2f_GrSLType);
 | 
| -            varyingHandler->addVarying("Vertex3", &v3, kHigh_GrSLPrecision);
 | 
| -            vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", 
 | 
| -                                   v3.vsOut(),
 | 
| -                                   te.inVertex3()->fName, 
 | 
| -                                   te.inVertex3()->fName);
 | 
| -
 | 
| -            GrGLSLVertToFrag delta1(kVec2f_GrSLType);
 | 
| -            varyingHandler->addVarying("delta1", &delta1, kHigh_GrSLPrecision);
 | 
| -            vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", 
 | 
| -                                   delta1.vsOut(), v1.vsOut(), v2.vsOut(), v2.vsOut(), v1.vsOut());
 | 
| -
 | 
| -            GrGLSLVertToFrag delta2(kVec2f_GrSLType);
 | 
| -            varyingHandler->addVarying("delta2", &delta2, kHigh_GrSLPrecision);
 | 
| -            vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", 
 | 
| -                                   delta2.vsOut(), v2.vsOut(), v3.vsOut(), v3.vsOut(), v2.vsOut());
 | 
| -
 | 
| -            GrGLSLVertToFrag delta3(kVec2f_GrSLType);
 | 
| -            varyingHandler->addVarying("delta3", &delta3, kHigh_GrSLPrecision);
 | 
| -            vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", 
 | 
| -                                   delta3.vsOut(), v3.vsOut(), v1.vsOut(), v1.vsOut(), v3.vsOut());
 | 
| -
 | 
| -            GrGLSLVertToFrag windings(kInt_GrSLType);
 | 
| -            varyingHandler->addVarying("windings", &windings, kLow_GrSLPrecision);
 | 
| -            vsBuilder->codeAppendf("%s = %s;", 
 | 
| -                                   windings.vsOut(), te.inWindings()->fName);
 | 
| -
 | 
| -            // emit transforms
 | 
| -            this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, 
 | 
| -                                 te.inPosition()->fName, te.localMatrix(), args.fTransformsIn, 
 | 
| -                                 args.fTransformsOut);
 | 
| -
 | 
| -            GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder;
 | 
| -            SkAssertResult(fsBuilder->enableFeature(
 | 
| -                           GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature));
 | 
| -            SkAssertResult(fsBuilder->enableFeature(
 | 
| -                    GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
 | 
| -            fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL);
 | 
| -            // Compute four subsamples, each shifted a quarter pixel along x and y from 
 | 
| -            // gl_FragCoord. The oriented box positioning of the subsamples is of course not 
 | 
| -            // optimal, but it greatly simplifies the math and this simplification is necessary for
 | 
| -            // performance reasons.
 | 
| -            fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);", 
 | 
| -                                   fsBuilder->fragmentPosition());
 | 
| -            fsBuilder->codeAppendf("highp vec2 delta1 = %s;", delta1.fsIn());
 | 
| -            fsBuilder->codeAppendf("highp vec2 delta2 = %s;", delta2.fsIn());
 | 
| -            fsBuilder->codeAppendf("highp vec2 delta3 = %s;", delta3.fsIn());
 | 
| -            // Check whether first sample is inside the triangle by computing three dot products. If
 | 
| -            // all are < 0, we're inside. The first vector in each case is half of what it is
 | 
| -            // "supposed" to be, because we re-use them later as adjustment factors for which half
 | 
| -            // is the correct value, so we multiply the dots by two to compensate.
 | 
| -            fsBuilder->codeAppendf("highp float d1 = dot(delta1, (firstSample - %s).yx) * 2.0;", 
 | 
| -                                   v1.fsIn());
 | 
| -            fsBuilder->codeAppendf("highp float d2 = dot(delta2, (firstSample - %s).yx) * 2.0;", 
 | 
| -                                   v2.fsIn());
 | 
| -            fsBuilder->codeAppendf("highp float d3 = dot(delta3, (firstSample - %s).yx) * 2.0;", 
 | 
| -                                   v3.fsIn());
 | 
| -            fsBuilder->codeAppend("highp float dmax = max(d1, max(d2, d3));");
 | 
| -            fsBuilder->codeAppendf("pls.windings[0] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
 | 
| -            // for subsequent samples, we don't recalculate the entire dot product -- just adjust it
 | 
| -            // to the value it would have if we did recompute it.
 | 
| -            fsBuilder->codeAppend("d1 += delta1.x;");
 | 
| -            fsBuilder->codeAppend("d2 += delta2.x;");
 | 
| -            fsBuilder->codeAppend("d3 += delta3.x;");
 | 
| -            fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));");
 | 
| -            fsBuilder->codeAppendf("pls.windings[1] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
 | 
| -            fsBuilder->codeAppend("d1 += delta1.y;");
 | 
| -            fsBuilder->codeAppend("d2 += delta2.y;");
 | 
| -            fsBuilder->codeAppend("d3 += delta3.y;");
 | 
| -            fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));");
 | 
| -            fsBuilder->codeAppendf("pls.windings[2] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
 | 
| -            fsBuilder->codeAppend("d1 -= delta1.x;");
 | 
| -            fsBuilder->codeAppend("d2 -= delta2.x;");
 | 
| -            fsBuilder->codeAppend("d3 -= delta3.x;");
 | 
| -            fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));");
 | 
| -            fsBuilder->codeAppendf("pls.windings[3] += (dmax <= 0.0) ? %s : 0;", windings.fsIn());
 | 
| -        }
 | 
| -
 | 
| -        static inline void GenKey(const GrGeometryProcessor& gp,
 | 
| -                                  const GrGLSLCaps&,
 | 
| -                                  GrProcessorKeyBuilder* b) {
 | 
| -            const PLSAATriangleEffect& te = gp.cast<PLSAATriangleEffect>();
 | 
| -            uint32_t key = 0;
 | 
| -            key |= te.localMatrix().hasPerspective() ? 0x1 : 0x0;
 | 
| -            b->add32(key);
 | 
| -        }
 | 
| -
 | 
| -        virtual void setData(const GrGLSLProgramDataManager& pdman,
 | 
| -                             const GrPrimitiveProcessor& gp) override {
 | 
| -        }
 | 
| -
 | 
| -        void setTransformData(const GrPrimitiveProcessor& primProc,
 | 
| -                              const GrGLSLProgramDataManager& pdman,
 | 
| -                              int index,
 | 
| -                              const SkTArray<const GrCoordTransform*, true>& transforms) override {
 | 
| -            this->setTransformDataHelper<PLSAATriangleEffect>(primProc, pdman, index, transforms);
 | 
| -        }
 | 
| -
 | 
| -    private:
 | 
| -        typedef GrGLSLGeometryProcessor INHERITED;
 | 
| -    };
 | 
| -
 | 
| -    virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
 | 
| -                                   GrProcessorKeyBuilder* b) const override {
 | 
| -        GLSLProcessor::GenKey(*this, caps, b);
 | 
| -    }
 | 
| -
 | 
| -    virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
 | 
| -        return new GLSLProcessor(*this);
 | 
| -    }
 | 
| -
 | 
| -private:
 | 
| -    PLSAATriangleEffect(const SkMatrix& localMatrix, bool usesLocalCoords)
 | 
| -        : fLocalMatrix(localMatrix)
 | 
| -        , fUsesLocalCoords(usesLocalCoords) {
 | 
| -        this->initClassID<PLSAATriangleEffect>();
 | 
| -        fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType, 
 | 
| -                                                       kHigh_GrSLPrecision));
 | 
| -        fInVertex1 = &this->addVertexAttrib(Attribute("inVertex1", kVec2f_GrVertexAttribType, 
 | 
| -                                                      kHigh_GrSLPrecision));
 | 
| -        fInVertex2 = &this->addVertexAttrib(Attribute("inVertex2", kVec2f_GrVertexAttribType, 
 | 
| -                                                      kHigh_GrSLPrecision));
 | 
| -        fInVertex3 = &this->addVertexAttrib(Attribute("inVertex3", kVec2f_GrVertexAttribType, 
 | 
| -                                                      kHigh_GrSLPrecision));
 | 
| -        fInWindings = &this->addVertexAttrib(Attribute("inWindings", kInt_GrVertexAttribType, 
 | 
| -                                                       kLow_GrSLPrecision));
 | 
| -        this->setWillReadFragmentPosition();
 | 
| -    }
 | 
| -
 | 
| -    const Attribute* fInPosition;
 | 
| -    const Attribute* fInVertex1;
 | 
| -    const Attribute* fInVertex2;
 | 
| -    const Attribute* fInVertex3;
 | 
| -    const Attribute* fInWindings;
 | 
| -    SkMatrix         fLocalMatrix;
 | 
| -    bool             fUsesLocalCoords;
 | 
| -    
 | 
| -    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
 | 
| -
 | 
| -    typedef GrGeometryProcessor INHERITED;
 | 
| -};
 | 
| -
 | 
| -///////////////////////////////////////////////////////////////////////////////
 | 
| -
 | 
| -/*
 | 
| - * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
 | 
| - * two components of the vertex attribute. Coverage is based on signed
 | 
| - * distance with negative being inside, positive outside. The edge is specified in
 | 
| - * window space (y-down). If either the third or fourth component of the interpolated
 | 
| - * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
 | 
| - * attempt to trim to a portion of the infinite quad.
 | 
| - * Requires shader derivative instruction support.
 | 
| - */
 | 
| -
 | 
| -class PLSQuadEdgeEffect : public GrPLSGeometryProcessor {
 | 
| -public:
 | 
| -
 | 
| -    static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix,
 | 
| -                                          bool usesLocalCoords) {
 | 
| -        return new PLSQuadEdgeEffect(localMatrix, usesLocalCoords);
 | 
| -    }
 | 
| -
 | 
| -    virtual ~PLSQuadEdgeEffect() {}
 | 
| -
 | 
| -    const char* name() const override { return "PLSQuadEdge"; }
 | 
| -
 | 
| -    const Attribute* inPosition() const { return fInPosition; }
 | 
| -    const Attribute* inUV() const { return fInUV; }
 | 
| -    const Attribute* inEndpoint1() const { return fInEndpoint1; }
 | 
| -    const Attribute* inEndpoint2() const { return fInEndpoint2; }
 | 
| -    const Attribute* inWindings() const { return fInWindings; }
 | 
| -    const SkMatrix& localMatrix() const { return fLocalMatrix; }
 | 
| -    bool usesLocalCoords() const { return fUsesLocalCoords; }
 | 
| -
 | 
| -    class GLSLProcessor : public GrGLSLGeometryProcessor {
 | 
| -    public:
 | 
| -        GLSLProcessor(const GrGeometryProcessor&) {}
 | 
| -
 | 
| -        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
 | 
| -            const PLSQuadEdgeEffect& qe = args.fGP.cast<PLSQuadEdgeEffect>();
 | 
| -            GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
 | 
| -            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 | 
| -            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
 | 
| -
 | 
| -            // emit attributes
 | 
| -            varyingHandler->emitAttributes(qe);
 | 
| -
 | 
| -            GrGLSLVertToFrag uv(kVec2f_GrSLType);
 | 
| -            varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision);
 | 
| -            vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qe.inUV()->fName);
 | 
| -
 | 
| -            GrGLSLVertToFrag ep1(kVec2f_GrSLType);
 | 
| -            varyingHandler->addVarying("endpoint1", &ep1, kHigh_GrSLPrecision);
 | 
| -            vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep1.vsOut(), 
 | 
| -                                  qe.inEndpoint1()->fName, qe.inEndpoint1()->fName);
 | 
| -
 | 
| -            GrGLSLVertToFrag ep2(kVec2f_GrSLType);
 | 
| -            varyingHandler->addVarying("endpoint2", &ep2, kHigh_GrSLPrecision);
 | 
| -            vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep2.vsOut(), 
 | 
| -                                  qe.inEndpoint2()->fName, qe.inEndpoint2()->fName);
 | 
| -
 | 
| -            GrGLSLVertToFrag delta(kVec2f_GrSLType);
 | 
| -            varyingHandler->addVarying("delta", &delta, kHigh_GrSLPrecision);
 | 
| -            vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", 
 | 
| -                                   delta.vsOut(), ep1.vsOut(), ep2.vsOut(), ep2.vsOut(), 
 | 
| -                                   ep1.vsOut());
 | 
| -
 | 
| -            GrGLSLVertToFrag windings(kInt_GrSLType);
 | 
| -            varyingHandler->addVarying("windings", &windings, kLow_GrSLPrecision);
 | 
| -            vsBuilder->codeAppendf("%s = %s;", 
 | 
| -                                   windings.vsOut(), qe.inWindings()->fName);
 | 
| -
 | 
| -            // Setup position
 | 
| -            this->setupPosition(vsBuilder, gpArgs, qe.inPosition()->fName);
 | 
| -
 | 
| -            // emit transforms
 | 
| -            this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, 
 | 
| -                                 qe.inPosition()->fName, qe.localMatrix(), args.fTransformsIn, 
 | 
| -                                 args.fTransformsOut);
 | 
| -
 | 
| -            GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder;
 | 
| -            SkAssertResult(fsBuilder->enableFeature(
 | 
| -                           GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature));
 | 
| -            SkAssertResult(fsBuilder->enableFeature(
 | 
| -                    GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
 | 
| -            static const int QUAD_ARGS = 2;
 | 
| -            GrGLSLShaderVar inQuadArgs[QUAD_ARGS] = {
 | 
| -                GrGLSLShaderVar("dot", kFloat_GrSLType, 0, kHigh_GrSLPrecision),
 | 
| -                GrGLSLShaderVar("uv", kVec2f_GrSLType, 0, kHigh_GrSLPrecision)
 | 
| -            };
 | 
| -            SkString inQuadName;
 | 
| -
 | 
| -            const char* inQuadCode = "if (uv.x * uv.x <= uv.y) {"
 | 
| -                                     "return dot >= 0.0;"
 | 
| -                                     "} else {"
 | 
| -                                     "return false;"
 | 
| -                                     "}";
 | 
| -            fsBuilder->emitFunction(kBool_GrSLType, "in_quad", QUAD_ARGS, inQuadArgs, inQuadCode, 
 | 
| -                                    &inQuadName);
 | 
| -            fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL);
 | 
| -            // keep the derivative instructions outside the conditional
 | 
| -            fsBuilder->codeAppendf("highp vec2 uvdX = dFdx(%s);", uv.fsIn());
 | 
| -            fsBuilder->codeAppendf("highp vec2 uvdY = dFdy(%s);", uv.fsIn());
 | 
| -            fsBuilder->codeAppend("highp vec2 uvIncX = uvdX * 0.45 + uvdY * -0.1;");
 | 
| -            fsBuilder->codeAppend("highp vec2 uvIncY = uvdX * 0.1 + uvdY * 0.55;");
 | 
| -            fsBuilder->codeAppendf("highp vec2 uv = %s.xy - uvdX * 0.35 - uvdY * 0.25;", 
 | 
| -                                   uv.fsIn());
 | 
| -            fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);",
 | 
| -                                   fsBuilder->fragmentPosition());
 | 
| -            fsBuilder->codeAppendf("highp float d = dot(%s, (firstSample - %s).yx) * 2.0;", 
 | 
| -                                   delta.fsIn(), ep1.fsIn());
 | 
| -            fsBuilder->codeAppendf("pls.windings[0] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), 
 | 
| -                                   windings.fsIn());
 | 
| -            fsBuilder->codeAppend("uv += uvIncX;");
 | 
| -            fsBuilder->codeAppendf("d += %s.x;", delta.fsIn());
 | 
| -            fsBuilder->codeAppendf("pls.windings[1] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), 
 | 
| -                                   windings.fsIn());
 | 
| -            fsBuilder->codeAppend("uv += uvIncY;");
 | 
| -            fsBuilder->codeAppendf("d += %s.y;", delta.fsIn());
 | 
| -            fsBuilder->codeAppendf("pls.windings[2] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), 
 | 
| -                                   windings.fsIn());
 | 
| -            fsBuilder->codeAppend("uv -= uvIncX;");
 | 
| -            fsBuilder->codeAppendf("d -= %s.x;", delta.fsIn());
 | 
| -            fsBuilder->codeAppendf("pls.windings[3] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), 
 | 
| -                                   windings.fsIn());
 | 
| -        }
 | 
| -
 | 
| -        static inline void GenKey(const GrGeometryProcessor& gp,
 | 
| -                                  const GrGLSLCaps&,
 | 
| -                                  GrProcessorKeyBuilder* b) {
 | 
| -            const PLSQuadEdgeEffect& qee = gp.cast<PLSQuadEdgeEffect>();
 | 
| -            uint32_t key = 0;
 | 
| -            key |= qee.usesLocalCoords() && qee.localMatrix().hasPerspective() ? 0x1 : 0x0;
 | 
| -            b->add32(key);
 | 
| -        }
 | 
| -
 | 
| -        virtual void setData(const GrGLSLProgramDataManager& pdman,
 | 
| -                             const GrPrimitiveProcessor& gp) override {
 | 
| -        }
 | 
| -
 | 
| -        void setTransformData(const GrPrimitiveProcessor& primProc,
 | 
| -                              const GrGLSLProgramDataManager& pdman,
 | 
| -                              int index,
 | 
| -                              const SkTArray<const GrCoordTransform*, true>& transforms) override {
 | 
| -            this->setTransformDataHelper<PLSQuadEdgeEffect>(primProc, pdman, index, transforms);
 | 
| -        }
 | 
| -
 | 
| -    private:
 | 
| -        typedef GrGLSLGeometryProcessor INHERITED;
 | 
| -    };
 | 
| -
 | 
| -    virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
 | 
| -                                   GrProcessorKeyBuilder* b) const override {
 | 
| -        GLSLProcessor::GenKey(*this, caps, b);
 | 
| -    }
 | 
| -
 | 
| -    virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
 | 
| -        return new GLSLProcessor(*this);
 | 
| -    }
 | 
| -
 | 
| -private:
 | 
| -    PLSQuadEdgeEffect(const SkMatrix& localMatrix, bool usesLocalCoords)
 | 
| -        : fLocalMatrix(localMatrix)
 | 
| -        , fUsesLocalCoords(usesLocalCoords) {
 | 
| -        this->initClassID<PLSQuadEdgeEffect>();
 | 
| -        fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType, 
 | 
| -                                                       kHigh_GrSLPrecision));
 | 
| -        fInUV = &this->addVertexAttrib(Attribute("inUV", kVec2f_GrVertexAttribType, 
 | 
| -                                                 kHigh_GrSLPrecision));
 | 
| -        fInEndpoint1 = &this->addVertexAttrib(Attribute("inEndpoint1", kVec2f_GrVertexAttribType, 
 | 
| -                                                        kHigh_GrSLPrecision));
 | 
| -        fInEndpoint2 = &this->addVertexAttrib(Attribute("inEndpoint2", kVec2f_GrVertexAttribType, 
 | 
| -                                                        kHigh_GrSLPrecision));
 | 
| -        fInWindings  = &this->addVertexAttrib(Attribute("inWindings", kInt_GrVertexAttribType, 
 | 
| -                                                        kLow_GrSLPrecision));
 | 
| -        this->setWillReadFragmentPosition();
 | 
| -    }
 | 
| -
 | 
| -    const Attribute* fInPosition;
 | 
| -    const Attribute* fInUV;
 | 
| -    const Attribute* fInEndpoint1;
 | 
| -    const Attribute* fInEndpoint2;
 | 
| -    const Attribute* fInWindings;
 | 
| -    SkMatrix         fLocalMatrix;
 | 
| -    bool             fUsesLocalCoords;
 | 
| -    
 | 
| -    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
 | 
| -
 | 
| -    typedef GrGeometryProcessor INHERITED;
 | 
| -};
 | 
| -
 | 
| -class PLSFinishEffect : public GrGeometryProcessor {
 | 
| -public:
 | 
| -
 | 
| -    static GrGeometryProcessor* Create(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix,
 | 
| -                                       bool usesLocalCoords) {
 | 
| -        return new PLSFinishEffect(color, useEvenOdd, localMatrix, usesLocalCoords);
 | 
| -    }
 | 
| -
 | 
| -    virtual ~PLSFinishEffect() {}
 | 
| -
 | 
| -    const char* name() const override { return "PLSFinish"; }
 | 
| -
 | 
| -    const Attribute* inPosition() const { return fInPosition; }
 | 
| -    GrColor color() const { return fColor; }
 | 
| -    bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
 | 
| -    const SkMatrix& localMatrix() const { return fLocalMatrix; }
 | 
| -    bool usesLocalCoords() const { return fUsesLocalCoords; }
 | 
| -    
 | 
| -    GrPixelLocalStorageState getPixelLocalStorageState() const override { 
 | 
| -        return GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState;
 | 
| -    }
 | 
| -
 | 
| -    const char* getDestColorOverride() const override {
 | 
| -        return GR_GL_PLS_DSTCOLOR_NAME; 
 | 
| -    }
 | 
| -
 | 
| -    class GLSLProcessor : public GrGLSLGeometryProcessor {
 | 
| -    public:
 | 
| -        GLSLProcessor(const GrGeometryProcessor&) {}
 | 
| -
 | 
| -        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
 | 
| -            const PLSFinishEffect& fe = args.fGP.cast<PLSFinishEffect>();
 | 
| -            GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder;
 | 
| -            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 | 
| -            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
 | 
| -
 | 
| -            fUseEvenOdd = uniformHandler->addUniform(GrGLUniformHandler::kFragment_Visibility,
 | 
| -                                                    kFloat_GrSLType, kLow_GrSLPrecision, 
 | 
| -                                                    "useEvenOdd");
 | 
| -            const char* useEvenOdd = uniformHandler->getUniformCStr(fUseEvenOdd);
 | 
| -
 | 
| -            varyingHandler->emitAttributes(fe);
 | 
| -            this->setupPosition(vsBuilder, gpArgs, fe.inPosition()->fName);
 | 
| -            this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, 
 | 
| -                                 fe.inPosition()->fName, fe.localMatrix(), args.fTransformsIn, 
 | 
| -                                 args.fTransformsOut);
 | 
| -
 | 
| -            GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder;
 | 
| -            SkAssertResult(fsBuilder->enableFeature(
 | 
| -                           GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature));
 | 
| -            fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL);
 | 
| -            fsBuilder->codeAppend("float coverage;");
 | 
| -            fsBuilder->codeAppendf("if (%s != 0.0) {", useEvenOdd);
 | 
| -            fsBuilder->codeAppend("coverage = float(abs(pls.windings[0]) % 2) * 0.25;");
 | 
| -            fsBuilder->codeAppend("coverage += float(abs(pls.windings[1]) % 2) * 0.25;");
 | 
| -            fsBuilder->codeAppend("coverage += float(abs(pls.windings[2]) % 2) * 0.25;");
 | 
| -            fsBuilder->codeAppend("coverage += float(abs(pls.windings[3]) % 2) * 0.25;");
 | 
| -            fsBuilder->codeAppend("} else {");
 | 
| -            fsBuilder->codeAppend("coverage = pls.windings[0] != 0 ? 0.25 : 0.0;");
 | 
| -            fsBuilder->codeAppend("coverage += pls.windings[1] != 0 ? 0.25 : 0.0;");
 | 
| -            fsBuilder->codeAppend("coverage += pls.windings[2] != 0 ? 0.25 : 0.0;");
 | 
| -            fsBuilder->codeAppend("coverage += pls.windings[3] != 0 ? 0.25 : 0.0;");
 | 
| -            fsBuilder->codeAppend("}");
 | 
| -            if (!fe.colorIgnored()) {
 | 
| -                this->setupUniformColor(fsBuilder, uniformHandler, args.fOutputColor, 
 | 
| -                                        &fColorUniform);
 | 
| -            }
 | 
| -            fsBuilder->codeAppendf("%s = vec4(coverage);", args.fOutputCoverage);
 | 
| -        }
 | 
| -
 | 
| -        static inline void GenKey(const GrGeometryProcessor& gp,
 | 
| -                                  const GrGLSLCaps&,
 | 
| -                                  GrProcessorKeyBuilder* b) {
 | 
| -            const PLSFinishEffect& fe = gp.cast<PLSFinishEffect>();
 | 
| -            uint32_t key = 0;
 | 
| -            key |= fe.usesLocalCoords() && fe.localMatrix().hasPerspective() ? 0x1 : 0x0;
 | 
| -            b->add32(key);
 | 
| -        }
 | 
| -
 | 
| -        virtual void setData(const GrGLSLProgramDataManager& pdman,
 | 
| -                             const GrPrimitiveProcessor& gp) override {
 | 
| -            const PLSFinishEffect& fe = gp.cast<PLSFinishEffect>();
 | 
| -            pdman.set1f(fUseEvenOdd, fe.fUseEvenOdd);
 | 
| -            if (fe.color() != fColor && !fe.colorIgnored()) {
 | 
| -                GrGLfloat c[4];
 | 
| -                GrColorToRGBAFloat(fe.color(), c);
 | 
| -                pdman.set4fv(fColorUniform, 1, c);
 | 
| -                fColor = fe.color();
 | 
| -            }
 | 
| -        }
 | 
| -
 | 
| -        void setTransformData(const GrPrimitiveProcessor& primProc,
 | 
| -                              const GrGLSLProgramDataManager& pdman,
 | 
| -                              int index,
 | 
| -                              const SkTArray<const GrCoordTransform*, true>& transforms) override {
 | 
| -            this->setTransformDataHelper<PLSFinishEffect>(primProc, pdman, index, transforms);
 | 
| -        }
 | 
| -
 | 
| -    private:
 | 
| -        GrColor fColor;
 | 
| -        UniformHandle fColorUniform;
 | 
| -        UniformHandle fUseEvenOdd;
 | 
| -
 | 
| -        typedef GrGLSLGeometryProcessor INHERITED;
 | 
| -    };
 | 
| -
 | 
| -    virtual void getGLSLProcessorKey(const GrGLSLCaps& caps,
 | 
| -                                   GrProcessorKeyBuilder* b) const override {
 | 
| -        GLSLProcessor::GenKey(*this, caps, b);
 | 
| -    }
 | 
| -
 | 
| -    virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const override {
 | 
| -        return new GLSLProcessor(*this);
 | 
| -    }
 | 
| -
 | 
| -private:
 | 
| -    PLSFinishEffect(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix, 
 | 
| -                    bool usesLocalCoords)
 | 
| -        : fColor(color)
 | 
| -        , fUseEvenOdd(useEvenOdd)
 | 
| -        , fLocalMatrix(localMatrix)
 | 
| -        , fUsesLocalCoords(usesLocalCoords) {
 | 
| -        this->initClassID<PLSFinishEffect>();
 | 
| -        fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType, 
 | 
| -                                                       kHigh_GrSLPrecision));
 | 
| -    }
 | 
| -
 | 
| -    const Attribute* fInPosition;
 | 
| -    GrColor          fColor;
 | 
| -    bool             fUseEvenOdd;
 | 
| -    SkMatrix         fLocalMatrix;
 | 
| -    bool             fUsesLocalCoords;
 | 
| -
 | 
| -    typedef GrGeometryProcessor INHERITED;
 | 
| -};
 | 
| -
 | 
| -///////////////////////////////////////////////////////////////////////////////
 | 
| -
 | 
| -bool GrPLSPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
 | 
| -    // We have support for even-odd rendering, but are having some troublesome
 | 
| -    // seams. Disable in the presence of even-odd for now.
 | 
| -    return args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias &&
 | 
| -            args.fStroke->isFillStyle() && !args.fPath->isInverseFillType() &&
 | 
| -            args.fPath->getFillType() == SkPath::FillType::kWinding_FillType;
 | 
| -}
 | 
| -
 | 
| -class PLSPathBatch : public GrVertexBatch {
 | 
| -public:
 | 
| -    DEFINE_BATCH_CLASS_ID
 | 
| -    struct Geometry {
 | 
| -        GrColor fColor;
 | 
| -        SkMatrix fViewMatrix;
 | 
| -        SkPath fPath;
 | 
| -    };
 | 
| -
 | 
| -    static GrDrawBatch* Create(const Geometry& geometry) {
 | 
| -        return new PLSPathBatch(geometry);
 | 
| -    }
 | 
| -
 | 
| -    const char* name() const override { return "PLSBatch"; }
 | 
| -
 | 
| -    void computePipelineOptimizations(GrInitInvariantOutput* color, 
 | 
| -                                      GrInitInvariantOutput* coverage,
 | 
| -                                      GrBatchToXPOverrides* overrides) const override {
 | 
| -        // When this is called on a batch, there is only one geometry bundle
 | 
| -        color->setKnownFourComponents(fGeoData[0].fColor);
 | 
| -        coverage->setUnknownSingleComponent();
 | 
| -        overrides->fUsePLSDstRead = true;
 | 
| -    }
 | 
| -
 | 
| -    void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
 | 
| -        // Handle any color overrides
 | 
| -        if (!overrides.readsColor()) {
 | 
| -            fGeoData[0].fColor = GrColor_ILLEGAL;
 | 
| -        }
 | 
| -        overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
 | 
| -
 | 
| -        // setup batch properties
 | 
| -        fBatch.fColorIgnored = !overrides.readsColor();
 | 
| -        fBatch.fColor = fGeoData[0].fColor;
 | 
| -        fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
 | 
| -        fBatch.fCoverageIgnored = !overrides.readsCoverage();
 | 
| -        fBatch.fCanTweakAlphaForCoverage = overrides.canTweakAlphaForCoverage();
 | 
| -    }
 | 
| -
 | 
| -    void onPrepareDraws(Target* target) const override {
 | 
| -        int instanceCount = fGeoData.count();
 | 
| -
 | 
| -        SkMatrix invert;
 | 
| -        if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
 | 
| -            SkDebugf("Could not invert viewmatrix\n");
 | 
| -            return;
 | 
| -        }
 | 
| -
 | 
| -        // Setup GrGeometryProcessors
 | 
| -        SkAutoTUnref<GrPLSGeometryProcessor> triangleProcessor(
 | 
| -                PLSAATriangleEffect::Create(invert, this->usesLocalCoords()));
 | 
| -        SkAutoTUnref<GrPLSGeometryProcessor> quadProcessor(
 | 
| -                PLSQuadEdgeEffect::Create(invert, this->usesLocalCoords()));
 | 
| -
 | 
| -        GrResourceProvider* rp = target->resourceProvider();
 | 
| -        for (int i = 0; i < instanceCount; ++i) {
 | 
| -            const Geometry& args = fGeoData[i];
 | 
| -            SkRect bounds = args.fPath.getBounds();
 | 
| -            args.fViewMatrix.mapRect(&bounds);
 | 
| -            bounds.fLeft = SkScalarFloorToScalar(bounds.fLeft);
 | 
| -            bounds.fTop = SkScalarFloorToScalar(bounds.fTop);
 | 
| -            bounds.fRight = SkScalarCeilToScalar(bounds.fRight);
 | 
| -            bounds.fBottom = SkScalarCeilToScalar(bounds.fBottom);
 | 
| -            triangleProcessor->setBounds(bounds);
 | 
| -            quadProcessor->setBounds(bounds);
 | 
| -
 | 
| -            // 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()) {
 | 
| -                SkPath* tmpPathPtr = tmpPath.init(*pathPtr);
 | 
| -                tmpPathPtr->setIsVolatile(true);
 | 
| -                tmpPathPtr->transform(*viewMatrix);
 | 
| -                viewMatrix = &SkMatrix::I();
 | 
| -                pathPtr = tmpPathPtr;
 | 
| -            }
 | 
| -
 | 
| -            GrVertices grVertices;
 | 
| -
 | 
| -            PLSVertices triVertices;
 | 
| -            PLSVertices quadVertices;
 | 
| -            if (!get_geometry(*pathPtr, *viewMatrix, triVertices, quadVertices, rp, bounds)) {
 | 
| -                continue;
 | 
| -            }
 | 
| -
 | 
| -            if (triVertices.count()) {
 | 
| -                const GrVertexBuffer* triVertexBuffer;
 | 
| -                int firstTriVertex;
 | 
| -                size_t triStride = triangleProcessor->getVertexStride();
 | 
| -                PLSVertex* triVerts = reinterpret_cast<PLSVertex*>(target->makeVertexSpace(
 | 
| -                        triStride, triVertices.count(), &triVertexBuffer, &firstTriVertex));
 | 
| -                if (!triVerts) {
 | 
| -                    SkDebugf("Could not allocate vertices\n");
 | 
| -                    return;
 | 
| -                }
 | 
| -                for (int i = 0; i < triVertices.count(); ++i) {
 | 
| -                    triVerts[i] = triVertices[i];
 | 
| -                }
 | 
| -                grVertices.init(kTriangles_GrPrimitiveType, triVertexBuffer, firstTriVertex, 
 | 
| -                                triVertices.count());
 | 
| -                target->initDraw(triangleProcessor, this->pipeline());
 | 
| -                target->draw(grVertices);
 | 
| -            }
 | 
| -
 | 
| -            if (quadVertices.count()) {
 | 
| -                const GrVertexBuffer* quadVertexBuffer;
 | 
| -                int firstQuadVertex;
 | 
| -                size_t quadStride = quadProcessor->getVertexStride();
 | 
| -                PLSVertex* quadVerts = reinterpret_cast<PLSVertex*>(target->makeVertexSpace(
 | 
| -                        quadStride, quadVertices.count(), &quadVertexBuffer, &firstQuadVertex));
 | 
| -                if (!quadVerts) {
 | 
| -                    SkDebugf("Could not allocate vertices\n");
 | 
| -                    return;
 | 
| -                }
 | 
| -                for (int i = 0; i < quadVertices.count(); ++i) {
 | 
| -                    quadVerts[i] = quadVertices[i];
 | 
| -                }
 | 
| -                grVertices.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex, 
 | 
| -                                quadVertices.count());
 | 
| -                target->initDraw(quadProcessor, this->pipeline());
 | 
| -                target->draw(grVertices);
 | 
| -            }
 | 
| -
 | 
| -            SkAutoTUnref<GrGeometryProcessor> finishProcessor(
 | 
| -                    PLSFinishEffect::Create(this->color(), 
 | 
| -                                            pathPtr->getFillType() == 
 | 
| -                                                                SkPath::FillType::kEvenOdd_FillType,
 | 
| -                                            invert, 
 | 
| -                                            this->usesLocalCoords()));
 | 
| -            const GrVertexBuffer* rectVertexBuffer;
 | 
| -            size_t finishStride = finishProcessor->getVertexStride();
 | 
| -            int firstRectVertex;
 | 
| -            static const int kRectVertexCount = 6;
 | 
| -            SkPoint* rectVerts = reinterpret_cast<SkPoint*>(target->makeVertexSpace(
 | 
| -                    finishStride, kRectVertexCount, &rectVertexBuffer, &firstRectVertex));
 | 
| -            if (!rectVerts) {
 | 
| -                SkDebugf("Could not allocate vertices\n");
 | 
| -                return;
 | 
| -            }
 | 
| -            rectVerts[0] = { bounds.fLeft, bounds.fTop };
 | 
| -            rectVerts[1] = { bounds.fLeft, bounds.fBottom };
 | 
| -            rectVerts[2] = { bounds.fRight, bounds.fBottom };
 | 
| -            rectVerts[3] = { bounds.fLeft, bounds.fTop };
 | 
| -            rectVerts[4] = { bounds.fRight, bounds.fTop };
 | 
| -            rectVerts[5] = { bounds.fRight, bounds.fBottom };
 | 
| -
 | 
| -            grVertices.init(kTriangles_GrPrimitiveType, rectVertexBuffer, firstRectVertex, 
 | 
| -                            kRectVertexCount);
 | 
| -            target->initDraw(finishProcessor, this->pipeline());
 | 
| -            target->draw(grVertices);
 | 
| -        }
 | 
| -    }
 | 
| -
 | 
| -    SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 | 
| -
 | 
| -private:
 | 
| -    PLSPathBatch(const Geometry& geometry) : INHERITED(ClassID()) {
 | 
| -        fGeoData.push_back(geometry);
 | 
| -
 | 
| -        // compute bounds
 | 
| -        fBounds = geometry.fPath.getBounds();
 | 
| -        geometry.fViewMatrix.mapRect(&fBounds);
 | 
| -    }
 | 
| -
 | 
| -    bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
 | 
| -        return false;
 | 
| -    }
 | 
| -
 | 
| -    GrColor color() const { return fBatch.fColor; }
 | 
| -    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
 | 
| -    bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
 | 
| -    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
 | 
| -    bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
 | 
| -
 | 
| -    struct BatchTracker {
 | 
| -        GrColor fColor;
 | 
| -        bool fUsesLocalCoords;
 | 
| -        bool fColorIgnored;
 | 
| -        bool fCoverageIgnored;
 | 
| -        bool fCanTweakAlphaForCoverage;
 | 
| -    };
 | 
| -
 | 
| -    BatchTracker fBatch;
 | 
| -    SkSTArray<1, Geometry, true> fGeoData;
 | 
| -
 | 
| -    typedef GrVertexBatch INHERITED;
 | 
| -};
 | 
| -
 | 
| -SkDEBUGCODE(bool inPLSDraw = false;)
 | 
| -bool GrPLSPathRenderer::onDrawPath(const DrawPathArgs& args) {
 | 
| -    if (args.fPath->isEmpty()) {
 | 
| -        return true;
 | 
| -    }
 | 
| -    SkASSERT(!inPLSDraw);
 | 
| -    SkDEBUGCODE(inPLSDraw = true;)
 | 
| -    PLSPathBatch::Geometry geometry;
 | 
| -    geometry.fColor = args.fColor;
 | 
| -    geometry.fViewMatrix = *args.fViewMatrix;
 | 
| -    geometry.fPath = *args.fPath;
 | 
| -
 | 
| -    SkAutoTUnref<GrDrawBatch> batch(PLSPathBatch::Create(geometry));
 | 
| -    args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
 | 
| -
 | 
| -    SkDEBUGCODE(inPLSDraw = false;)
 | 
| -    return true;
 | 
| -
 | 
| -}
 | 
| -
 | 
| -///////////////////////////////////////////////////////////////////////////////////////////////////
 | 
| -
 | 
| -#ifdef GR_TEST_UTILS
 | 
| -
 | 
| -DRAW_BATCH_TEST_DEFINE(PLSPathBatch) {
 | 
| -    PLSPathBatch::Geometry geometry;
 | 
| -    geometry.fColor = GrRandomColor(random);
 | 
| -    geometry.fViewMatrix = GrTest::TestMatrixInvertible(random);
 | 
| -    geometry.fPath = GrTest::TestPathConvex(random);
 | 
| -
 | 
| -    return PLSPathBatch::Create(geometry);
 | 
| -}
 | 
| -
 | 
| -#endif
 | 
| 
 |