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