1 /*
2  * Copyright 2014 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 "GrRRectEffect.h"
9 
10 #include "GrConvexPolyEffect.h"
11 #include "GrFragmentProcessor.h"
12 #include "GrOvalEffect.h"
13 #include "GrShaderCaps.h"
14 #include "SkRRect.h"
15 #include "SkTLazy.h"
16 #include "glsl/GrGLSLFragmentProcessor.h"
17 #include "glsl/GrGLSLFragmentShaderBuilder.h"
18 #include "glsl/GrGLSLProgramDataManager.h"
19 #include "glsl/GrGLSLUniformHandler.h"
20 
21 // The effects defined here only handle rrect radii >= kRadiusMin.
22 static const SkScalar kRadiusMin = SK_ScalarHalf;
23 
24 //////////////////////////////////////////////////////////////////////////////
25 
26 class CircularRRectEffect : public GrFragmentProcessor {
27 public:
28 
29     enum CornerFlags {
30         kTopLeft_CornerFlag     = (1 << SkRRect::kUpperLeft_Corner),
31         kTopRight_CornerFlag    = (1 << SkRRect::kUpperRight_Corner),
32         kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner),
33         kBottomLeft_CornerFlag  = (1 << SkRRect::kLowerLeft_Corner),
34 
35         kLeft_CornerFlags   = kTopLeft_CornerFlag    | kBottomLeft_CornerFlag,
36         kTop_CornerFlags    = kTopLeft_CornerFlag    | kTopRight_CornerFlag,
37         kRight_CornerFlags  = kTopRight_CornerFlag   | kBottomRight_CornerFlag,
38         kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
39 
40         kAll_CornerFlags = kTopLeft_CornerFlag    | kTopRight_CornerFlag |
41                            kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
42 
43         kNone_CornerFlags = 0
44     };
45 
46     // The flags are used to indicate which corners are circluar (unflagged corners are assumed to
47     // be square).
48     static sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType, uint32_t circularCornerFlags,
49                                            const SkRRect&);
50 
~CircularRRectEffect()51     ~CircularRRectEffect() override {}
52 
name() const53     const char* name() const override { return "CircularRRect"; }
54 
getRRect() const55     const SkRRect& getRRect() const { return fRRect; }
56 
getCircularCornerFlags() const57     uint32_t getCircularCornerFlags() const { return fCircularCornerFlags; }
58 
getEdgeType() const59     GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
60 
61 private:
62     CircularRRectEffect(GrPrimitiveEdgeType, uint32_t circularCornerFlags, const SkRRect&);
63 
64     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
65 
66     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
67 
68     bool onIsEqual(const GrFragmentProcessor& other) const override;
69 
70     SkRRect                fRRect;
71     GrPrimitiveEdgeType    fEdgeType;
72     uint32_t               fCircularCornerFlags;
73 
74     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
75 
76     typedef GrFragmentProcessor INHERITED;
77 };
78 
Make(GrPrimitiveEdgeType edgeType,uint32_t circularCornerFlags,const SkRRect & rrect)79 sk_sp<GrFragmentProcessor> CircularRRectEffect::Make(GrPrimitiveEdgeType edgeType,
80                                                      uint32_t circularCornerFlags,
81                                                      const SkRRect& rrect) {
82     if (kFillAA_GrProcessorEdgeType != edgeType && kInverseFillAA_GrProcessorEdgeType != edgeType) {
83         return nullptr;
84     }
85     return sk_sp<GrFragmentProcessor>(
86         new CircularRRectEffect(edgeType, circularCornerFlags, rrect));
87 }
88 
CircularRRectEffect(GrPrimitiveEdgeType edgeType,uint32_t circularCornerFlags,const SkRRect & rrect)89 CircularRRectEffect::CircularRRectEffect(GrPrimitiveEdgeType edgeType, uint32_t circularCornerFlags,
90                                          const SkRRect& rrect)
91         : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag)
92         , fRRect(rrect)
93         , fEdgeType(edgeType)
94         , fCircularCornerFlags(circularCornerFlags) {
95     this->initClassID<CircularRRectEffect>();
96 }
97 
onIsEqual(const GrFragmentProcessor & other) const98 bool CircularRRectEffect::onIsEqual(const GrFragmentProcessor& other) const {
99     const CircularRRectEffect& crre = other.cast<CircularRRectEffect>();
100     // The corner flags are derived from fRRect, so no need to check them.
101     return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect;
102 }
103 
104 //////////////////////////////////////////////////////////////////////////////
105 
106 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircularRRectEffect);
107 
108 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)109 sk_sp<GrFragmentProcessor> CircularRRectEffect::TestCreate(GrProcessorTestData* d) {
110     SkScalar w = d->fRandom->nextRangeScalar(20.f, 1000.f);
111     SkScalar h = d->fRandom->nextRangeScalar(20.f, 1000.f);
112     SkScalar r = d->fRandom->nextRangeF(kRadiusMin, 9.f);
113     SkRRect rrect;
114     rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
115     sk_sp<GrFragmentProcessor> fp;
116     do {
117         GrPrimitiveEdgeType et =
118                 (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt);
119         fp = GrRRectEffect::Make(et, rrect);
120     } while (nullptr == fp);
121     return fp;
122 }
123 #endif
124 
125 //////////////////////////////////////////////////////////////////////////////
126 
127 class GLCircularRRectEffect : public GrGLSLFragmentProcessor {
128 public:
GLCircularRRectEffect()129     GLCircularRRectEffect() {
130         fPrevRRect.setEmpty();
131     }
132 
133     virtual void emitCode(EmitArgs&) override;
134 
135     static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
136 
137 protected:
138     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
139 
140 private:
141     GrGLSLProgramDataManager::UniformHandle fInnerRectUniform;
142     GrGLSLProgramDataManager::UniformHandle fRadiusPlusHalfUniform;
143     SkRRect                                 fPrevRRect;
144     typedef GrGLSLFragmentProcessor INHERITED;
145 };
146 
emitCode(EmitArgs & args)147 void GLCircularRRectEffect::emitCode(EmitArgs& args) {
148     const CircularRRectEffect& crre = args.fFp.cast<CircularRRectEffect>();
149     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
150     const char *rectName;
151     const char *radiusPlusHalfName;
152     // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom
153     // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has
154     // only rectangular corners, that side's value corresponds to the rect edge's value outset by
155     // half a pixel.
156     fInnerRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
157                                                    kVec4f_GrSLType, kDefault_GrSLPrecision,
158                                                    "innerRect",
159                                                    &rectName);
160     // x is (r + .5) and y is 1/(r + .5)
161     fRadiusPlusHalfUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
162                                                         kVec2f_GrSLType, kDefault_GrSLPrecision,
163                                                         "radiusPlusHalf",
164                                                         &radiusPlusHalfName);
165 
166     // If we're on a device with a "real" mediump then the length calculation could overflow.
167     SkString clampedCircleDistance;
168     if (args.fShaderCaps->floatPrecisionVaries()) {
169         clampedCircleDistance.printf("clamp(%s.x * (1.0 - length(dxy * %s.y)), 0.0, 1.0);",
170                                      radiusPlusHalfName, radiusPlusHalfName);
171     } else {
172         clampedCircleDistance.printf("clamp(%s.x - length(dxy), 0.0, 1.0);", radiusPlusHalfName);
173     }
174 
175     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
176     // At each quarter-circle corner we compute a vector that is the offset of the fragment position
177     // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant
178     // to that corner. This means that points near the interior near the rrect top edge will have
179     // a vector that points straight up for both the TL left and TR corners. Computing an
180     // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
181     // fragments near the other three edges will get the correct AA. Fragments in the interior of
182     // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will
183     // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
184     // The code below is a simplified version of the above that performs maxs on the vector
185     // components before computing distances and alpha values so that only one distance computation
186     // need be computed to determine the min alpha.
187     //
188     // For the cases where one half of the rrect is rectangular we drop one of the x or y
189     // computations, compute a separate rect edge alpha for the rect side, and mul the two computed
190     // alphas together.
191     switch (crre.getCircularCornerFlags()) {
192         case CircularRRectEffect::kAll_CornerFlags:
193             fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName);
194             fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName);
195             fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);");
196             fragBuilder->codeAppendf("float alpha = %s;", clampedCircleDistance.c_str());
197             break;
198         case CircularRRectEffect::kTopLeft_CornerFlag:
199             fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - sk_FragCoord.xy, 0.0);",
200                                      rectName);
201             fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);",
202                                      rectName);
203             fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);",
204                                      rectName);
205             fragBuilder->codeAppendf("float alpha = bottomAlpha * rightAlpha * %s;",
206                                      clampedCircleDistance.c_str());
207             break;
208         case CircularRRectEffect::kTopRight_CornerFlag:
209             fragBuilder->codeAppendf("vec2 dxy = max(vec2(sk_FragCoord.x - %s.z, "
210                                                          "%s.y - sk_FragCoord.y), 0.0);",
211                                      rectName, rectName);
212             fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);",
213                                      rectName);
214             fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);",
215                                      rectName);
216             fragBuilder->codeAppendf("float alpha = bottomAlpha * leftAlpha * %s;",
217                                      clampedCircleDistance.c_str());
218             break;
219         case CircularRRectEffect::kBottomRight_CornerFlag:
220             fragBuilder->codeAppendf("vec2 dxy = max(sk_FragCoord.xy - %s.zw, 0.0);",
221                                      rectName);
222             fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);",
223                                      rectName);
224             fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);",
225                                      rectName);
226             fragBuilder->codeAppendf("float alpha = topAlpha * leftAlpha * %s;",
227                                      clampedCircleDistance.c_str());
228             break;
229         case CircularRRectEffect::kBottomLeft_CornerFlag:
230             fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - sk_FragCoord.x, sk_FragCoord.y - "
231                                      "%s.w), 0.0);",
232                                      rectName, rectName);
233             fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);",
234                                      rectName);
235             fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);",
236                                      rectName);
237             fragBuilder->codeAppendf("float alpha = topAlpha * rightAlpha * %s;",
238                                      clampedCircleDistance.c_str());
239             break;
240         case CircularRRectEffect::kLeft_CornerFlags:
241             fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName);
242             fragBuilder->codeAppendf("float dy1 = sk_FragCoord.y - %s.w;", rectName);
243             fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);");
244             fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);",
245                                      rectName);
246             fragBuilder->codeAppendf("float alpha = rightAlpha * %s;",
247                                      clampedCircleDistance.c_str());
248             break;
249         case CircularRRectEffect::kTop_CornerFlags:
250             fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName);
251             fragBuilder->codeAppendf("float dx1 = sk_FragCoord.x - %s.z;", rectName);
252             fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);");
253             fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);",
254                                      rectName);
255             fragBuilder->codeAppendf("float alpha = bottomAlpha * %s;",
256                                      clampedCircleDistance.c_str());
257             break;
258         case CircularRRectEffect::kRight_CornerFlags:
259             fragBuilder->codeAppendf("float dy0 = %s.y - sk_FragCoord.y;", rectName);
260             fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName);
261             fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);");
262             fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);",
263                                      rectName);
264             fragBuilder->codeAppendf("float alpha = leftAlpha * %s;",
265                                      clampedCircleDistance.c_str());
266             break;
267         case CircularRRectEffect::kBottom_CornerFlags:
268             fragBuilder->codeAppendf("float dx0 = %s.x - sk_FragCoord.x;", rectName);
269             fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName);
270             fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);");
271             fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);",
272                                      rectName);
273             fragBuilder->codeAppendf("float alpha = topAlpha * %s;",
274                                      clampedCircleDistance.c_str());
275             break;
276     }
277 
278     if (kInverseFillAA_GrProcessorEdgeType == crre.getEdgeType()) {
279         fragBuilder->codeAppend("alpha = 1.0 - alpha;");
280     }
281 
282     fragBuilder->codeAppendf("%s = %s;", args.fOutputColor,
283                              (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str());
284 }
285 
GenKey(const GrProcessor & processor,const GrShaderCaps &,GrProcessorKeyBuilder * b)286 void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&,
287                                    GrProcessorKeyBuilder* b) {
288     const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>();
289     GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8);
290     b->add32((crre.getCircularCornerFlags() << 3) | crre.getEdgeType());
291 }
292 
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & processor)293 void GLCircularRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman,
294                                       const GrProcessor& processor) {
295     const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>();
296     const SkRRect& rrect = crre.getRRect();
297     if (rrect != fPrevRRect) {
298         SkRect rect = rrect.getBounds();
299         SkScalar radius = 0;
300         switch (crre.getCircularCornerFlags()) {
301             case CircularRRectEffect::kAll_CornerFlags:
302                 SkASSERT(rrect.isSimpleCircular());
303                 radius = rrect.getSimpleRadii().fX;
304                 SkASSERT(radius >= kRadiusMin);
305                 rect.inset(radius, radius);
306                 break;
307             case CircularRRectEffect::kTopLeft_CornerFlag:
308                 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
309                 rect.fLeft += radius;
310                 rect.fTop += radius;
311                 rect.fRight += 0.5f;
312                 rect.fBottom += 0.5f;
313                 break;
314             case CircularRRectEffect::kTopRight_CornerFlag:
315                 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
316                 rect.fLeft -= 0.5f;
317                 rect.fTop += radius;
318                 rect.fRight -= radius;
319                 rect.fBottom += 0.5f;
320                 break;
321             case CircularRRectEffect::kBottomRight_CornerFlag:
322                 radius = rrect.radii(SkRRect::kLowerRight_Corner).fX;
323                 rect.fLeft -= 0.5f;
324                 rect.fTop -= 0.5f;
325                 rect.fRight -= radius;
326                 rect.fBottom -= radius;
327                 break;
328             case CircularRRectEffect::kBottomLeft_CornerFlag:
329                 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
330                 rect.fLeft += radius;
331                 rect.fTop -= 0.5f;
332                 rect.fRight += 0.5f;
333                 rect.fBottom -= radius;
334                 break;
335             case CircularRRectEffect::kLeft_CornerFlags:
336                 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
337                 rect.fLeft += radius;
338                 rect.fTop += radius;
339                 rect.fRight += 0.5f;
340                 rect.fBottom -= radius;
341                 break;
342             case CircularRRectEffect::kTop_CornerFlags:
343                 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
344                 rect.fLeft += radius;
345                 rect.fTop += radius;
346                 rect.fRight -= radius;
347                 rect.fBottom += 0.5f;
348                 break;
349             case CircularRRectEffect::kRight_CornerFlags:
350                 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
351                 rect.fLeft -= 0.5f;
352                 rect.fTop += radius;
353                 rect.fRight -= radius;
354                 rect.fBottom -= radius;
355                 break;
356             case CircularRRectEffect::kBottom_CornerFlags:
357                 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
358                 rect.fLeft += radius;
359                 rect.fTop -= 0.5f;
360                 rect.fRight -= radius;
361                 rect.fBottom -= radius;
362                 break;
363             default:
364                 SkFAIL("Should have been one of the above cases.");
365         }
366         pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
367         radius += 0.5f;
368         pdman.set2f(fRadiusPlusHalfUniform, radius, 1.f / radius);
369         fPrevRRect = rrect;
370     }
371 }
372 
373 ////////////////////////////////////////////////////////////////////////////////////////////////////
374 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const375 void CircularRRectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
376                                                 GrProcessorKeyBuilder* b) const {
377     GLCircularRRectEffect::GenKey(*this, caps, b);
378 }
379 
onCreateGLSLInstance() const380 GrGLSLFragmentProcessor* CircularRRectEffect::onCreateGLSLInstance() const  {
381     return new GLCircularRRectEffect;
382 }
383 
384 //////////////////////////////////////////////////////////////////////////////
385 
386 class EllipticalRRectEffect : public GrFragmentProcessor {
387 public:
388     static sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType, const SkRRect&);
389 
~EllipticalRRectEffect()390     ~EllipticalRRectEffect() override {}
391 
name() const392     const char* name() const override { return "EllipticalRRect"; }
393 
getRRect() const394     const SkRRect& getRRect() const { return fRRect; }
395 
getEdgeType() const396     GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
397 
398 private:
399     EllipticalRRectEffect(GrPrimitiveEdgeType, const SkRRect&);
400 
401     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
402 
403     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
404 
405     bool onIsEqual(const GrFragmentProcessor& other) const override;
406 
407     SkRRect fRRect;
408     GrPrimitiveEdgeType fEdgeType;
409 
410     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
411 
412     typedef GrFragmentProcessor INHERITED;
413 };
414 
415 sk_sp<GrFragmentProcessor>
Make(GrPrimitiveEdgeType edgeType,const SkRRect & rrect)416 EllipticalRRectEffect::Make(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) {
417     if (kFillAA_GrProcessorEdgeType != edgeType && kInverseFillAA_GrProcessorEdgeType != edgeType) {
418         return nullptr;
419     }
420     return sk_sp<GrFragmentProcessor>(new EllipticalRRectEffect(edgeType, rrect));
421 }
422 
EllipticalRRectEffect(GrPrimitiveEdgeType edgeType,const SkRRect & rrect)423 EllipticalRRectEffect::EllipticalRRectEffect(GrPrimitiveEdgeType edgeType, const SkRRect& rrect)
424         : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag)
425         , fRRect(rrect)
426         , fEdgeType(edgeType) {
427     this->initClassID<EllipticalRRectEffect>();
428 }
429 
onIsEqual(const GrFragmentProcessor & other) const430 bool EllipticalRRectEffect::onIsEqual(const GrFragmentProcessor& other) const {
431     const EllipticalRRectEffect& erre = other.cast<EllipticalRRectEffect>();
432     return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect;
433 }
434 
435 //////////////////////////////////////////////////////////////////////////////
436 
437 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipticalRRectEffect);
438 
439 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)440 sk_sp<GrFragmentProcessor> EllipticalRRectEffect::TestCreate(GrProcessorTestData* d) {
441     SkScalar w = d->fRandom->nextRangeScalar(20.f, 1000.f);
442     SkScalar h = d->fRandom->nextRangeScalar(20.f, 1000.f);
443     SkVector r[4];
444     r[SkRRect::kUpperLeft_Corner].fX = d->fRandom->nextRangeF(kRadiusMin, 9.f);
445     // ensure at least one corner really is elliptical
446     do {
447         r[SkRRect::kUpperLeft_Corner].fY = d->fRandom->nextRangeF(kRadiusMin, 9.f);
448     } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX);
449 
450     SkRRect rrect;
451     if (d->fRandom->nextBool()) {
452         // half the time create a four-radii rrect.
453         r[SkRRect::kLowerRight_Corner].fX = d->fRandom->nextRangeF(kRadiusMin, 9.f);
454         r[SkRRect::kLowerRight_Corner].fY = d->fRandom->nextRangeF(kRadiusMin, 9.f);
455 
456         r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX;
457         r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY;
458 
459         r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX;
460         r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY;
461 
462         rrect.setRectRadii(SkRect::MakeWH(w, h), r);
463     } else {
464         rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX,
465                                               r[SkRRect::kUpperLeft_Corner].fY);
466     }
467     sk_sp<GrFragmentProcessor> fp;
468     do {
469         GrPrimitiveEdgeType et =
470                 (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt);
471         fp = GrRRectEffect::Make(et, rrect);
472     } while (nullptr == fp);
473     return fp;
474 }
475 #endif
476 
477 //////////////////////////////////////////////////////////////////////////////
478 
479 class GLEllipticalRRectEffect : public GrGLSLFragmentProcessor {
480 public:
GLEllipticalRRectEffect()481     GLEllipticalRRectEffect() {
482         fPrevRRect.setEmpty();
483     }
484 
485     void emitCode(EmitArgs&) override;
486 
487     static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
488 
489 protected:
490     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
491 
492 private:
493     GrGLSLProgramDataManager::UniformHandle fInnerRectUniform;
494     GrGLSLProgramDataManager::UniformHandle fInvRadiiSqdUniform;
495     GrGLSLProgramDataManager::UniformHandle fScaleUniform;
496     SkRRect                                 fPrevRRect;
497     typedef GrGLSLFragmentProcessor INHERITED;
498 };
499 
emitCode(EmitArgs & args)500 void GLEllipticalRRectEffect::emitCode(EmitArgs& args) {
501     const EllipticalRRectEffect& erre = args.fFp.cast<EllipticalRRectEffect>();
502     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
503     const char *rectName;
504     // The inner rect is the rrect bounds inset by the x/y radii
505     fInnerRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
506                                                    kVec4f_GrSLType, kDefault_GrSLPrecision,
507                                                    "innerRect",
508                                                    &rectName);
509 
510     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
511     // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos
512     // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant
513     // to that corner. This means that points near the interior near the rrect top edge will have
514     // a vector that points straight up for both the TL left and TR corners. Computing an
515     // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
516     // fragments near the other three edges will get the correct AA. Fragments in the interior of
517     // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will
518     // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
519     //
520     // The code below is a simplified version of the above that performs maxs on the vector
521     // components before computing distances and alpha values so that only one distance computation
522     // need be computed to determine the min alpha.
523     fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName);
524     fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName);
525 
526     // If we're on a device with a "real" mediump then we'll do the distance computation in a space
527     // that is normalized by the largest radius. The scale uniform will be scale, 1/scale. The
528     // radii uniform values are already in this normalized space.
529     const char* scaleName = nullptr;
530     if (args.fShaderCaps->floatPrecisionVaries()) {
531         fScaleUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
532                                                    kVec2f_GrSLType, kDefault_GrSLPrecision,
533                                                    "scale", &scaleName);
534     }
535 
536     // The uniforms with the inv squared radii are highp to prevent underflow.
537     switch (erre.getRRect().getType()) {
538         case SkRRect::kSimple_Type: {
539             const char *invRadiiXYSqdName;
540             fInvRadiiSqdUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
541                                                              kVec2f_GrSLType,
542                                                              kDefault_GrSLPrecision,
543                                                              "invRadiiXY",
544                                                              &invRadiiXYSqdName);
545             fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);");
546             if (scaleName) {
547                 fragBuilder->codeAppendf("dxy *= %s.y;", scaleName);
548             }
549             // Z is the x/y offsets divided by squared radii.
550             fragBuilder->codeAppendf("vec2 Z = dxy * %s.xy;", invRadiiXYSqdName);
551             break;
552         }
553         case SkRRect::kNinePatch_Type: {
554             const char *invRadiiLTRBSqdName;
555             fInvRadiiSqdUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
556                                                              kVec4f_GrSLType,
557                                                              kDefault_GrSLPrecision,
558                                                              "invRadiiLTRB",
559                                                              &invRadiiLTRBSqdName);
560             if (scaleName) {
561                 fragBuilder->codeAppendf("dxy0 *= %s.y;", scaleName);
562                 fragBuilder->codeAppendf("dxy1 *= %s.y;", scaleName);
563             }
564             fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);");
565             // Z is the x/y offsets divided by squared radii. We only care about the (at most) one
566             // corner where both the x and y offsets are positive, hence the maxes. (The inverse
567             // squared radii will always be positive.)
568             fragBuilder->codeAppendf("vec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);",
569                                      invRadiiLTRBSqdName, invRadiiLTRBSqdName);
570 
571             break;
572         }
573         default:
574             SkFAIL("RRect should always be simple or nine-patch.");
575     }
576     // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1.
577     fragBuilder->codeAppend("float implicit = dot(Z, dxy) - 1.0;");
578     // grad_dot is the squared length of the gradient of the implicit.
579     fragBuilder->codeAppend("float grad_dot = 4.0 * dot(Z, Z);");
580     // avoid calling inversesqrt on zero.
581     fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
582     fragBuilder->codeAppend("float approx_dist = implicit * inversesqrt(grad_dot);");
583     if (scaleName) {
584         fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName);
585     }
586 
587     if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) {
588         fragBuilder->codeAppend("float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);");
589     } else {
590         fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);");
591     }
592 
593     fragBuilder->codeAppendf("%s = %s;", args.fOutputColor,
594                              (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str());
595 }
596 
GenKey(const GrProcessor & effect,const GrShaderCaps &,GrProcessorKeyBuilder * b)597 void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&,
598                                      GrProcessorKeyBuilder* b) {
599     const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>();
600     GR_STATIC_ASSERT(kLast_GrProcessorEdgeType < (1 << 3));
601     b->add32(erre.getRRect().getType() | erre.getEdgeType() << 3);
602 }
603 
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & effect)604 void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman,
605                                         const GrProcessor& effect) {
606     const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>();
607     const SkRRect& rrect = erre.getRRect();
608     // If we're using a scale factor to work around precision issues, choose the largest radius
609     // as the scale factor. The inv radii need to be pre-adjusted by the scale factor.
610     if (rrect != fPrevRRect) {
611         SkRect rect = rrect.getBounds();
612         const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
613         SkASSERT(r0.fX >= kRadiusMin);
614         SkASSERT(r0.fY >= kRadiusMin);
615         switch (erre.getRRect().getType()) {
616             case SkRRect::kSimple_Type:
617                 rect.inset(r0.fX, r0.fY);
618                 if (fScaleUniform.isValid()) {
619                     if (r0.fX > r0.fY) {
620                         pdman.set2f(fInvRadiiSqdUniform, 1.f, (r0.fX * r0.fX) / (r0.fY * r0.fY));
621                         pdman.set2f(fScaleUniform, r0.fX, 1.f / r0.fX);
622                     } else {
623                         pdman.set2f(fInvRadiiSqdUniform, (r0.fY * r0.fY) / (r0.fX * r0.fX), 1.f);
624                         pdman.set2f(fScaleUniform, r0.fY, 1.f / r0.fY);
625                     }
626                 } else {
627                     pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
628                                                      1.f / (r0.fY * r0.fY));
629                 }
630                 break;
631             case SkRRect::kNinePatch_Type: {
632                 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
633                 SkASSERT(r1.fX >= kRadiusMin);
634                 SkASSERT(r1.fY >= kRadiusMin);
635                 rect.fLeft += r0.fX;
636                 rect.fTop += r0.fY;
637                 rect.fRight -= r1.fX;
638                 rect.fBottom -= r1.fY;
639                 if (fScaleUniform.isValid()) {
640                     float scale = SkTMax(SkTMax(r0.fX, r0.fY), SkTMax(r1.fX, r1.fY));
641                     float scaleSqd = scale * scale;
642                     pdman.set4f(fInvRadiiSqdUniform, scaleSqd / (r0.fX * r0.fX),
643                                                      scaleSqd / (r0.fY * r0.fY),
644                                                      scaleSqd / (r1.fX * r1.fX),
645                                                      scaleSqd / (r1.fY * r1.fY));
646                     pdman.set2f(fScaleUniform, scale, 1.f / scale);
647                 } else {
648                     pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
649                                                      1.f / (r0.fY * r0.fY),
650                                                      1.f / (r1.fX * r1.fX),
651                                                      1.f / (r1.fY * r1.fY));
652                 }
653                 break;
654             }
655         default:
656             SkFAIL("RRect should always be simple or nine-patch.");
657         }
658         pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
659         fPrevRRect = rrect;
660     }
661 }
662 
663 ////////////////////////////////////////////////////////////////////////////////////////////////////
664 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const665 void EllipticalRRectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
666                                                   GrProcessorKeyBuilder* b) const {
667     GLEllipticalRRectEffect::GenKey(*this, caps, b);
668 }
669 
onCreateGLSLInstance() const670 GrGLSLFragmentProcessor* EllipticalRRectEffect::onCreateGLSLInstance() const  {
671     return new GLEllipticalRRectEffect;
672 }
673 
674 //////////////////////////////////////////////////////////////////////////////
675 
Make(GrPrimitiveEdgeType edgeType,const SkRRect & rrect)676 sk_sp<GrFragmentProcessor> GrRRectEffect::Make(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) {
677     if (rrect.isRect()) {
678         return GrConvexPolyEffect::Make(edgeType, rrect.getBounds());
679     }
680 
681     if (rrect.isOval()) {
682         return GrOvalEffect::Make(edgeType, rrect.getBounds());
683     }
684 
685     if (rrect.isSimple()) {
686         if (rrect.getSimpleRadii().fX < kRadiusMin || rrect.getSimpleRadii().fY < kRadiusMin) {
687             // In this case the corners are extremely close to rectangular and we collapse the
688             // clip to a rectangular clip.
689             return GrConvexPolyEffect::Make(edgeType, rrect.getBounds());
690         }
691         if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) {
692             return CircularRRectEffect::Make(edgeType, CircularRRectEffect::kAll_CornerFlags,
693                                                rrect);
694         } else {
695             return EllipticalRRectEffect::Make(edgeType, rrect);
696         }
697     }
698 
699     if (rrect.isComplex() || rrect.isNinePatch()) {
700         // Check for the "tab" cases - two adjacent circular corners and two square corners.
701         SkScalar circularRadius = 0;
702         uint32_t cornerFlags  = 0;
703 
704         SkVector radii[4];
705         bool squashedRadii = false;
706         for (int c = 0; c < 4; ++c) {
707             radii[c] = rrect.radii((SkRRect::Corner)c);
708             SkASSERT((0 == radii[c].fX) == (0 == radii[c].fY));
709             if (0 == radii[c].fX) {
710                 // The corner is square, so no need to squash or flag as circular.
711                 continue;
712             }
713             if (radii[c].fX < kRadiusMin || radii[c].fY < kRadiusMin) {
714                 radii[c].set(0, 0);
715                 squashedRadii = true;
716                 continue;
717             }
718             if (radii[c].fX != radii[c].fY) {
719                 cornerFlags = ~0U;
720                 break;
721             }
722             if (!cornerFlags) {
723                 circularRadius = radii[c].fX;
724                 cornerFlags = 1 << c;
725             } else {
726                 if (radii[c].fX != circularRadius) {
727                    cornerFlags = ~0U;
728                    break;
729                 }
730                 cornerFlags |= 1 << c;
731             }
732         }
733 
734         switch (cornerFlags) {
735             case CircularRRectEffect::kAll_CornerFlags:
736                 // This rrect should have been caught in the simple case above. Though, it would
737                 // be correctly handled in the fallthrough code.
738                 SkASSERT(false);
739             case CircularRRectEffect::kTopLeft_CornerFlag:
740             case CircularRRectEffect::kTopRight_CornerFlag:
741             case CircularRRectEffect::kBottomRight_CornerFlag:
742             case CircularRRectEffect::kBottomLeft_CornerFlag:
743             case CircularRRectEffect::kLeft_CornerFlags:
744             case CircularRRectEffect::kTop_CornerFlags:
745             case CircularRRectEffect::kRight_CornerFlags:
746             case CircularRRectEffect::kBottom_CornerFlags: {
747                 SkTCopyOnFirstWrite<SkRRect> rr(rrect);
748                 if (squashedRadii) {
749                     rr.writable()->setRectRadii(rrect.getBounds(), radii);
750                 }
751                 return CircularRRectEffect::Make(edgeType, cornerFlags, *rr);
752             }
753             case CircularRRectEffect::kNone_CornerFlags:
754                 return GrConvexPolyEffect::Make(edgeType, rrect.getBounds());
755             default: {
756                 if (squashedRadii) {
757                     // If we got here then we squashed some but not all the radii to zero. (If all
758                     // had been squashed cornerFlags would be 0.) The elliptical effect doesn't
759                     // support some rounded and some square corners.
760                     return nullptr;
761                 }
762                 if (rrect.isNinePatch()) {
763                     return EllipticalRRectEffect::Make(edgeType, rrect);
764                 }
765                 return nullptr;
766             }
767         }
768     }
769 
770     return nullptr;
771 }
772