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