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.
20static const SkScalar kRadiusMin = SK_ScalarHalf;
21
22//////////////////////////////////////////////////////////////////////////////
23
24class GLCircularRRectEffect;
25
26class CircularRRectEffect : public GrFragmentProcessor {
27public:
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
66private:
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
80GrFragmentProcessor* 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
89void CircularRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
90    *validFlags = 0;
91}
92
93const GrBackendFragmentProcessorFactory& CircularRRectEffect::getFactory() const {
94    return GrTBackendFragmentProcessorFactory<CircularRRectEffect>::getInstance();
95}
96
97CircularRRectEffect::CircularRRectEffect(GrPrimitiveEdgeType edgeType, uint32_t circularCornerFlags,
98                                         const SkRRect& rrect)
99    : fRRect(rrect)
100    , fEdgeType(edgeType)
101    , fCircularCornerFlags(circularCornerFlags) {
102    this->setWillReadFragmentPosition();
103}
104
105bool 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
113GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircularRRectEffect);
114
115GrFragmentProcessor* 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
135class GLCircularRRectEffect : public GrGLFragmentProcessor {
136public:
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
151private:
152    GrGLProgramDataManager::UniformHandle fInnerRectUniform;
153    GrGLProgramDataManager::UniformHandle fRadiusPlusHalfUniform;
154    SkRRect                               fPrevRRect;
155    typedef GrGLFragmentProcessor INHERITED;
156};
157
158GLCircularRRectEffect::GLCircularRRectEffect(const GrBackendProcessorFactory& factory,
159                                             const GrProcessor& )
160    : INHERITED (factory) {
161    fPrevRRect.setEmpty();
162}
163
164void 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
298void 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
305void 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
386class GLEllipticalRRectEffect;
387
388class EllipticalRRectEffect : public GrFragmentProcessor {
389public:
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
406private:
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
419GrFragmentProcessor*
420EllipticalRRectEffect::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
427void EllipticalRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
428    *validFlags = 0;
429}
430
431const GrBackendFragmentProcessorFactory& EllipticalRRectEffect::getFactory() const {
432    return GrTBackendFragmentProcessorFactory<EllipticalRRectEffect>::getInstance();
433}
434
435EllipticalRRectEffect::EllipticalRRectEffect(GrPrimitiveEdgeType edgeType, const SkRRect& rrect)
436    : fRRect(rrect)
437    , fEdgeType(edgeType){
438    this->setWillReadFragmentPosition();
439}
440
441bool 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
448GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipticalRRectEffect);
449
450GrFragmentProcessor* 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
490class GLEllipticalRRectEffect : public GrGLFragmentProcessor {
491public:
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
506private:
507    GrGLProgramDataManager::UniformHandle fInnerRectUniform;
508    GrGLProgramDataManager::UniformHandle fInvRadiiSqdUniform;
509    SkRRect                               fPrevRRect;
510    typedef GrGLFragmentProcessor INHERITED;
511};
512
513GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrBackendProcessorFactory& factory,
514                             const GrProcessor& effect)
515    : INHERITED (factory) {
516    fPrevRRect.setEmpty();
517}
518
519void 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
596void 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
603void 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
642GrFragmentProcessor* 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}
738