181312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org/*
281312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org * Copyright 2013 Google Inc.
381312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org *
481312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org * Use of this source code is governed by a BSD-style license that can be
581312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org * found in the LICENSE file.
681312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org */
781312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
8289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon#include "GrOvalOpFactory.h"
981312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
105ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian Salomon#include "GrDrawOpTest.h"
11eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "GrGeometryProcessor.h"
12742e31de1599f3902810aecdf2e2e3eed3b40a09Brian Salomon#include "GrOpFlushState.h"
1376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt#include "GrProcessor.h"
14ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon#include "GrResourceProvider.h"
1594efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon#include "GrShaderCaps.h"
164f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon#include "GrStyle.h"
17f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org#include "SkRRect.h"
1881312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org#include "SkStrokeRec.h"
192d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel#include "glsl/GrGLSLFragmentShaderBuilder.h"
20e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel#include "glsl/GrGLSLGeometryProcessor.h"
21018fb62d12d1febf121fe265da5b6117b86a6541egdaniel#include "glsl/GrGLSLProgramDataManager.h"
227ea439b2203855db97330b25945b87dd4b170b8begdaniel#include "glsl/GrGLSLUniformHandler.h"
2364c4728c70001ed074fecf5c4e083781987b12e9egdaniel#include "glsl/GrGLSLUtil.h"
24dad2923b8ec9270d810c1e8e76da8e6768d8f9ddBrian Salomon#include "glsl/GrGLSLVarying.h"
25dad2923b8ec9270d810c1e8e76da8e6768d8f9ddBrian Salomon#include "glsl/GrGLSLVertexShaderBuilder.h"
26895274391db8df7357334aec260edca2e1735626Brian Salomon#include "ops/GrMeshDrawOp.h"
27234d4fba75aac009e34c088037fcd9e244798c40commit-bot@chromium.org
2825a880960a9a689a745a01071ecba3fe494b5940Brian Salomon// TODO(joshualitt) - Break this file up during GrOp post implementation cleanup
2976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
3081312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.orgnamespace {
31bb2ff94e223014403f775c3532a25cc25b00c949brianosman
3281312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.orgstruct EllipseVertex {
33289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkPoint fPos;
34289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    GrColor fColor;
35289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkPoint fOffset;
36289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkPoint fOuterRadii;
37289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkPoint fInnerRadii;
38f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org};
39f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
405242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.orgstruct DIEllipseVertex {
41289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkPoint fPos;
42289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    GrColor fColor;
43289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkPoint fOuterOffset;
44289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkPoint fInnerOffset;
455242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org};
465242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
47289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomonstatic inline bool circle_stays_circle(const SkMatrix& m) { return m.isSimilarity(); }
4881312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org}
4981312830ef73420efdc4821feb7c2d6fd9152af8commit-bot@chromium.org
5090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
5190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
5290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/**
53ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon * The output of this effect is a modulation of the input color and coverage for a circle. It
54ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon * operates in a space normalized by the circle radius (outer radius in the case of a stroke)
55cdaa97bf664e0d584187efc125bfff670a064a9absalomon * with origin at the circle center. Three vertex attributes are used:
56ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *    vec2f : position in device space of the bounding geometry vertices
57cdaa97bf664e0d584187efc125bfff670a064a9absalomon *    vec4ub: color
58ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *    vec4f : (p.xy, outerRad, innerRad)
59ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *             p is the position in the normalized space.
60ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *             outerRad is the outerRadius in device space.
61ce1c8869cf5e37753f9c8193314d93bff897d014bsalomon *             innerRad is the innerRadius in normalized space (ignored if not stroking).
62fc6c37b981daeece7474ce61070c707c37eefa62Mike Klein * If fUsesDistanceVectorField is set in fragment processors in the same program, then
636c177a1a49fcfe8bfd5f3ffda3ee50bbe2679463jvanverth * an additional vertex attribute is available via args.fFragBuilder->distanceVectorName():
646c177a1a49fcfe8bfd5f3ffda3ee50bbe2679463jvanverth *    vec4f : (v.xy, outerDistance, innerDistance)
656c177a1a49fcfe8bfd5f3ffda3ee50bbe2679463jvanverth *             v is a normalized vector pointing to the outer edge
666c177a1a49fcfe8bfd5f3ffda3ee50bbe2679463jvanverth *             outerDistance is the distance to the outer edge, < 0 if we are outside of the shape
676c177a1a49fcfe8bfd5f3ffda3ee50bbe2679463jvanverth *             if stroking, innerDistance is the distance to the inner edge, < 0 if outside
684f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon * Additional clip planes are supported for rendering circular arcs. The additional planes are
694f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon * either intersected or unioned together. Up to three planes are supported (an initial plane,
704f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon * a plane intersected with the initial plane, and a plane unioned with the first two). Only two
7153e4c3c0da40b58638d05e0f753ab6d450b961f5Brian Salomon * are useful for any given arc, but having all three in one instance allows combining different
724f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon * types of arcs.
7390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org */
7490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
75cdaa97bf664e0d584187efc125bfff670a064a9absalomonclass CircleGeometryProcessor : public GrGeometryProcessor {
7690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgpublic:
774f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    CircleGeometryProcessor(bool stroke, bool clipPlane, bool isectPlane, bool unionPlane,
784f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            const SkMatrix& localMatrix)
794f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            : fLocalMatrix(localMatrix) {
80cdaa97bf664e0d584187efc125bfff670a064a9absalomon        this->initClassID<CircleGeometryProcessor>();
816cb807bf99ac0f8f166e1790f91bcb3afbfb5458bsalomon        fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
826cb807bf99ac0f8f166e1790f91bcb3afbfb5458bsalomon                                             kHigh_GrSLPrecision);
836cb807bf99ac0f8f166e1790f91bcb3afbfb5458bsalomon        fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
846750e91544b98b839c3148baef996ab2860233a4Jim Van Verth        fInCircleEdge = &this->addVertexAttrib("inCircleEdge", kVec4f_GrVertexAttribType,
856750e91544b98b839c3148baef996ab2860233a4Jim Van Verth                                               kHigh_GrSLPrecision);
864f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        if (clipPlane) {
874f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            fInClipPlane = &this->addVertexAttrib("inClipPlane", kVec3f_GrVertexAttribType);
884f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        } else {
894f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            fInClipPlane = nullptr;
904f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        }
914f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        if (isectPlane) {
924f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            fInIsectPlane = &this->addVertexAttrib("inIsectPlane", kVec3f_GrVertexAttribType);
934f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        } else {
944f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            fInIsectPlane = nullptr;
954f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        }
964f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        if (unionPlane) {
974f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            fInUnionPlane = &this->addVertexAttrib("inUnionPlane", kVec3f_GrVertexAttribType);
984f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        } else {
994f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            fInUnionPlane = nullptr;
1004f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        }
101cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fStroke = stroke;
10290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
10390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
104fc6c37b981daeece7474ce61070c707c37eefa62Mike Klein    bool implementsDistanceVector() const override { return !fInClipPlane; }
10568f2f7dc4229c3761dd5074a94c35878abcb9a36dvonbeck
106d3b65972aad96453ff4510caa3e25a2b847c6d1eBrian Salomon    ~CircleGeometryProcessor() override {}
10790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
10836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "CircleEdge"; }
10990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
11094efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon    void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
11131df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon        GLSLProcessor::GenKey(*this, caps, b);
11231df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon    }
11331df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon
11494efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
11531df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon        return new GLSLProcessor();
11631df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon    }
11731df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon
11831df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomonprivate:
11957d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    class GLSLProcessor : public GrGLSLGeometryProcessor {
12090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    public:
121bb2ff94e223014403f775c3532a25cc25b00c949brianosman        GLSLProcessor() {}
12290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
123289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
124cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const CircleGeometryProcessor& cgp = args.fGP.cast<CircleGeometryProcessor>();
1254ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
1260eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
1277ea439b2203855db97330b25945b87dd4b170b8begdaniel            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1284f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
1292dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
130abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit attributes
131cdaa97bf664e0d584187efc125bfff670a064a9absalomon            varyingHandler->emitAttributes(cgp);
1326750e91544b98b839c3148baef996ab2860233a4Jim Van Verth            fragBuilder->codeAppend("highp vec4 circleEdge;");
1336750e91544b98b839c3148baef996ab2860233a4Jim Van Verth            varyingHandler->addPassThroughAttribute(cgp.fInCircleEdge, "circleEdge",
1346750e91544b98b839c3148baef996ab2860233a4Jim Van Verth                                                    kHigh_GrSLPrecision);
1354f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            if (cgp.fInClipPlane) {
1364f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                fragBuilder->codeAppend("vec3 clipPlane;");
1374f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                varyingHandler->addPassThroughAttribute(cgp.fInClipPlane, "clipPlane");
1384f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            }
1394f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            if (cgp.fInIsectPlane) {
1404f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                SkASSERT(cgp.fInClipPlane);
1414f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                fragBuilder->codeAppend("vec3 isectPlane;");
1424f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                varyingHandler->addPassThroughAttribute(cgp.fInIsectPlane, "isectPlane");
1434f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            }
1444f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            if (cgp.fInUnionPlane) {
1454f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                SkASSERT(cgp.fInClipPlane);
1464f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                fragBuilder->codeAppend("vec3 unionPlane;");
1474f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                varyingHandler->addPassThroughAttribute(cgp.fInUnionPlane, "unionPlane");
1484f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            }
149abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
150b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt            // setup pass through color
15131df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon            varyingHandler->addPassThroughAttribute(cgp.fInColor, args.fOutputColor);
1529b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
153abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // Setup position
15431df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon            this->setupPosition(vertBuilder, gpArgs, cgp.fInPosition->fName);
155abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
156abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit transforms
1577ea439b2203855db97330b25945b87dd4b170b8begdaniel            this->emitTransforms(vertBuilder,
1580eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel                                 varyingHandler,
1597ea439b2203855db97330b25945b87dd4b170b8begdaniel                                 uniformHandler,
1604ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 gpArgs->fPositionVar,
16131df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon                                 cgp.fInPosition->fName,
16231df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon                                 cgp.fLocalMatrix,
163a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon                                 args.fFPCoordTransformHandler);
1644ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
1656750e91544b98b839c3148baef996ab2860233a4Jim Van Verth            fragBuilder->codeAppend("highp float d = length(circleEdge.xy);");
1664f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            fragBuilder->codeAppend("float distanceToOuterEdge = circleEdge.z * (1.0 - d);");
1674f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            fragBuilder->codeAppend("float edgeAlpha = clamp(distanceToOuterEdge, 0.0, 1.0);");
168cdaa97bf664e0d584187efc125bfff670a064a9absalomon            if (cgp.fStroke) {
169289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                fragBuilder->codeAppend(
170289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        "float distanceToInnerEdge = circleEdge.z * (d - circleEdge.w);");
1716c177a1a49fcfe8bfd5f3ffda3ee50bbe2679463jvanverth                fragBuilder->codeAppend("float innerAlpha = clamp(distanceToInnerEdge, 0.0, 1.0);");
1724ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("edgeAlpha *= innerAlpha;");
17390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            }
1740a6cb602e5866f7a8cd1630d0c907749f5182837commit-bot@chromium.org
17568f2f7dc4229c3761dd5074a94c35878abcb9a36dvonbeck            if (args.fDistanceVectorName) {
176adf4edc4d6ddf781b2910f457ba360d99072604absalomon                const char* innerEdgeDistance = cgp.fStroke ? "distanceToInnerEdge" : "0.0";
177289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                fragBuilder->codeAppendf(
178289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        "if (d == 0.0) {"  // if on the center of the circle
179289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        "    %s = vec4(1.0, 0.0, distanceToOuterEdge, "
180289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        "              %s);",  // no normalize
181289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        args.fDistanceVectorName,
182289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        innerEdgeDistance);
183289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                fragBuilder->codeAppendf(
184289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        "} else {"
185289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        "    %s = vec4(normalize(circleEdge.xy),"
186289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        "              distanceToOuterEdge, %s);"
187289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        "}",
188289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        args.fDistanceVectorName, innerEdgeDistance);
18968f2f7dc4229c3761dd5074a94c35878abcb9a36dvonbeck            }
1904f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            if (cgp.fInClipPlane) {
191289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                fragBuilder->codeAppend(
192289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        "float clip = clamp(circleEdge.z * dot(circleEdge.xy, clipPlane.xy) + "
193289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        "clipPlane.z, 0.0, 1.0);");
1944f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                if (cgp.fInIsectPlane) {
195289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    fragBuilder->codeAppend(
196289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                            "clip *= clamp(circleEdge.z * dot(circleEdge.xy, isectPlane.xy) + "
197289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                            "isectPlane.z, 0.0, 1.0);");
1984f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                }
1994f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                if (cgp.fInUnionPlane) {
200289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    fragBuilder->codeAppend(
201289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                            "clip += (1.0 - clip)*clamp(circleEdge.z * dot(circleEdge.xy, "
202289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                            "unionPlane.xy) + unionPlane.z, 0.0, 1.0);");
2034f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                }
2044f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                fragBuilder->codeAppend("edgeAlpha *= clip;");
2054f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            }
2064ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
20790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
20890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
20946d36f0e7b709a077c647841eee23bd3efdc4117robertphillips        static void GenKey(const GrGeometryProcessor& gp,
21094efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon                           const GrShaderCaps&,
211b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                           GrProcessorKeyBuilder* b) {
212cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const CircleGeometryProcessor& cgp = gp.cast<CircleGeometryProcessor>();
2134f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            uint16_t key;
214289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            key = cgp.fStroke ? 0x01 : 0x0;
2154f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            key |= cgp.fLocalMatrix.hasPerspective() ? 0x02 : 0x0;
216289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            key |= cgp.fInClipPlane ? 0x04 : 0x0;
217289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            key |= cgp.fInIsectPlane ? 0x08 : 0x0;
218289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            key |= cgp.fInUnionPlane ? 0x10 : 0x0;
219b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt            b->add32(key);
22090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
22190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
222a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon        void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc,
223a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon                     FPCoordTransformIter&& transformIter) override {
224e4f2461113806e3080aeb8bc5637e82d1b3d8295bsalomon            this->setTransformDataHelper(primProc.cast<CircleGeometryProcessor>().fLocalMatrix,
225a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon                                         pdman, &transformIter);
226e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        }
227e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt
22890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    private:
229e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel        typedef GrGLSLGeometryProcessor INHERITED;
23090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    };
23190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
232289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkMatrix fLocalMatrix;
23371c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInPosition;
234bb2ff94e223014403f775c3532a25cc25b00c949brianosman    const Attribute* fInColor;
23571c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInCircleEdge;
2364f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    const Attribute* fInClipPlane;
2374f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    const Attribute* fInIsectPlane;
2384f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    const Attribute* fInUnionPlane;
239289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    bool fStroke;
24090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
241b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
24290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
243249af15fb82833d2274850c589812b6e69df0033joshualitt    typedef GrGeometryProcessor INHERITED;
24490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org};
24590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
246cdaa97bf664e0d584187efc125bfff670a064a9absalomonGR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleGeometryProcessor);
24790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
2486f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#if GR_TEST_UTILS
24906ca8ec87cf6fab57cadd043a5ac18c4154a4129bungemansk_sp<GrGeometryProcessor> CircleGeometryProcessor::TestCreate(GrProcessorTestData* d) {
250289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    return sk_sp<GrGeometryProcessor>(new CircleGeometryProcessor(
251289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            d->fRandom->nextBool(), d->fRandom->nextBool(), d->fRandom->nextBool(),
252289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            d->fRandom->nextBool(), GrTest::TestMatrix(d->fRandom)));
25390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org}
2546f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#endif
25590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
25690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
25790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
25890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/**
25990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * The output of this effect is a modulation of the input color and coverage for an axis-aligned
2608be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com * ellipse, specified as a 2D offset from center, and the reciprocals of the outer and inner radii,
2618be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com * in both x and y directions.
2628be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com *
2636bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0.
26490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org */
26590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
266cdaa97bf664e0d584187efc125bfff670a064a9absalomonclass EllipseGeometryProcessor : public GrGeometryProcessor {
26790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgpublic:
268289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    EllipseGeometryProcessor(bool stroke, const SkMatrix& localMatrix) : fLocalMatrix(localMatrix) {
269cdaa97bf664e0d584187efc125bfff670a064a9absalomon        this->initClassID<EllipseGeometryProcessor>();
2706cb807bf99ac0f8f166e1790f91bcb3afbfb5458bsalomon        fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType);
2716cb807bf99ac0f8f166e1790f91bcb3afbfb5458bsalomon        fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
2726cb807bf99ac0f8f166e1790f91bcb3afbfb5458bsalomon        fInEllipseOffset = &this->addVertexAttrib("inEllipseOffset", kVec2f_GrVertexAttribType);
2736cb807bf99ac0f8f166e1790f91bcb3afbfb5458bsalomon        fInEllipseRadii = &this->addVertexAttrib("inEllipseRadii", kVec4f_GrVertexAttribType);
274cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fStroke = stroke;
27590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    }
27690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
277d3b65972aad96453ff4510caa3e25a2b847c6d1eBrian Salomon    ~EllipseGeometryProcessor() override {}
27890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
27936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "EllipseEdge"; }
2802dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
28194efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon    void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
28231df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon        GLSLProcessor::GenKey(*this, caps, b);
28331df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon    }
28431df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon
28594efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
28631df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon        return new GLSLProcessor();
28731df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon    }
28831df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon
28931df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomonprivate:
29057d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    class GLSLProcessor : public GrGLSLGeometryProcessor {
29190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    public:
292bb2ff94e223014403f775c3532a25cc25b00c949brianosman        GLSLProcessor() {}
29390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
294289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
295cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const EllipseGeometryProcessor& egp = args.fGP.cast<EllipseGeometryProcessor>();
2964ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
2970eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
2987ea439b2203855db97330b25945b87dd4b170b8begdaniel            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
29990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
300abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit attributes
301cdaa97bf664e0d584187efc125bfff670a064a9absalomon            varyingHandler->emitAttributes(egp);
302abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
3038dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel            GrGLSLVertToFrag ellipseOffsets(kVec2f_GrSLType);
3040eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            varyingHandler->addVarying("EllipseOffsets", &ellipseOffsets);
3054ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            vertBuilder->codeAppendf("%s = %s;", ellipseOffsets.vsOut(),
30631df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon                                     egp.fInEllipseOffset->fName);
30790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
3088dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel            GrGLSLVertToFrag ellipseRadii(kVec4f_GrSLType);
3090eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            varyingHandler->addVarying("EllipseRadii", &ellipseRadii);
310289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            vertBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(), egp.fInEllipseRadii->fName);
3112dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
3128528541dd7f09f5bd76f3f1ce5f45d08ac7347c7cdalton            GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
313b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt            // setup pass through color
31431df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon            varyingHandler->addPassThroughAttribute(egp.fInColor, args.fOutputColor);
3159b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
316abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // Setup position
31731df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon            this->setupPosition(vertBuilder, gpArgs, egp.fInPosition->fName);
318abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
319abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit transforms
3207ea439b2203855db97330b25945b87dd4b170b8begdaniel            this->emitTransforms(vertBuilder,
3210eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel                                 varyingHandler,
3227ea439b2203855db97330b25945b87dd4b170b8begdaniel                                 uniformHandler,
3234ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 gpArgs->fPositionVar,
32431df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon                                 egp.fInPosition->fName,
32531df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon                                 egp.fLocalMatrix,
326a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon                                 args.fFPCoordTransformHandler);
3274973d9da4aeb7c4d8b8e67e167586c7cc9534eeejoshualitt
3288be02fc2a72ae69a9142de68a483edf378aff1c8skia.committer@gmail.com            // for outer curve
3294ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 scaledOffset = %s*%s.xy;", ellipseOffsets.fsIn(),
3304ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                     ellipseRadii.fsIn());
3314ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
3324ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 grad = 2.0*scaledOffset*%s.xy;", ellipseRadii.fsIn());
3334ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float grad_dot = dot(grad, grad);");
33474077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt
3351b035d82d2b8b50ae334463edd06e4c5e0639311commit-bot@chromium.org            // avoid calling inversesqrt on zero.
3364ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
3374ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
338c6052ac41a704cc64f16c49780a8fd05c7f550d4brianosman            fragBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
339f58d8540a42e5138e7cdb1dd1e0b4de0fa3c4a10jvanverth@google.com
3406bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org            // for inner curve
341cdaa97bf664e0d584187efc125bfff670a064a9absalomon            if (egp.fStroke) {
342289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                fragBuilder->codeAppendf("scaledOffset = %s*%s.zw;", ellipseOffsets.fsIn(),
3434ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                         ellipseRadii.fsIn());
344289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
345289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                fragBuilder->codeAppendf("grad = 2.0*scaledOffset*%s.zw;", ellipseRadii.fsIn());
3464ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
3474ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
34890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org            }
34990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
3504ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
35190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
35290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
35346d36f0e7b709a077c647841eee23bd3efdc4117robertphillips        static void GenKey(const GrGeometryProcessor& gp,
35494efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon                           const GrShaderCaps&,
355b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                           GrProcessorKeyBuilder* b) {
356cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const EllipseGeometryProcessor& egp = gp.cast<EllipseGeometryProcessor>();
357cdaa97bf664e0d584187efc125bfff670a064a9absalomon            uint16_t key = egp.fStroke ? 0x1 : 0x0;
35831df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon            key |= egp.fLocalMatrix.hasPerspective() ? 0x2 : 0x0;
359b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt            b->add32(key);
36090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org        }
36190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
362a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon        void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc,
363a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon                     FPCoordTransformIter&& transformIter) override {
364a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon            const EllipseGeometryProcessor& egp = primProc.cast<EllipseGeometryProcessor>();
365a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon            this->setTransformDataHelper(egp.fLocalMatrix, pdman, &transformIter);
366e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt        }
367e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt
36890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    private:
369e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel        typedef GrGLSLGeometryProcessor INHERITED;
37090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    };
37190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
37271c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInPosition;
373bb2ff94e223014403f775c3532a25cc25b00c949brianosman    const Attribute* fInColor;
37471c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInEllipseOffset;
37571c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInEllipseRadii;
376e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    SkMatrix fLocalMatrix;
37790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org    bool fStroke;
37890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
379b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
38090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
381249af15fb82833d2274850c589812b6e69df0033joshualitt    typedef GrGeometryProcessor INHERITED;
38290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org};
38390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
384cdaa97bf664e0d584187efc125bfff670a064a9absalomonGR_DEFINE_GEOMETRY_PROCESSOR_TEST(EllipseGeometryProcessor);
38590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
3866f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#if GR_TEST_UTILS
38706ca8ec87cf6fab57cadd043a5ac18c4154a4129bungemansk_sp<GrGeometryProcessor> EllipseGeometryProcessor::TestCreate(GrProcessorTestData* d) {
38806ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman    return sk_sp<GrGeometryProcessor>(
389289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            new EllipseGeometryProcessor(d->fRandom->nextBool(), GrTest::TestMatrix(d->fRandom)));
39090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org}
3916f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#endif
39290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
39390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
39490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org
3955242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org/**
3966fc1b4998917791a73bf54428513940fe77dc058skia.committer@gmail.com * The output of this effect is a modulation of the input color and coverage for an ellipse,
3975242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org * specified as a 2D offset from center for both the outer and inner paths (if stroked). The
3985242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org * implict equation used is for a unit circle (x^2 + y^2 - 1 = 0) and the edge corrected by
3995242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org * using differentials.
4005242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org *
4015242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org * The result is device-independent and can be used with any affine matrix.
4025242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org */
4035242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
404cdaa97bf664e0d584187efc125bfff670a064a9absalomonenum class DIEllipseStyle { kStroke = 0, kHairline, kFill };
4055242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
406cdaa97bf664e0d584187efc125bfff670a064a9absalomonclass DIEllipseGeometryProcessor : public GrGeometryProcessor {
407cdaa97bf664e0d584187efc125bfff670a064a9absalomonpublic:
408cdaa97bf664e0d584187efc125bfff670a064a9absalomon    DIEllipseGeometryProcessor(const SkMatrix& viewMatrix, DIEllipseStyle style)
409289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            : fViewMatrix(viewMatrix) {
410cdaa97bf664e0d584187efc125bfff670a064a9absalomon        this->initClassID<DIEllipseGeometryProcessor>();
4116cb807bf99ac0f8f166e1790f91bcb3afbfb5458bsalomon        fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
4126cb807bf99ac0f8f166e1790f91bcb3afbfb5458bsalomon                                             kHigh_GrSLPrecision);
4136cb807bf99ac0f8f166e1790f91bcb3afbfb5458bsalomon        fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
4146cb807bf99ac0f8f166e1790f91bcb3afbfb5458bsalomon        fInEllipseOffsets0 = &this->addVertexAttrib("inEllipseOffsets0", kVec2f_GrVertexAttribType);
4156cb807bf99ac0f8f166e1790f91bcb3afbfb5458bsalomon        fInEllipseOffsets1 = &this->addVertexAttrib("inEllipseOffsets1", kVec2f_GrVertexAttribType);
416cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fStyle = style;
4175242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    }
4185242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
419d3b65972aad96453ff4510caa3e25a2b847c6d1eBrian Salomon    ~DIEllipseGeometryProcessor() override {}
4205242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
42136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "DIEllipseEdge"; }
4225242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
42394efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon    void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
42431df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon        GLSLProcessor::GenKey(*this, caps, b);
42531df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon    }
42631df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon
42794efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon    GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
42831df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon        return new GLSLProcessor();
42931df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon    }
4309d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
43131df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomonprivate:
43257d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    class GLSLProcessor : public GrGLSLGeometryProcessor {
4335242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    public:
434289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        GLSLProcessor() : fViewMatrix(SkMatrix::InvalidMatrix()) {}
4355242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
436465283cdf98ed9ab5285ca7b9814e430fca1d452joshualitt        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
437cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const DIEllipseGeometryProcessor& diegp = args.fGP.cast<DIEllipseGeometryProcessor>();
4384ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
4390eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
4407ea439b2203855db97330b25945b87dd4b170b8begdaniel            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
4415242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
442abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit attributes
443cdaa97bf664e0d584187efc125bfff670a064a9absalomon            varyingHandler->emitAttributes(diegp);
444abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
4458dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel            GrGLSLVertToFrag offsets0(kVec2f_GrSLType);
4460eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            varyingHandler->addVarying("EllipseOffsets0", &offsets0);
447289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            vertBuilder->codeAppendf("%s = %s;", offsets0.vsOut(), diegp.fInEllipseOffsets0->fName);
44874077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt
4498dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel            GrGLSLVertToFrag offsets1(kVec2f_GrSLType);
4500eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel            varyingHandler->addVarying("EllipseOffsets1", &offsets1);
451289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            vertBuilder->codeAppendf("%s = %s;", offsets1.vsOut(), diegp.fInEllipseOffsets1->fName);
4522dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
4538528541dd7f09f5bd76f3f1ce5f45d08ac7347c7cdalton            GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
45431df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon            varyingHandler->addPassThroughAttribute(diegp.fInColor, args.fOutputColor);
4559b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
456abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // Setup position
4577ea439b2203855db97330b25945b87dd4b170b8begdaniel            this->setupPosition(vertBuilder,
4587ea439b2203855db97330b25945b87dd4b170b8begdaniel                                uniformHandler,
4594ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                gpArgs,
46031df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon                                diegp.fInPosition->fName,
46131df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon                                diegp.fViewMatrix,
4625559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt                                &fViewMatrixUniform);
463abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
464abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt            // emit transforms
4657ea439b2203855db97330b25945b87dd4b170b8begdaniel            this->emitTransforms(vertBuilder,
4660eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel                                 varyingHandler,
4677ea439b2203855db97330b25945b87dd4b170b8begdaniel                                 uniformHandler,
4684ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 gpArgs->fPositionVar,
46931df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon                                 diegp.fInPosition->fName,
470a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon                                 args.fFPCoordTransformHandler);
4714ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
4725242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            // for outer curve
4734ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 scaledOffset = %s.xy;", offsets0.fsIn());
4744ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
4754ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 duvdx = dFdx(%s);", offsets0.fsIn());
4764ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 duvdy = dFdy(%s);", offsets0.fsIn());
477289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            fragBuilder->codeAppendf(
478289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "vec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
479289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "                 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
480289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn());
4814ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
4824ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float grad_dot = dot(grad, grad);");
4831b035d82d2b8b50ae334463edd06e4c5e0639311commit-bot@chromium.org            // avoid calling inversesqrt on zero.
4844ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
4854ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
486cdaa97bf664e0d584187efc125bfff670a064a9absalomon            if (DIEllipseStyle::kHairline == diegp.fStyle) {
4875242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org                // can probably do this with one step
4884ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("float edgeAlpha = clamp(1.0-test*invlen, 0.0, 1.0);");
4894ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("edgeAlpha *= clamp(1.0+test*invlen, 0.0, 1.0);");
4905242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            } else {
4914ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
4925242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            }
4935242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
4945242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            // for inner curve
495cdaa97bf664e0d584187efc125bfff670a064a9absalomon            if (DIEllipseStyle::kStroke == diegp.fStyle) {
4964ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppendf("scaledOffset = %s.xy;", offsets1.fsIn());
4974ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
4984ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppendf("duvdx = dFdx(%s);", offsets1.fsIn());
4994ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppendf("duvdy = dFdy(%s);", offsets1.fsIn());
500289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                fragBuilder->codeAppendf(
501289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        "grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
502289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        "            2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
503289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        offsets1.fsIn(), offsets1.fsIn(), offsets1.fsIn(), offsets1.fsIn());
5044ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
5054ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
5065242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org            }
5075242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5084ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
5095242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
5105242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
51146d36f0e7b709a077c647841eee23bd3efdc4117robertphillips        static void GenKey(const GrGeometryProcessor& gp,
51294efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon                           const GrShaderCaps&,
513b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                           GrProcessorKeyBuilder* b) {
514cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const DIEllipseGeometryProcessor& diegp = gp.cast<DIEllipseGeometryProcessor>();
515cdaa97bf664e0d584187efc125bfff670a064a9absalomon            uint16_t key = static_cast<uint16_t>(diegp.fStyle);
51631df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon            key |= ComputePosKey(diegp.fViewMatrix) << 10;
517b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt            b->add32(key);
5185242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
5195242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
520a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon        void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp,
521a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon                     FPCoordTransformIter&& transformIter) override {
522cdaa97bf664e0d584187efc125bfff670a064a9absalomon            const DIEllipseGeometryProcessor& diegp = gp.cast<DIEllipseGeometryProcessor>();
5235559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt
52431df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon            if (!diegp.fViewMatrix.isIdentity() && !fViewMatrix.cheapEqualTo(diegp.fViewMatrix)) {
52531df31c12fe2ce2a6688f226dd3ea24c06999f63bsalomon                fViewMatrix = diegp.fViewMatrix;
526018fb62d12d1febf121fe265da5b6117b86a6541egdaniel                float viewMatrix[3 * 3];
52764c4728c70001ed074fecf5c4e083781987b12e9egdaniel                GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
5285559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt                pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
5295559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt            }
530a624bf3d1cb454c1959c5bbbf23a3afdfa3481f3bsalomon            this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
5315242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org        }
5325242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5335242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    private:
5345559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        SkMatrix fViewMatrix;
5355559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        UniformHandle fViewMatrixUniform;
5369b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
537e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel        typedef GrGLSLGeometryProcessor INHERITED;
5385242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org    };
5395242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
54071c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInPosition;
541bb2ff94e223014403f775c3532a25cc25b00c949brianosman    const Attribute* fInColor;
54271c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInEllipseOffsets0;
54371c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    const Attribute* fInEllipseOffsets1;
544289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkMatrix fViewMatrix;
545289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    DIEllipseStyle fStyle;
5465242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
547b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
5485242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
549249af15fb82833d2274850c589812b6e69df0033joshualitt    typedef GrGeometryProcessor INHERITED;
5505242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org};
5515242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
552cdaa97bf664e0d584187efc125bfff670a064a9absalomonGR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseGeometryProcessor);
5535242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5546f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#if GR_TEST_UTILS
55506ca8ec87cf6fab57cadd043a5ac18c4154a4129bungemansk_sp<GrGeometryProcessor> DIEllipseGeometryProcessor::TestCreate(GrProcessorTestData* d) {
556289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    return sk_sp<GrGeometryProcessor>(new DIEllipseGeometryProcessor(
557289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            GrTest::TestMatrix(d->fRandom), (DIEllipseStyle)(d->fRandom->nextRangeU(0, 2))));
5585242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org}
5596f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#endif
5605242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5615242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
5625242ed761fc60470f31ffa6ea529c2a2f6afe6f5commit-bot@chromium.org
5636ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth// We have two possible cases for geometry for a circle:
5646ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
5656ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth// In the case of a normal fill, we draw geometry for the circle as an octagon.
5666ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverthstatic const uint16_t gFillCircleIndices[] = {
567289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // enter the octagon
568289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // clang-format off
569289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        0, 1, 8, 1, 2, 8,
570289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        2, 3, 8, 3, 4, 8,
571289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        4, 5, 8, 5, 6, 8,
572289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        6, 7, 8, 7, 0, 8
573289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // clang-format on
5746ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth};
5756ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
5766ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth// For stroked circles, we use two nested octagons.
5776ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverthstatic const uint16_t gStrokeCircleIndices[] = {
578289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // enter the octagon
579289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // clang-format off
580289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        0, 1,  9, 0, 9,   8,
581289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        1, 2, 10, 1, 10,  9,
582289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        2, 3, 11, 2, 11, 10,
583289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        3, 4, 12, 3, 12, 11,
584289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        4, 5, 13, 4, 13, 12,
585289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        5, 6, 14, 5, 14, 13,
586289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        6, 7, 15, 6, 15, 14,
587289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        7, 0,  8, 7,  8, 15,
588289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // clang-format on
5896ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth};
5906ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
591289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon
5926ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverthstatic const int kIndicesPerFillCircle = SK_ARRAY_COUNT(gFillCircleIndices);
5936ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverthstatic const int kIndicesPerStrokeCircle = SK_ARRAY_COUNT(gStrokeCircleIndices);
5946ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverthstatic const int kVertsPerStrokeCircle = 16;
5956ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverthstatic const int kVertsPerFillCircle = 9;
5966ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
5976ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverthstatic int circle_type_to_vert_count(bool stroked) {
5986ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth    return stroked ? kVertsPerStrokeCircle : kVertsPerFillCircle;
5996ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth}
6006ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
6016ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverthstatic int circle_type_to_index_count(bool stroked) {
6026ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth    return stroked ? kIndicesPerStrokeCircle : kIndicesPerFillCircle;
6036ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth}
6046ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
6056ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverthstatic const uint16_t* circle_type_to_indices(bool stroked) {
6066ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth    return stroked ? gStrokeCircleIndices : gFillCircleIndices;
6076ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth}
6086ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
6096ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth///////////////////////////////////////////////////////////////////////////////
6106ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
611289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomonclass CircleOp final : public GrMeshDrawOp {
6124b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomonpublic:
61325a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    DEFINE_OP_CLASS_ID
614f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
6154f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    /** Optional extra params to render a partial arc rather than a full circle. */
6164f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    struct ArcParams {
6174f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkScalar fStartAngleRadians;
6184f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkScalar fSweepAngleRadians;
6194f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        bool fUseCenter;
6204f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    };
621649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon    static std::unique_ptr<GrMeshDrawOp> Make(GrColor color, const SkMatrix& viewMatrix,
622649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                              SkPoint center, SkScalar radius, const GrStyle& style,
623649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                              const ArcParams* arcParams = nullptr) {
6244f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkASSERT(circle_stays_circle(viewMatrix));
6254f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        const SkStrokeRec& stroke = style.strokeRec();
6264f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        if (style.hasPathEffect()) {
6274f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            return nullptr;
6284f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        }
6294f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkStrokeRec::Style recStyle = stroke.getStyle();
6304f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        if (arcParams) {
6314f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            // Arc support depends on the style.
6324f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            switch (recStyle) {
6334f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                case SkStrokeRec::kStrokeAndFill_Style:
634289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    // This produces a strange result that this op doesn't implement.
6354f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                    return nullptr;
6364f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                case SkStrokeRec::kFill_Style:
6374f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                    // This supports all fills.
6384f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                    break;
639289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                case SkStrokeRec::kStroke_Style:  // fall through
6404f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                case SkStrokeRec::kHairline_Style:
6414f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                    // Strokes that don't use the center point are supported with butt cap.
6424f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                    if (arcParams->fUseCenter || stroke.getCap() != SkPaint::kButt_Cap) {
6434f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                        return nullptr;
6444f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                    }
6454f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                    break;
6464f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            }
6474f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        }
6484f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon
6494b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        viewMatrix.mapPoints(&center, 1);
6504f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        radius = viewMatrix.mapRadius(radius);
6514b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
6521b55a963a2374a14bb82eb887bb99ee91680f0ebreed
653289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        bool isStrokeOnly =
654289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                SkStrokeRec::kStroke_Style == recStyle || SkStrokeRec::kHairline_Style == recStyle;
6554f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == recStyle;
65676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
6576ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        SkScalar innerRadius = -SK_ScalarHalf;
6584b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar outerRadius = radius;
6594b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar halfWidth = 0;
6604b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        if (hasStroke) {
6614b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (SkScalarNearlyZero(strokeWidth)) {
6624b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                halfWidth = SK_ScalarHalf;
6634b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            } else {
6644b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                halfWidth = SkScalarHalf(strokeWidth);
6654b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
6665fd209e8ee477c703bc5c11b008f247d515fc0fcbsalomon
6674b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            outerRadius += halfWidth;
6684b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (isStrokeOnly) {
6694b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                innerRadius = radius - halfWidth;
6704b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
6714b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        }
6727f06c6947a3bef78dc57b9252779567c33604c90bsalomon
6734b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // The radii are outset for two reasons. First, it allows the shader to simply perform
6744b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
6754b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // Second, the outer radius is used to compute the verts of the bounding box that is
6764b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // rendered and the outset ensures the box will cover all partially covered by the circle.
6774b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        outerRadius += SK_ScalarHalf;
6784b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        innerRadius -= SK_ScalarHalf;
6796ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        bool stroked = isStrokeOnly && innerRadius > 0.0f;
680f8334781914363caf537f22f012fcd5c03c60dadBrian Salomon        std::unique_ptr<CircleOp> op(new CircleOp());
681289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->fViewMatrixIfUsingLocalCoords = viewMatrix;
68211bf8b2eae7d1780cb969146422a2ab3b933047absalomon
6834f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        // This makes every point fully inside the intersection plane.
6844f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        static constexpr SkScalar kUnusedIsectPlane[] = {0.f, 0.f, 1.f};
6854f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        // This makes every point fully outside the union plane.
6864f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        static constexpr SkScalar kUnusedUnionPlane[] = {0.f, 0.f, 0.f};
6874f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkRect devBounds = SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius,
6884f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                                            center.fX + outerRadius, center.fY + outerRadius);
6894f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        if (arcParams) {
6904f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            // The shader operates in a space where the circle is translated to be centered at the
6914f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            // origin. Here we compute points on the unit circle at the starting and ending angles.
6924f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            SkPoint startPoint, stopPoint;
6934f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            startPoint.fY = SkScalarSinCos(arcParams->fStartAngleRadians, &startPoint.fX);
6944f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            SkScalar endAngle = arcParams->fStartAngleRadians + arcParams->fSweepAngleRadians;
6954f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            stopPoint.fY = SkScalarSinCos(endAngle, &stopPoint.fX);
6964f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            // Like a fill without useCenter, butt-cap stroke can be implemented by clipping against
6974f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            // radial lines. However, in both cases we have to be careful about the half-circle.
6984f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            // case. In that case the two radial lines are equal and so that edge gets clipped
6994f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            // twice. Since the shared edge goes through the center we fall back on the useCenter
7004f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            // case.
701289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            bool useCenter =
702289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    (arcParams->fUseCenter || isStrokeOnly) &&
703289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    !SkScalarNearlyEqual(SkScalarAbs(arcParams->fSweepAngleRadians), SK_ScalarPI);
7044f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            if (useCenter) {
7054f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                SkVector norm0 = {startPoint.fY, -startPoint.fX};
7064f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                SkVector norm1 = {stopPoint.fY, -stopPoint.fX};
7074f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                if (arcParams->fSweepAngleRadians > 0) {
7084f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                    norm0.negate();
7094f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                } else {
7104f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                    norm1.negate();
7114f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                }
712289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                op->fClipPlane = true;
7134f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                if (SkScalarAbs(arcParams->fSweepAngleRadians) > SK_ScalarPI) {
714289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    op->fGeoData.emplace_back(Geometry{
7154f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            color,
7164f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            innerRadius,
7174f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            outerRadius,
7184f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            {norm0.fX, norm0.fY, 0.5f},
7194f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2]},
7204f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            {norm1.fX, norm1.fY, 0.5f},
7216ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                            devBounds,
722289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                            stroked});
723289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    op->fClipPlaneIsect = false;
724289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    op->fClipPlaneUnion = true;
7254f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                } else {
726289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    op->fGeoData.emplace_back(Geometry{
7274f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            color,
7284f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            innerRadius,
7294f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            outerRadius,
7304f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            {norm0.fX, norm0.fY, 0.5f},
7314f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            {norm1.fX, norm1.fY, 0.5f},
7324f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                            {kUnusedUnionPlane[0], kUnusedUnionPlane[1], kUnusedUnionPlane[2]},
7336ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                            devBounds,
734289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                            stroked});
735289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    op->fClipPlaneIsect = true;
736289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    op->fClipPlaneUnion = false;
7374f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                }
7384f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            } else {
7394f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                // We clip to a secant of the original circle.
7404f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                startPoint.scale(radius);
7414f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                stopPoint.scale(radius);
7424f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                SkVector norm = {startPoint.fY - stopPoint.fY, stopPoint.fX - startPoint.fX};
7434f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                norm.normalize();
7444f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                if (arcParams->fSweepAngleRadians > 0) {
7454f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                    norm.negate();
7464f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                }
7474f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                SkScalar d = -norm.dot(startPoint) + 0.5f;
7484f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon
749289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                op->fGeoData.emplace_back(
750289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        Geometry{color,
751289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                 innerRadius,
752289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                 outerRadius,
753289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                 {norm.fX, norm.fY, d},
754289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                 {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2]},
755289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                 {kUnusedUnionPlane[0], kUnusedUnionPlane[1], kUnusedUnionPlane[2]},
756289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                 devBounds,
757289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                 stroked});
758289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                op->fClipPlane = true;
759289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                op->fClipPlaneIsect = false;
760289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                op->fClipPlaneUnion = false;
7614f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            }
7624f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        } else {
763289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            op->fGeoData.emplace_back(
764289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    Geometry{color,
765289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                             innerRadius,
766289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                             outerRadius,
767289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                             {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2]},
768289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                             {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2]},
769289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                             {kUnusedUnionPlane[0], kUnusedUnionPlane[1], kUnusedUnionPlane[2]},
770289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                             devBounds,
771289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                             stroked});
772289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            op->fClipPlane = false;
773289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            op->fClipPlaneIsect = false;
774289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            op->fClipPlaneUnion = false;
7754f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        }
77688cf17d099085b8085ab11571b5094163dbb2c84bsalomon        // Use the original radius and stroke radius for the bounds so that it does not include the
77788cf17d099085b8085ab11571b5094163dbb2c84bsalomon        // AA bloat.
77888cf17d099085b8085ab11571b5094163dbb2c84bsalomon        radius += halfWidth;
779289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->setBounds(
780289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                {center.fX - radius, center.fY - radius, center.fX + radius, center.fY + radius},
781289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                HasAABloat::kYes, IsZeroArea::kNo);
782289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->fVertCount = circle_type_to_vert_count(stroked);
783289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->fIndexCount = circle_type_to_index_count(stroked);
784289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->fAllFill = !stroked;
785289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        return std::move(op);
786c79fc33d3e83664ffbd3651df3131c3e9e0b635chush    }
7874b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
788289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    const char* name() const override { return "CircleOp"; }
78976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
790e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips    SkString dumpInfo() const override {
791e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips        SkString string;
792e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips        for (int i = 0; i < fGeoData.count(); ++i) {
793289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            string.appendf(
794289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
795289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "InnerRad: %.2f, OuterRad: %.2f\n",
796289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    fGeoData[i].fColor, fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop,
797289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom,
798289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    fGeoData[i].fInnerRadius, fGeoData[i].fOuterRadius);
799e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips        }
8007c3e7180948766321c51d165737555e78910de51Brian Salomon        string.append(DumpPipelineInfo(*this->pipeline()));
801e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips        string.append(INHERITED::dumpInfo());
802e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips        return string;
803e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips    }
804e004bfc0a5e28cc083158f1a75e981ffd58a8134robertphillips
805e46f9feb44780a6269c6dcfe993f4215427fd98ebsalomonprivate:
806289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    CircleOp() : INHERITED(ClassID()) {}
80792aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon
808c0b642ca48d58416409e555549434066f09692b7Brian Salomon    void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor* color,
809c0b642ca48d58416409e555549434066f09692b7Brian Salomon                                            GrPipelineAnalysisCoverage* coverage) const override {
810c0b642ca48d58416409e555549434066f09692b7Brian Salomon        color->setToConstant(fGeoData[0].fColor);
811c0b642ca48d58416409e555549434066f09692b7Brian Salomon        *coverage = GrPipelineAnalysisCoverage::kSingleChannel;
81292aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    }
81392aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon
81492aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override {
81592aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        optimizations.getOverrideColorIfSet(&fGeoData[0].fColor);
81692aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        if (!optimizations.readsLocalCoords()) {
817cdaa97bf664e0d584187efc125bfff670a064a9absalomon            fViewMatrixIfUsingLocalCoords.reset();
818cdaa97bf664e0d584187efc125bfff670a064a9absalomon        }
81976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
82076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
821144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt    void onPrepareDraws(Target* target) const override {
822cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkMatrix localMatrix;
823cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) {
82476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return;
82576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
82676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
82776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
828289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        sk_sp<GrGeometryProcessor> gp(new CircleGeometryProcessor(
829289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                !fAllFill, fClipPlane, fClipPlaneIsect, fClipPlaneUnion, localMatrix));
8304f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon
8314f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        struct CircleVertex {
832289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            SkPoint fPos;
833289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            GrColor fColor;
834289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            SkPoint fOffset;
8354f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            SkScalar fOuterRadius;
8364f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            SkScalar fInnerRadius;
8374f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            // These planes may or may not be present in the vertex buffer.
8384f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            SkScalar fHalfPlanes[3][3];
8394f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        };
84076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
84176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
84276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
843289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        SkASSERT(vertexStride ==
844289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                 sizeof(CircleVertex) - (fClipPlane ? 0 : 3 * sizeof(SkScalar)) -
845289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                         (fClipPlaneIsect ? 0 : 3 * sizeof(SkScalar)) -
846289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                         (fClipPlaneUnion ? 0 : 3 * sizeof(SkScalar)));
8476ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
8486ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        const GrBuffer* vertexBuffer;
8496ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        int firstVertex;
850289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        char* vertices = (char*)target->makeVertexSpace(vertexStride, fVertCount, &vertexBuffer,
851289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                                        &firstVertex);
8524f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        if (!vertices) {
8536ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            SkDebugf("Could not allocate vertices\n");
8546ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            return;
8556ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        }
8566ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
8576ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        const GrBuffer* indexBuffer = nullptr;
8586ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        int firstIndex = 0;
8596ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        uint16_t* indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
8606ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        if (!indices) {
8616ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            SkDebugf("Could not allocate indices\n");
8624b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
8634b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
8644b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
8656ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        int currStartVertex = 0;
86676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
867144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt            const Geometry& geom = fGeoData[i];
86876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
869bb2ff94e223014403f775c3532a25cc25b00c949brianosman            GrColor color = geom.fColor;
870b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar innerRadius = geom.fInnerRadius;
871b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar outerRadius = geom.fOuterRadius;
87276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
873b5238a7571c243ba4a154a62575570c3078b3741bsalomon            const SkRect& bounds = geom.fDevBounds;
874289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            CircleVertex* v0 = reinterpret_cast<CircleVertex*>(vertices + 0 * vertexStride);
875289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            CircleVertex* v1 = reinterpret_cast<CircleVertex*>(vertices + 1 * vertexStride);
876289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            CircleVertex* v2 = reinterpret_cast<CircleVertex*>(vertices + 2 * vertexStride);
877289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            CircleVertex* v3 = reinterpret_cast<CircleVertex*>(vertices + 3 * vertexStride);
878289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            CircleVertex* v4 = reinterpret_cast<CircleVertex*>(vertices + 4 * vertexStride);
879289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            CircleVertex* v5 = reinterpret_cast<CircleVertex*>(vertices + 5 * vertexStride);
880289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            CircleVertex* v6 = reinterpret_cast<CircleVertex*>(vertices + 6 * vertexStride);
881289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            CircleVertex* v7 = reinterpret_cast<CircleVertex*>(vertices + 7 * vertexStride);
88276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
88376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // The inner radius in the vertex data must be specified in normalized space.
88476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            innerRadius = innerRadius / outerRadius;
8856ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
8866ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            SkPoint center = SkPoint::Make(bounds.centerX(), bounds.centerY());
887289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            SkScalar halfWidth = 0.5f * bounds.width();
8886ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            SkScalar octOffset = 0.41421356237f;  // sqrt(2) - 1
88960c05f98aa22d89e4ef25acb4799936f5df3cff2Herb Derby
890289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            v0->fPos = center + SkPoint::Make(-octOffset * halfWidth, -halfWidth);
8914f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            v0->fColor = color;
8926ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v0->fOffset = SkPoint::Make(-octOffset, -1);
8934f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            v0->fOuterRadius = outerRadius;
8944f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            v0->fInnerRadius = innerRadius;
8954f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon
896289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            v1->fPos = center + SkPoint::Make(octOffset * halfWidth, -halfWidth);
8974f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            v1->fColor = color;
8986ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v1->fOffset = SkPoint::Make(octOffset, -1);
8994f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            v1->fOuterRadius = outerRadius;
9004f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            v1->fInnerRadius = innerRadius;
9014f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon
902289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            v2->fPos = center + SkPoint::Make(halfWidth, -octOffset * halfWidth);
9034f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            v2->fColor = color;
9046ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v2->fOffset = SkPoint::Make(1, -octOffset);
9054f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            v2->fOuterRadius = outerRadius;
9064f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            v2->fInnerRadius = innerRadius;
9074f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon
908289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            v3->fPos = center + SkPoint::Make(halfWidth, octOffset * halfWidth);
9094f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            v3->fColor = color;
9106ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v3->fOffset = SkPoint::Make(1, octOffset);
9114f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            v3->fOuterRadius = outerRadius;
9124f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            v3->fInnerRadius = innerRadius;
9134f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon
914289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            v4->fPos = center + SkPoint::Make(octOffset * halfWidth, halfWidth);
9156ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v4->fColor = color;
9166ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v4->fOffset = SkPoint::Make(octOffset, 1);
9176ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v4->fOuterRadius = outerRadius;
9186ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v4->fInnerRadius = innerRadius;
9196ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
920289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            v5->fPos = center + SkPoint::Make(-octOffset * halfWidth, halfWidth);
9216ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v5->fColor = color;
9226ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v5->fOffset = SkPoint::Make(-octOffset, 1);
9236ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v5->fOuterRadius = outerRadius;
9246ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v5->fInnerRadius = innerRadius;
9256ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
926289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            v6->fPos = center + SkPoint::Make(-halfWidth, octOffset * halfWidth);
9276ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v6->fColor = color;
9286ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v6->fOffset = SkPoint::Make(-1, octOffset);
9296ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v6->fOuterRadius = outerRadius;
9306ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v6->fInnerRadius = innerRadius;
9316ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
932289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            v7->fPos = center + SkPoint::Make(-halfWidth, -octOffset * halfWidth);
9336ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v7->fColor = color;
9346ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v7->fOffset = SkPoint::Make(-1, -octOffset);
9356ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v7->fOuterRadius = outerRadius;
9366ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            v7->fInnerRadius = innerRadius;
9376ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
9384f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            if (fClipPlane) {
9394f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                memcpy(v0->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
9404f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                memcpy(v1->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
9414f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                memcpy(v2->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
9424f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                memcpy(v3->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
9436ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                memcpy(v4->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
9446ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                memcpy(v5->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
9456ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                memcpy(v6->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
9466ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                memcpy(v7->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
9474f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            }
9484f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            int unionIdx = 1;
9494f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            if (fClipPlaneIsect) {
9504f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                memcpy(v0->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
9514f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                memcpy(v1->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
9524f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                memcpy(v2->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
9534f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                memcpy(v3->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
9546ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                memcpy(v4->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
9556ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                memcpy(v5->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
9566ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                memcpy(v6->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
9576ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                memcpy(v7->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
9584f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                unionIdx = 2;
9594f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            }
9604f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            if (fClipPlaneUnion) {
9614f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                memcpy(v0->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
9624f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                memcpy(v1->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
9634f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                memcpy(v2->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
9644f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon                memcpy(v3->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
9656ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                memcpy(v4->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
9666ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                memcpy(v5->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
9676ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                memcpy(v6->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
9686ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                memcpy(v7->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
9696ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            }
9706ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
9716ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            if (geom.fStroked) {
9726ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                // compute the inner ring
9736ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                CircleVertex* v0 = reinterpret_cast<CircleVertex*>(vertices + 8 * vertexStride);
9746ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                CircleVertex* v1 = reinterpret_cast<CircleVertex*>(vertices + 9 * vertexStride);
9756ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                CircleVertex* v2 = reinterpret_cast<CircleVertex*>(vertices + 10 * vertexStride);
9766ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                CircleVertex* v3 = reinterpret_cast<CircleVertex*>(vertices + 11 * vertexStride);
9776ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                CircleVertex* v4 = reinterpret_cast<CircleVertex*>(vertices + 12 * vertexStride);
9786ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                CircleVertex* v5 = reinterpret_cast<CircleVertex*>(vertices + 13 * vertexStride);
9796ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                CircleVertex* v6 = reinterpret_cast<CircleVertex*>(vertices + 14 * vertexStride);
9806ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                CircleVertex* v7 = reinterpret_cast<CircleVertex*>(vertices + 15 * vertexStride);
9816ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
9826ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                // cosine and sine of pi/8
9836ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                SkScalar c = 0.923579533f;
9846ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                SkScalar s = 0.382683432f;
9856ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                SkScalar r = geom.fInnerRadius;
9866ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
987289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v0->fPos = center + SkPoint::Make(-s * r, -c * r);
9886ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v0->fColor = color;
989289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v0->fOffset = SkPoint::Make(-s * innerRadius, -c * innerRadius);
9906ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v0->fOuterRadius = outerRadius;
9916ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v0->fInnerRadius = innerRadius;
9926ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
993289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v1->fPos = center + SkPoint::Make(s * r, -c * r);
9946ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v1->fColor = color;
995289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v1->fOffset = SkPoint::Make(s * innerRadius, -c * innerRadius);
9966ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v1->fOuterRadius = outerRadius;
9976ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v1->fInnerRadius = innerRadius;
9986ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
999289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v2->fPos = center + SkPoint::Make(c * r, -s * r);
10006ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v2->fColor = color;
1001289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v2->fOffset = SkPoint::Make(c * innerRadius, -s * innerRadius);
10026ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v2->fOuterRadius = outerRadius;
10036ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v2->fInnerRadius = innerRadius;
10046ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
1005289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v3->fPos = center + SkPoint::Make(c * r, s * r);
10066ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v3->fColor = color;
1007289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v3->fOffset = SkPoint::Make(c * innerRadius, s * innerRadius);
10086ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v3->fOuterRadius = outerRadius;
10096ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v3->fInnerRadius = innerRadius;
10106ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
1011289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v4->fPos = center + SkPoint::Make(s * r, c * r);
10126ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v4->fColor = color;
1013289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v4->fOffset = SkPoint::Make(s * innerRadius, c * innerRadius);
10146ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v4->fOuterRadius = outerRadius;
10156ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v4->fInnerRadius = innerRadius;
10166ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
1017289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v5->fPos = center + SkPoint::Make(-s * r, c * r);
10186ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v5->fColor = color;
1019289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v5->fOffset = SkPoint::Make(-s * innerRadius, c * innerRadius);
10206ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v5->fOuterRadius = outerRadius;
10216ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v5->fInnerRadius = innerRadius;
10226ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
1023289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v6->fPos = center + SkPoint::Make(-c * r, s * r);
10246ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v6->fColor = color;
1025289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v6->fOffset = SkPoint::Make(-c * innerRadius, s * innerRadius);
10266ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v6->fOuterRadius = outerRadius;
10276ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v6->fInnerRadius = innerRadius;
10286ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
1029289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v7->fPos = center + SkPoint::Make(-c * r, -s * r);
10306ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v7->fColor = color;
1031289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                v7->fOffset = SkPoint::Make(-c * innerRadius, -s * innerRadius);
10326ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v7->fOuterRadius = outerRadius;
10336ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v7->fInnerRadius = innerRadius;
10346ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
10356ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                if (fClipPlane) {
10366ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v0->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
10376ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v1->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
10386ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v2->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
10396ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v3->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
10406ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v4->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
10416ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v5->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
10426ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v6->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
10436ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v7->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
10446ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                }
10456ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                int unionIdx = 1;
10466ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                if (fClipPlaneIsect) {
10476ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v0->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
10486ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v1->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
10496ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v2->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
10506ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v3->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
10516ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v4->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
10526ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v5->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
10536ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v6->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
10546ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v7->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
10556ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    unionIdx = 2;
10566ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                }
10576ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                if (fClipPlaneUnion) {
10586ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v0->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
10596ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v1->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
10606ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v2->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
10616ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v3->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
10626ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v4->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
10636ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v5->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
10646ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v6->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
10656ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v7->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
10666ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                }
10676ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            } else {
10686ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                // filled
10696ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                CircleVertex* v8 = reinterpret_cast<CircleVertex*>(vertices + 8 * vertexStride);
10706ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v8->fPos = center;
10716ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v8->fColor = color;
10726ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v8->fOffset = SkPoint::Make(0, 0);
10736ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v8->fOuterRadius = outerRadius;
10746ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                v8->fInnerRadius = innerRadius;
10756ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                if (fClipPlane) {
10766ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v8->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar));
10776ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                }
10786ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                int unionIdx = 1;
10796ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                if (fClipPlaneIsect) {
10806ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v8->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar));
10816ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    unionIdx = 2;
10826ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                }
10836ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                if (fClipPlaneUnion) {
10846ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                    memcpy(v8->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(SkScalar));
10856ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                }
10864f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            }
10876ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
10886ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            const uint16_t* primIndices = circle_type_to_indices(geom.fStroked);
10896ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            const int primIndexCount = circle_type_to_index_count(geom.fStroked);
10906ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            for (int i = 0; i < primIndexCount; ++i) {
10916ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                *indices++ = primIndices[i] + currStartVertex;
10926ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            }
10936ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
10946ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth            currStartVertex += circle_type_to_vert_count(geom.fStroked);
1095289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            vertices += circle_type_to_vert_count(geom.fStroked) * vertexStride;
109676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
10976ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth
10986ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        GrMesh mesh;
10996ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex,
11006ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth                         firstIndex, fVertCount, fIndexCount);
11016ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        target->draw(gp.get(), mesh);
110276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
110376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
110425a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
1105289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        CircleOp* that = t->cast<CircleOp>();
11068cefe40ab094bfbea532761dad1a857eb3d4b831Jim Van Verth
11078cefe40ab094bfbea532761dad1a857eb3d4b831Jim Van Verth        // can only represent 65535 unique vertices with 16-bit indices
1108e549a05dc20c84597b324b19b9764136da54e5f1Jim Van Verth        if (fVertCount + that->fVertCount > 65536) {
11098cefe40ab094bfbea532761dad1a857eb3d4b831Jim Van Verth            return false;
11108cefe40ab094bfbea532761dad1a857eb3d4b831Jim Van Verth        }
11118cefe40ab094bfbea532761dad1a857eb3d4b831Jim Van Verth
1112abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1113abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                    that->bounds(), caps)) {
11148cab9a7685e872427e6f0388f149575a9b6016eejoshualitt            return false;
11158cab9a7685e872427e6f0388f149575a9b6016eejoshualitt        }
11168cab9a7685e872427e6f0388f149575a9b6016eejoshualitt
11176ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
111876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
111976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
112076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1121289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // Because we've set up the ops that don't use the planes with noop values
1122289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // we can just accumulate used planes by later ops.
11234f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        fClipPlane |= that->fClipPlane;
11244f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        fClipPlaneIsect |= that->fClipPlaneIsect;
11254f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        fClipPlaneUnion |= that->fClipPlaneUnion;
11264f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon
1127cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
112888cf17d099085b8085ab11571b5094163dbb2c84bsalomon        this->joinBounds(*that);
11296ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        fVertCount += that->fVertCount;
11306ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        fIndexCount += that->fIndexCount;
11316ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth        fAllFill = fAllFill && that->fAllFill;
113276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
113376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
113476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
11354b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    struct Geometry {
1136289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        GrColor fColor;
11374b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fInnerRadius;
11384b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fOuterRadius;
11394f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkScalar fClipPlane[3];
11404f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkScalar fIsectPlane[3];
11414f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkScalar fUnionPlane[3];
1142289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        SkRect fDevBounds;
1143289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        bool fStroked;
11444b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    };
11454b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
11466ca48820407244bbdeb8f9e0ed7d76dd94270460jvanverth    SkSTArray<1, Geometry, true> fGeoData;
1147289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkMatrix fViewMatrixIfUsingLocalCoords;
1148289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    int fVertCount;
1149289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    int fIndexCount;
1150289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    bool fAllFill;
1151289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    bool fClipPlane;
1152289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    bool fClipPlaneIsect;
1153289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    bool fClipPlaneUnion;
11541b55a963a2374a14bb82eb887bb99ee91680f0ebreed
1155dad2923b8ec9270d810c1e8e76da8e6768d8f9ddBrian Salomon    typedef GrMeshDrawOp INHERITED;
115676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
115776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1158f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
1159f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1160289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomonclass EllipseOp : public GrMeshDrawOp {
116176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittpublic:
116225a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    DEFINE_OP_CLASS_ID
1163649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon    static std::unique_ptr<GrMeshDrawOp> Make(GrColor color, const SkMatrix& viewMatrix,
1164649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                              const SkRect& ellipse, const SkStrokeRec& stroke) {
11654b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkASSERT(viewMatrix.rectStaysRect());
11664b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
11674b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // do any matrix crunching before we reset the draw state for device coords
11684b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
11694b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        viewMatrix.mapPoints(&center, 1);
11704b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
11714b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
1172289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX] * ellipseXRadius +
1173289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                       viewMatrix[SkMatrix::kMSkewY] * ellipseYRadius);
1174289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX] * ellipseXRadius +
1175289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                       viewMatrix[SkMatrix::kMScaleY] * ellipseYRadius);
11764b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
11774b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // do (potentially) anisotropic mapping of stroke
11784b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkVector scaledStroke;
11794b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar strokeWidth = stroke.getWidth();
1180289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        scaledStroke.fX = SkScalarAbs(
1181289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                strokeWidth * (viewMatrix[SkMatrix::kMScaleX] + viewMatrix[SkMatrix::kMSkewY]));
1182289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        scaledStroke.fY = SkScalarAbs(
1183289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                strokeWidth * (viewMatrix[SkMatrix::kMSkewX] + viewMatrix[SkMatrix::kMScaleY]));
11844b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
11854b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkStrokeRec::Style style = stroke.getStyle();
1186289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        bool isStrokeOnly =
1187289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style;
11884b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
11894b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
11904b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar innerXRadius = 0;
11914b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar innerYRadius = 0;
11924b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        if (hasStroke) {
11934b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (SkScalarNearlyZero(scaledStroke.length())) {
11944b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
11954b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            } else {
11964b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                scaledStroke.scale(SK_ScalarHalf);
11974b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
11985fd209e8ee477c703bc5c11b008f247d515fc0fcbsalomon
11994b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            // we only handle thick strokes for near-circular ellipses
12004b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (scaledStroke.length() > SK_ScalarHalf &&
1201289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                (SK_ScalarHalf * xRadius > yRadius || SK_ScalarHalf * yRadius > xRadius)) {
12024b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                return nullptr;
12034b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
120411bf8b2eae7d1780cb969146422a2ab3b933047absalomon
12054b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1206289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            if (scaledStroke.fX * (yRadius * yRadius) <
1207289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        (scaledStroke.fY * scaledStroke.fY) * xRadius ||
1208289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                scaledStroke.fY * (xRadius * xRadius) <
1209289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                        (scaledStroke.fX * scaledStroke.fX) * yRadius) {
12104b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                return nullptr;
12114b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
12124b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
12134b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            // this is legit only if scale & translation (which should be the case at the moment)
12144b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (isStrokeOnly) {
12154b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                innerXRadius = xRadius - scaledStroke.fX;
12164b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                innerYRadius = yRadius - scaledStroke.fY;
12174b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
12184b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
12194b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            xRadius += scaledStroke.fX;
12204b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            yRadius += scaledStroke.fY;
12214b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        }
12224b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
1223f8334781914363caf537f22f012fcd5c03c60dadBrian Salomon        std::unique_ptr<EllipseOp> op(new EllipseOp());
1224289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->fGeoData.emplace_back(
1225289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                Geometry{color, xRadius, yRadius, innerXRadius, innerYRadius,
1226289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                         SkRect::MakeLTRB(center.fX - xRadius, center.fY - yRadius,
1227289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                          center.fX + xRadius, center.fY + yRadius)});
12284b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
1229289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->setBounds(op->fGeoData.back().fDevBounds, HasAABloat::kYes, IsZeroArea::kNo);
123088cf17d099085b8085ab11571b5094163dbb2c84bsalomon
12314b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // Outset bounds to include half-pixel width antialiasing.
1232289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->fGeoData[0].fDevBounds.outset(SK_ScalarHalf, SK_ScalarHalf);
12334b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
1234289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->fStroked = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0;
1235289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->fViewMatrixIfUsingLocalCoords = viewMatrix;
1236289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        return std::move(op);
1237cdaa97bf664e0d584187efc125bfff670a064a9absalomon    }
123876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1239289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    const char* name() const override { return "EllipseOp"; }
124076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
12417c3e7180948766321c51d165737555e78910de51Brian Salomon    SkString dumpInfo() const override {
12427c3e7180948766321c51d165737555e78910de51Brian Salomon        SkString string;
12437c3e7180948766321c51d165737555e78910de51Brian Salomon        string.appendf("Stroked: %d\n", fStroked);
12447c3e7180948766321c51d165737555e78910de51Brian Salomon        for (const auto& geo : fGeoData) {
1245289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            string.appendf(
1246289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
1247289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "XRad: %.2f, YRad: %.2f, InnerXRad: %.2f, InnerYRad: %.2f\n",
1248289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    geo.fColor, geo.fDevBounds.fLeft, geo.fDevBounds.fTop, geo.fDevBounds.fRight,
1249289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    geo.fDevBounds.fBottom, geo.fXRadius, geo.fYRadius, geo.fInnerXRadius,
1250289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    geo.fInnerYRadius);
12517c3e7180948766321c51d165737555e78910de51Brian Salomon        }
12527c3e7180948766321c51d165737555e78910de51Brian Salomon        string.append(DumpPipelineInfo(*this->pipeline()));
12537c3e7180948766321c51d165737555e78910de51Brian Salomon        string.append(INHERITED::dumpInfo());
12547c3e7180948766321c51d165737555e78910de51Brian Salomon        return string;
12557c3e7180948766321c51d165737555e78910de51Brian Salomon    }
12567c3e7180948766321c51d165737555e78910de51Brian Salomon
1257e46f9feb44780a6269c6dcfe993f4215427fd98ebsalomonprivate:
1258289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    EllipseOp() : INHERITED(ClassID()) {}
12594b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
1260c0b642ca48d58416409e555549434066f09692b7Brian Salomon    void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor* color,
1261c0b642ca48d58416409e555549434066f09692b7Brian Salomon                                            GrPipelineAnalysisCoverage* coverage) const override {
1262c0b642ca48d58416409e555549434066f09692b7Brian Salomon        color->setToConstant(fGeoData[0].fColor);
1263c0b642ca48d58416409e555549434066f09692b7Brian Salomon        *coverage = GrPipelineAnalysisCoverage::kSingleChannel;
126492aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    }
126592aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon
126692aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override {
126792aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        if (!optimizations.readsLocalCoords()) {
1268cdaa97bf664e0d584187efc125bfff670a064a9absalomon            fViewMatrixIfUsingLocalCoords.reset();
1269cdaa97bf664e0d584187efc125bfff670a064a9absalomon        }
127076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
127176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1272144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt    void onPrepareDraws(Target* target) const override {
1273cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkMatrix localMatrix;
1274cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) {
127576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return;
127676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
127776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
127876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
1279144caf55ffc692bcda77703a73bb9a894f7d024fHal Canary        sk_sp<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, localMatrix));
128076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
128176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
1282b5238a7571c243ba4a154a62575570c3078b3741bsalomon        QuadHelper helper;
128376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
128419e0058a650a9e4dc9c35ed26c5e91916bcc0601joshualitt        SkASSERT(vertexStride == sizeof(EllipseVertex));
1285289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        EllipseVertex* verts =
1286289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                reinterpret_cast<EllipseVertex*>(helper.init(target, vertexStride, instanceCount));
1287b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts) {
12884b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
12894b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
12904b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
129176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
1292144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt            const Geometry& geom = fGeoData[i];
129376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1294bb2ff94e223014403f775c3532a25cc25b00c949brianosman            GrColor color = geom.fColor;
1295b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar xRadius = geom.fXRadius;
1296b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar yRadius = geom.fYRadius;
129776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
129876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // Compute the reciprocals of the radii here to save time in the shader
129976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar xRadRecip = SkScalarInvert(xRadius);
130076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yRadRecip = SkScalarInvert(yRadius);
1301b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar xInnerRadRecip = SkScalarInvert(geom.fInnerXRadius);
1302b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar yInnerRadRecip = SkScalarInvert(geom.fInnerYRadius);
130376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1304b5238a7571c243ba4a154a62575570c3078b3741bsalomon            const SkRect& bounds = geom.fDevBounds;
130576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1306977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            // fOffsets are expanded from xyRadii to include the half-pixel antialiasing width.
1307977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            SkScalar xMaxOffset = xRadius + SK_ScalarHalf;
1308977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            SkScalar yMaxOffset = yRadius + SK_ScalarHalf;
1309977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack
131076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // The inner radius in the vertex data must be specified in normalized space.
1311289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
1312bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[0].fColor = color;
1313977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            verts[0].fOffset = SkPoint::Make(-xMaxOffset, -yMaxOffset);
131476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
131576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
131676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1317289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
1318bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[1].fColor = color;
1319977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            verts[1].fOffset = SkPoint::Make(-xMaxOffset, yMaxOffset);
132076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
132176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
132276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
132376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
1324bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[2].fColor = color;
1325977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            verts[2].fOffset = SkPoint::Make(xMaxOffset, yMaxOffset);
132676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
132776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
132876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
132976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
1330bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[3].fColor = color;
1331977996dd0e0c6e6686a980a23e97e6fb5da1a592vjiaoblack            verts[3].fOffset = SkPoint::Make(xMaxOffset, -yMaxOffset);
133276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
133376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
133476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1335b5238a7571c243ba4a154a62575570c3078b3741bsalomon            verts += kVerticesPerQuad;
133676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
1337144caf55ffc692bcda77703a73bb9a894f7d024fHal Canary        helper.recordDraw(target, gp.get());
133876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
133976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
134025a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
1341289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        EllipseOp* that = t->cast<EllipseOp>();
1342abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon
1343abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1344abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                    that->bounds(), caps)) {
13458cab9a7685e872427e6f0388f149575a9b6016eejoshualitt            return false;
13468cab9a7685e872427e6f0388f149575a9b6016eejoshualitt        }
13478cab9a7685e872427e6f0388f149575a9b6016eejoshualitt
1348cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (fStroked != that->fStroked) {
134976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
135076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
135176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1352cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
135376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
135476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
135576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1356cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
135788cf17d099085b8085ab11571b5094163dbb2c84bsalomon        this->joinBounds(*that);
135876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
135976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
136076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
13614b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    struct Geometry {
13624b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        GrColor fColor;
13634b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fXRadius;
13644b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fYRadius;
13654b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fInnerXRadius;
13664b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fInnerYRadius;
13674b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkRect fDevBounds;
13684b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    };
136976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1370289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    bool fStroked;
1371289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkMatrix fViewMatrixIfUsingLocalCoords;
137276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true> fGeoData;
13731b55a963a2374a14bb82eb887bb99ee91680f0ebreed
1374dad2923b8ec9270d810c1e8e76da8e6768d8f9ddBrian Salomon    typedef GrMeshDrawOp INHERITED;
137576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
137676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
13774b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon/////////////////////////////////////////////////////////////////////////////////////////////////
13786bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
1379289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomonclass DIEllipseOp : public GrMeshDrawOp {
13804b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomonpublic:
138125a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    DEFINE_OP_CLASS_ID
13826bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
1383649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon    static std::unique_ptr<GrMeshDrawOp> Make(GrColor color,
1384649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                              const SkMatrix& viewMatrix,
1385649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                              const SkRect& ellipse,
1386649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                              const SkStrokeRec& stroke) {
13874b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
13884b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar xRadius = SkScalarHalf(ellipse.width());
13894b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar yRadius = SkScalarHalf(ellipse.height());
13904b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
13914b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkStrokeRec::Style style = stroke.getStyle();
1392289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        DIEllipseStyle dieStyle = (SkStrokeRec::kStroke_Style == style)
1393289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                          ? DIEllipseStyle::kStroke
1394289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                          : (SkStrokeRec::kHairline_Style == style)
1395289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                                    ? DIEllipseStyle::kHairline
1396289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                                    : DIEllipseStyle::kFill;
13974b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
13984b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar innerXRadius = 0;
13994b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar innerYRadius = 0;
14004b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
14014b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            SkScalar strokeWidth = stroke.getWidth();
14024b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
14034b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (SkScalarNearlyZero(strokeWidth)) {
14044b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                strokeWidth = SK_ScalarHalf;
14054b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            } else {
14064b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                strokeWidth *= SK_ScalarHalf;
14074b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
14086bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
14094b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            // we only handle thick strokes for near-circular ellipses
14104b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (strokeWidth > SK_ScalarHalf &&
1411289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                (SK_ScalarHalf * xRadius > yRadius || SK_ScalarHalf * yRadius > xRadius)) {
14124b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                return nullptr;
14134b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
1414fc5b70a8e427ee115868786fa361c2c813ab566bbenjaminwagner
14154b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1416289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            if (strokeWidth * (yRadius * yRadius) < (strokeWidth * strokeWidth) * xRadius ||
1417289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                strokeWidth * (xRadius * xRadius) < (strokeWidth * strokeWidth) * yRadius) {
14184b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                return nullptr;
14194b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
1420df4f47b8ff6378c4d8f775dcb3169ac7c64f2510benjaminwagner
14214b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            // set inner radius (if needed)
14224b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (SkStrokeRec::kStroke_Style == style) {
14234b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                innerXRadius = xRadius - strokeWidth;
14244b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                innerYRadius = yRadius - strokeWidth;
14254b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
1426c79fc33d3e83664ffbd3651df3131c3e9e0b635chush
14274b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            xRadius += strokeWidth;
14284b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            yRadius += strokeWidth;
14294b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        }
14304b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        if (DIEllipseStyle::kStroke == dieStyle) {
1431289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            dieStyle = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseStyle::kStroke
1432289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                                              : DIEllipseStyle::kFill;
14336bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org        }
14346bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
14354b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // This expands the outer rect so that after CTM we end up with a half-pixel border
14364b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar a = viewMatrix[SkMatrix::kMScaleX];
14374b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar b = viewMatrix[SkMatrix::kMSkewX];
14384b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar c = viewMatrix[SkMatrix::kMSkewY];
14394b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar d = viewMatrix[SkMatrix::kMScaleY];
1440289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a * a + c * c);
1441289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b * b + d * d);
1442289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon
1443f8334781914363caf537f22f012fcd5c03c60dadBrian Salomon        std::unique_ptr<DIEllipseOp> op(new DIEllipseOp());
1444289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->fGeoData.emplace_back(Geometry{
1445289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                viewMatrix, color, xRadius, yRadius, innerXRadius, innerYRadius, geoDx, geoDy,
1446289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                dieStyle,
1447289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy,
1448289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                 center.fX + xRadius + geoDx, center.fY + yRadius + geoDy)});
1449289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->setTransformedBounds(op->fGeoData[0].fBounds, viewMatrix, HasAABloat::kYes,
1450289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                 IsZeroArea::kNo);
1451289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        return std::move(op);
145276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
145376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1454289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    const char* name() const override { return "DIEllipseOp"; }
145576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
14567c3e7180948766321c51d165737555e78910de51Brian Salomon    SkString dumpInfo() const override {
14577c3e7180948766321c51d165737555e78910de51Brian Salomon        SkString string;
14587c3e7180948766321c51d165737555e78910de51Brian Salomon        for (const auto& geo : fGeoData) {
1459289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            string.appendf(
1460289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], XRad: %.2f, "
1461289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "YRad: %.2f, InnerXRad: %.2f, InnerYRad: %.2f, GeoDX: %.2f, "
1462289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "GeoDY: %.2f\n",
1463289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    geo.fColor, geo.fBounds.fLeft, geo.fBounds.fTop, geo.fBounds.fRight,
1464289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    geo.fBounds.fBottom, geo.fXRadius, geo.fYRadius, geo.fInnerXRadius,
1465289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    geo.fInnerYRadius, geo.fGeoDx, geo.fGeoDy);
14667c3e7180948766321c51d165737555e78910de51Brian Salomon        }
14677c3e7180948766321c51d165737555e78910de51Brian Salomon        string.append(DumpPipelineInfo(*this->pipeline()));
14687c3e7180948766321c51d165737555e78910de51Brian Salomon        string.append(INHERITED::dumpInfo());
14697c3e7180948766321c51d165737555e78910de51Brian Salomon        return string;
14707c3e7180948766321c51d165737555e78910de51Brian Salomon    }
14717c3e7180948766321c51d165737555e78910de51Brian Salomon
1472e46f9feb44780a6269c6dcfe993f4215427fd98ebsalomonprivate:
1473289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    DIEllipseOp() : INHERITED(ClassID()) {}
14744b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
1475c0b642ca48d58416409e555549434066f09692b7Brian Salomon    void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor* color,
1476c0b642ca48d58416409e555549434066f09692b7Brian Salomon                                            GrPipelineAnalysisCoverage* coverage) const override {
1477c0b642ca48d58416409e555549434066f09692b7Brian Salomon        color->setToConstant(fGeoData[0].fColor);
1478c0b642ca48d58416409e555549434066f09692b7Brian Salomon        *coverage = GrPipelineAnalysisCoverage::kSingleChannel;
147992aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    }
148092aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon
148192aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override {
148292aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        optimizations.getOverrideColorIfSet(&fGeoData[0].fColor);
148392aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        fUsesLocalCoords = optimizations.readsLocalCoords();
148476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
148576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1486144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt    void onPrepareDraws(Target* target) const override {
148776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
1488289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        sk_sp<GrGeometryProcessor> gp(
1489289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                new DIEllipseGeometryProcessor(this->viewMatrix(), this->style()));
149076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
149176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
149276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
149319e0058a650a9e4dc9c35ed26c5e91916bcc0601joshualitt        SkASSERT(vertexStride == sizeof(DIEllipseVertex));
1494b5238a7571c243ba4a154a62575570c3078b3741bsalomon        QuadHelper helper;
1495b5238a7571c243ba4a154a62575570c3078b3741bsalomon        DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(
1496289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                helper.init(target, vertexStride, instanceCount));
1497b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts) {
14984b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
14994b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
15004b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
150176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
1502144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt            const Geometry& geom = fGeoData[i];
150376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1504bb2ff94e223014403f775c3532a25cc25b00c949brianosman            GrColor color = geom.fColor;
1505b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar xRadius = geom.fXRadius;
1506b5238a7571c243ba4a154a62575570c3078b3741bsalomon            SkScalar yRadius = geom.fYRadius;
150776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1508b5238a7571c243ba4a154a62575570c3078b3741bsalomon            const SkRect& bounds = geom.fBounds;
150976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
151076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // This adjusts the "radius" to include the half-pixel border
151180ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            SkScalar offsetDx = geom.fGeoDx / xRadius;
151280ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            SkScalar offsetDy = geom.fGeoDy / yRadius;
151376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
151480ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            SkScalar innerRatioX = xRadius / geom.fInnerXRadius;
151580ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed            SkScalar innerRatioY = yRadius / geom.fInnerYRadius;
151676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
151776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
1518bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[0].fColor = color;
151976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy);
152076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy);
152176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1522289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
1523bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[1].fColor = color;
152476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy);
152576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[1].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy);
152676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
152776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
1528bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[2].fColor = color;
152976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy);
153076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[2].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy);
153176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
153276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
1533bb2ff94e223014403f775c3532a25cc25b00c949brianosman            verts[3].fColor = color;
153476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy);
153576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
153676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1537b5238a7571c243ba4a154a62575570c3078b3741bsalomon            verts += kVerticesPerQuad;
153876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
1539144caf55ffc692bcda77703a73bb9a894f7d024fHal Canary        helper.recordDraw(target, gp.get());
154076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
15419d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
154225a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
1543289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        DIEllipseOp* that = t->cast<DIEllipseOp>();
1544abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
1545abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                    that->bounds(), caps)) {
15468cab9a7685e872427e6f0388f149575a9b6016eejoshualitt            return false;
15478cab9a7685e872427e6f0388f149575a9b6016eejoshualitt        }
15488cab9a7685e872427e6f0388f149575a9b6016eejoshualitt
1549cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (this->style() != that->style()) {
155076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
155176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
155276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1553d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt        // TODO rewrite to allow positioning on CPU
1554d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt        if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
155576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
155676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
155776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1558cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
155988cf17d099085b8085ab11571b5094163dbb2c84bsalomon        this->joinBounds(*that);
156076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
156176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
156276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
156376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1564cdaa97bf664e0d584187efc125bfff670a064a9absalomon    DIEllipseStyle style() const { return fGeoData[0].fStyle; }
156576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
15664b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    struct Geometry {
15674b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkMatrix fViewMatrix;
15684b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        GrColor fColor;
15694b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fXRadius;
15704b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fYRadius;
15714b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fInnerXRadius;
15724b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fInnerYRadius;
15734b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fGeoDx;
15744b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fGeoDy;
15754b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        DIEllipseStyle fStyle;
15764b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkRect fBounds;
15774b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    };
15784b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
1579289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    bool fUsesLocalCoords;
158076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true> fGeoData;
15811b55a963a2374a14bb82eb887bb99ee91680f0ebreed
1582dad2923b8ec9270d810c1e8e76da8e6768d8f9ddBrian Salomon    typedef GrMeshDrawOp INHERITED;
158376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
1584f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1585f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
1586f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
1587fc6c37b981daeece7474ce61070c707c37eefa62Mike Klein// We have three possible cases for geometry for a roundrect.
1588c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//
1589c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth// In the case of a normal fill or a stroke, we draw the roundrect as a 9-patch:
1590c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//    ____________
1591c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//   |_|________|_|
1592c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//   | |        | |
1593c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//   | |        | |
1594c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//   | |        | |
1595c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//   |_|________|_|
1596c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//   |_|________|_|
1597c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//
1598c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth// For strokes, we don't draw the center quad.
1599c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//
1600c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth// For circular roundrects, in the case where the stroke width is greater than twice
1601c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth// the corner radius (overstroke), we add additional geometry to mark out the rectangle
16026a3976114d8a6aaa564c3c7571cfe7d1727a3a6ejvanverth// in the center. The shared vertices are duplicated so we can set a different outer radius
16036a3976114d8a6aaa564c3c7571cfe7d1727a3a6ejvanverth// for the fill calculation.
1604c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//    ____________
1605c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//   |_|________|_|
1606c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//   | |\ ____ /| |
1607c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//   | | |    | | |
1608c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//   | | |____| | |
1609c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//   |_|/______\|_|
1610c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//   |_|________|_|
1611c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth//
1612c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth// We don't draw the center quad from the fill rect in this case.
161379839d45f893ad5690fc83c951567b3686e781e6Robert Phillips//
161479839d45f893ad5690fc83c951567b3686e781e6Robert Phillips// For filled rrects that need to provide a distance vector we resuse the overstroke
161579839d45f893ad5690fc83c951567b3686e781e6Robert Phillips// geometry but make the inner rect degenerate (either a point or a horizontal or
161679839d45f893ad5690fc83c951567b3686e781e6Robert Phillips// vertical line).
1617c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth
161884839f6fb3d0de9088be3d53e81df195331ed1c9jvanverthstatic const uint16_t gOverstrokeRRectIndices[] = {
1619289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // clang-format off
1620289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // overstroke quads
1621289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // we place this at the beginning so that we can skip these indices when rendering normally
1622289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        16, 17, 19, 16, 19, 18,
1623289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        19, 17, 23, 19, 23, 21,
1624289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        21, 23, 22, 21, 22, 20,
1625289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        22, 16, 18, 22, 18, 20,
1626289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon
1627289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // corners
1628289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        0, 1, 5, 0, 5, 4,
1629289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        2, 3, 7, 2, 7, 6,
1630289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        8, 9, 13, 8, 13, 12,
1631289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        10, 11, 15, 10, 15, 14,
1632289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon
1633289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // edges
1634289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        1, 2, 6, 1, 6, 5,
1635289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        4, 5, 9, 4, 9, 8,
1636289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        6, 7, 11, 6, 11, 10,
1637289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        9, 10, 14, 9, 14, 13,
1638289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon
1639289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // center
1640289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // we place this at the end so that we can ignore these indices when not rendering as filled
1641289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        5, 6, 10, 5, 10, 9,
1642289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // clang-format on
1643f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org};
1644289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon
164584839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth// fill and standard stroke indices skip the overstroke "ring"
1646289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomonstatic const uint16_t* gStandardRRectIndices = gOverstrokeRRectIndices + 6 * 4;
1647f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
164884839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth// overstroke count is arraysize minus the center indices
164984839f6fb3d0de9088be3d53e81df195331ed1c9jvanverthstatic const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gOverstrokeRRectIndices) - 6;
165084839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth// fill count skips overstroke indices and includes center
1651289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomonstatic const int kIndicesPerFillRRect = kIndicesPerOverstrokeRRect - 6 * 4 + 6;
165284839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth// stroke count is fill count minus center indices
1653c3d0e422761702c52a974411eaf0b06d223fe98ejvanverthstatic const int kIndicesPerStrokeRRect = kIndicesPerFillRRect - 6;
1654c3d0e422761702c52a974411eaf0b06d223fe98ejvanverthstatic const int kVertsPerStandardRRect = 16;
16556a3976114d8a6aaa564c3c7571cfe7d1727a3a6ejvanverthstatic const int kVertsPerOverstrokeRRect = 24;
16565ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt
1657c3d0e422761702c52a974411eaf0b06d223fe98ejvanverthenum RRectType {
1658c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth    kFill_RRectType,
1659c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth    kStroke_RRectType,
166084839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth    kOverstroke_RRectType,
166179839d45f893ad5690fc83c951567b3686e781e6Robert Phillips    kFillWithDist_RRectType
1662c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth};
1663c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth
166484839f6fb3d0de9088be3d53e81df195331ed1c9jvanverthstatic int rrect_type_to_vert_count(RRectType type) {
1665289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    switch (type) {
1666289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        case kFill_RRectType:
1667289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        case kStroke_RRectType:
1668289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            return kVertsPerStandardRRect;
1669289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        case kOverstroke_RRectType:
1670289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        case kFillWithDist_RRectType:
1671289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            return kVertsPerOverstrokeRRect;
1672289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    }
1673289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkFAIL("Invalid type");
1674289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    return 0;
167584839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth}
167684839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth
167784839f6fb3d0de9088be3d53e81df195331ed1c9jvanverthstatic int rrect_type_to_index_count(RRectType type) {
1678289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    switch (type) {
1679289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        case kFill_RRectType:
1680289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            return kIndicesPerFillRRect;
1681289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        case kStroke_RRectType:
1682289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            return kIndicesPerStrokeRRect;
1683289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        case kOverstroke_RRectType:
1684289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        case kFillWithDist_RRectType:
1685289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            return kIndicesPerOverstrokeRRect;
1686289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    }
1687289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkFAIL("Invalid type");
1688289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    return 0;
168984839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth}
169084839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth
169184839f6fb3d0de9088be3d53e81df195331ed1c9jvanverthstatic const uint16_t* rrect_type_to_indices(RRectType type) {
1692289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    switch (type) {
1693289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        case kFill_RRectType:
1694289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        case kStroke_RRectType:
1695289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            return gStandardRRectIndices;
1696289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        case kOverstroke_RRectType:
1697289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        case kFillWithDist_RRectType:
1698289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            return gOverstrokeRRectIndices;
1699289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    }
1700289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkFAIL("Invalid type");
1701289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    return 0;
1702ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon}
1703ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon
170476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt///////////////////////////////////////////////////////////////////////////////////////////////////
170576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
170679839d45f893ad5690fc83c951567b3686e781e6Robert Phillips// For distance computations in the interior of filled rrects we:
170779839d45f893ad5690fc83c951567b3686e781e6Robert Phillips//
170879839d45f893ad5690fc83c951567b3686e781e6Robert Phillips//   add a interior degenerate (point or line) rect
170979839d45f893ad5690fc83c951567b3686e781e6Robert Phillips//   each vertex of that rect gets -outerRad as its radius
171079839d45f893ad5690fc83c951567b3686e781e6Robert Phillips//      this makes the computation of the distance to the outer edge be negative
171179839d45f893ad5690fc83c951567b3686e781e6Robert Phillips//      negative values are caught and then handled differently in the GP's onEmitCode
171279839d45f893ad5690fc83c951567b3686e781e6Robert Phillips//   each vertex is also given the normalized x & y distance from the interior rect's edge
171379839d45f893ad5690fc83c951567b3686e781e6Robert Phillips//      the GP takes the min of those depths +1 to get the normalized distance to the outer edge
171479839d45f893ad5690fc83c951567b3686e781e6Robert Phillips
1715289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomonclass CircularRRectOp : public GrMeshDrawOp {
171676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittpublic:
171725a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    DEFINE_OP_CLASS_ID
17181b55a963a2374a14bb82eb887bb99ee91680f0ebreed
17194b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    // A devStrokeWidth <= 0 indicates a fill only. If devStrokeWidth > 0 then strokeOnly indicates
17204b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    // whether the rrect is only stroked or stroked and filled.
1721289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    CircularRRectOp(GrColor color, bool needsDistance, const SkMatrix& viewMatrix,
1722289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    const SkRect& devRect, float devRadius, float devStrokeWidth, bool strokeOnly)
1723289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            : INHERITED(ClassID()), fViewMatrixIfUsingLocalCoords(viewMatrix) {
17244b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkRect bounds = devRect;
17254b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkASSERT(!(devStrokeWidth <= 0 && strokeOnly));
17264b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar innerRadius = 0.0f;
17274b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar outerRadius = devRadius;
17284b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar halfWidth = 0;
172984839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        RRectType type = kFill_RRectType;
17304b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        if (devStrokeWidth > 0) {
17314b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (SkScalarNearlyZero(devStrokeWidth)) {
17324b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                halfWidth = SK_ScalarHalf;
17334b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            } else {
17344b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                halfWidth = SkScalarHalf(devStrokeWidth);
17354b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
173611bf8b2eae7d1780cb969146422a2ab3b933047absalomon
17374b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (strokeOnly) {
1738c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth                // Outset stroke by 1/4 pixel
1739c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth                devStrokeWidth += 0.25f;
1740c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth                // If stroke is greater than width or height, this is still a fill
1741c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth                // Otherwise we compute stroke params
1742289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                if (devStrokeWidth <= devRect.width() && devStrokeWidth <= devRect.height()) {
1743c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth                    innerRadius = devRadius - halfWidth;
174484839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth                    type = (innerRadius >= 0) ? kStroke_RRectType : kOverstroke_RRectType;
1745c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth                }
17464b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
17474b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            outerRadius += halfWidth;
17484b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            bounds.outset(halfWidth, halfWidth);
17494b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        }
175079839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        if (kFill_RRectType == type && needsDistance) {
175179839d45f893ad5690fc83c951567b3686e781e6Robert Phillips            type = kFillWithDist_RRectType;
175279839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        }
175311bf8b2eae7d1780cb969146422a2ab3b933047absalomon
17544b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // The radii are outset for two reasons. First, it allows the shader to simply perform
17554b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
17564b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // Second, the outer radius is used to compute the verts of the bounding box that is
17574b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // rendered and the outset ensures the box will cover all partially covered by the rrect
17584b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        // corners.
17594b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        outerRadius += SK_ScalarHalf;
17604b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        innerRadius -= SK_ScalarHalf;
17614b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
176288cf17d099085b8085ab11571b5094163dbb2c84bsalomon        this->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo);
176388cf17d099085b8085ab11571b5094163dbb2c84bsalomon
176488cf17d099085b8085ab11571b5094163dbb2c84bsalomon        // Expand the rect for aa to generate correct vertices.
17654b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
17664b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
1767289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        fGeoData.emplace_back(Geometry{color, innerRadius, outerRadius, bounds, type});
176884839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        fVertCount = rrect_type_to_vert_count(type);
176984839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        fIndexCount = rrect_type_to_index_count(type);
177084839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        fAllFill = (kFill_RRectType == type);
177176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
177276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1773289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    const char* name() const override { return "CircularRRectOp"; }
177476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1775c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth    SkString dumpInfo() const override {
1776c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth        SkString string;
1777c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth        for (int i = 0; i < fGeoData.count(); ++i) {
1778289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            string.appendf(
1779289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
1780289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "InnerRad: %.2f, OuterRad: %.2f\n",
1781289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    fGeoData[i].fColor, fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop,
1782289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom,
1783289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    fGeoData[i].fInnerRadius, fGeoData[i].fOuterRadius);
1784c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth        }
17857c3e7180948766321c51d165737555e78910de51Brian Salomon        string.append(DumpPipelineInfo(*this->pipeline()));
1786c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth        string.append(INHERITED::dumpInfo());
1787c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth        return string;
1788c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth    }
1789c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth
179092aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomonprivate:
1791c0b642ca48d58416409e555549434066f09692b7Brian Salomon    void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor* color,
1792c0b642ca48d58416409e555549434066f09692b7Brian Salomon                                            GrPipelineAnalysisCoverage* coverage) const override {
1793c0b642ca48d58416409e555549434066f09692b7Brian Salomon        color->setToConstant(fGeoData[0].fColor);
1794c0b642ca48d58416409e555549434066f09692b7Brian Salomon        *coverage = GrPipelineAnalysisCoverage::kSingleChannel;
179576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
179676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
179792aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override {
179892aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        optimizations.getOverrideColorIfSet(&fGeoData[0].fColor);
179992aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        if (!optimizations.readsLocalCoords()) {
1800cdaa97bf664e0d584187efc125bfff670a064a9absalomon            fViewMatrixIfUsingLocalCoords.reset();
1801cdaa97bf664e0d584187efc125bfff670a064a9absalomon        }
180276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
180376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
180479839d45f893ad5690fc83c951567b3686e781e6Robert Phillips    struct CircleVertex {
1805289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        SkPoint fPos;
1806289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        GrColor fColor;
1807289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        SkPoint fOffset;
180879839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        SkScalar fOuterRadius;
180979839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        SkScalar fInnerRadius;
181079839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        // No half plane, we don't use it here.
181179839d45f893ad5690fc83c951567b3686e781e6Robert Phillips    };
181279839d45f893ad5690fc83c951567b3686e781e6Robert Phillips
1813289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    static void FillInOverstrokeVerts(CircleVertex** verts, const SkRect& bounds, SkScalar smInset,
1814289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                      SkScalar bigInset, SkScalar xOffset, SkScalar outerRadius,
1815289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                      SkScalar innerRadius, GrColor color) {
181679839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        SkASSERT(smInset < bigInset);
181779839d45f893ad5690fc83c951567b3686e781e6Robert Phillips
181879839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        // TL
181979839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fPos = SkPoint::Make(bounds.fLeft + smInset, bounds.fTop + smInset);
182079839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fColor = color;
182179839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOffset = SkPoint::Make(xOffset, 0);
182279839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOuterRadius = outerRadius;
18233786c7716c4796146835e60d7145cff252ed50bdRobert Phillips        (*verts)->fInnerRadius = innerRadius;
182479839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)++;
182579839d45f893ad5690fc83c951567b3686e781e6Robert Phillips
182679839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        // TR
1827289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        (*verts)->fPos = SkPoint::Make(bounds.fRight - smInset, bounds.fTop + smInset);
182879839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fColor = color;
182979839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOffset = SkPoint::Make(xOffset, 0);
183079839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOuterRadius = outerRadius;
18313786c7716c4796146835e60d7145cff252ed50bdRobert Phillips        (*verts)->fInnerRadius = innerRadius;
183279839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)++;
183379839d45f893ad5690fc83c951567b3686e781e6Robert Phillips
1834289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        (*verts)->fPos = SkPoint::Make(bounds.fLeft + bigInset, bounds.fTop + bigInset);
183579839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fColor = color;
183679839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOffset = SkPoint::Make(0, 0);
183779839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOuterRadius = outerRadius;
18383786c7716c4796146835e60d7145cff252ed50bdRobert Phillips        (*verts)->fInnerRadius = innerRadius;
183979839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)++;
184079839d45f893ad5690fc83c951567b3686e781e6Robert Phillips
1841289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        (*verts)->fPos = SkPoint::Make(bounds.fRight - bigInset, bounds.fTop + bigInset);
184279839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fColor = color;
184379839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOffset = SkPoint::Make(0, 0);
184479839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOuterRadius = outerRadius;
18453786c7716c4796146835e60d7145cff252ed50bdRobert Phillips        (*verts)->fInnerRadius = innerRadius;
184679839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)++;
184779839d45f893ad5690fc83c951567b3686e781e6Robert Phillips
184879839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fPos = SkPoint::Make(bounds.fLeft + bigInset, bounds.fBottom - bigInset);
184979839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fColor = color;
185079839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOffset = SkPoint::Make(0, 0);
185179839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOuterRadius = outerRadius;
18523786c7716c4796146835e60d7145cff252ed50bdRobert Phillips        (*verts)->fInnerRadius = innerRadius;
185379839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)++;
185479839d45f893ad5690fc83c951567b3686e781e6Robert Phillips
185579839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fPos = SkPoint::Make(bounds.fRight - bigInset, bounds.fBottom - bigInset);
185679839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fColor = color;
185779839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOffset = SkPoint::Make(0, 0);
185879839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOuterRadius = outerRadius;
18593786c7716c4796146835e60d7145cff252ed50bdRobert Phillips        (*verts)->fInnerRadius = innerRadius;
186079839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)++;
186179839d45f893ad5690fc83c951567b3686e781e6Robert Phillips
186279839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        // BL
186379839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fPos = SkPoint::Make(bounds.fLeft + smInset, bounds.fBottom - smInset);
186479839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fColor = color;
186579839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOffset = SkPoint::Make(xOffset, 0);
186679839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOuterRadius = outerRadius;
18673786c7716c4796146835e60d7145cff252ed50bdRobert Phillips        (*verts)->fInnerRadius = innerRadius;
186879839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)++;
186979839d45f893ad5690fc83c951567b3686e781e6Robert Phillips
187079839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        // BR
187179839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fPos = SkPoint::Make(bounds.fRight - smInset, bounds.fBottom - smInset);
187279839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fColor = color;
187379839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOffset = SkPoint::Make(xOffset, 0);
187479839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)->fOuterRadius = outerRadius;
18753786c7716c4796146835e60d7145cff252ed50bdRobert Phillips        (*verts)->fInnerRadius = innerRadius;
187679839d45f893ad5690fc83c951567b3686e781e6Robert Phillips        (*verts)++;
187779839d45f893ad5690fc83c951567b3686e781e6Robert Phillips    }
187879839d45f893ad5690fc83c951567b3686e781e6Robert Phillips
1879144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt    void onPrepareDraws(Target* target) const override {
1880cdaa97bf664e0d584187efc125bfff670a064a9absalomon        // Invert the view matrix as a local matrix (if any other processors require coords).
1881cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkMatrix localMatrix;
1882cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) {
188376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return;
188476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
188576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
188676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
1887289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        sk_sp<GrGeometryProcessor> gp(
1888289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                new CircleGeometryProcessor(!fAllFill, false, false, false, localMatrix));
188976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
189076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
189176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
189284839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        SkASSERT(sizeof(CircleVertex) == vertexStride);
189384839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth
189484839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        const GrBuffer* vertexBuffer;
189584839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        int firstVertex;
189684839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth
1897289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        CircleVertex* verts = (CircleVertex*)target->makeVertexSpace(vertexStride, fVertCount,
1898289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                                                     &vertexBuffer, &firstVertex);
189984839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        if (!verts) {
19004b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            SkDebugf("Could not allocate vertices\n");
19014b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
19024b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
19034b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
190484839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        const GrBuffer* indexBuffer = nullptr;
190584839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        int firstIndex = 0;
190684839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        uint16_t* indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
190784839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        if (!indices) {
190884839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            SkDebugf("Could not allocate indices\n");
190984839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            return;
191084839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        }
191184839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth
191284839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        int currStartVertex = 0;
191376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
1914144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt            const Geometry& args = fGeoData[i];
191576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1916bb2ff94e223014403f775c3532a25cc25b00c949brianosman            GrColor color = args.fColor;
191776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar outerRadius = args.fOuterRadius;
191876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1919bc227140ffea6eb15e2e8b147eb6d8ec6228d95aegdaniel            const SkRect& bounds = args.fDevBounds;
192076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1921289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            SkScalar yCoords[4] = {bounds.fTop, bounds.fTop + outerRadius,
1922289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                   bounds.fBottom - outerRadius, bounds.fBottom};
192376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
1924289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            SkScalar yOuterRadii[4] = {-1, 0, 0, 1};
192576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // The inner radius in the vertex data must be specified in normalized space.
192684839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            // For fills, specifying -1/outerRadius guarantees an alpha of 1.0 at the inner radius.
1927289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            SkScalar innerRadius =
1928289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    args.fType != kFill_RRectType && args.fType != kFillWithDist_RRectType
1929289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                            ? args.fInnerRadius / args.fOuterRadius
1930289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                            : -1.0f / args.fOuterRadius;
193176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            for (int i = 0; i < 4; ++i) {
193276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
1933bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
193476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
193576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadius = outerRadius;
193676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadius = innerRadius;
193776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
193876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
193976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
1940bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
194176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
194276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadius = outerRadius;
194376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadius = innerRadius;
194476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
194576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
194676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
1947bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
194876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
194976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadius = outerRadius;
195076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadius = innerRadius;
195176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
195276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
195376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1954bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
195576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
195676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadius = outerRadius;
195776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadius = innerRadius;
195876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
195976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            }
1960c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth            // Add the additional vertices for overstroked rrects.
1961a4f1af8f9778462184c2bef91de1b1827568c08bjvanverth            // Effectively this is an additional stroked rrect, with its
1962a4f1af8f9778462184c2bef91de1b1827568c08bjvanverth            // outer radius = outerRadius - innerRadius, and inner radius = 0.
1963a4f1af8f9778462184c2bef91de1b1827568c08bjvanverth            // This will give us correct AA in the center and the correct
1964a4f1af8f9778462184c2bef91de1b1827568c08bjvanverth            // distance to the outer edge.
1965c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth            //
1966a4f1af8f9778462184c2bef91de1b1827568c08bjvanverth            // Also, the outer offset is a constant vector pointing to the right, which
1967a4f1af8f9778462184c2bef91de1b1827568c08bjvanverth            // guarantees that the distance value along the outer rectangle is constant.
196884839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            if (kOverstroke_RRectType == args.fType) {
196979839d45f893ad5690fc83c951567b3686e781e6Robert Phillips                SkASSERT(args.fInnerRadius <= 0.0f);
197079839d45f893ad5690fc83c951567b3686e781e6Robert Phillips
1971a4f1af8f9778462184c2bef91de1b1827568c08bjvanverth                SkScalar overstrokeOuterRadius = outerRadius - args.fInnerRadius;
1972a4f1af8f9778462184c2bef91de1b1827568c08bjvanverth                // this is the normalized distance from the outer rectangle of this
1973a4f1af8f9778462184c2bef91de1b1827568c08bjvanverth                // geometry to the outer edge
197484839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth                SkScalar maxOffset = -args.fInnerRadius / overstrokeOuterRadius;
1975a4f1af8f9778462184c2bef91de1b1827568c08bjvanverth
1976289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                FillInOverstrokeVerts(&verts, bounds, outerRadius, overstrokeOuterRadius, maxOffset,
1977289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                      overstrokeOuterRadius, 0.0f, color);
197879839d45f893ad5690fc83c951567b3686e781e6Robert Phillips            }
1979c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth
198079839d45f893ad5690fc83c951567b3686e781e6Robert Phillips            if (kFillWithDist_RRectType == args.fType) {
198179839d45f893ad5690fc83c951567b3686e781e6Robert Phillips                SkScalar halfMinDim = 0.5f * SkTMin(bounds.width(), bounds.height());
19826a3976114d8a6aaa564c3c7571cfe7d1727a3a6ejvanverth
198379839d45f893ad5690fc83c951567b3686e781e6Robert Phillips                SkScalar xOffset = 1.0f - outerRadius / halfMinDim;
19846a3976114d8a6aaa564c3c7571cfe7d1727a3a6ejvanverth
1985289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                FillInOverstrokeVerts(&verts, bounds, outerRadius, halfMinDim, xOffset, halfMinDim,
1986289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                      -1.0f, color);
1987c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth            }
198884839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth
198984839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            const uint16_t* primIndices = rrect_type_to_indices(args.fType);
199084839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            const int primIndexCount = rrect_type_to_index_count(args.fType);
199184839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            for (int i = 0; i < primIndexCount; ++i) {
199284839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth                *indices++ = primIndices[i] + currStartVertex;
199384839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            }
199484839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth
199584839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            currStartVertex += rrect_type_to_vert_count(args.fType);
199676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
199776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
199884839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        GrMesh mesh;
199984839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex,
200084839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth                         firstIndex, fVertCount, fIndexCount);
200184839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        target->draw(gp.get(), mesh);
200276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
200376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
200425a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
2005289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        CircularRRectOp* that = t->cast<CircularRRectOp>();
20068cefe40ab094bfbea532761dad1a857eb3d4b831Jim Van Verth
20078cefe40ab094bfbea532761dad1a857eb3d4b831Jim Van Verth        // can only represent 65535 unique vertices with 16-bit indices
2008e549a05dc20c84597b324b19b9764136da54e5f1Jim Van Verth        if (fVertCount + that->fVertCount > 65536) {
20098cefe40ab094bfbea532761dad1a857eb3d4b831Jim Van Verth            return false;
20108cefe40ab094bfbea532761dad1a857eb3d4b831Jim Van Verth        }
20118cefe40ab094bfbea532761dad1a857eb3d4b831Jim Van Verth
2012abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
2013abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                    that->bounds(), caps)) {
20148cab9a7685e872427e6f0388f149575a9b6016eejoshualitt            return false;
20158cab9a7685e872427e6f0388f149575a9b6016eejoshualitt        }
20168cab9a7685e872427e6f0388f149575a9b6016eejoshualitt
2017cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
201876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
201976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
202076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2021cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
202288cf17d099085b8085ab11571b5094163dbb2c84bsalomon        this->joinBounds(*that);
202384839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        fVertCount += that->fVertCount;
202484839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        fIndexCount += that->fIndexCount;
202584839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        fAllFill = fAllFill && that->fAllFill;
202676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
202776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
202876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
20294b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    struct Geometry {
2030289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        GrColor fColor;
20314b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fInnerRadius;
20324b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fOuterRadius;
20334b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkRect fDevBounds;
203484839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        RRectType fType;
20354b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    };
20364b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
203776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    SkSTArray<1, Geometry, true> fGeoData;
2038289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkMatrix fViewMatrixIfUsingLocalCoords;
2039289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    int fVertCount;
2040289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    int fIndexCount;
2041289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    bool fAllFill;
20421b55a963a2374a14bb82eb887bb99ee91680f0ebreed
2043dad2923b8ec9270d810c1e8e76da8e6768d8f9ddBrian Salomon    typedef GrMeshDrawOp INHERITED;
204476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
204576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
204684839f6fb3d0de9088be3d53e81df195331ed1c9jvanverthstatic const int kNumRRectsInIndexBuffer = 256;
204784839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth
204884839f6fb3d0de9088be3d53e81df195331ed1c9jvanverthGR_DECLARE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
204984839f6fb3d0de9088be3d53e81df195331ed1c9jvanverthGR_DECLARE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
205084839f6fb3d0de9088be3d53e81df195331ed1c9jvanverthstatic const GrBuffer* ref_rrect_index_buffer(RRectType type,
205184839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth                                              GrResourceProvider* resourceProvider) {
205284839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth    GR_DEFINE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
205384839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth    GR_DEFINE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
205484839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth    switch (type) {
205584839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        case kFill_RRectType:
205684839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            return resourceProvider->findOrCreateInstancedIndexBuffer(
2057289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    gStandardRRectIndices, kIndicesPerFillRRect, kNumRRectsInIndexBuffer,
2058289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    kVertsPerStandardRRect, gRRectOnlyIndexBufferKey);
205984839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        case kStroke_RRectType:
206084839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            return resourceProvider->findOrCreateInstancedIndexBuffer(
2061289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    gStandardRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer,
2062289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    kVertsPerStandardRRect, gStrokeRRectOnlyIndexBufferKey);
206384839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth        default:
206484839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            SkASSERT(false);
206584839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth            return nullptr;
206684839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth    };
206784839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth}
206884839f6fb3d0de9088be3d53e81df195331ed1c9jvanverth
2069289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomonclass EllipticalRRectOp : public GrMeshDrawOp {
207076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualittpublic:
207125a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    DEFINE_OP_CLASS_ID
20721b55a963a2374a14bb82eb887bb99ee91680f0ebreed
20734b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    // If devStrokeWidths values are <= 0 indicates then fill only. Otherwise, strokeOnly indicates
20744b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    // whether the rrect is only stroked or stroked and filled.
2075649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon    static std::unique_ptr<GrMeshDrawOp> Make(GrColor color, const SkMatrix& viewMatrix,
2076649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                              const SkRect& devRect, float devXRadius,
2077649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                              float devYRadius, SkVector devStrokeWidths,
2078649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                              bool strokeOnly) {
20794b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkASSERT(devXRadius > 0.5);
20804b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkASSERT(devYRadius > 0.5);
20814b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkASSERT((devStrokeWidths.fX > 0) == (devStrokeWidths.fY > 0));
20824b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkASSERT(!(strokeOnly && devStrokeWidths.fX <= 0));
20834b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar innerXRadius = 0.0f;
20844b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar innerYRadius = 0.0f;
20854b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkRect bounds = devRect;
20864b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        bool stroked = false;
20874b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        if (devStrokeWidths.fX > 0) {
20884b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (SkScalarNearlyZero(devStrokeWidths.length())) {
20894b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                devStrokeWidths.set(SK_ScalarHalf, SK_ScalarHalf);
20904b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            } else {
20914b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                devStrokeWidths.scale(SK_ScalarHalf);
20924b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
20934b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
20944b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            // we only handle thick strokes for near-circular ellipses
20954b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (devStrokeWidths.length() > SK_ScalarHalf &&
2096289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                (SK_ScalarHalf * devXRadius > devYRadius ||
2097289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                 SK_ScalarHalf * devYRadius > devXRadius)) {
20984b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                return nullptr;
20994b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
21004b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
21014b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            // we don't handle it if curvature of the stroke is less than curvature of the ellipse
2102289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            if (devStrokeWidths.fX * (devYRadius * devYRadius) <
2103289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                (devStrokeWidths.fY * devStrokeWidths.fY) * devXRadius) {
21044b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                return nullptr;
21054b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
2106289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            if (devStrokeWidths.fY * (devXRadius * devXRadius) <
2107289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                (devStrokeWidths.fX * devStrokeWidths.fX) * devYRadius) {
21084b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                return nullptr;
21094b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
211011bf8b2eae7d1780cb969146422a2ab3b933047absalomon
21114b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            // this is legit only if scale & translation (which should be the case at the moment)
21124b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            if (strokeOnly) {
21134b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                innerXRadius = devXRadius - devStrokeWidths.fX;
21144b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                innerYRadius = devYRadius - devStrokeWidths.fY;
21154b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon                stroked = (innerXRadius >= 0 && innerYRadius >= 0);
21164b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            }
21174b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
21184b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            devXRadius += devStrokeWidths.fX;
21194b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            devYRadius += devStrokeWidths.fY;
21204b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon            bounds.outset(devStrokeWidths.fX, devStrokeWidths.fY);
21214b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        }
21224b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
2123f8334781914363caf537f22f012fcd5c03c60dadBrian Salomon        std::unique_ptr<EllipticalRRectOp> op(new EllipticalRRectOp());
2124289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->fStroked = stroked;
2125289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->fViewMatrixIfUsingLocalCoords = viewMatrix;
2126289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo);
212788cf17d099085b8085ab11571b5094163dbb2c84bsalomon        // Expand the rect for aa in order to generate the correct vertices.
212888cf17d099085b8085ab11571b5094163dbb2c84bsalomon        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
2129289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        op->fGeoData.emplace_back(
2130289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                Geometry{color, devXRadius, devYRadius, innerXRadius, innerYRadius, bounds});
2131289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        return std::move(op);
213276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
213376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2134289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    const char* name() const override { return "EllipticalRRectOp"; }
213576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
21367c3e7180948766321c51d165737555e78910de51Brian Salomon    SkString dumpInfo() const override {
21377c3e7180948766321c51d165737555e78910de51Brian Salomon        SkString string;
21387c3e7180948766321c51d165737555e78910de51Brian Salomon        string.appendf("Stroked: %d\n", fStroked);
21397c3e7180948766321c51d165737555e78910de51Brian Salomon        for (const auto& geo : fGeoData) {
2140289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            string.appendf(
2141289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
2142289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    "XRad: %.2f, YRad: %.2f, InnerXRad: %.2f, InnerYRad: %.2f\n",
2143289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    geo.fColor, geo.fDevBounds.fLeft, geo.fDevBounds.fTop, geo.fDevBounds.fRight,
2144289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    geo.fDevBounds.fBottom, geo.fXRadius, geo.fYRadius, geo.fInnerXRadius,
2145289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    geo.fInnerYRadius);
21467c3e7180948766321c51d165737555e78910de51Brian Salomon        }
21477c3e7180948766321c51d165737555e78910de51Brian Salomon        string.append(DumpPipelineInfo(*this->pipeline()));
21487c3e7180948766321c51d165737555e78910de51Brian Salomon        string.append(INHERITED::dumpInfo());
21497c3e7180948766321c51d165737555e78910de51Brian Salomon        return string;
21507c3e7180948766321c51d165737555e78910de51Brian Salomon    }
21517c3e7180948766321c51d165737555e78910de51Brian Salomon
2152e46f9feb44780a6269c6dcfe993f4215427fd98ebsalomonprivate:
2153289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    EllipticalRRectOp() : INHERITED(ClassID()) {}
21544b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
2155c0b642ca48d58416409e555549434066f09692b7Brian Salomon    void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor* color,
2156c0b642ca48d58416409e555549434066f09692b7Brian Salomon                                            GrPipelineAnalysisCoverage* coverage) const override {
2157c0b642ca48d58416409e555549434066f09692b7Brian Salomon        color->setToConstant(fGeoData[0].fColor);
2158c0b642ca48d58416409e555549434066f09692b7Brian Salomon        *coverage = GrPipelineAnalysisCoverage::kSingleChannel;
215992aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    }
216092aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon
216192aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override {
216292aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        optimizations.getOverrideColorIfSet(&fGeoData[0].fColor);
216392aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        if (!optimizations.readsLocalCoords()) {
2164cdaa97bf664e0d584187efc125bfff670a064a9absalomon            fViewMatrixIfUsingLocalCoords.reset();
2165cdaa97bf664e0d584187efc125bfff670a064a9absalomon        }
216676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
216776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2168144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt    void onPrepareDraws(Target* target) const override {
2169cdaa97bf664e0d584187efc125bfff670a064a9absalomon        SkMatrix localMatrix;
2170cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) {
217176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return;
217276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
217376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
217476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        // Setup geometry processor
2175144caf55ffc692bcda77703a73bb9a894f7d024fHal Canary        sk_sp<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, localMatrix));
217676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
217776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        int instanceCount = fGeoData.count();
217876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        size_t vertexStride = gp->getVertexStride();
217976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        SkASSERT(vertexStride == sizeof(EllipseVertex));
218076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2181b5238a7571c243ba4a154a62575570c3078b3741bsalomon        // drop out the middle quad if we're stroked
2182c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth        int indicesPerInstance = fStroked ? kIndicesPerStrokeRRect : kIndicesPerFillRRect;
2183289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        sk_sp<const GrBuffer> indexBuffer(ref_rrect_index_buffer(
2184289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                fStroked ? kStroke_RRectType : kFill_RRectType, target->resourceProvider()));
218576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2186b5238a7571c243ba4a154a62575570c3078b3741bsalomon        InstancedHelper helper;
2187b5238a7571c243ba4a154a62575570c3078b3741bsalomon        EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
2188289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(),
2189289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                            kVertsPerStandardRRect, indicesPerInstance, instanceCount));
2190b5238a7571c243ba4a154a62575570c3078b3741bsalomon        if (!verts || !indexBuffer) {
21914b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            SkDebugf("Could not allocate vertices\n");
21924b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt            return;
21934b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt        }
21944b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt
219576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        for (int i = 0; i < instanceCount; i++) {
2196144c3c8b7ff3ebc389b41211f3388fb24a7ff0c2joshualitt            const Geometry& args = fGeoData[i];
219776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2198bb2ff94e223014403f775c3532a25cc25b00c949brianosman            GrColor color = args.fColor;
2199bb2ff94e223014403f775c3532a25cc25b00c949brianosman
220076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // Compute the reciprocals of the radii here to save time in the shader
220176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar xRadRecip = SkScalarInvert(args.fXRadius);
220276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yRadRecip = SkScalarInvert(args.fYRadius);
220376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar xInnerRadRecip = SkScalarInvert(args.fInnerXRadius);
220476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yInnerRadRecip = SkScalarInvert(args.fInnerYRadius);
220576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
220676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            // Extend the radii out half a pixel to antialias.
220776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar xOuterRadius = args.fXRadius + SK_ScalarHalf;
220876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            SkScalar yOuterRadius = args.fYRadius + SK_ScalarHalf;
220976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2210bc227140ffea6eb15e2e8b147eb6d8ec6228d95aegdaniel            const SkRect& bounds = args.fDevBounds;
221176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2212289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            SkScalar yCoords[4] = {bounds.fTop, bounds.fTop + yOuterRadius,
2213289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                   bounds.fBottom - yOuterRadius, bounds.fBottom};
2214289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            SkScalar yOuterOffsets[4] = {yOuterRadius,
2215289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                         SK_ScalarNearlyZero,  // we're using inversesqrt() in
2216289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                                               // shader, so can't be exactly 0
2217289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                         SK_ScalarNearlyZero, yOuterRadius};
221876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
221976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            for (int i = 0; i < 4; ++i) {
222076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
2221bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
222276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
222376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
222476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
222576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
222676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
222776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]);
2228bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
222976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
223076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
223176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
223276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
223376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
223476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]);
2235bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
223676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
223776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
223876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
223976e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
224076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
224176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
2242bb2ff94e223014403f775c3532a25cc25b00c949brianosman                verts->fColor = color;
224376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
224476e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
224576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
224676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt                verts++;
224776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            }
224876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
2249144caf55ffc692bcda77703a73bb9a894f7d024fHal Canary        helper.recordDraw(target, gp.get());
225076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
225176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
225225a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
2253289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        EllipticalRRectOp* that = t->cast<EllipticalRRectOp>();
2254abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon
2255abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
2256abd30f54b7ff1704a8930c4307ea242d09425d02bsalomon                                    that->bounds(), caps)) {
22578cab9a7685e872427e6f0388f149575a9b6016eejoshualitt            return false;
22588cab9a7685e872427e6f0388f149575a9b6016eejoshualitt        }
22598cab9a7685e872427e6f0388f149575a9b6016eejoshualitt
2260cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (fStroked != that->fStroked) {
226176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
226276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
226376e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2264cdaa97bf664e0d584187efc125bfff670a064a9absalomon        if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
226576e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt            return false;
226676e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        }
226776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2268cdaa97bf664e0d584187efc125bfff670a064a9absalomon        fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
226988cf17d099085b8085ab11571b5094163dbb2c84bsalomon        this->joinBounds(*that);
227076e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt        return true;
227176e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt    }
227276e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
22734b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    struct Geometry {
22744b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        GrColor fColor;
22754b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fXRadius;
22764b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fYRadius;
22774b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fInnerXRadius;
22784b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkScalar fInnerYRadius;
22794b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon        SkRect fDevBounds;
22804b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    };
22814b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
2282289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    bool fStroked;
2283289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkMatrix fViewMatrixIfUsingLocalCoords;
2284289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkSTArray<1, Geometry, true> fGeoData;
22851b55a963a2374a14bb82eb887bb99ee91680f0ebreed
2286dad2923b8ec9270d810c1e8e76da8e6768d8f9ddBrian Salomon    typedef GrMeshDrawOp INHERITED;
228776e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt};
228876e7fb6cbaa0994778cc4cf48bfe5e70bae59821joshualitt
2289649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomonstatic std::unique_ptr<GrMeshDrawOp> make_rrect_op(GrColor color,
2290649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                   bool needsDistance,
2291649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                   const SkMatrix& viewMatrix,
2292649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                   const SkRRect& rrect,
2293649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                   const SkStrokeRec& stroke) {
22943e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkASSERT(viewMatrix.rectStaysRect());
22953e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkASSERT(rrect.isSimple());
22963e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkASSERT(!rrect.isOval());
22973e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
229853e4c3c0da40b58638d05e0f753ab6d450b961f5Brian Salomon    // RRect ops only handle simple, but not too simple, rrects.
229953e4c3c0da40b58638d05e0f753ab6d450b961f5Brian Salomon    // Do any matrix crunching before we reset the draw state for device coords.
2300f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    const SkRect& rrectBounds = rrect.getBounds();
2301d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    SkRect bounds;
2302d96a67bcb196aa4f73ff773bd45810a94ca872d8joshualitt    viewMatrix.mapRect(&bounds, rrectBounds);
2303f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
2304f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    SkVector radii = rrect.getSimpleRadii();
2305289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX] * radii.fX +
2306289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                   viewMatrix[SkMatrix::kMSkewY] * radii.fY);
2307289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX] * radii.fX +
2308289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                   viewMatrix[SkMatrix::kMScaleY] * radii.fY);
23096bb3efc4db8e4e348c6ef6033ffaf8410a82eae5commit-bot@chromium.org
2310f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    SkStrokeRec::Style style = stroke.getStyle();
2311f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
23124b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    // Do (potentially) anisotropic mapping of stroke. Use -1s to indicate fill-only draws.
23134b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    SkVector scaledStroke = {-1, -1};
2314f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    SkScalar strokeWidth = stroke.getWidth();
2315f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
2316289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    bool isStrokeOnly =
2317289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style;
23180a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
23190a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org
2320c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth    bool isCircular = (xRadius == yRadius);
23210a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    if (hasStroke) {
23220a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        if (SkStrokeRec::kHairline_Style == style) {
23230a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org            scaledStroke.set(1, 1);
23240a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        } else {
2325289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            scaledStroke.fX = SkScalarAbs(
2326289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    strokeWidth * (viewMatrix[SkMatrix::kMScaleX] + viewMatrix[SkMatrix::kMSkewY]));
2327289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon            scaledStroke.fY = SkScalarAbs(
2328289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                    strokeWidth * (viewMatrix[SkMatrix::kMSkewX] + viewMatrix[SkMatrix::kMScaleY]));
23290a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        }
23300a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org
2331c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth        isCircular = isCircular && scaledStroke.fX == scaledStroke.fY;
2332c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth        // for non-circular rrects, if half of strokewidth is greater than radius,
2333c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth        // we don't handle that right now
2334289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        if (!isCircular && (SK_ScalarHalf * scaledStroke.fX > xRadius ||
2335289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                            SK_ScalarHalf * scaledStroke.fY > yRadius)) {
233696fcdcc219d2a0d3579719b84b28bede76efba64halcanary            return nullptr;
23370a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org        }
23380a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    }
23390a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org
23400a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // The way the effect interpolates the offset-to-ellipse/circle-center attribute only works on
23410a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner rect of the nine-
23420a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // patch will have fractional coverage. This only matters when the interior is actually filled.
23430a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // We could consider falling back to rect rendering here, since a tiny radius is
23440a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    // indistinguishable from a square corner.
23450a09d7195b8d9945e5c9c76cc4cfe6ef65d6d390commit-bot@chromium.org    if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
234696fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
2347f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    }
2348f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org
2349f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    // if the corners are circles, use the circle renderer
2350c3d0e422761702c52a974411eaf0b06d223fe98ejvanverth    if (isCircular) {
2351649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon        return std::unique_ptr<GrMeshDrawOp>(new CircularRRectOp(
2352f8334781914363caf537f22f012fcd5c03c60dadBrian Salomon                color, needsDistance, viewMatrix, bounds, xRadius, scaledStroke.fX, isStrokeOnly));
2353289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        // otherwise we use the ellipse renderer
2354f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    } else {
2355289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        return EllipticalRRectOp::Make(color, viewMatrix, bounds, xRadius, yRadius, scaledStroke,
2356289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                       isStrokeOnly);
2357f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org    }
23583e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
23593e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
2360649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomonstd::unique_ptr<GrMeshDrawOp> GrOvalOpFactory::MakeRRectOp(GrColor color,
2361649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                           bool needsDistance,
2362649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                           const SkMatrix& viewMatrix,
2363649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                           const SkRRect& rrect,
2364649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                           const SkStrokeRec& stroke,
2365649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                           const GrShaderCaps* shaderCaps) {
23660cc2f85a19d50b45573d71d8c9d6ee1292c9fd3arobertphillips    if (rrect.isOval()) {
2367289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        return MakeOvalOp(color, viewMatrix, rrect.getBounds(), stroke, shaderCaps);
23683e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    }
23693e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
23700cc2f85a19d50b45573d71d8c9d6ee1292c9fd3arobertphillips    if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) {
23710cc2f85a19d50b45573d71d8c9d6ee1292c9fd3arobertphillips        return nullptr;
23723e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    }
23733e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
2374289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    return make_rrect_op(color, needsDistance, viewMatrix, rrect, stroke);
2375f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2commit-bot@chromium.org}
23763e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
23774b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon///////////////////////////////////////////////////////////////////////////////
23784b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
2379649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomonstd::unique_ptr<GrMeshDrawOp> GrOvalOpFactory::MakeOvalOp(GrColor color,
2380649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                          const SkMatrix& viewMatrix,
2381649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                          const SkRect& oval,
2382649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                          const SkStrokeRec& stroke,
2383649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                          const GrShaderCaps* shaderCaps) {
23844b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    // we can draw circles
23854f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    SkScalar width = oval.width();
23864f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    if (SkScalarNearlyEqual(width, oval.height()) && circle_stays_circle(viewMatrix)) {
23874f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkPoint center = {oval.centerX(), oval.centerY()};
2388289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        return CircleOp::Make(color, viewMatrix, center, width / 2.f, GrStyle(stroke, nullptr));
23894b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    }
23904b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
2391eb868aa3a25e7b380e28ceffb45b89185af1afebStan Iliev    // prefer the device space ellipse op for batchability
23924b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    if (viewMatrix.rectStaysRect()) {
2393289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        return EllipseOp::Make(color, viewMatrix, oval, stroke);
23944b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    }
23954b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
2396eb868aa3a25e7b380e28ceffb45b89185af1afebStan Iliev    // Otherwise, if we have shader derivative support, render as device-independent
2397eb868aa3a25e7b380e28ceffb45b89185af1afebStan Iliev    if (shaderCaps->shaderDerivativeSupport()) {
2398eb868aa3a25e7b380e28ceffb45b89185af1afebStan Iliev        return DIEllipseOp::Make(color, viewMatrix, oval, stroke);
2399eb868aa3a25e7b380e28ceffb45b89185af1afebStan Iliev    }
2400eb868aa3a25e7b380e28ceffb45b89185af1afebStan Iliev
24014b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon    return nullptr;
24024b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon}
24034b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon
24044b4a7cca638ce18b97399e40d158a7e9fb448d64bsalomon///////////////////////////////////////////////////////////////////////////////
24053e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
2406649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomonstd::unique_ptr<GrMeshDrawOp> GrOvalOpFactory::MakeArcOp(GrColor color, const SkMatrix& viewMatrix,
2407649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                         const SkRect& oval, SkScalar startAngle,
2408649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                         SkScalar sweepAngle, bool useCenter,
2409649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                         const GrStyle& style,
2410649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                         const GrShaderCaps* shaderCaps) {
241121af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon    SkASSERT(!oval.isEmpty());
241221af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon    SkASSERT(sweepAngle);
24134f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    SkScalar width = oval.width();
241421af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon    if (SkScalarAbs(sweepAngle) >= 360.f) {
241521af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon        return nullptr;
241621af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon    }
24174f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    if (!SkScalarNearlyEqual(width, oval.height()) || !circle_stays_circle(viewMatrix)) {
24184f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        return nullptr;
24194f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    }
24204f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    SkPoint center = {oval.centerX(), oval.centerY()};
2421289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    CircleOp::ArcParams arcParams = {SkDegreesToRadians(startAngle), SkDegreesToRadians(sweepAngle),
2422289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon                                     useCenter};
2423289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon    return CircleOp::Make(color, viewMatrix, center, width / 2.f, style, &arcParams);
24244f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon}
24254f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon
24264f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon///////////////////////////////////////////////////////////////////////////////
24274f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon
24286f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#if GR_TEST_UTILS
24293e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
24305ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian SalomonDRAW_OP_TEST_DEFINE(CircleOp) {
24314f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    do {
2432cadf75a8a41a11081af344c25601aad09099d0b4bsalomon        SkScalar rotate = random->nextSScalar1() * 360.f;
2433cadf75a8a41a11081af344c25601aad09099d0b4bsalomon        SkScalar translateX = random->nextSScalar1() * 1000.f;
2434cadf75a8a41a11081af344c25601aad09099d0b4bsalomon        SkScalar translateY = random->nextSScalar1() * 1000.f;
2435cadf75a8a41a11081af344c25601aad09099d0b4bsalomon        SkScalar scale = random->nextSScalar1() * 100.f;
2436cadf75a8a41a11081af344c25601aad09099d0b4bsalomon        SkMatrix viewMatrix;
2437cadf75a8a41a11081af344c25601aad09099d0b4bsalomon        viewMatrix.setRotate(rotate);
2438cadf75a8a41a11081af344c25601aad09099d0b4bsalomon        viewMatrix.postTranslate(translateX, translateY);
2439cadf75a8a41a11081af344c25601aad09099d0b4bsalomon        viewMatrix.postScale(scale, scale);
24404f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        GrColor color = GrRandomColor(random);
24414f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkRect circle = GrTest::TestSquare(random);
24424f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkPoint center = {circle.centerX(), circle.centerY()};
24434f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkScalar radius = circle.width() / 2.f;
24444f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        SkStrokeRec stroke = GrTest::TestStrokeRec(random);
2445289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        CircleOp::ArcParams arcParamsTmp;
2446289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        const CircleOp::ArcParams* arcParams = nullptr;
24474f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        if (random->nextBool()) {
24484f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            arcParamsTmp.fStartAngleRadians = random->nextSScalar1() * SK_ScalarPI * 2;
244908197b22656c1b1200b0ac7b50e247b998a6db11robertphillips            arcParamsTmp.fSweepAngleRadians = random->nextSScalar1() * SK_ScalarPI * 2 - .01f;
245008197b22656c1b1200b0ac7b50e247b998a6db11robertphillips            arcParamsTmp.fUseCenter = random->nextBool();
24514f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon            arcParams = &arcParamsTmp;
24524f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        }
2453649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon        std::unique_ptr<GrMeshDrawOp> op = CircleOp::Make(color, viewMatrix, center, radius,
2454649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                          GrStyle(stroke, nullptr), arcParams);
2455289e3d8dd70b08b509aa29594fe831e0278304efBrian Salomon        if (op) {
24565ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian Salomon            return op;
24574f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon        }
24584f3a0ca85d28a8fc7fcc1ac5c4a1864c66bdea14bsalomon    } while (true);
24593e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
24603e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
24615ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian SalomonDRAW_OP_TEST_DEFINE(EllipseOp) {
24623e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
24633e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    GrColor color = GrRandomColor(random);
24646c891107ce0a8431f2327cb8b2f1bfd363cabbbejoshualitt    SkRect ellipse = GrTest::TestSquare(random);
24655ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian Salomon    return EllipseOp::Make(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random));
24663e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
24673e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
24685ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian SalomonDRAW_OP_TEST_DEFINE(DIEllipseOp) {
24693e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkMatrix viewMatrix = GrTest::TestMatrix(random);
24703e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    GrColor color = GrRandomColor(random);
24716c891107ce0a8431f2327cb8b2f1bfd363cabbbejoshualitt    SkRect ellipse = GrTest::TestSquare(random);
24725ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian Salomon    return DIEllipseOp::Make(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random));
24733e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
24743e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
24755ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian SalomonDRAW_OP_TEST_DEFINE(RRectOp) {
24763e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
24773e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    GrColor color = GrRandomColor(random);
24783e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt    const SkRRect& rrect = GrTest::TestRRectSimple(random);
247979839d45f893ad5690fc83c951567b3686e781e6Robert Phillips    bool needsDistance = random->nextBool();
24805ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian Salomon    return make_rrect_op(color, needsDistance, viewMatrix, rrect, GrTest::TestStrokeRec(random));
24813e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt}
24823e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt
24833e708c53f79a04b588b6ca8e535e61f986d80b47joshualitt#endif
2484