Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2014 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "GrRRectEffect.h"
      9 
     10 #include "GrConvexPolyEffect.h"
     11 #include "GrFragmentProcessor.h"
     12 #include "GrOvalEffect.h"
     13 #include "GrShaderCaps.h"
     14 #include "SkRRect.h"
     15 #include "SkTLazy.h"
     16 #include "glsl/GrGLSLFragmentProcessor.h"
     17 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     18 #include "glsl/GrGLSLProgramDataManager.h"
     19 #include "glsl/GrGLSLUniformHandler.h"
     20 
     21 // The effects defined here only handle rrect radii >= kRadiusMin.
     22 static const SkScalar kRadiusMin = SK_ScalarHalf;
     23 
     24 //////////////////////////////////////////////////////////////////////////////
     25 
     26 class CircularRRectEffect : public GrFragmentProcessor {
     27 public:
     28 
     29     enum CornerFlags {
     30         kTopLeft_CornerFlag     = (1 << SkRRect::kUpperLeft_Corner),
     31         kTopRight_CornerFlag    = (1 << SkRRect::kUpperRight_Corner),
     32         kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner),
     33         kBottomLeft_CornerFlag  = (1 << SkRRect::kLowerLeft_Corner),
     34 
     35         kLeft_CornerFlags   = kTopLeft_CornerFlag    | kBottomLeft_CornerFlag,
     36         kTop_CornerFlags    = kTopLeft_CornerFlag    | kTopRight_CornerFlag,
     37         kRight_CornerFlags  = kTopRight_CornerFlag   | kBottomRight_CornerFlag,
     38         kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
     39 
     40         kAll_CornerFlags = kTopLeft_CornerFlag    | kTopRight_CornerFlag |
     41                            kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
     42 
     43         kNone_CornerFlags = 0
     44     };
     45 
     46     // The flags are used to indicate which corners are circluar (unflagged corners are assumed to
     47     // be square).
     48     static sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType, uint32_t circularCornerFlags,
     49                                            const SkRRect&);
     50 
     51     ~CircularRRectEffect() override {}
     52 
     53     const char* name() const override { return "CircularRRect"; }
     54 
     55     const SkRRect& getRRect() const { return fRRect; }
     56 
     57     uint32_t getCircularCornerFlags() const { return fCircularCornerFlags; }
     58 
     59     GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
     60 
     61 private:
     62     CircularRRectEffect(GrPrimitiveEdgeType, uint32_t circularCornerFlags, const SkRRect&);
     63 
     64     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     65 
     66     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
     67 
     68     bool onIsEqual(const GrFragmentProcessor& other) const override;
     69 
     70     SkRRect                fRRect;
     71     GrPrimitiveEdgeType    fEdgeType;
     72     uint32_t               fCircularCornerFlags;
     73 
     74     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
     75 
     76     typedef GrFragmentProcessor INHERITED;
     77 };
     78 
     79 sk_sp<GrFragmentProcessor> CircularRRectEffect::Make(GrPrimitiveEdgeType edgeType,
     80                                                      uint32_t circularCornerFlags,
     81                                                      const SkRRect& rrect) {
     82     if (kFillAA_GrProcessorEdgeType != edgeType && kInverseFillAA_GrProcessorEdgeType != edgeType) {
     83         return nullptr;
     84     }
     85     return sk_sp<GrFragmentProcessor>(
     86         new CircularRRectEffect(edgeType, circularCornerFlags, rrect));
     87 }
     88 
     89 CircularRRectEffect::CircularRRectEffect(GrPrimitiveEdgeType edgeType, uint32_t circularCornerFlags,
     90                                          const SkRRect& rrect)
     91         : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag)
     92         , fRRect(rrect)
     93         , fEdgeType(edgeType)
     94         , fCircularCornerFlags(circularCornerFlags) {
     95     this->initClassID<CircularRRectEffect>();
     96 }
     97 
     98 bool CircularRRectEffect::onIsEqual(const GrFragmentProcessor& other) const {
     99     const CircularRRectEffect& crre = other.cast<CircularRRectEffect>();
    100     // The corner flags are derived from fRRect, so no need to check them.
    101     return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect;
    102 }
    103 
    104 //////////////////////////////////////////////////////////////////////////////
    105 
    106 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircularRRectEffect);
    107 
    108 #if GR_TEST_UTILS
    109 sk_sp<GrFragmentProcessor> CircularRRectEffect::TestCreate(GrProcessorTestData* d) {
    110     SkScalar w = d->fRandom->nextRangeScalar(20.f, 1000.f);
    111     SkScalar h = d->fRandom->nextRangeScalar(20.f, 1000.f);
    112     SkScalar r = d->fRandom->nextRangeF(kRadiusMin, 9.f);
    113     SkRRect rrect;
    114     rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
    115     sk_sp<GrFragmentProcessor> fp;
    116     do {
    117         GrPrimitiveEdgeType et =
    118                 (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt);
    119         fp = GrRRectEffect::Make(et, rrect);
    120     } while (nullptr == fp);
    121     return fp;
    122 }
    123 #endif
    124 
    125 //////////////////////////////////////////////////////////////////////////////
    126 
    127 class GLCircularRRectEffect : public GrGLSLFragmentProcessor {
    128 public:
    129     GLCircularRRectEffect() {
    130         fPrevRRect.setEmpty();
    131     }
    132 
    133     virtual void emitCode(EmitArgs&) override;
    134 
    135     static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
    136 
    137 protected:
    138     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
    139 
    140 private:
    141     GrGLSLProgramDataManager::UniformHandle fInnerRectUniform;
    142     GrGLSLProgramDataManager::UniformHandle fRadiusPlusHalfUniform;
    143     SkRRect                                 fPrevRRect;
    144     typedef GrGLSLFragmentProcessor INHERITED;
    145 };
    146 
    147 void GLCircularRRectEffect::emitCode(EmitArgs& args) {
    148     const CircularRRectEffect& crre = args.fFp.cast<CircularRRectEffect>();
    149     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
    150     const char *rectName;
    151     const char *radiusPlusHalfName;
    152     // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom
    153     // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has
    154     // only rectangular corners, that side's value corresponds to the rect edge's value outset by
    155     // half a pixel.
    156     fInnerRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
    157                                                    kVec4f_GrSLType, kDefault_GrSLPrecision,
    158                                                    "innerRect",
    159                                                    &rectName);
    160     // x is (r + .5) and y is 1/(r + .5)
    161     fRadiusPlusHalfUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
    162                                                         kVec2f_GrSLType, kDefault_GrSLPrecision,
    163                                                         "radiusPlusHalf",
    164                                                         &radiusPlusHalfName);
    165 
    166     // If we're on a device with a "real" mediump then the length calculation could overflow.
    167     SkString clampedCircleDistance;
    168     if (args.fShaderCaps->floatPrecisionVaries()) {
    169         clampedCircleDistance.printf("clamp(%s.x * (1.0 - length(dxy * %s.y)), 0.0, 1.0);",
    170                                      radiusPlusHalfName, radiusPlusHalfName);
    171     } else {
    172         clampedCircleDistance.printf("clamp(%s.x - length(dxy), 0.0, 1.0);", radiusPlusHalfName);
    173     }
    174 
    175     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
    176     // At each quarter-circle corner we compute a vector that is the offset of the fragment position
    177     // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant
    178     // to that corner. This means that points near the interior near the rrect top edge will have
    179     // a vector that points straight up for both the TL left and TR corners. Computing an
    180     // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
    181     // fragments near the other three edges will get the correct AA. Fragments in the interior of
    182     // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will
    183     // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
    184     // The code below is a simplified version of the above that performs maxs on the vector
    185     // components before computing distances and alpha values so that only one distance computation
    186     // need be computed to determine the min alpha.
    187     //
    188     // For the cases where one half of the rrect is rectangular we drop one of the x or y
    189     // computations, compute a separate rect edge alpha for the rect side, and mul the two computed
    190     // alphas together.
    191     switch (crre.getCircularCornerFlags()) {
    192         case CircularRRectEffect::kAll_CornerFlags:
    193             fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName);
    194             fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName);
    195             fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);");
    196             fragBuilder->codeAppendf("float alpha = %s;", clampedCircleDistance.c_str());
    197             break;
    198         case CircularRRectEffect::kTopLeft_CornerFlag:
    199             fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - sk_FragCoord.xy, 0.0);",
    200                                      rectName);
    201             fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);",
    202                                      rectName);
    203             fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);",
    204                                      rectName);
    205             fragBuilder->codeAppendf("float alpha = bottomAlpha * rightAlpha * %s;",
    206                                      clampedCircleDistance.c_str());
    207             break;
    208         case CircularRRectEffect::kTopRight_CornerFlag:
    209             fragBuilder->codeAppendf("vec2 dxy = max(vec2(sk_FragCoord.x - %s.z, "
    210                                                          "%s.y - sk_FragCoord.y), 0.0);",
    211                                      rectName, rectName);
    212             fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);",
    213                                      rectName);
    214             fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);",
    215                                      rectName);
    216             fragBuilder->codeAppendf("float alpha = bottomAlpha * leftAlpha * %s;",
    217                                      clampedCircleDistance.c_str());
    218             break;
    219         case CircularRRectEffect::kBottomRight_CornerFlag:
    220             fragBuilder->codeAppendf("vec2 dxy = max(sk_FragCoord.xy - %s.zw, 0.0);",
    221                                      rectName);
    222             fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);",
    223                                      rectName);
    224             fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);",
    225                                      rectName);
    226             fragBuilder->codeAppendf("float alpha = topAlpha * leftAlpha * %s;",
    227                                      clampedCircleDistance.c_str());
    228             break;
    229         case CircularRRectEffect::kBottomLeft_CornerFlag:
    230             fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - sk_FragCoord.x, sk_FragCoord.y - "
    231                                      "%s.w), 0.0);",
    232                                      rectName, rectName);
    233             fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);",
    234                                      rectName);
    235             fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);",
    236                                      rectName);
    237             fragBuilder->codeAppendf("float alpha = topAlpha * rightAlpha * %s;",
    238                                      clampedCircleDistance.c_str());
    239             break;
    240         case CircularRRectEffect::kLeft_CornerFlags:
    241             fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName);
    242             fragBuilder->codeAppendf("float dy1 = sk_FragCoord.y - %s.w;", rectName);
    243             fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);");
    244             fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - sk_FragCoord.x, 0.0, 1.0);",
    245                                      rectName);
    246             fragBuilder->codeAppendf("float alpha = rightAlpha * %s;",
    247                                      clampedCircleDistance.c_str());
    248             break;
    249         case CircularRRectEffect::kTop_CornerFlags:
    250             fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName);
    251             fragBuilder->codeAppendf("float dx1 = sk_FragCoord.x - %s.z;", rectName);
    252             fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);");
    253             fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - sk_FragCoord.y, 0.0, 1.0);",
    254                                      rectName);
    255             fragBuilder->codeAppendf("float alpha = bottomAlpha * %s;",
    256                                      clampedCircleDistance.c_str());
    257             break;
    258         case CircularRRectEffect::kRight_CornerFlags:
    259             fragBuilder->codeAppendf("float dy0 = %s.y - sk_FragCoord.y;", rectName);
    260             fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName);
    261             fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);");
    262             fragBuilder->codeAppendf("float leftAlpha = clamp(sk_FragCoord.x - %s.x, 0.0, 1.0);",
    263                                      rectName);
    264             fragBuilder->codeAppendf("float alpha = leftAlpha * %s;",
    265                                      clampedCircleDistance.c_str());
    266             break;
    267         case CircularRRectEffect::kBottom_CornerFlags:
    268             fragBuilder->codeAppendf("float dx0 = %s.x - sk_FragCoord.x;", rectName);
    269             fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName);
    270             fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);");
    271             fragBuilder->codeAppendf("float topAlpha = clamp(sk_FragCoord.y - %s.y, 0.0, 1.0);",
    272                                      rectName);
    273             fragBuilder->codeAppendf("float alpha = topAlpha * %s;",
    274                                      clampedCircleDistance.c_str());
    275             break;
    276     }
    277 
    278     if (kInverseFillAA_GrProcessorEdgeType == crre.getEdgeType()) {
    279         fragBuilder->codeAppend("alpha = 1.0 - alpha;");
    280     }
    281 
    282     fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor);
    283 }
    284 
    285 void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&,
    286                                    GrProcessorKeyBuilder* b) {
    287     const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>();
    288     GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8);
    289     b->add32((crre.getCircularCornerFlags() << 3) | crre.getEdgeType());
    290 }
    291 
    292 void 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(rrect.isSimpleCircular());
    302                 radius = rrect.getSimpleRadii().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                 SkFAIL("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 
    374 void CircularRRectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
    375                                                 GrProcessorKeyBuilder* b) const {
    376     GLCircularRRectEffect::GenKey(*this, caps, b);
    377 }
    378 
    379 GrGLSLFragmentProcessor* CircularRRectEffect::onCreateGLSLInstance() const  {
    380     return new GLCircularRRectEffect;
    381 }
    382 
    383 //////////////////////////////////////////////////////////////////////////////
    384 
    385 class EllipticalRRectEffect : public GrFragmentProcessor {
    386 public:
    387     static sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType, const SkRRect&);
    388 
    389     ~EllipticalRRectEffect() override {}
    390 
    391     const char* name() const override { return "EllipticalRRect"; }
    392 
    393     const SkRRect& getRRect() const { return fRRect; }
    394 
    395     GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
    396 
    397 private:
    398     EllipticalRRectEffect(GrPrimitiveEdgeType, const SkRRect&);
    399 
    400     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
    401 
    402     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
    403 
    404     bool onIsEqual(const GrFragmentProcessor& other) const override;
    405 
    406     SkRRect fRRect;
    407     GrPrimitiveEdgeType fEdgeType;
    408 
    409     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
    410 
    411     typedef GrFragmentProcessor INHERITED;
    412 };
    413 
    414 sk_sp<GrFragmentProcessor>
    415 EllipticalRRectEffect::Make(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) {
    416     if (kFillAA_GrProcessorEdgeType != edgeType && kInverseFillAA_GrProcessorEdgeType != edgeType) {
    417         return nullptr;
    418     }
    419     return sk_sp<GrFragmentProcessor>(new EllipticalRRectEffect(edgeType, rrect));
    420 }
    421 
    422 EllipticalRRectEffect::EllipticalRRectEffect(GrPrimitiveEdgeType edgeType, const SkRRect& rrect)
    423         : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag)
    424         , fRRect(rrect)
    425         , fEdgeType(edgeType) {
    426     this->initClassID<EllipticalRRectEffect>();
    427 }
    428 
    429 bool EllipticalRRectEffect::onIsEqual(const GrFragmentProcessor& other) const {
    430     const EllipticalRRectEffect& erre = other.cast<EllipticalRRectEffect>();
    431     return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect;
    432 }
    433 
    434 //////////////////////////////////////////////////////////////////////////////
    435 
    436 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipticalRRectEffect);
    437 
    438 #if GR_TEST_UTILS
    439 sk_sp<GrFragmentProcessor> EllipticalRRectEffect::TestCreate(GrProcessorTestData* d) {
    440     SkScalar w = d->fRandom->nextRangeScalar(20.f, 1000.f);
    441     SkScalar h = d->fRandom->nextRangeScalar(20.f, 1000.f);
    442     SkVector r[4];
    443     r[SkRRect::kUpperLeft_Corner].fX = d->fRandom->nextRangeF(kRadiusMin, 9.f);
    444     // ensure at least one corner really is elliptical
    445     do {
    446         r[SkRRect::kUpperLeft_Corner].fY = d->fRandom->nextRangeF(kRadiusMin, 9.f);
    447     } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX);
    448 
    449     SkRRect rrect;
    450     if (d->fRandom->nextBool()) {
    451         // half the time create a four-radii rrect.
    452         r[SkRRect::kLowerRight_Corner].fX = d->fRandom->nextRangeF(kRadiusMin, 9.f);
    453         r[SkRRect::kLowerRight_Corner].fY = d->fRandom->nextRangeF(kRadiusMin, 9.f);
    454 
    455         r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX;
    456         r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY;
    457 
    458         r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX;
    459         r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY;
    460 
    461         rrect.setRectRadii(SkRect::MakeWH(w, h), r);
    462     } else {
    463         rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX,
    464                                               r[SkRRect::kUpperLeft_Corner].fY);
    465     }
    466     sk_sp<GrFragmentProcessor> fp;
    467     do {
    468         GrPrimitiveEdgeType et =
    469                 (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt);
    470         fp = GrRRectEffect::Make(et, rrect);
    471     } while (nullptr == fp);
    472     return fp;
    473 }
    474 #endif
    475 
    476 //////////////////////////////////////////////////////////////////////////////
    477 
    478 class GLEllipticalRRectEffect : public GrGLSLFragmentProcessor {
    479 public:
    480     GLEllipticalRRectEffect() {
    481         fPrevRRect.setEmpty();
    482     }
    483 
    484     void emitCode(EmitArgs&) override;
    485 
    486     static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
    487 
    488 protected:
    489     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
    490 
    491 private:
    492     GrGLSLProgramDataManager::UniformHandle fInnerRectUniform;
    493     GrGLSLProgramDataManager::UniformHandle fInvRadiiSqdUniform;
    494     GrGLSLProgramDataManager::UniformHandle fScaleUniform;
    495     SkRRect                                 fPrevRRect;
    496     typedef GrGLSLFragmentProcessor INHERITED;
    497 };
    498 
    499 void GLEllipticalRRectEffect::emitCode(EmitArgs& args) {
    500     const EllipticalRRectEffect& erre = args.fFp.cast<EllipticalRRectEffect>();
    501     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
    502     const char *rectName;
    503     // The inner rect is the rrect bounds inset by the x/y radii
    504     fInnerRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
    505                                                    kVec4f_GrSLType, kDefault_GrSLPrecision,
    506                                                    "innerRect",
    507                                                    &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("vec2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName);
    523     fragBuilder->codeAppendf("vec2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName);
    524 
    525     // If we're on a device with a "real" mediump 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->floatPrecisionVaries()) {
    530         fScaleUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
    531                                                    kVec2f_GrSLType, kDefault_GrSLPrecision,
    532                                                    "scale", &scaleName);
    533     }
    534 
    535     // The uniforms with the inv squared radii are highp to prevent underflow.
    536     switch (erre.getRRect().getType()) {
    537         case SkRRect::kSimple_Type: {
    538             const char *invRadiiXYSqdName;
    539             fInvRadiiSqdUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
    540                                                              kVec2f_GrSLType,
    541                                                              kDefault_GrSLPrecision,
    542                                                              "invRadiiXY",
    543                                                              &invRadiiXYSqdName);
    544             fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);");
    545             if (scaleName) {
    546                 fragBuilder->codeAppendf("dxy *= %s.y;", scaleName);
    547             }
    548             // Z is the x/y offsets divided by squared radii.
    549             fragBuilder->codeAppendf("vec2 Z = dxy * %s.xy;", invRadiiXYSqdName);
    550             break;
    551         }
    552         case SkRRect::kNinePatch_Type: {
    553             const char *invRadiiLTRBSqdName;
    554             fInvRadiiSqdUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
    555                                                              kVec4f_GrSLType,
    556                                                              kDefault_GrSLPrecision,
    557                                                              "invRadiiLTRB",
    558                                                              &invRadiiLTRBSqdName);
    559             if (scaleName) {
    560                 fragBuilder->codeAppendf("dxy0 *= %s.y;", scaleName);
    561                 fragBuilder->codeAppendf("dxy1 *= %s.y;", scaleName);
    562             }
    563             fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);");
    564             // Z is the x/y offsets divided by squared radii. We only care about the (at most) one
    565             // corner where both the x and y offsets are positive, hence the maxes. (The inverse
    566             // squared radii will always be positive.)
    567             fragBuilder->codeAppendf("vec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);",
    568                                      invRadiiLTRBSqdName, invRadiiLTRBSqdName);
    569 
    570             break;
    571         }
    572         default:
    573             SkFAIL("RRect should always be simple or nine-patch.");
    574     }
    575     // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1.
    576     fragBuilder->codeAppend("float implicit = dot(Z, dxy) - 1.0;");
    577     // grad_dot is the squared length of the gradient of the implicit.
    578     fragBuilder->codeAppend("float grad_dot = 4.0 * dot(Z, Z);");
    579     // avoid calling inversesqrt on zero.
    580     fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
    581     fragBuilder->codeAppend("float approx_dist = implicit * inversesqrt(grad_dot);");
    582     if (scaleName) {
    583         fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName);
    584     }
    585 
    586     if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) {
    587         fragBuilder->codeAppend("float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);");
    588     } else {
    589         fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);");
    590     }
    591 
    592     fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor);
    593 }
    594 
    595 void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&,
    596                                      GrProcessorKeyBuilder* b) {
    597     const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>();
    598     GR_STATIC_ASSERT(kLast_GrProcessorEdgeType < (1 << 3));
    599     b->add32(erre.getRRect().getType() | erre.getEdgeType() << 3);
    600 }
    601 
    602 void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman,
    603                                         const GrFragmentProcessor& effect) {
    604     const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>();
    605     const SkRRect& rrect = erre.getRRect();
    606     // If we're using a scale factor to work around precision issues, choose the largest radius
    607     // as the scale factor. The inv radii need to be pre-adjusted by the scale factor.
    608     if (rrect != fPrevRRect) {
    609         SkRect rect = rrect.getBounds();
    610         const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
    611         SkASSERT(r0.fX >= kRadiusMin);
    612         SkASSERT(r0.fY >= kRadiusMin);
    613         switch (erre.getRRect().getType()) {
    614             case SkRRect::kSimple_Type:
    615                 rect.inset(r0.fX, r0.fY);
    616                 if (fScaleUniform.isValid()) {
    617                     if (r0.fX > r0.fY) {
    618                         pdman.set2f(fInvRadiiSqdUniform, 1.f, (r0.fX * r0.fX) / (r0.fY * r0.fY));
    619                         pdman.set2f(fScaleUniform, r0.fX, 1.f / r0.fX);
    620                     } else {
    621                         pdman.set2f(fInvRadiiSqdUniform, (r0.fY * r0.fY) / (r0.fX * r0.fX), 1.f);
    622                         pdman.set2f(fScaleUniform, r0.fY, 1.f / r0.fY);
    623                     }
    624                 } else {
    625                     pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
    626                                                      1.f / (r0.fY * r0.fY));
    627                 }
    628                 break;
    629             case SkRRect::kNinePatch_Type: {
    630                 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
    631                 SkASSERT(r1.fX >= kRadiusMin);
    632                 SkASSERT(r1.fY >= kRadiusMin);
    633                 rect.fLeft += r0.fX;
    634                 rect.fTop += r0.fY;
    635                 rect.fRight -= r1.fX;
    636                 rect.fBottom -= r1.fY;
    637                 if (fScaleUniform.isValid()) {
    638                     float scale = SkTMax(SkTMax(r0.fX, r0.fY), SkTMax(r1.fX, r1.fY));
    639                     float scaleSqd = scale * scale;
    640                     pdman.set4f(fInvRadiiSqdUniform, scaleSqd / (r0.fX * r0.fX),
    641                                                      scaleSqd / (r0.fY * r0.fY),
    642                                                      scaleSqd / (r1.fX * r1.fX),
    643                                                      scaleSqd / (r1.fY * r1.fY));
    644                     pdman.set2f(fScaleUniform, scale, 1.f / scale);
    645                 } else {
    646                     pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
    647                                                      1.f / (r0.fY * r0.fY),
    648                                                      1.f / (r1.fX * r1.fX),
    649                                                      1.f / (r1.fY * r1.fY));
    650                 }
    651                 break;
    652             }
    653         default:
    654             SkFAIL("RRect should always be simple or nine-patch.");
    655         }
    656         pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
    657         fPrevRRect = rrect;
    658     }
    659 }
    660 
    661 ////////////////////////////////////////////////////////////////////////////////////////////////////
    662 
    663 void EllipticalRRectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
    664                                                   GrProcessorKeyBuilder* b) const {
    665     GLEllipticalRRectEffect::GenKey(*this, caps, b);
    666 }
    667 
    668 GrGLSLFragmentProcessor* EllipticalRRectEffect::onCreateGLSLInstance() const  {
    669     return new GLEllipticalRRectEffect;
    670 }
    671 
    672 //////////////////////////////////////////////////////////////////////////////
    673 
    674 sk_sp<GrFragmentProcessor> GrRRectEffect::Make(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) {
    675     if (rrect.isRect()) {
    676         return GrConvexPolyEffect::Make(edgeType, rrect.getBounds());
    677     }
    678 
    679     if (rrect.isOval()) {
    680         return GrOvalEffect::Make(edgeType, rrect.getBounds());
    681     }
    682 
    683     if (rrect.isSimple()) {
    684         if (rrect.getSimpleRadii().fX < kRadiusMin || rrect.getSimpleRadii().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 (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().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