1c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth/*
2c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth * Copyright 2016 Google Inc.
3c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth *
4c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth * Use of this source code is governed by a BSD-style license that can be
5c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth * found in the LICENSE file.
6c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth */
7c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
8fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon#include "GrShadowRRectOp.h"
9c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
105ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian Salomon#include "GrDrawOpTest.h"
11742e31de1599f3902810aecdf2e2e3eed3b40a09Brian Salomon#include "GrOpFlushState.h"
12c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth#include "GrResourceProvider.h"
13c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth#include "GrStyle.h"
14c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
15c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth#include "effects/GrShadowGeoProc.h"
16c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
17c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth///////////////////////////////////////////////////////////////////////////////
18c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
19c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// We have two possible cases for geometry for a circle:
20c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
21c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// In the case of a normal fill, we draw geometry for the circle as an octagon.
22c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const uint16_t gFillCircleIndices[] = {
23fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        // enter the octagon
24fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        // clang-format off
25fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        0, 1, 8, 1, 2, 8,
26fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        2, 3, 8, 3, 4, 8,
27fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        4, 5, 8, 5, 6, 8,
28fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        6, 7, 8, 7, 0, 8,
29fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        // clang-format on
30c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth};
31c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
32c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// For stroked circles, we use two nested octagons.
33c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const uint16_t gStrokeCircleIndices[] = {
34fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        // enter the octagon
35fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        // clang-format off
36fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        0, 1,  9, 0,  9,  8,
37fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        1, 2, 10, 1, 10,  9,
38fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        2, 3, 11, 2, 11, 10,
39fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        3, 4, 12, 3, 12, 11,
40fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        4, 5, 13, 4, 13, 12,
41fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        5, 6, 14, 5, 14, 13,
42fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        6, 7, 15, 6, 15, 14,
43fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        7, 0,  8, 7,  8, 15,
44fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        // clang-format on
45c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth};
46c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
47c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const int kIndicesPerFillCircle = SK_ARRAY_COUNT(gFillCircleIndices);
48c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const int kIndicesPerStrokeCircle = SK_ARRAY_COUNT(gStrokeCircleIndices);
49c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const int kVertsPerStrokeCircle = 16;
50c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const int kVertsPerFillCircle = 9;
51c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
52c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic int circle_type_to_vert_count(bool stroked) {
53c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    return stroked ? kVertsPerStrokeCircle : kVertsPerFillCircle;
54c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth}
55c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
56c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic int circle_type_to_index_count(bool stroked) {
57c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    return stroked ? kIndicesPerStrokeCircle : kIndicesPerFillCircle;
58c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth}
59c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
60c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const uint16_t* circle_type_to_indices(bool stroked) {
61c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    return stroked ? gStrokeCircleIndices : gFillCircleIndices;
62c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth}
63c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
64c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth///////////////////////////////////////////////////////////////////////////////
65c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
66fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomonclass ShadowCircleOp final : public GrMeshDrawOp {
67c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthpublic:
6825a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    DEFINE_OP_CLASS_ID
69c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
70649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon    static std::unique_ptr<GrMeshDrawOp> Make(GrColor color, const SkMatrix& viewMatrix,
71649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                              SkPoint center, SkScalar radius, SkScalar blurRadius,
72649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                              const GrStyle& style) {
73c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkASSERT(viewMatrix.isSimilarity());
74c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        const SkStrokeRec& stroke = style.strokeRec();
75c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (style.hasPathEffect()) {
76c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            return nullptr;
77c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
78c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkStrokeRec::Style recStyle = stroke.getStyle();
79c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
80c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        viewMatrix.mapPoints(&center, 1);
81c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        radius = viewMatrix.mapRadius(radius);
82c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
83c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
84fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        bool isStrokeOnly =
85fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                SkStrokeRec::kStroke_Style == recStyle || SkStrokeRec::kHairline_Style == recStyle;
86c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == recStyle;
87c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
88c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar innerRadius = -SK_ScalarHalf;
89c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar outerRadius = radius;
90c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar halfWidth = 0;
91c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (hasStroke) {
92c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            if (SkScalarNearlyZero(strokeWidth)) {
93c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                halfWidth = SK_ScalarHalf;
94c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            } else {
95c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                halfWidth = SkScalarHalf(strokeWidth);
96c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            }
97c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
98c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            outerRadius += halfWidth;
99c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            if (isStrokeOnly) {
100c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                innerRadius = radius - halfWidth;
101c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            }
102c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
103c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
104c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        bool stroked = isStrokeOnly && innerRadius > 0.0f;
105f8334781914363caf537f22f012fcd5c03c60dadBrian Salomon        std::unique_ptr<ShadowCircleOp> op(new ShadowCircleOp());
106fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        op->fViewMatrixIfUsingLocalCoords = viewMatrix;
107c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
108c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkRect devBounds = SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius,
109c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                                            center.fX + outerRadius, center.fY + outerRadius);
110c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
11192aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        op->fCircles.emplace_back(
11292aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon                Circle{color, outerRadius, innerRadius, blurRadius, devBounds, stroked});
113c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
114c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        // Use the original radius and stroke radius for the bounds so that it does not include the
115c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        // AA bloat.
116c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        radius += halfWidth;
117fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        op->setBounds(
118fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                {center.fX - radius, center.fY - radius, center.fX + radius, center.fY + radius},
119fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                HasAABloat::kNo, IsZeroArea::kNo);
120fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        op->fVertCount = circle_type_to_vert_count(stroked);
121fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        op->fIndexCount = circle_type_to_index_count(stroked);
122fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        return std::move(op);
123c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
124c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
125fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    const char* name() const override { return "ShadowCircleOp"; }
126c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
127c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkString dumpInfo() const override {
128c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkString string;
12992aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        for (int i = 0; i < fCircles.count(); ++i) {
130fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            string.appendf(
131fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                    "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
132fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                    "OuterRad: %.2f, InnerRad: %.2f, BlurRad: %.2f\n",
13392aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon                    fCircles[i].fColor, fCircles[i].fDevBounds.fLeft, fCircles[i].fDevBounds.fTop,
13492aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon                    fCircles[i].fDevBounds.fRight, fCircles[i].fDevBounds.fBottom,
13592aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon                    fCircles[i].fOuterRadius, fCircles[i].fInnerRadius, fCircles[i].fBlurRadius);
136c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
1377c3e7180948766321c51d165737555e78910de51Brian Salomon        string.append(DumpPipelineInfo(*this->pipeline()));
138c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        string.append(INHERITED::dumpInfo());
139c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        return string;
140c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
141c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
142c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthprivate:
143fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    ShadowCircleOp() : INHERITED(ClassID()) {}
14492aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon
145c0b642ca48d58416409e555549434066f09692b7Brian Salomon    void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor* color,
146c0b642ca48d58416409e555549434066f09692b7Brian Salomon                                            GrPipelineAnalysisCoverage* coverage) const override {
147c0b642ca48d58416409e555549434066f09692b7Brian Salomon        color->setToConstant(fCircles[0].fColor);
148c0b642ca48d58416409e555549434066f09692b7Brian Salomon        *coverage = GrPipelineAnalysisCoverage::kSingleChannel;
14992aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    }
15092aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon
15192aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override {
15292aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        optimizations.getOverrideColorIfSet(&fCircles[0].fColor);
15392aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        if (!optimizations.readsLocalCoords()) {
154c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            fViewMatrixIfUsingLocalCoords.reset();
155c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
156c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
157c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
158c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    void onPrepareDraws(Target* target) const override {
159c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkMatrix localMatrix;
160c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) {
161c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            return;
162c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
163c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
164c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        // Setup geometry processor
165c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        sk_sp<GrGeometryProcessor> gp(GrRRectShadowGeoProc::Make(localMatrix));
166c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
167c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        struct CircleVertex {
168fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            SkPoint fPos;
169fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            GrColor fColor;
170fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            SkPoint fOffset;
171c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            SkScalar fOuterRadius;
172c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            SkScalar fBlurRadius;
173c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        };
174c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
17592aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        int instanceCount = fCircles.count();
176c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        size_t vertexStride = gp->getVertexStride();
177c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkASSERT(vertexStride == sizeof(CircleVertex));
178c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
179c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        const GrBuffer* vertexBuffer;
180c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        int firstVertex;
181fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        char* vertices = (char*)target->makeVertexSpace(vertexStride, fVertCount, &vertexBuffer,
182fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                                                        &firstVertex);
183c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (!vertices) {
184c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            SkDebugf("Could not allocate vertices\n");
185c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            return;
186c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
187c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
188c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        const GrBuffer* indexBuffer = nullptr;
189c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        int firstIndex = 0;
190c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        uint16_t* indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
191c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (!indices) {
192c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            SkDebugf("Could not allocate indices\n");
193c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            return;
194c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
195c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
196c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        int currStartVertex = 0;
197c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        for (int i = 0; i < instanceCount; i++) {
19892aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon            const Circle& circle = fCircles[i];
199c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
20092aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon            GrColor color = circle.fColor;
20192aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon            SkScalar outerRadius = circle.fOuterRadius;
20292aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon            SkScalar innerRadius = circle.fInnerRadius;
20392aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon            SkScalar blurRadius = circle.fBlurRadius;
204c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
20592aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon            const SkRect& bounds = circle.fDevBounds;
206c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            CircleVertex* ov0 = reinterpret_cast<CircleVertex*>(vertices + 0 * vertexStride);
207c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            CircleVertex* ov1 = reinterpret_cast<CircleVertex*>(vertices + 1 * vertexStride);
208c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            CircleVertex* ov2 = reinterpret_cast<CircleVertex*>(vertices + 2 * vertexStride);
209c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            CircleVertex* ov3 = reinterpret_cast<CircleVertex*>(vertices + 3 * vertexStride);
210c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            CircleVertex* ov4 = reinterpret_cast<CircleVertex*>(vertices + 4 * vertexStride);
211c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            CircleVertex* ov5 = reinterpret_cast<CircleVertex*>(vertices + 5 * vertexStride);
212c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            CircleVertex* ov6 = reinterpret_cast<CircleVertex*>(vertices + 6 * vertexStride);
213c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            CircleVertex* ov7 = reinterpret_cast<CircleVertex*>(vertices + 7 * vertexStride);
214c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
215c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            // The inner radius in the vertex data must be specified in normalized space.
216c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            innerRadius = innerRadius / outerRadius;
21760c05f98aa22d89e4ef25acb4799936f5df3cff2Herb Derby
218c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            SkPoint center = SkPoint::Make(bounds.centerX(), bounds.centerY());
219fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            SkScalar halfWidth = 0.5f * bounds.width();
220c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            SkScalar octOffset = 0.41421356237f;  // sqrt(2) - 1
221c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
222fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            ov0->fPos = center + SkPoint::Make(-octOffset * halfWidth, -halfWidth);
223c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov0->fColor = color;
224c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov0->fOffset = SkPoint::Make(-octOffset, -1);
225c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov0->fOuterRadius = outerRadius;
226c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov0->fBlurRadius = blurRadius;
227c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
228fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            ov1->fPos = center + SkPoint::Make(octOffset * halfWidth, -halfWidth);
229c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov1->fColor = color;
230c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov1->fOffset = SkPoint::Make(octOffset, -1);
231c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov1->fOuterRadius = outerRadius;
232c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov1->fBlurRadius = blurRadius;
233c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
234fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            ov2->fPos = center + SkPoint::Make(halfWidth, -octOffset * halfWidth);
235c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov2->fColor = color;
236c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov2->fOffset = SkPoint::Make(1, -octOffset);
237c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov2->fOuterRadius = outerRadius;
238c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov2->fBlurRadius = blurRadius;
239c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
240fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            ov3->fPos = center + SkPoint::Make(halfWidth, octOffset * halfWidth);
241c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov3->fColor = color;
242c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov3->fOffset = SkPoint::Make(1, octOffset);
243c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov3->fOuterRadius = outerRadius;
244c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov3->fBlurRadius = blurRadius;
245c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
246fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            ov4->fPos = center + SkPoint::Make(octOffset * halfWidth, halfWidth);
247c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov4->fColor = color;
248c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov4->fOffset = SkPoint::Make(octOffset, 1);
249c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov4->fOuterRadius = outerRadius;
250c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov4->fBlurRadius = blurRadius;
251c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
252fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            ov5->fPos = center + SkPoint::Make(-octOffset * halfWidth, halfWidth);
253c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov5->fColor = color;
254c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov5->fOffset = SkPoint::Make(-octOffset, 1);
255c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov5->fOuterRadius = outerRadius;
256c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov5->fBlurRadius = blurRadius;
257c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
258fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            ov6->fPos = center + SkPoint::Make(-halfWidth, octOffset * halfWidth);
259c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov6->fColor = color;
260c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov6->fOffset = SkPoint::Make(-1, octOffset);
261c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov6->fOuterRadius = outerRadius;
262c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov6->fBlurRadius = blurRadius;
263c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
264fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            ov7->fPos = center + SkPoint::Make(-halfWidth, -octOffset * halfWidth);
265c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov7->fColor = color;
266c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov7->fOffset = SkPoint::Make(-1, -octOffset);
267c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov7->fOuterRadius = outerRadius;
268c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            ov7->fBlurRadius = blurRadius;
269c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
27092aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon            if (circle.fStroked) {
271c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                // compute the inner ring
272c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                CircleVertex* iv0 = reinterpret_cast<CircleVertex*>(vertices + 8 * vertexStride);
273c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                CircleVertex* iv1 = reinterpret_cast<CircleVertex*>(vertices + 9 * vertexStride);
274c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                CircleVertex* iv2 = reinterpret_cast<CircleVertex*>(vertices + 10 * vertexStride);
275c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                CircleVertex* iv3 = reinterpret_cast<CircleVertex*>(vertices + 11 * vertexStride);
276c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                CircleVertex* iv4 = reinterpret_cast<CircleVertex*>(vertices + 12 * vertexStride);
277c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                CircleVertex* iv5 = reinterpret_cast<CircleVertex*>(vertices + 13 * vertexStride);
278c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                CircleVertex* iv6 = reinterpret_cast<CircleVertex*>(vertices + 14 * vertexStride);
279c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                CircleVertex* iv7 = reinterpret_cast<CircleVertex*>(vertices + 15 * vertexStride);
280c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
281c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                // cosine and sine of pi/8
282c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                SkScalar c = 0.923579533f;
283c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                SkScalar s = 0.382683432f;
28492aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon                SkScalar r = circle.fInnerRadius;
285c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
286fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv0->fPos = center + SkPoint::Make(-s * r, -c * r);
287c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv0->fColor = color;
288fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv0->fOffset = SkPoint::Make(-s * innerRadius, -c * innerRadius);
289c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv0->fOuterRadius = outerRadius;
290c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv0->fBlurRadius = blurRadius;
291c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
292fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv1->fPos = center + SkPoint::Make(s * r, -c * r);
293c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv1->fColor = color;
294fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv1->fOffset = SkPoint::Make(s * innerRadius, -c * innerRadius);
295c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv1->fOuterRadius = outerRadius;
296c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv1->fBlurRadius = blurRadius;
297c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
298fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv2->fPos = center + SkPoint::Make(c * r, -s * r);
299c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv2->fColor = color;
300fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv2->fOffset = SkPoint::Make(c * innerRadius, -s * innerRadius);
301c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv2->fOuterRadius = outerRadius;
302c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv2->fBlurRadius = blurRadius;
303c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
304fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv3->fPos = center + SkPoint::Make(c * r, s * r);
305c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv3->fColor = color;
306fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv3->fOffset = SkPoint::Make(c * innerRadius, s * innerRadius);
307c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv3->fOuterRadius = outerRadius;
308c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv3->fBlurRadius = blurRadius;
309c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
310fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv4->fPos = center + SkPoint::Make(s * r, c * r);
311c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv4->fColor = color;
312fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv4->fOffset = SkPoint::Make(s * innerRadius, c * innerRadius);
313c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv4->fOuterRadius = outerRadius;
314c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv4->fBlurRadius = blurRadius;
315c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
316fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv5->fPos = center + SkPoint::Make(-s * r, c * r);
317c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv5->fColor = color;
318fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv5->fOffset = SkPoint::Make(-s * innerRadius, c * innerRadius);
319c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv5->fOuterRadius = outerRadius;
320c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv5->fBlurRadius = blurRadius;
321c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
322fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv6->fPos = center + SkPoint::Make(-c * r, s * r);
323c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv6->fColor = color;
324fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv6->fOffset = SkPoint::Make(-c * innerRadius, s * innerRadius);
325c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv6->fOuterRadius = outerRadius;
326c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv6->fBlurRadius = blurRadius;
327c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
328fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv7->fPos = center + SkPoint::Make(-c * r, -s * r);
329c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv7->fColor = color;
330fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                iv7->fOffset = SkPoint::Make(-c * innerRadius, -s * innerRadius);
331c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv7->fOuterRadius = outerRadius;
332c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv7->fBlurRadius = blurRadius;
333c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            } else {
334c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                // filled
335c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                CircleVertex* iv = reinterpret_cast<CircleVertex*>(vertices + 8 * vertexStride);
336c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv->fPos = center;
337c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv->fColor = color;
338c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv->fOffset = SkPoint::Make(0, 0);
339c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv->fOuterRadius = outerRadius;
340c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                iv->fBlurRadius = blurRadius;
341c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            }
342c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
34392aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon            const uint16_t* primIndices = circle_type_to_indices(circle.fStroked);
34492aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon            const int primIndexCount = circle_type_to_index_count(circle.fStroked);
345c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            for (int i = 0; i < primIndexCount; ++i) {
346c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                *indices++ = primIndices[i] + currStartVertex;
347c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            }
348c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
34992aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon            currStartVertex += circle_type_to_vert_count(circle.fStroked);
35092aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon            vertices += circle_type_to_vert_count(circle.fStroked) * vertexStride;
351c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
352c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
353c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        GrMesh mesh;
354c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex,
355c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                         firstIndex, fVertCount, fIndexCount);
356c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        target->draw(gp.get(), mesh);
357c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
358c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
35925a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
360fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        ShadowCircleOp* that = t->cast<ShadowCircleOp>();
361c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
362c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                                    that->bounds(), caps)) {
363c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            return false;
364c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
365c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
366c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
367c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            return false;
368c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
369c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
37092aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        fCircles.push_back_n(that->fCircles.count(), that->fCircles.begin());
371c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        this->joinBounds(*that);
372c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        fVertCount += that->fVertCount;
373c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        fIndexCount += that->fIndexCount;
374c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        return true;
375c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
376c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
37792aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    struct Circle {
378fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        GrColor fColor;
379c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar fOuterRadius;
380c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar fInnerRadius;
381c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar fBlurRadius;
382fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        SkRect fDevBounds;
383fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        bool fStroked;
384c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    };
385c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
38692aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    SkSTArray<1, Circle, true> fCircles;
387fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    SkMatrix fViewMatrixIfUsingLocalCoords;
388fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    int fVertCount;
389fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    int fIndexCount;
390c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
391dad2923b8ec9270d810c1e8e76da8e6768d8f9ddBrian Salomon    typedef GrMeshDrawOp INHERITED;
392c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth};
393c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
394c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth///////////////////////////////////////////////////////////////////////////////////////////////////
395c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
396c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// We have two possible cases for geometry for a shadow roundrect.
397c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//
398c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// In the case of a normal stroke, we draw the roundrect as a 9-patch without the center quad.
399c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//    ____________
400c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   |_|________|_|
401c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   | |        | |
402c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   | |        | |
403c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   | |        | |
404c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   |_|________|_|
405c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   |_|________|_|
406c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//
407c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// In the case where the stroke width is greater than twice the corner radius (overstroke),
408c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// we add additional geometry to mark out the rectangle in the center. The shared vertices
409c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// are duplicated so we can set a different outer radius for the fill calculation.
410c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//    ____________
411c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   |_|________|_|
412c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   | |\ ____ /| |
413c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   | | |    | | |
414c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   | | |____| | |
415c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   |_|/______\|_|
416c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   |_|________|_|
417c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//
418c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// For filled rrects we reuse the overstroke geometry but make the inner rect degenerate
419c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// (either a point or a horizontal or vertical line).
420c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
421c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const uint16_t gOverstrokeRRectIndices[] = {
422fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        // clang-format off
423fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        // corners
424fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        0, 1, 5, 0, 5, 4,
425fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        2, 3, 7, 2, 7, 6,
426fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        8, 9, 13, 8, 13, 12,
427fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        10, 11, 15, 10, 15, 14,
428fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon
429fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        // edges
430fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        1, 2, 6, 1, 6, 5,
431fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        4, 5, 9, 4, 9, 8,
432fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        6, 7, 11, 6, 11, 10,
433fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        9, 10, 14, 9, 14, 13,
434fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon
435fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        // overstroke quads
436fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        // we place this at the end so that we can skip these indices when rendering as stroked
437fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        16, 17, 19, 16, 19, 18,
438fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        19, 17, 23, 19, 23, 21,
439fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        21, 23, 22, 21, 22, 20,
440fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        22, 16, 18, 22, 18, 20,
441fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        // clang-format on
442c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth};
443c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// standard stroke indices start at the same place, but will skip the overstroke "ring"
444c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const uint16_t* gStrokeRRectIndices = gOverstrokeRRectIndices;
445c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
446c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// overstroke count
447c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gOverstrokeRRectIndices);
448c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// simple stroke count skips overstroke indices
449c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const int kIndicesPerStrokeRRect = kIndicesPerOverstrokeRRect - 6 * 4 + 6;
450c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const int kVertsPerStrokeRRect = 16;
451c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const int kVertsPerOverstrokeRRect = 24;
452c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
453c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthenum RRectType {
454c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    kFill_RRectType,
455c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    kStroke_RRectType,
456c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    kOverstroke_RRectType,
457c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth};
458c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
459c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic int rrect_type_to_vert_count(RRectType type) {
460fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    switch (type) {
461fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        case kFill_RRectType:
462fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            return kVertsPerOverstrokeRRect;
463fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        case kStroke_RRectType:
464fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            return kVertsPerStrokeRRect;
465fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        case kOverstroke_RRectType:
466fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            return kVertsPerOverstrokeRRect;
467fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    }
468fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    SkFAIL("Invalid type");
469fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    return 0;
470c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth}
471c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
472c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic int rrect_type_to_index_count(RRectType type) {
473fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    switch (type) {
474fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        case kFill_RRectType:
475fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            return kIndicesPerOverstrokeRRect;
476fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        case kStroke_RRectType:
477fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            return kIndicesPerStrokeRRect;
478fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        case kOverstroke_RRectType:
479fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            return kIndicesPerOverstrokeRRect;
480fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    }
481fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    SkFAIL("Invalid type");
482fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    return 0;
483c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth}
484c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
485c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthstatic const uint16_t* rrect_type_to_indices(RRectType type) {
486fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    switch (type) {
487fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        case kFill_RRectType:
488fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            return gOverstrokeRRectIndices;
489fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        case kStroke_RRectType:
490fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            return gStrokeRRectIndices;
491fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        case kOverstroke_RRectType:
492fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            return gOverstrokeRRectIndices;
493fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    }
494fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    SkFAIL("Invalid type");
495fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    return nullptr;
496c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth}
497c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
498c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth// For distance computations in the interior of filled rrects we:
499c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//
500c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   add a interior degenerate (point or line) rect
501c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   each vertex of that rect gets -outerRad as its radius
502c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//      this makes the computation of the distance to the outer edge be negative
503c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//      negative values are caught and then handled differently in the GP's onEmitCode
504c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//   each vertex is also given the normalized x & y distance from the interior rect's edge
505c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth//      the GP takes the min of those depths +1 to get the normalized distance to the outer edge
506c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
507fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomonclass ShadowCircularRRectOp final : public GrMeshDrawOp {
508c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verthpublic:
50925a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    DEFINE_OP_CLASS_ID
510c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
511c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    // A devStrokeWidth <= 0 indicates a fill only. If devStrokeWidth > 0 then strokeOnly indicates
512c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    // whether the rrect is only stroked or stroked and filled.
513fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    ShadowCircularRRectOp(GrColor color, const SkMatrix& viewMatrix, const SkRect& devRect,
514fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                          float devRadius, float blurRadius, float devStrokeWidth, bool strokeOnly)
515fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            : INHERITED(ClassID()), fViewMatrixIfUsingLocalCoords(viewMatrix) {
516c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkRect bounds = devRect;
517c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkASSERT(!(devStrokeWidth <= 0 && strokeOnly));
518c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar innerRadius = 0.0f;
519c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar outerRadius = devRadius;
520c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar halfWidth = 0;
521c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        RRectType type = kFill_RRectType;
522c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (devStrokeWidth > 0) {
523c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            if (SkScalarNearlyZero(devStrokeWidth)) {
524c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                halfWidth = SK_ScalarHalf;
525c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            } else {
526c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                halfWidth = SkScalarHalf(devStrokeWidth);
527c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            }
528c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
529c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            if (strokeOnly) {
530c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                // If stroke is greater than width or height, this is still a fill
531c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                // Otherwise we compute stroke params
532fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                if (devStrokeWidth <= devRect.width() && devStrokeWidth <= devRect.height()) {
533c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                    innerRadius = devRadius - halfWidth;
534c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                    type = (innerRadius >= 0) ? kStroke_RRectType : kOverstroke_RRectType;
535c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                }
536c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            }
537c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            outerRadius += halfWidth;
538c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            bounds.outset(halfWidth, halfWidth);
539c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
540c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
541cf40e307cd7c78c3ac8812229a7f4f2796b8688eJim Van Verth        this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
542c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
543c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        fGeoData.emplace_back(Geometry{color, outerRadius, innerRadius, blurRadius, bounds, type});
544c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        fVertCount = rrect_type_to_vert_count(type);
545c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        fIndexCount = rrect_type_to_index_count(type);
546c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
547c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
548fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    const char* name() const override { return "ShadowCircularRRectOp"; }
549c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
550c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkString dumpInfo() const override {
551c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkString string;
552c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        for (int i = 0; i < fGeoData.count(); ++i) {
553fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            string.appendf(
554fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                    "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
555fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                    "OuterRad: %.2f, InnerRad: %.2f, BlurRad: %.2f\n",
556fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                    fGeoData[i].fColor, fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop,
557fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                    fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom,
558fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                    fGeoData[i].fOuterRadius, fGeoData[i].fInnerRadius, fGeoData[i].fBlurRadius);
559c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
5607c3e7180948766321c51d165737555e78910de51Brian Salomon        string.append(DumpPipelineInfo(*this->pipeline()));
561c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        string.append(INHERITED::dumpInfo());
562c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        return string;
563c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
564c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
56592aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomonprivate:
566c0b642ca48d58416409e555549434066f09692b7Brian Salomon    void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor* color,
567c0b642ca48d58416409e555549434066f09692b7Brian Salomon                                            GrPipelineAnalysisCoverage* coverage) const override {
568c0b642ca48d58416409e555549434066f09692b7Brian Salomon        color->setToConstant(fGeoData[0].fColor);
569c0b642ca48d58416409e555549434066f09692b7Brian Salomon        *coverage = GrPipelineAnalysisCoverage::kSingleChannel;
570c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
571c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
57292aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon    void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override {
57392aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        optimizations.getOverrideColorIfSet(&fGeoData[0].fColor);
57492aee3d6857386f2b5b8e1148e680a7b58e9b1fcBrian Salomon        if (!optimizations.readsLocalCoords()) {
575c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            fViewMatrixIfUsingLocalCoords.reset();
576c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
577c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
578c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
579c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    struct CircleVertex {
580fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        SkPoint fPos;
581fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        GrColor fColor;
582fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        SkPoint fOffset;
583c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar fOuterRadius;
584c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar fBlurRadius;
585c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    };
586c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
587fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    static void FillInOverstrokeVerts(CircleVertex** verts, const SkRect& bounds, SkScalar smInset,
588fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                                      SkScalar bigInset, SkScalar xOffset, SkScalar outerRadius,
589fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                                      GrColor color, SkScalar blurRadius) {
590c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkASSERT(smInset < bigInset);
591c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
592c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        // TL
593c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fPos = SkPoint::Make(bounds.fLeft + smInset, bounds.fTop + smInset);
594c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fColor = color;
595c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOffset = SkPoint::Make(xOffset, 0);
596c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOuterRadius = outerRadius;
597c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fBlurRadius = blurRadius;
598c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)++;
599c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
600c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        // TR
601c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fPos = SkPoint::Make(bounds.fRight - smInset, bounds.fTop + smInset);
602c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fColor = color;
603c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOffset = SkPoint::Make(xOffset, 0);
604c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOuterRadius = outerRadius;
605c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fBlurRadius = blurRadius;
606c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)++;
607c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
608c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fPos = SkPoint::Make(bounds.fLeft + bigInset, bounds.fTop + bigInset);
609c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fColor = color;
610c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOffset = SkPoint::Make(0, 0);
611c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOuterRadius = outerRadius;
612c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fBlurRadius = blurRadius;
613c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)++;
614c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
615c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fPos = SkPoint::Make(bounds.fRight - bigInset, bounds.fTop + bigInset);
616c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fColor = color;
617c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOffset = SkPoint::Make(0, 0);
618c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOuterRadius = outerRadius;
619c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fBlurRadius = blurRadius;
620c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)++;
621c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
622c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fPos = SkPoint::Make(bounds.fLeft + bigInset, bounds.fBottom - bigInset);
623c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fColor = color;
624c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOffset = SkPoint::Make(0, 0);
625c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOuterRadius = outerRadius;
626c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fBlurRadius = blurRadius;
627c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)++;
628c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
629c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fPos = SkPoint::Make(bounds.fRight - bigInset, bounds.fBottom - bigInset);
630c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fColor = color;
631c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOffset = SkPoint::Make(0, 0);
632c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOuterRadius = outerRadius;
633c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fBlurRadius = blurRadius;
634c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)++;
635c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
636c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        // BL
637c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fPos = SkPoint::Make(bounds.fLeft + smInset, bounds.fBottom - smInset);
638c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fColor = color;
639c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOffset = SkPoint::Make(xOffset, 0);
640c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOuterRadius = outerRadius;
641c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fBlurRadius = blurRadius;
642c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)++;
643c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
644c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        // BR
645c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fPos = SkPoint::Make(bounds.fRight - smInset, bounds.fBottom - smInset);
646c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fColor = color;
647c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOffset = SkPoint::Make(xOffset, 0);
648c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fOuterRadius = outerRadius;
649c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)->fBlurRadius = blurRadius;
650c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        (*verts)++;
651c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
652c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
653c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    void onPrepareDraws(Target* target) const override {
654c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        // Invert the view matrix as a local matrix (if any other processors require coords).
655c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkMatrix localMatrix;
656c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) {
657c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            return;
658c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
659c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
660c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        // Setup geometry processor
661c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        sk_sp<GrGeometryProcessor> gp(GrRRectShadowGeoProc::Make(localMatrix));
662c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
663c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        int instanceCount = fGeoData.count();
664c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        size_t vertexStride = gp->getVertexStride();
665c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkASSERT(sizeof(CircleVertex) == vertexStride);
666c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
667c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        const GrBuffer* vertexBuffer;
668c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        int firstVertex;
669c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
670c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        CircleVertex* verts = (CircleVertex*)target->makeVertexSpace(vertexStride, fVertCount,
671c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                                                                     &vertexBuffer, &firstVertex);
672c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (!verts) {
673c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            SkDebugf("Could not allocate vertices\n");
674c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            return;
675c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
676c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
677c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        const GrBuffer* indexBuffer = nullptr;
678c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        int firstIndex = 0;
679c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        uint16_t* indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
680c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (!indices) {
681c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            SkDebugf("Could not allocate indices\n");
682c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            return;
683c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
684c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
685c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        int currStartVertex = 0;
686c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        for (int i = 0; i < instanceCount; i++) {
687c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            const Geometry& args = fGeoData[i];
688c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
689c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            GrColor color = args.fColor;
690c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            SkScalar outerRadius = args.fOuterRadius;
691c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
692c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            const SkRect& bounds = args.fDevBounds;
693c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
694fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            SkScalar yCoords[4] = {bounds.fTop, bounds.fTop + outerRadius,
695fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                                   bounds.fBottom - outerRadius, bounds.fBottom};
696c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
697fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            SkScalar yOuterRadii[4] = {-1, 0, 0, 1};
698c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            // The inner radius in the vertex data must be specified in normalized space.
699c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            // For fills, specifying -1/outerRadius guarantees an alpha of 1.0 at the inner radius.
700c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            SkScalar blurRadius = args.fBlurRadius;
701c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            for (int i = 0; i < 4; ++i) {
702c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
703c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fColor = color;
704c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
705c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fOuterRadius = outerRadius;
706c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fBlurRadius = blurRadius;
707c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts++;
708c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
709c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
710c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fColor = color;
711c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
712c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fOuterRadius = outerRadius;
713c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fBlurRadius = blurRadius;
714c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts++;
715c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
716c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
717c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fColor = color;
718c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
719c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fOuterRadius = outerRadius;
720c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fBlurRadius = blurRadius;
721c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts++;
722c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
723c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
724c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fColor = color;
725c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
726c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fOuterRadius = outerRadius;
727c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts->fBlurRadius = blurRadius;
728c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                verts++;
729c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            }
730c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            // Add the additional vertices for overstroked rrects.
731c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            // Effectively this is an additional stroked rrect, with its
732c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            // outer radius = outerRadius - innerRadius, and inner radius = 0.
733c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            // This will give us correct AA in the center and the correct
734c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            // distance to the outer edge.
735c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            //
736c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            // Also, the outer offset is a constant vector pointing to the right, which
737c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            // guarantees that the distance value along the outer rectangle is constant.
738c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            if (kOverstroke_RRectType == args.fType) {
739c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                SkASSERT(args.fInnerRadius <= 0.0f);
740c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
741c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                SkScalar overstrokeOuterRadius = outerRadius - args.fInnerRadius;
742c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                // this is the normalized distance from the outer rectangle of this
743c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                // geometry to the outer edge
744c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                SkScalar maxOffset = -args.fInnerRadius / overstrokeOuterRadius;
745c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
746fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                FillInOverstrokeVerts(&verts, bounds, outerRadius, overstrokeOuterRadius, maxOffset,
747fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                                      overstrokeOuterRadius, color, blurRadius);
748c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            }
749c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
750c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            if (kFill_RRectType == args.fType) {
751c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                SkScalar halfMinDim = 0.5f * SkTMin(bounds.width(), bounds.height());
752c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
753c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                SkScalar xOffset = 1.0f - outerRadius / halfMinDim;
754c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
755fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                FillInOverstrokeVerts(&verts, bounds, outerRadius, halfMinDim, xOffset, halfMinDim,
756fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                                      color, blurRadius);
757c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            }
758c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
759c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            const uint16_t* primIndices = rrect_type_to_indices(args.fType);
760c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            const int primIndexCount = rrect_type_to_index_count(args.fType);
761c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            for (int i = 0; i < primIndexCount; ++i) {
762c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                *indices++ = primIndices[i] + currStartVertex;
763c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            }
764c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
765c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            currStartVertex += rrect_type_to_vert_count(args.fType);
766c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
767c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
768c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        GrMesh mesh;
769c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        mesh.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex,
770c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                         firstIndex, fVertCount, fIndexCount);
771c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        target->draw(gp.get(), mesh);
772c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
773c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
77425a880960a9a689a745a01071ecba3fe494b5940Brian Salomon    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
775fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        ShadowCircularRRectOp* that = t->cast<ShadowCircularRRectOp>();
776c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
777c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                                    that->bounds(), caps)) {
778c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            return false;
779c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
780c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
781c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
782c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            return false;
783c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
784c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
785c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
786c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        this->joinBounds(*that);
787c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        fVertCount += that->fVertCount;
788c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        fIndexCount += that->fIndexCount;
789c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        return true;
790c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
791c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
792c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    struct Geometry {
793fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        GrColor fColor;
794c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar fOuterRadius;
795c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar fInnerRadius;
796c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar fBlurRadius;
797c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkRect fDevBounds;
798c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        RRectType fType;
799c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    };
800c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
801c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkSTArray<1, Geometry, true> fGeoData;
802fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    SkMatrix fViewMatrixIfUsingLocalCoords;
803fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    int fVertCount;
804fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    int fIndexCount;
805c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
806dad2923b8ec9270d810c1e8e76da8e6768d8f9ddBrian Salomon    typedef GrMeshDrawOp INHERITED;
807c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth};
808c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
809c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth///////////////////////////////////////////////////////////////////////////////
810c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
811649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomonstd::unique_ptr<GrMeshDrawOp> make_shadow_circle_op(GrColor color,
812649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                    const SkMatrix& viewMatrix,
813649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                    const SkRect& oval,
814649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                    SkScalar blurRadius,
815649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                    const SkStrokeRec& stroke,
816649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                    const GrShaderCaps* shaderCaps) {
817c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    // we can only draw circles
818c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkScalar width = oval.width();
819c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkASSERT(SkScalarNearlyEqual(width, oval.height()) && viewMatrix.isSimilarity());
820fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    SkPoint center = {oval.centerX(), oval.centerY()};
821fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    return ShadowCircleOp::Make(color, viewMatrix, center, width / 2.f, blurRadius,
822fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                                GrStyle(stroke, nullptr));
823c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth}
824c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
825649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomonstatic std::unique_ptr<GrMeshDrawOp> make_shadow_rrect_op(GrColor color,
826649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                          const SkMatrix& viewMatrix,
827649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                          const SkRRect& rrect,
828649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                          SkScalar blurRadius,
829649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                                          const SkStrokeRec& stroke) {
830c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkASSERT(viewMatrix.rectStaysRect());
831c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkASSERT(rrect.isSimple());
832c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkASSERT(!rrect.isOval());
833c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
83453e4c3c0da40b58638d05e0f753ab6d450b961f5Brian Salomon    // Shadow rrect ops only handle simple circular rrects.
83553e4c3c0da40b58638d05e0f753ab6d450b961f5Brian Salomon    // Do any matrix crunching before we reset the draw state for device coords.
836c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    const SkRect& rrectBounds = rrect.getBounds();
837c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkRect bounds;
838c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    viewMatrix.mapRect(&bounds, rrectBounds);
839c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
840c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkVector radii = rrect.getSimpleRadii();
841c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX] * radii.fX +
842c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                                   viewMatrix[SkMatrix::kMSkewY] * radii.fY);
843c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX] * radii.fX +
844c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth                                   viewMatrix[SkMatrix::kMScaleY] * radii.fY);
845c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkASSERT(SkScalarNearlyEqual(xRadius, yRadius));
846c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
847c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkStrokeRec::Style style = stroke.getStyle();
848c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
849c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    // Do (potentially) anisotropic mapping of stroke. Use -1s to indicate fill-only draws.
850fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    SkVector scaledStroke = {-1, -1};
851c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkScalar strokeWidth = stroke.getWidth();
852c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
853fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon    bool isStrokeOnly =
854fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style;
855c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
856c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
857c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    if (hasStroke) {
858c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (SkStrokeRec::kHairline_Style == style) {
859c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            scaledStroke.set(1, 1);
860c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        } else {
861fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            scaledStroke.fX = SkScalarAbs(
862fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                    strokeWidth * (viewMatrix[SkMatrix::kMScaleX] + viewMatrix[SkMatrix::kMSkewY]));
863fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon            scaledStroke.fY = SkScalarAbs(
864fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon                    strokeWidth * (viewMatrix[SkMatrix::kMSkewX] + viewMatrix[SkMatrix::kMScaleY]));
865c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
866c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
867c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        // we don't handle anisotropic strokes
868c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        if (!SkScalarNearlyEqual(scaledStroke.fX, scaledStroke.fY)) {
869c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth            return nullptr;
870c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
871c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
872c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
873c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    // The way the effect interpolates the offset-to-ellipse/circle-center attribute only works on
874c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner rect of the nine-
875c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    // patch will have fractional coverage. This only matters when the interior is actually filled.
876c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    // We could consider falling back to rect rendering here, since a tiny radius is
877c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    // indistinguishable from a square corner.
878c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
879c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        return nullptr;
880c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
881c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
882649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon    return std::unique_ptr<GrMeshDrawOp>(new ShadowCircularRRectOp(
883f8334781914363caf537f22f012fcd5c03c60dadBrian Salomon            color, viewMatrix, bounds, xRadius, blurRadius, scaledStroke.fX, isStrokeOnly));
884c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth}
885c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
886fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomonnamespace GrShadowRRectOp {
887649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomonstd::unique_ptr<GrMeshDrawOp> Make(GrColor color,
888649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                   const SkMatrix& viewMatrix,
889649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                   const SkRRect& rrect,
890649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                   const SkScalar blurRadius,
891649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                   const SkStrokeRec& stroke,
892649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                                   const GrShaderCaps* shaderCaps) {
893c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    if (rrect.isOval()) {
89453e4c3c0da40b58638d05e0f753ab6d450b961f5Brian Salomon        return make_shadow_circle_op(color, viewMatrix, rrect.getBounds(), blurRadius, stroke,
89553e4c3c0da40b58638d05e0f753ab6d450b961f5Brian Salomon                                     shaderCaps);
896c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
897c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
898c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) {
899c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        return nullptr;
900c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    }
901c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
90253e4c3c0da40b58638d05e0f753ab6d450b961f5Brian Salomon    return make_shadow_rrect_op(color, viewMatrix, rrect, blurRadius, stroke);
903fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon}
904c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth}
905c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth///////////////////////////////////////////////////////////////////////////////
906c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
9076f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#if GR_TEST_UTILS
908c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
9095ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian SalomonDRAW_OP_TEST_DEFINE(ShadowCircleOp) {
910c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    do {
911c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar rotate = random->nextSScalar1() * 360.f;
912c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar translateX = random->nextSScalar1() * 1000.f;
913c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar translateY = random->nextSScalar1() * 1000.f;
914c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar scale = random->nextSScalar1() * 100.f;
915c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkMatrix viewMatrix;
916c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        viewMatrix.setRotate(rotate);
917c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        viewMatrix.postTranslate(translateX, translateY);
918c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        viewMatrix.postScale(scale, scale);
919c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        GrColor color = GrRandomColor(random);
920c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkRect circle = GrTest::TestSquare(random);
921fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        SkPoint center = {circle.centerX(), circle.centerY()};
922c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar radius = circle.width() / 2.f;
923c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkStrokeRec stroke = GrTest::TestStrokeRec(random);
924c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        SkScalar blurRadius = random->nextSScalar1() * 72.f;
925649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon        std::unique_ptr<GrMeshDrawOp> op = ShadowCircleOp::Make(
926649a3411f99a8aea3c46e4ef1f495f61b9801164Brian Salomon                color, viewMatrix, center, radius, blurRadius, GrStyle(stroke, nullptr));
927fc527d27641bb693a0a7703ba9d35100f7500fd7Brian Salomon        if (op) {
9285ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian Salomon            return op;
929c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth        }
930c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    } while (true);
931c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth}
932c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
9335ec9def2dd7bba572398ff2aa9361fbbb3b478edBrian SalomonDRAW_OP_TEST_DEFINE(ShadowRRectOp) {
934c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
935c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    GrColor color = GrRandomColor(random);
936c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    const SkRRect& rrect = GrTest::TestRRectSimple(random);
937c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth    SkScalar blurRadius = random->nextSScalar1() * 72.f;
93853e4c3c0da40b58638d05e0f753ab6d450b961f5Brian Salomon    return make_shadow_rrect_op(color, viewMatrix, rrect, blurRadius,
93953e4c3c0da40b58638d05e0f753ab6d450b961f5Brian Salomon                                GrTest::TestStrokeRec(random));
940c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth}
941c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth
942c59034145862bf6dc0c503cb1e47eecd321ffa8cJim Van Verth#endif
943