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