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