1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/ops/ShadowRRectOp.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/gpu/GrRecordingContext.h"
11cb93a386Sopenharmony_ci#include "src/core/SkRRectPriv.h"
12cb93a386Sopenharmony_ci#include "src/gpu/GrMemoryPool.h"
13cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h"
14cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h"
17cb93a386Sopenharmony_ci#include "src/gpu/GrThreadSafeCache.h"
18cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h"
19cb93a386Sopenharmony_ci#include "src/gpu/effects/GrShadowGeoProc.h"
20cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_cinamespace {
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
25cb93a386Sopenharmony_ci// Circle Data
26cb93a386Sopenharmony_ci//
27cb93a386Sopenharmony_ci// We have two possible cases for geometry for a circle:
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci// In the case of a normal fill, we draw geometry for the circle as an octagon.
30cb93a386Sopenharmony_cistatic const uint16_t gFillCircleIndices[] = {
31cb93a386Sopenharmony_ci        // enter the octagon
32cb93a386Sopenharmony_ci        // clang-format off
33cb93a386Sopenharmony_ci        0, 1, 8, 1, 2, 8,
34cb93a386Sopenharmony_ci        2, 3, 8, 3, 4, 8,
35cb93a386Sopenharmony_ci        4, 5, 8, 5, 6, 8,
36cb93a386Sopenharmony_ci        6, 7, 8, 7, 0, 8,
37cb93a386Sopenharmony_ci        // clang-format on
38cb93a386Sopenharmony_ci};
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ci// For stroked circles, we use two nested octagons.
41cb93a386Sopenharmony_cistatic const uint16_t gStrokeCircleIndices[] = {
42cb93a386Sopenharmony_ci        // enter the octagon
43cb93a386Sopenharmony_ci        // clang-format off
44cb93a386Sopenharmony_ci        0, 1,  9, 0,  9,  8,
45cb93a386Sopenharmony_ci        1, 2, 10, 1, 10,  9,
46cb93a386Sopenharmony_ci        2, 3, 11, 2, 11, 10,
47cb93a386Sopenharmony_ci        3, 4, 12, 3, 12, 11,
48cb93a386Sopenharmony_ci        4, 5, 13, 4, 13, 12,
49cb93a386Sopenharmony_ci        5, 6, 14, 5, 14, 13,
50cb93a386Sopenharmony_ci        6, 7, 15, 6, 15, 14,
51cb93a386Sopenharmony_ci        7, 0,  8, 7,  8, 15,
52cb93a386Sopenharmony_ci        // clang-format on
53cb93a386Sopenharmony_ci};
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_cistatic const int kIndicesPerFillCircle = SK_ARRAY_COUNT(gFillCircleIndices);
56cb93a386Sopenharmony_cistatic const int kIndicesPerStrokeCircle = SK_ARRAY_COUNT(gStrokeCircleIndices);
57cb93a386Sopenharmony_cistatic const int kVertsPerStrokeCircle = 16;
58cb93a386Sopenharmony_cistatic const int kVertsPerFillCircle = 9;
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_ciint circle_type_to_vert_count(bool stroked) {
61cb93a386Sopenharmony_ci    return stroked ? kVertsPerStrokeCircle : kVertsPerFillCircle;
62cb93a386Sopenharmony_ci}
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ciint circle_type_to_index_count(bool stroked) {
65cb93a386Sopenharmony_ci    return stroked ? kIndicesPerStrokeCircle : kIndicesPerFillCircle;
66cb93a386Sopenharmony_ci}
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ciconst uint16_t* circle_type_to_indices(bool stroked) {
69cb93a386Sopenharmony_ci    return stroked ? gStrokeCircleIndices : gFillCircleIndices;
70cb93a386Sopenharmony_ci}
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
73cb93a386Sopenharmony_ci// RoundRect Data
74cb93a386Sopenharmony_ci//
75cb93a386Sopenharmony_ci// The geometry for a shadow roundrect is similar to a 9-patch:
76cb93a386Sopenharmony_ci//    ____________
77cb93a386Sopenharmony_ci//   |_|________|_|
78cb93a386Sopenharmony_ci//   | |        | |
79cb93a386Sopenharmony_ci//   | |        | |
80cb93a386Sopenharmony_ci//   | |        | |
81cb93a386Sopenharmony_ci//   |_|________|_|
82cb93a386Sopenharmony_ci//   |_|________|_|
83cb93a386Sopenharmony_ci//
84cb93a386Sopenharmony_ci// However, each corner is rendered as a fan rather than a simple quad, as below. (The diagram
85cb93a386Sopenharmony_ci// shows the upper part of the upper left corner. The bottom triangle would similarly be split
86cb93a386Sopenharmony_ci// into two triangles.)
87cb93a386Sopenharmony_ci//    ________
88cb93a386Sopenharmony_ci//   |\  \   |
89cb93a386Sopenharmony_ci//   |  \ \  |
90cb93a386Sopenharmony_ci//   |    \\ |
91cb93a386Sopenharmony_ci//   |      \|
92cb93a386Sopenharmony_ci//   --------
93cb93a386Sopenharmony_ci//
94cb93a386Sopenharmony_ci// The center of the fan handles the curve of the corner. For roundrects where the stroke width
95cb93a386Sopenharmony_ci// is greater than the corner radius, the outer triangles blend from the curve to the straight
96cb93a386Sopenharmony_ci// sides. Otherwise these triangles will be degenerate.
97cb93a386Sopenharmony_ci//
98cb93a386Sopenharmony_ci// In the case where the stroke width is greater than the corner radius and the
99cb93a386Sopenharmony_ci// blur radius (overstroke), we add additional geometry to mark out the rectangle in the center.
100cb93a386Sopenharmony_ci// This rectangle extends the coverage values of the center edges of the 9-patch.
101cb93a386Sopenharmony_ci//    ____________
102cb93a386Sopenharmony_ci//   |_|________|_|
103cb93a386Sopenharmony_ci//   | |\ ____ /| |
104cb93a386Sopenharmony_ci//   | | |    | | |
105cb93a386Sopenharmony_ci//   | | |____| | |
106cb93a386Sopenharmony_ci//   |_|/______\|_|
107cb93a386Sopenharmony_ci//   |_|________|_|
108cb93a386Sopenharmony_ci//
109cb93a386Sopenharmony_ci// For filled rrects we reuse the stroke geometry but add an additional quad to the center.
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_cistatic const uint16_t gRRectIndices[] = {
112cb93a386Sopenharmony_ci    // clang-format off
113cb93a386Sopenharmony_ci    // overstroke quads
114cb93a386Sopenharmony_ci    // we place this at the beginning so that we can skip these indices when rendering as filled
115cb93a386Sopenharmony_ci    0, 6, 25, 0, 25, 24,
116cb93a386Sopenharmony_ci    6, 18, 27, 6, 27, 25,
117cb93a386Sopenharmony_ci    18, 12, 26, 18, 26, 27,
118cb93a386Sopenharmony_ci    12, 0, 24, 12, 24, 26,
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_ci    // corners
121cb93a386Sopenharmony_ci    0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5,
122cb93a386Sopenharmony_ci    6, 11, 10, 6, 10, 9, 6, 9, 8, 6, 8, 7,
123cb93a386Sopenharmony_ci    12, 17, 16, 12, 16, 15, 12, 15, 14, 12, 14, 13,
124cb93a386Sopenharmony_ci    18, 19, 20, 18, 20, 21, 18, 21, 22, 18, 22, 23,
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci    // edges
127cb93a386Sopenharmony_ci    0, 5, 11, 0, 11, 6,
128cb93a386Sopenharmony_ci    6, 7, 19, 6, 19, 18,
129cb93a386Sopenharmony_ci    18, 23, 17, 18, 17, 12,
130cb93a386Sopenharmony_ci    12, 13, 1, 12, 1, 0,
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ci    // fill quad
133cb93a386Sopenharmony_ci    // we place this at the end so that we can skip these indices when rendering as stroked
134cb93a386Sopenharmony_ci    0, 6, 18, 0, 18, 12,
135cb93a386Sopenharmony_ci    // clang-format on
136cb93a386Sopenharmony_ci};
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci// overstroke count
139cb93a386Sopenharmony_cistatic const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6;
140cb93a386Sopenharmony_ci// simple stroke count skips overstroke indices
141cb93a386Sopenharmony_cistatic const int kIndicesPerStrokeRRect = kIndicesPerOverstrokeRRect - 6*4;
142cb93a386Sopenharmony_ci// fill count adds final quad to stroke count
143cb93a386Sopenharmony_cistatic const int kIndicesPerFillRRect = kIndicesPerStrokeRRect + 6;
144cb93a386Sopenharmony_cistatic const int kVertsPerStrokeRRect = 24;
145cb93a386Sopenharmony_cistatic const int kVertsPerOverstrokeRRect = 28;
146cb93a386Sopenharmony_cistatic const int kVertsPerFillRRect = 24;
147cb93a386Sopenharmony_ci
148cb93a386Sopenharmony_cienum RRectType {
149cb93a386Sopenharmony_ci    kFill_RRectType,
150cb93a386Sopenharmony_ci    kStroke_RRectType,
151cb93a386Sopenharmony_ci    kOverstroke_RRectType,
152cb93a386Sopenharmony_ci};
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ciint rrect_type_to_vert_count(RRectType type) {
155cb93a386Sopenharmony_ci    switch (type) {
156cb93a386Sopenharmony_ci        case kFill_RRectType:
157cb93a386Sopenharmony_ci            return kVertsPerFillRRect;
158cb93a386Sopenharmony_ci        case kStroke_RRectType:
159cb93a386Sopenharmony_ci            return kVertsPerStrokeRRect;
160cb93a386Sopenharmony_ci        case kOverstroke_RRectType:
161cb93a386Sopenharmony_ci            return kVertsPerOverstrokeRRect;
162cb93a386Sopenharmony_ci    }
163cb93a386Sopenharmony_ci    SK_ABORT("Invalid type");
164cb93a386Sopenharmony_ci}
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ciint rrect_type_to_index_count(RRectType type) {
167cb93a386Sopenharmony_ci    switch (type) {
168cb93a386Sopenharmony_ci        case kFill_RRectType:
169cb93a386Sopenharmony_ci            return kIndicesPerFillRRect;
170cb93a386Sopenharmony_ci        case kStroke_RRectType:
171cb93a386Sopenharmony_ci            return kIndicesPerStrokeRRect;
172cb93a386Sopenharmony_ci        case kOverstroke_RRectType:
173cb93a386Sopenharmony_ci            return kIndicesPerOverstrokeRRect;
174cb93a386Sopenharmony_ci    }
175cb93a386Sopenharmony_ci    SK_ABORT("Invalid type");
176cb93a386Sopenharmony_ci}
177cb93a386Sopenharmony_ci
178cb93a386Sopenharmony_ciconst uint16_t* rrect_type_to_indices(RRectType type) {
179cb93a386Sopenharmony_ci    switch (type) {
180cb93a386Sopenharmony_ci        case kFill_RRectType:
181cb93a386Sopenharmony_ci        case kStroke_RRectType:
182cb93a386Sopenharmony_ci            return gRRectIndices + 6*4;
183cb93a386Sopenharmony_ci        case kOverstroke_RRectType:
184cb93a386Sopenharmony_ci            return gRRectIndices;
185cb93a386Sopenharmony_ci    }
186cb93a386Sopenharmony_ci    SK_ABORT("Invalid type");
187cb93a386Sopenharmony_ci}
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
190cb93a386Sopenharmony_ci
191cb93a386Sopenharmony_ciclass ShadowCircularRRectOp final : public GrMeshDrawOp {
192cb93a386Sopenharmony_cipublic:
193cb93a386Sopenharmony_ci    DEFINE_OP_CLASS_ID
194cb93a386Sopenharmony_ci
195cb93a386Sopenharmony_ci    // An insetWidth > 1/2 rect width or height indicates a simple fill.
196cb93a386Sopenharmony_ci    ShadowCircularRRectOp(GrColor color, const SkRect& devRect,
197cb93a386Sopenharmony_ci                          float devRadius, bool isCircle, float blurRadius, float insetWidth,
198cb93a386Sopenharmony_ci                          GrSurfaceProxyView falloffView)
199cb93a386Sopenharmony_ci            : INHERITED(ClassID())
200cb93a386Sopenharmony_ci            , fFalloffView(std::move(falloffView)) {
201cb93a386Sopenharmony_ci        SkRect bounds = devRect;
202cb93a386Sopenharmony_ci        SkASSERT(insetWidth > 0);
203cb93a386Sopenharmony_ci        SkScalar innerRadius = 0.0f;
204cb93a386Sopenharmony_ci        SkScalar outerRadius = devRadius;
205cb93a386Sopenharmony_ci        SkScalar umbraInset;
206cb93a386Sopenharmony_ci
207cb93a386Sopenharmony_ci        RRectType type = kFill_RRectType;
208cb93a386Sopenharmony_ci        if (isCircle) {
209cb93a386Sopenharmony_ci            umbraInset = 0;
210cb93a386Sopenharmony_ci        } else {
211cb93a386Sopenharmony_ci            umbraInset = std::max(outerRadius, blurRadius);
212cb93a386Sopenharmony_ci        }
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ci        // If stroke is greater than width or height, this is still a fill,
215cb93a386Sopenharmony_ci        // otherwise we compute stroke params.
216cb93a386Sopenharmony_ci        if (isCircle) {
217cb93a386Sopenharmony_ci            innerRadius = devRadius - insetWidth;
218cb93a386Sopenharmony_ci            type = innerRadius > 0 ? kStroke_RRectType : kFill_RRectType;
219cb93a386Sopenharmony_ci        } else {
220cb93a386Sopenharmony_ci            if (insetWidth <= 0.5f*std::min(devRect.width(), devRect.height())) {
221cb93a386Sopenharmony_ci                // We don't worry about a real inner radius, we just need to know if we
222cb93a386Sopenharmony_ci                // need to create overstroke vertices.
223cb93a386Sopenharmony_ci                innerRadius = std::max(insetWidth - umbraInset, 0.0f);
224cb93a386Sopenharmony_ci                type = innerRadius > 0 ? kOverstroke_RRectType : kStroke_RRectType;
225cb93a386Sopenharmony_ci            }
226cb93a386Sopenharmony_ci        }
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_ci        this->setBounds(bounds, HasAABloat::kNo, IsHairline::kNo);
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci        fGeoData.emplace_back(Geometry{color, outerRadius, umbraInset, innerRadius,
231cb93a386Sopenharmony_ci                                       blurRadius, bounds, type, isCircle});
232cb93a386Sopenharmony_ci        if (isCircle) {
233cb93a386Sopenharmony_ci            fVertCount = circle_type_to_vert_count(kStroke_RRectType == type);
234cb93a386Sopenharmony_ci            fIndexCount = circle_type_to_index_count(kStroke_RRectType == type);
235cb93a386Sopenharmony_ci        } else {
236cb93a386Sopenharmony_ci            fVertCount = rrect_type_to_vert_count(type);
237cb93a386Sopenharmony_ci            fIndexCount = rrect_type_to_index_count(type);
238cb93a386Sopenharmony_ci        }
239cb93a386Sopenharmony_ci    }
240cb93a386Sopenharmony_ci
241cb93a386Sopenharmony_ci    const char* name() const override { return "ShadowCircularRRectOp"; }
242cb93a386Sopenharmony_ci
243cb93a386Sopenharmony_ci    FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci    GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
246cb93a386Sopenharmony_ci        return GrProcessorSet::EmptySetAnalysis();
247cb93a386Sopenharmony_ci    }
248cb93a386Sopenharmony_ci
249cb93a386Sopenharmony_ciprivate:
250cb93a386Sopenharmony_ci    struct Geometry {
251cb93a386Sopenharmony_ci        GrColor   fColor;
252cb93a386Sopenharmony_ci        SkScalar  fOuterRadius;
253cb93a386Sopenharmony_ci        SkScalar  fUmbraInset;
254cb93a386Sopenharmony_ci        SkScalar  fInnerRadius;
255cb93a386Sopenharmony_ci        SkScalar  fBlurRadius;
256cb93a386Sopenharmony_ci        SkRect    fDevBounds;
257cb93a386Sopenharmony_ci        RRectType fType;
258cb93a386Sopenharmony_ci        bool      fIsCircle;
259cb93a386Sopenharmony_ci    };
260cb93a386Sopenharmony_ci
261cb93a386Sopenharmony_ci    struct CircleVertex {
262cb93a386Sopenharmony_ci        SkPoint fPos;
263cb93a386Sopenharmony_ci        GrColor fColor;
264cb93a386Sopenharmony_ci        SkPoint fOffset;
265cb93a386Sopenharmony_ci        SkScalar fDistanceCorrection;
266cb93a386Sopenharmony_ci    };
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_ci    void fillInCircleVerts(const Geometry& args, bool isStroked, CircleVertex** verts) const {
269cb93a386Sopenharmony_ci
270cb93a386Sopenharmony_ci        GrColor color = args.fColor;
271cb93a386Sopenharmony_ci        SkScalar outerRadius = args.fOuterRadius;
272cb93a386Sopenharmony_ci        SkScalar innerRadius = args.fInnerRadius;
273cb93a386Sopenharmony_ci        SkScalar blurRadius = args.fBlurRadius;
274cb93a386Sopenharmony_ci        SkScalar distanceCorrection = outerRadius / blurRadius;
275cb93a386Sopenharmony_ci
276cb93a386Sopenharmony_ci        const SkRect& bounds = args.fDevBounds;
277cb93a386Sopenharmony_ci
278cb93a386Sopenharmony_ci        // The inner radius in the vertex data must be specified in normalized space.
279cb93a386Sopenharmony_ci        innerRadius = innerRadius / outerRadius;
280cb93a386Sopenharmony_ci
281cb93a386Sopenharmony_ci        SkPoint center = SkPoint::Make(bounds.centerX(), bounds.centerY());
282cb93a386Sopenharmony_ci        SkScalar halfWidth = 0.5f * bounds.width();
283cb93a386Sopenharmony_ci        SkScalar octOffset = 0.41421356237f;  // sqrt(2) - 1
284cb93a386Sopenharmony_ci
285cb93a386Sopenharmony_ci        (*verts)->fPos = center + SkPoint::Make(-octOffset * halfWidth, -halfWidth);
286cb93a386Sopenharmony_ci        (*verts)->fColor = color;
287cb93a386Sopenharmony_ci        (*verts)->fOffset = SkPoint::Make(-octOffset, -1);
288cb93a386Sopenharmony_ci        (*verts)->fDistanceCorrection = distanceCorrection;
289cb93a386Sopenharmony_ci        (*verts)++;
290cb93a386Sopenharmony_ci
291cb93a386Sopenharmony_ci        (*verts)->fPos = center + SkPoint::Make(octOffset * halfWidth, -halfWidth);
292cb93a386Sopenharmony_ci        (*verts)->fColor = color;
293cb93a386Sopenharmony_ci        (*verts)->fOffset = SkPoint::Make(octOffset, -1);
294cb93a386Sopenharmony_ci        (*verts)->fDistanceCorrection = distanceCorrection;
295cb93a386Sopenharmony_ci        (*verts)++;
296cb93a386Sopenharmony_ci
297cb93a386Sopenharmony_ci        (*verts)->fPos = center + SkPoint::Make(halfWidth, -octOffset * halfWidth);
298cb93a386Sopenharmony_ci        (*verts)->fColor = color;
299cb93a386Sopenharmony_ci        (*verts)->fOffset = SkPoint::Make(1, -octOffset);
300cb93a386Sopenharmony_ci        (*verts)->fDistanceCorrection = distanceCorrection;
301cb93a386Sopenharmony_ci        (*verts)++;
302cb93a386Sopenharmony_ci
303cb93a386Sopenharmony_ci        (*verts)->fPos = center + SkPoint::Make(halfWidth, octOffset * halfWidth);
304cb93a386Sopenharmony_ci        (*verts)->fColor = color;
305cb93a386Sopenharmony_ci        (*verts)->fOffset = SkPoint::Make(1, octOffset);
306cb93a386Sopenharmony_ci        (*verts)->fDistanceCorrection = distanceCorrection;
307cb93a386Sopenharmony_ci        (*verts)++;
308cb93a386Sopenharmony_ci
309cb93a386Sopenharmony_ci        (*verts)->fPos = center + SkPoint::Make(octOffset * halfWidth, halfWidth);
310cb93a386Sopenharmony_ci        (*verts)->fColor = color;
311cb93a386Sopenharmony_ci        (*verts)->fOffset = SkPoint::Make(octOffset, 1);
312cb93a386Sopenharmony_ci        (*verts)->fDistanceCorrection = distanceCorrection;
313cb93a386Sopenharmony_ci        (*verts)++;
314cb93a386Sopenharmony_ci
315cb93a386Sopenharmony_ci        (*verts)->fPos = center + SkPoint::Make(-octOffset * halfWidth, halfWidth);
316cb93a386Sopenharmony_ci        (*verts)->fColor = color;
317cb93a386Sopenharmony_ci        (*verts)->fOffset = SkPoint::Make(-octOffset, 1);
318cb93a386Sopenharmony_ci        (*verts)->fDistanceCorrection = distanceCorrection;
319cb93a386Sopenharmony_ci        (*verts)++;
320cb93a386Sopenharmony_ci
321cb93a386Sopenharmony_ci        (*verts)->fPos = center + SkPoint::Make(-halfWidth, octOffset * halfWidth);
322cb93a386Sopenharmony_ci        (*verts)->fColor = color;
323cb93a386Sopenharmony_ci        (*verts)->fOffset = SkPoint::Make(-1, octOffset);
324cb93a386Sopenharmony_ci        (*verts)->fDistanceCorrection = distanceCorrection;
325cb93a386Sopenharmony_ci        (*verts)++;
326cb93a386Sopenharmony_ci
327cb93a386Sopenharmony_ci        (*verts)->fPos = center + SkPoint::Make(-halfWidth, -octOffset * halfWidth);
328cb93a386Sopenharmony_ci        (*verts)->fColor = color;
329cb93a386Sopenharmony_ci        (*verts)->fOffset = SkPoint::Make(-1, -octOffset);
330cb93a386Sopenharmony_ci        (*verts)->fDistanceCorrection = distanceCorrection;
331cb93a386Sopenharmony_ci        (*verts)++;
332cb93a386Sopenharmony_ci
333cb93a386Sopenharmony_ci        if (isStroked) {
334cb93a386Sopenharmony_ci            // compute the inner ring
335cb93a386Sopenharmony_ci
336cb93a386Sopenharmony_ci            // cosine and sine of pi/8
337cb93a386Sopenharmony_ci            SkScalar c = 0.923579533f;
338cb93a386Sopenharmony_ci            SkScalar s = 0.382683432f;
339cb93a386Sopenharmony_ci            SkScalar r = args.fInnerRadius;
340cb93a386Sopenharmony_ci
341cb93a386Sopenharmony_ci            (*verts)->fPos = center + SkPoint::Make(-s * r, -c * r);
342cb93a386Sopenharmony_ci            (*verts)->fColor = color;
343cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(-s * innerRadius, -c * innerRadius);
344cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
345cb93a386Sopenharmony_ci            (*verts)++;
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_ci            (*verts)->fPos = center + SkPoint::Make(s * r, -c * r);
348cb93a386Sopenharmony_ci            (*verts)->fColor = color;
349cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(s * innerRadius, -c * innerRadius);
350cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
351cb93a386Sopenharmony_ci            (*verts)++;
352cb93a386Sopenharmony_ci
353cb93a386Sopenharmony_ci            (*verts)->fPos = center + SkPoint::Make(c * r, -s * r);
354cb93a386Sopenharmony_ci            (*verts)->fColor = color;
355cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(c * innerRadius, -s * innerRadius);
356cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
357cb93a386Sopenharmony_ci            (*verts)++;
358cb93a386Sopenharmony_ci
359cb93a386Sopenharmony_ci            (*verts)->fPos = center + SkPoint::Make(c * r, s * r);
360cb93a386Sopenharmony_ci            (*verts)->fColor = color;
361cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(c * innerRadius, s * innerRadius);
362cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
363cb93a386Sopenharmony_ci            (*verts)++;
364cb93a386Sopenharmony_ci
365cb93a386Sopenharmony_ci            (*verts)->fPos = center + SkPoint::Make(s * r, c * r);
366cb93a386Sopenharmony_ci            (*verts)->fColor = color;
367cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(s * innerRadius, c * innerRadius);
368cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
369cb93a386Sopenharmony_ci            (*verts)++;
370cb93a386Sopenharmony_ci
371cb93a386Sopenharmony_ci            (*verts)->fPos = center + SkPoint::Make(-s * r, c * r);
372cb93a386Sopenharmony_ci            (*verts)->fColor = color;
373cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(-s * innerRadius, c * innerRadius);
374cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
375cb93a386Sopenharmony_ci            (*verts)++;
376cb93a386Sopenharmony_ci
377cb93a386Sopenharmony_ci            (*verts)->fPos = center + SkPoint::Make(-c * r, s * r);
378cb93a386Sopenharmony_ci            (*verts)->fColor = color;
379cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(-c * innerRadius, s * innerRadius);
380cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
381cb93a386Sopenharmony_ci            (*verts)++;
382cb93a386Sopenharmony_ci
383cb93a386Sopenharmony_ci            (*verts)->fPos = center + SkPoint::Make(-c * r, -s * r);
384cb93a386Sopenharmony_ci            (*verts)->fColor = color;
385cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(-c * innerRadius, -s * innerRadius);
386cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
387cb93a386Sopenharmony_ci            (*verts)++;
388cb93a386Sopenharmony_ci        } else {
389cb93a386Sopenharmony_ci            // filled
390cb93a386Sopenharmony_ci            (*verts)->fPos = center;
391cb93a386Sopenharmony_ci            (*verts)->fColor = color;
392cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(0, 0);
393cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
394cb93a386Sopenharmony_ci            (*verts)++;
395cb93a386Sopenharmony_ci        }
396cb93a386Sopenharmony_ci    }
397cb93a386Sopenharmony_ci
398cb93a386Sopenharmony_ci    void fillInRRectVerts(const Geometry& args, CircleVertex** verts) const {
399cb93a386Sopenharmony_ci        GrColor color = args.fColor;
400cb93a386Sopenharmony_ci        SkScalar outerRadius = args.fOuterRadius;
401cb93a386Sopenharmony_ci
402cb93a386Sopenharmony_ci        const SkRect& bounds = args.fDevBounds;
403cb93a386Sopenharmony_ci
404cb93a386Sopenharmony_ci        SkScalar umbraInset = args.fUmbraInset;
405cb93a386Sopenharmony_ci        SkScalar minDim = 0.5f*std::min(bounds.width(), bounds.height());
406cb93a386Sopenharmony_ci        if (umbraInset > minDim) {
407cb93a386Sopenharmony_ci            umbraInset = minDim;
408cb93a386Sopenharmony_ci        }
409cb93a386Sopenharmony_ci
410cb93a386Sopenharmony_ci        SkScalar xInner[4] = { bounds.fLeft + umbraInset, bounds.fRight - umbraInset,
411cb93a386Sopenharmony_ci            bounds.fLeft + umbraInset, bounds.fRight - umbraInset };
412cb93a386Sopenharmony_ci        SkScalar xMid[4] = { bounds.fLeft + outerRadius, bounds.fRight - outerRadius,
413cb93a386Sopenharmony_ci            bounds.fLeft + outerRadius, bounds.fRight - outerRadius };
414cb93a386Sopenharmony_ci        SkScalar xOuter[4] = { bounds.fLeft, bounds.fRight,
415cb93a386Sopenharmony_ci            bounds.fLeft, bounds.fRight };
416cb93a386Sopenharmony_ci        SkScalar yInner[4] = { bounds.fTop + umbraInset, bounds.fTop + umbraInset,
417cb93a386Sopenharmony_ci            bounds.fBottom - umbraInset, bounds.fBottom - umbraInset };
418cb93a386Sopenharmony_ci        SkScalar yMid[4] = { bounds.fTop + outerRadius, bounds.fTop + outerRadius,
419cb93a386Sopenharmony_ci            bounds.fBottom - outerRadius, bounds.fBottom - outerRadius };
420cb93a386Sopenharmony_ci        SkScalar yOuter[4] = { bounds.fTop, bounds.fTop,
421cb93a386Sopenharmony_ci            bounds.fBottom, bounds.fBottom };
422cb93a386Sopenharmony_ci
423cb93a386Sopenharmony_ci        SkScalar blurRadius = args.fBlurRadius;
424cb93a386Sopenharmony_ci
425cb93a386Sopenharmony_ci        // In the case where we have to inset more for the umbra, our two triangles in the
426cb93a386Sopenharmony_ci        // corner get skewed to a diamond rather than a square. To correct for that,
427cb93a386Sopenharmony_ci        // we also skew the vectors we send to the shader that help define the circle.
428cb93a386Sopenharmony_ci        // By doing so, we end up with a quarter circle in the corner rather than the
429cb93a386Sopenharmony_ci        // elliptical curve.
430cb93a386Sopenharmony_ci
431cb93a386Sopenharmony_ci        // This is a bit magical, but it gives us the correct results at extrema:
432cb93a386Sopenharmony_ci        //   a) umbraInset == outerRadius produces an orthogonal vector
433cb93a386Sopenharmony_ci        //   b) outerRadius == 0 produces a diagonal vector
434cb93a386Sopenharmony_ci        // And visually the corner looks correct.
435cb93a386Sopenharmony_ci        SkVector outerVec = SkVector::Make(outerRadius - umbraInset, -outerRadius - umbraInset);
436cb93a386Sopenharmony_ci        outerVec.normalize();
437cb93a386Sopenharmony_ci        // We want the circle edge to fall fractionally along the diagonal at
438cb93a386Sopenharmony_ci        //      (sqrt(2)*(umbraInset - outerRadius) + outerRadius)/sqrt(2)*umbraInset
439cb93a386Sopenharmony_ci        //
440cb93a386Sopenharmony_ci        // Setting the components of the diagonal offset to the following value will give us that.
441cb93a386Sopenharmony_ci        SkScalar diagVal = umbraInset / (SK_ScalarSqrt2*(outerRadius - umbraInset) - outerRadius);
442cb93a386Sopenharmony_ci        SkVector diagVec = SkVector::Make(diagVal, diagVal);
443cb93a386Sopenharmony_ci        SkScalar distanceCorrection = umbraInset / blurRadius;
444cb93a386Sopenharmony_ci
445cb93a386Sopenharmony_ci        // build corner by corner
446cb93a386Sopenharmony_ci        for (int i = 0; i < 4; ++i) {
447cb93a386Sopenharmony_ci            // inner point
448cb93a386Sopenharmony_ci            (*verts)->fPos = SkPoint::Make(xInner[i], yInner[i]);
449cb93a386Sopenharmony_ci            (*verts)->fColor = color;
450cb93a386Sopenharmony_ci            (*verts)->fOffset = SkVector::Make(0, 0);
451cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
452cb93a386Sopenharmony_ci            (*verts)++;
453cb93a386Sopenharmony_ci
454cb93a386Sopenharmony_ci            // outer points
455cb93a386Sopenharmony_ci            (*verts)->fPos = SkPoint::Make(xOuter[i], yInner[i]);
456cb93a386Sopenharmony_ci            (*verts)->fColor = color;
457cb93a386Sopenharmony_ci            (*verts)->fOffset = SkVector::Make(0, -1);
458cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
459cb93a386Sopenharmony_ci            (*verts)++;
460cb93a386Sopenharmony_ci
461cb93a386Sopenharmony_ci            (*verts)->fPos = SkPoint::Make(xOuter[i], yMid[i]);
462cb93a386Sopenharmony_ci            (*verts)->fColor = color;
463cb93a386Sopenharmony_ci            (*verts)->fOffset = outerVec;
464cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
465cb93a386Sopenharmony_ci            (*verts)++;
466cb93a386Sopenharmony_ci
467cb93a386Sopenharmony_ci            (*verts)->fPos = SkPoint::Make(xOuter[i], yOuter[i]);
468cb93a386Sopenharmony_ci            (*verts)->fColor = color;
469cb93a386Sopenharmony_ci            (*verts)->fOffset = diagVec;
470cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
471cb93a386Sopenharmony_ci            (*verts)++;
472cb93a386Sopenharmony_ci
473cb93a386Sopenharmony_ci            (*verts)->fPos = SkPoint::Make(xMid[i], yOuter[i]);
474cb93a386Sopenharmony_ci            (*verts)->fColor = color;
475cb93a386Sopenharmony_ci            (*verts)->fOffset = outerVec;
476cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
477cb93a386Sopenharmony_ci            (*verts)++;
478cb93a386Sopenharmony_ci
479cb93a386Sopenharmony_ci            (*verts)->fPos = SkPoint::Make(xInner[i], yOuter[i]);
480cb93a386Sopenharmony_ci            (*verts)->fColor = color;
481cb93a386Sopenharmony_ci            (*verts)->fOffset = SkVector::Make(0, -1);
482cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
483cb93a386Sopenharmony_ci            (*verts)++;
484cb93a386Sopenharmony_ci        }
485cb93a386Sopenharmony_ci
486cb93a386Sopenharmony_ci        // Add the additional vertices for overstroked rrects.
487cb93a386Sopenharmony_ci        // Effectively this is an additional stroked rrect, with its
488cb93a386Sopenharmony_ci        // parameters equal to those in the center of the 9-patch. This will
489cb93a386Sopenharmony_ci        // give constant values across this inner ring.
490cb93a386Sopenharmony_ci        if (kOverstroke_RRectType == args.fType) {
491cb93a386Sopenharmony_ci            SkASSERT(args.fInnerRadius > 0.0f);
492cb93a386Sopenharmony_ci
493cb93a386Sopenharmony_ci            SkScalar inset =  umbraInset + args.fInnerRadius;
494cb93a386Sopenharmony_ci
495cb93a386Sopenharmony_ci            // TL
496cb93a386Sopenharmony_ci            (*verts)->fPos = SkPoint::Make(bounds.fLeft + inset, bounds.fTop + inset);
497cb93a386Sopenharmony_ci            (*verts)->fColor = color;
498cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(0, 0);
499cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
500cb93a386Sopenharmony_ci            (*verts)++;
501cb93a386Sopenharmony_ci
502cb93a386Sopenharmony_ci            // TR
503cb93a386Sopenharmony_ci            (*verts)->fPos = SkPoint::Make(bounds.fRight - inset, bounds.fTop + inset);
504cb93a386Sopenharmony_ci            (*verts)->fColor = color;
505cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(0, 0);
506cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
507cb93a386Sopenharmony_ci            (*verts)++;
508cb93a386Sopenharmony_ci
509cb93a386Sopenharmony_ci            // BL
510cb93a386Sopenharmony_ci            (*verts)->fPos = SkPoint::Make(bounds.fLeft + inset, bounds.fBottom - inset);
511cb93a386Sopenharmony_ci            (*verts)->fColor = color;
512cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(0, 0);
513cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
514cb93a386Sopenharmony_ci            (*verts)++;
515cb93a386Sopenharmony_ci
516cb93a386Sopenharmony_ci            // BR
517cb93a386Sopenharmony_ci            (*verts)->fPos = SkPoint::Make(bounds.fRight - inset, bounds.fBottom - inset);
518cb93a386Sopenharmony_ci            (*verts)->fColor = color;
519cb93a386Sopenharmony_ci            (*verts)->fOffset = SkPoint::Make(0, 0);
520cb93a386Sopenharmony_ci            (*verts)->fDistanceCorrection = distanceCorrection;
521cb93a386Sopenharmony_ci            (*verts)++;
522cb93a386Sopenharmony_ci        }
523cb93a386Sopenharmony_ci
524cb93a386Sopenharmony_ci    }
525cb93a386Sopenharmony_ci
526cb93a386Sopenharmony_ci    GrProgramInfo* programInfo() override { return fProgramInfo; }
527cb93a386Sopenharmony_ci
528cb93a386Sopenharmony_ci    void onCreateProgramInfo(const GrCaps* caps,
529cb93a386Sopenharmony_ci                             SkArenaAlloc* arena,
530cb93a386Sopenharmony_ci                             const GrSurfaceProxyView& writeView,
531cb93a386Sopenharmony_ci                             bool usesMSAASurface,
532cb93a386Sopenharmony_ci                             GrAppliedClip&& appliedClip,
533cb93a386Sopenharmony_ci                             const GrDstProxyView& dstProxyView,
534cb93a386Sopenharmony_ci                             GrXferBarrierFlags renderPassXferBarriers,
535cb93a386Sopenharmony_ci                             GrLoadOp colorLoadOp) override {
536cb93a386Sopenharmony_ci        GrGeometryProcessor* gp = GrRRectShadowGeoProc::Make(arena, fFalloffView);
537cb93a386Sopenharmony_ci        SkASSERT(sizeof(CircleVertex) == gp->vertexStride());
538cb93a386Sopenharmony_ci
539cb93a386Sopenharmony_ci        fProgramInfo = GrSimpleMeshDrawOpHelper::CreateProgramInfo(caps, arena, writeView,
540cb93a386Sopenharmony_ci                                                                   usesMSAASurface,
541cb93a386Sopenharmony_ci                                                                   std::move(appliedClip),
542cb93a386Sopenharmony_ci                                                                   dstProxyView, gp,
543cb93a386Sopenharmony_ci                                                                   GrProcessorSet::MakeEmptySet(),
544cb93a386Sopenharmony_ci                                                                   GrPrimitiveType::kTriangles,
545cb93a386Sopenharmony_ci                                                                   renderPassXferBarriers,
546cb93a386Sopenharmony_ci                                                                   colorLoadOp,
547cb93a386Sopenharmony_ci                                                                   GrPipeline::InputFlags::kNone,
548cb93a386Sopenharmony_ci                                                                   &GrUserStencilSettings::kUnused);
549cb93a386Sopenharmony_ci    }
550cb93a386Sopenharmony_ci
551cb93a386Sopenharmony_ci    void onPrepareDraws(GrMeshDrawTarget* target) override {
552cb93a386Sopenharmony_ci        int instanceCount = fGeoData.count();
553cb93a386Sopenharmony_ci
554cb93a386Sopenharmony_ci        sk_sp<const GrBuffer> vertexBuffer;
555cb93a386Sopenharmony_ci        int firstVertex;
556cb93a386Sopenharmony_ci        CircleVertex* verts = (CircleVertex*)target->makeVertexSpace(
557cb93a386Sopenharmony_ci                sizeof(CircleVertex), fVertCount, &vertexBuffer, &firstVertex);
558cb93a386Sopenharmony_ci        if (!verts) {
559cb93a386Sopenharmony_ci            SkDebugf("Could not allocate vertices\n");
560cb93a386Sopenharmony_ci            return;
561cb93a386Sopenharmony_ci        }
562cb93a386Sopenharmony_ci
563cb93a386Sopenharmony_ci        sk_sp<const GrBuffer> indexBuffer;
564cb93a386Sopenharmony_ci        int firstIndex = 0;
565cb93a386Sopenharmony_ci        uint16_t* indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
566cb93a386Sopenharmony_ci        if (!indices) {
567cb93a386Sopenharmony_ci            SkDebugf("Could not allocate indices\n");
568cb93a386Sopenharmony_ci            return;
569cb93a386Sopenharmony_ci        }
570cb93a386Sopenharmony_ci
571cb93a386Sopenharmony_ci        int currStartVertex = 0;
572cb93a386Sopenharmony_ci        for (int i = 0; i < instanceCount; i++) {
573cb93a386Sopenharmony_ci            const Geometry& args = fGeoData[i];
574cb93a386Sopenharmony_ci
575cb93a386Sopenharmony_ci            if (args.fIsCircle) {
576cb93a386Sopenharmony_ci                bool isStroked = SkToBool(kStroke_RRectType == args.fType);
577cb93a386Sopenharmony_ci                this->fillInCircleVerts(args, isStroked, &verts);
578cb93a386Sopenharmony_ci
579cb93a386Sopenharmony_ci                const uint16_t* primIndices = circle_type_to_indices(isStroked);
580cb93a386Sopenharmony_ci                const int primIndexCount = circle_type_to_index_count(isStroked);
581cb93a386Sopenharmony_ci                for (int j = 0; j < primIndexCount; ++j) {
582cb93a386Sopenharmony_ci                    *indices++ = primIndices[j] + currStartVertex;
583cb93a386Sopenharmony_ci                }
584cb93a386Sopenharmony_ci
585cb93a386Sopenharmony_ci                currStartVertex += circle_type_to_vert_count(isStroked);
586cb93a386Sopenharmony_ci
587cb93a386Sopenharmony_ci            } else {
588cb93a386Sopenharmony_ci                this->fillInRRectVerts(args, &verts);
589cb93a386Sopenharmony_ci
590cb93a386Sopenharmony_ci                const uint16_t* primIndices = rrect_type_to_indices(args.fType);
591cb93a386Sopenharmony_ci                const int primIndexCount = rrect_type_to_index_count(args.fType);
592cb93a386Sopenharmony_ci                for (int j = 0; j < primIndexCount; ++j) {
593cb93a386Sopenharmony_ci                    *indices++ = primIndices[j] + currStartVertex;
594cb93a386Sopenharmony_ci                }
595cb93a386Sopenharmony_ci
596cb93a386Sopenharmony_ci                currStartVertex += rrect_type_to_vert_count(args.fType);
597cb93a386Sopenharmony_ci            }
598cb93a386Sopenharmony_ci        }
599cb93a386Sopenharmony_ci
600cb93a386Sopenharmony_ci        fMesh = target->allocMesh();
601cb93a386Sopenharmony_ci        fMesh->setIndexed(std::move(indexBuffer), fIndexCount, firstIndex, 0, fVertCount - 1,
602cb93a386Sopenharmony_ci                          GrPrimitiveRestart::kNo, std::move(vertexBuffer), firstVertex);
603cb93a386Sopenharmony_ci    }
604cb93a386Sopenharmony_ci
605cb93a386Sopenharmony_ci    void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
606cb93a386Sopenharmony_ci        if (!fProgramInfo) {
607cb93a386Sopenharmony_ci            this->createProgramInfo(flushState);
608cb93a386Sopenharmony_ci        }
609cb93a386Sopenharmony_ci
610cb93a386Sopenharmony_ci        if (!fProgramInfo || !fMesh) {
611cb93a386Sopenharmony_ci            return;
612cb93a386Sopenharmony_ci        }
613cb93a386Sopenharmony_ci
614cb93a386Sopenharmony_ci        flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
615cb93a386Sopenharmony_ci        flushState->bindTextures(fProgramInfo->geomProc(), *fFalloffView.proxy(),
616cb93a386Sopenharmony_ci                                 fProgramInfo->pipeline());
617cb93a386Sopenharmony_ci        flushState->drawMesh(*fMesh);
618cb93a386Sopenharmony_ci    }
619cb93a386Sopenharmony_ci
620cb93a386Sopenharmony_ci    CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
621cb93a386Sopenharmony_ci        ShadowCircularRRectOp* that = t->cast<ShadowCircularRRectOp>();
622cb93a386Sopenharmony_ci        fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
623cb93a386Sopenharmony_ci        fVertCount += that->fVertCount;
624cb93a386Sopenharmony_ci        fIndexCount += that->fIndexCount;
625cb93a386Sopenharmony_ci        return CombineResult::kMerged;
626cb93a386Sopenharmony_ci    }
627cb93a386Sopenharmony_ci
628cb93a386Sopenharmony_ci#if GR_TEST_UTILS
629cb93a386Sopenharmony_ci    SkString onDumpInfo() const override {
630cb93a386Sopenharmony_ci        SkString string;
631cb93a386Sopenharmony_ci        for (int i = 0; i < fGeoData.count(); ++i) {
632cb93a386Sopenharmony_ci            string.appendf(
633cb93a386Sopenharmony_ci                    "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
634cb93a386Sopenharmony_ci                    "OuterRad: %.2f, Umbra: %.2f, InnerRad: %.2f, BlurRad: %.2f\n",
635cb93a386Sopenharmony_ci                    fGeoData[i].fColor, fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.fTop,
636cb93a386Sopenharmony_ci                    fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds.fBottom,
637cb93a386Sopenharmony_ci                    fGeoData[i].fOuterRadius, fGeoData[i].fUmbraInset,
638cb93a386Sopenharmony_ci                    fGeoData[i].fInnerRadius, fGeoData[i].fBlurRadius);
639cb93a386Sopenharmony_ci        }
640cb93a386Sopenharmony_ci        return string;
641cb93a386Sopenharmony_ci    }
642cb93a386Sopenharmony_ci#endif
643cb93a386Sopenharmony_ci
644cb93a386Sopenharmony_ci    void visitProxies(const GrVisitProxyFunc& func) const override {
645cb93a386Sopenharmony_ci        func(fFalloffView.proxy(), GrMipmapped(false));
646cb93a386Sopenharmony_ci        if (fProgramInfo) {
647cb93a386Sopenharmony_ci            fProgramInfo->visitFPProxies(func);
648cb93a386Sopenharmony_ci        }
649cb93a386Sopenharmony_ci    }
650cb93a386Sopenharmony_ci
651cb93a386Sopenharmony_ci    SkSTArray<1, Geometry, true> fGeoData;
652cb93a386Sopenharmony_ci    int fVertCount;
653cb93a386Sopenharmony_ci    int fIndexCount;
654cb93a386Sopenharmony_ci    GrSurfaceProxyView fFalloffView;
655cb93a386Sopenharmony_ci
656cb93a386Sopenharmony_ci    GrSimpleMesh*      fMesh = nullptr;
657cb93a386Sopenharmony_ci    GrProgramInfo*     fProgramInfo = nullptr;
658cb93a386Sopenharmony_ci
659cb93a386Sopenharmony_ci    using INHERITED = GrMeshDrawOp;
660cb93a386Sopenharmony_ci};
661cb93a386Sopenharmony_ci
662cb93a386Sopenharmony_ci}  // anonymous namespace
663cb93a386Sopenharmony_ci
664cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
665cb93a386Sopenharmony_ci
666cb93a386Sopenharmony_cinamespace skgpu::v1::ShadowRRectOp {
667cb93a386Sopenharmony_ci
668cb93a386Sopenharmony_cistatic GrSurfaceProxyView create_falloff_texture(GrRecordingContext* rContext) {
669cb93a386Sopenharmony_ci    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
670cb93a386Sopenharmony_ci    GrUniqueKey key;
671cb93a386Sopenharmony_ci    GrUniqueKey::Builder builder(&key, kDomain, 0, "Shadow Gaussian Falloff");
672cb93a386Sopenharmony_ci    builder.finish();
673cb93a386Sopenharmony_ci
674cb93a386Sopenharmony_ci    auto threadSafeCache = rContext->priv().threadSafeCache();
675cb93a386Sopenharmony_ci
676cb93a386Sopenharmony_ci    GrSurfaceProxyView view = threadSafeCache->find(key);
677cb93a386Sopenharmony_ci    if (view) {
678cb93a386Sopenharmony_ci        SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin);
679cb93a386Sopenharmony_ci        return view;
680cb93a386Sopenharmony_ci    }
681cb93a386Sopenharmony_ci
682cb93a386Sopenharmony_ci    static const int kWidth = 128;
683cb93a386Sopenharmony_ci    static const size_t kRowBytes = kWidth * GrColorTypeBytesPerPixel(GrColorType::kAlpha_8);
684cb93a386Sopenharmony_ci    SkImageInfo ii = SkImageInfo::MakeA8(kWidth, 1);
685cb93a386Sopenharmony_ci
686cb93a386Sopenharmony_ci    SkBitmap bitmap;
687cb93a386Sopenharmony_ci    bitmap.allocPixels(ii, kRowBytes);
688cb93a386Sopenharmony_ci
689cb93a386Sopenharmony_ci    unsigned char* values = (unsigned char*)bitmap.getPixels();
690cb93a386Sopenharmony_ci    for (int i = 0; i < 128; ++i) {
691cb93a386Sopenharmony_ci        SkScalar d = SK_Scalar1 - i / SkIntToScalar(127);
692cb93a386Sopenharmony_ci        values[i] = SkScalarRoundToInt((SkScalarExp(-4 * d * d) - 0.018f) * 255);
693cb93a386Sopenharmony_ci    }
694cb93a386Sopenharmony_ci    bitmap.setImmutable();
695cb93a386Sopenharmony_ci
696cb93a386Sopenharmony_ci    view = std::get<0>(GrMakeUncachedBitmapProxyView(rContext, bitmap));
697cb93a386Sopenharmony_ci    if (!view) {
698cb93a386Sopenharmony_ci        return {};
699cb93a386Sopenharmony_ci    }
700cb93a386Sopenharmony_ci
701cb93a386Sopenharmony_ci    view = threadSafeCache->add(key, view);
702cb93a386Sopenharmony_ci    SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin);
703cb93a386Sopenharmony_ci    return view;
704cb93a386Sopenharmony_ci}
705cb93a386Sopenharmony_ci
706cb93a386Sopenharmony_ciGrOp::Owner Make(GrRecordingContext* context,
707cb93a386Sopenharmony_ci                 GrColor color,
708cb93a386Sopenharmony_ci                 const SkMatrix& viewMatrix,
709cb93a386Sopenharmony_ci                 const SkRRect& rrect,
710cb93a386Sopenharmony_ci                 SkScalar blurWidth,
711cb93a386Sopenharmony_ci                 SkScalar insetWidth) {
712cb93a386Sopenharmony_ci    // Shadow rrect ops only handle simple circular rrects.
713cb93a386Sopenharmony_ci    SkASSERT(viewMatrix.isSimilarity() && SkRRectPriv::EqualRadii(rrect));
714cb93a386Sopenharmony_ci
715cb93a386Sopenharmony_ci    GrSurfaceProxyView falloffView = create_falloff_texture(context);
716cb93a386Sopenharmony_ci    if (!falloffView) {
717cb93a386Sopenharmony_ci        return nullptr;
718cb93a386Sopenharmony_ci    }
719cb93a386Sopenharmony_ci
720cb93a386Sopenharmony_ci    // Do any matrix crunching before we reset the draw state for device coords.
721cb93a386Sopenharmony_ci    const SkRect& rrectBounds = rrect.getBounds();
722cb93a386Sopenharmony_ci    SkRect bounds;
723cb93a386Sopenharmony_ci    viewMatrix.mapRect(&bounds, rrectBounds);
724cb93a386Sopenharmony_ci
725cb93a386Sopenharmony_ci    // Map radius and inset. As the matrix is a similarity matrix, this should be isotropic.
726cb93a386Sopenharmony_ci    SkScalar radius = SkRRectPriv::GetSimpleRadii(rrect).fX;
727cb93a386Sopenharmony_ci    SkScalar matrixFactor = viewMatrix[SkMatrix::kMScaleX] + viewMatrix[SkMatrix::kMSkewX];
728cb93a386Sopenharmony_ci    SkScalar scaledRadius = SkScalarAbs(radius*matrixFactor);
729cb93a386Sopenharmony_ci    SkScalar scaledInsetWidth = SkScalarAbs(insetWidth*matrixFactor);
730cb93a386Sopenharmony_ci
731cb93a386Sopenharmony_ci    if (scaledInsetWidth <= 0) {
732cb93a386Sopenharmony_ci        return nullptr;
733cb93a386Sopenharmony_ci    }
734cb93a386Sopenharmony_ci
735cb93a386Sopenharmony_ci    return GrOp::Make<ShadowCircularRRectOp>(context,
736cb93a386Sopenharmony_ci                                             color,
737cb93a386Sopenharmony_ci                                             bounds,
738cb93a386Sopenharmony_ci                                             scaledRadius,
739cb93a386Sopenharmony_ci                                             rrect.isOval(),
740cb93a386Sopenharmony_ci                                             blurWidth,
741cb93a386Sopenharmony_ci                                             scaledInsetWidth,
742cb93a386Sopenharmony_ci                                             std::move(falloffView));
743cb93a386Sopenharmony_ci}
744cb93a386Sopenharmony_ci
745cb93a386Sopenharmony_ci}  // namespace skgpu::v1::ShadowRRectOp
746cb93a386Sopenharmony_ci
747cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
748cb93a386Sopenharmony_ci
749cb93a386Sopenharmony_ci#if GR_TEST_UTILS
750cb93a386Sopenharmony_ci
751cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h"
752cb93a386Sopenharmony_ci
753cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(ShadowRRectOp) {
754cb93a386Sopenharmony_ci    // We may choose matrix and inset values that cause the factory to fail. We loop until we find
755cb93a386Sopenharmony_ci    // an acceptable combination.
756cb93a386Sopenharmony_ci    do {
757cb93a386Sopenharmony_ci        // create a similarity matrix
758cb93a386Sopenharmony_ci        SkScalar rotate = random->nextSScalar1() * 360.f;
759cb93a386Sopenharmony_ci        SkScalar translateX = random->nextSScalar1() * 1000.f;
760cb93a386Sopenharmony_ci        SkScalar translateY = random->nextSScalar1() * 1000.f;
761cb93a386Sopenharmony_ci        SkScalar scale = random->nextSScalar1() * 100.f;
762cb93a386Sopenharmony_ci        SkMatrix viewMatrix;
763cb93a386Sopenharmony_ci        viewMatrix.setRotate(rotate);
764cb93a386Sopenharmony_ci        viewMatrix.postTranslate(translateX, translateY);
765cb93a386Sopenharmony_ci        viewMatrix.postScale(scale, scale);
766cb93a386Sopenharmony_ci        SkScalar insetWidth = random->nextSScalar1() * 72.f;
767cb93a386Sopenharmony_ci        SkScalar blurWidth = random->nextSScalar1() * 72.f;
768cb93a386Sopenharmony_ci        bool isCircle = random->nextBool();
769cb93a386Sopenharmony_ci        // This op doesn't use a full GrPaint, just a color.
770cb93a386Sopenharmony_ci        GrColor color = paint.getColor4f().toBytes_RGBA();
771cb93a386Sopenharmony_ci        if (isCircle) {
772cb93a386Sopenharmony_ci            SkRect circle = GrTest::TestSquare(random);
773cb93a386Sopenharmony_ci            SkRRect rrect = SkRRect::MakeOval(circle);
774cb93a386Sopenharmony_ci            if (auto op = skgpu::v1::ShadowRRectOp::Make(
775cb93a386Sopenharmony_ci                    context, color, viewMatrix, rrect, blurWidth, insetWidth)) {
776cb93a386Sopenharmony_ci                return op;
777cb93a386Sopenharmony_ci            }
778cb93a386Sopenharmony_ci        } else {
779cb93a386Sopenharmony_ci            SkRRect rrect;
780cb93a386Sopenharmony_ci            do {
781cb93a386Sopenharmony_ci                // This may return a rrect with elliptical corners, which will cause an assert.
782cb93a386Sopenharmony_ci                rrect = GrTest::TestRRectSimple(random);
783cb93a386Sopenharmony_ci            } while (!SkRRectPriv::IsSimpleCircular(rrect));
784cb93a386Sopenharmony_ci            if (auto op = skgpu::v1::ShadowRRectOp::Make(
785cb93a386Sopenharmony_ci                    context, color, viewMatrix, rrect, blurWidth, insetWidth)) {
786cb93a386Sopenharmony_ci                return op;
787cb93a386Sopenharmony_ci            }
788cb93a386Sopenharmony_ci        }
789cb93a386Sopenharmony_ci    } while (true);
790cb93a386Sopenharmony_ci}
791cb93a386Sopenharmony_ci
792cb93a386Sopenharmony_ci#endif // GR_TEST_UTILS
793