gfx/skia/trunk/src/gpu/effects/GrRRectEffect.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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  */
     8 #include "GrRRectEffect.h"
    10 #include "gl/GrGLEffect.h"
    11 #include "gl/GrGLSL.h"
    12 #include "GrTBackendEffectFactory.h"
    14 #include "SkRRect.h"
    16 class GLCircularRRectEffect;
    18 class CircularRRectEffect : public GrEffect {
    19 public:
    20     // This effect only supports circular corner rrects where the radius is >= kRadiusMin.
    21     static const SkScalar kRadiusMin;
    23     enum CornerFlags {
    24         kTopLeft_CornerFlag     = (1 << SkRRect::kUpperLeft_Corner),
    25         kTopRight_CornerFlag    = (1 << SkRRect::kUpperRight_Corner),
    26         kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner),
    27         kBottomLeft_CornerFlag  = (1 << SkRRect::kLowerLeft_Corner),
    29         kLeft_CornerFlags   = kTopLeft_CornerFlag    | kBottomLeft_CornerFlag,
    30         kTop_CornerFlags    = kTopLeft_CornerFlag    | kTopRight_CornerFlag,
    31         kRight_CornerFlags  = kTopRight_CornerFlag   | kBottomRight_CornerFlag,
    32         kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
    34         kAll_CornerFlags = kTopLeft_CornerFlag    | kTopRight_CornerFlag |
    35                            kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
    37     };
    39     // The flags are used to indicate which corners are circluar (unflagged corners are assumed to
    40     // be square).
    41     static GrEffectRef* Create(GrEffectEdgeType, uint32_t circularCornerFlags, const SkRRect&);
    43     virtual ~CircularRRectEffect() {};
    44     static const char* Name() { return "CircularRRect"; }
    46     const SkRRect& getRRect() const { return fRRect; }
    48     uint32_t getCircularCornerFlags() const { return fCircularCornerFlags; }
    50     GrEffectEdgeType getEdgeType() const { return fEdgeType; }
    52     typedef GLCircularRRectEffect GLEffect;
    54     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
    56     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
    58 private:
    59     CircularRRectEffect(GrEffectEdgeType, uint32_t circularCornerFlags, const SkRRect&);
    61     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
    63     SkRRect             fRRect;
    64     GrEffectEdgeType    fEdgeType;
    65     uint32_t            fCircularCornerFlags;
    67     GR_DECLARE_EFFECT_TEST;
    69     typedef GrEffect INHERITED;
    70 };
    72 const SkScalar CircularRRectEffect::kRadiusMin = 0.5f;
    74 GrEffectRef* CircularRRectEffect::Create(GrEffectEdgeType edgeType,
    75                                  uint32_t circularCornerFlags,
    76                                  const SkRRect& rrect) {
    77     SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdgeType == edgeType);
    78     return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircularRRectEffect,
    79                                                       (edgeType, circularCornerFlags, rrect))));
    80 }
    82 void CircularRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
    83     *validFlags = 0;
    84 }
    86 const GrBackendEffectFactory& CircularRRectEffect::getFactory() const {
    87     return GrTBackendEffectFactory<CircularRRectEffect>::getInstance();
    88 }
    90 CircularRRectEffect::CircularRRectEffect(GrEffectEdgeType edgeType, uint32_t circularCornerFlags,
    91                          const SkRRect& rrect)
    92     : fRRect(rrect)
    93     , fEdgeType(edgeType)
    94     , fCircularCornerFlags(circularCornerFlags) {
    95     this->setWillReadFragmentPosition();
    96 }
    98 bool CircularRRectEffect::onIsEqual(const GrEffect& other) const {
    99     const CircularRRectEffect& crre = CastEffect<CircularRRectEffect>(other);
   100     // The corner flags are derived from fRRect, so no need to check them.
   101     return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect;
   102 }
   104 //////////////////////////////////////////////////////////////////////////////
   106 GR_DEFINE_EFFECT_TEST(CircularRRectEffect);
   108 GrEffectRef* CircularRRectEffect::TestCreate(SkRandom* random,
   109                                      GrContext*,
   110                                      const GrDrawTargetCaps& caps,
   111                                      GrTexture*[]) {
   112     SkScalar w = random->nextRangeScalar(20.f, 1000.f);
   113     SkScalar h = random->nextRangeScalar(20.f, 1000.f);
   114     SkScalar r = random->nextRangeF(kRadiusMin, 9.f);
   115     SkRRect rrect;
   116     rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
   117     GrEffectRef* effect;
   118     do {
   119         GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
   120         effect = GrRRectEffect::Create(et, rrect);
   121     } while (NULL == effect);
   122     return effect;
   123 }
   125 //////////////////////////////////////////////////////////////////////////////
   127 class GLCircularRRectEffect : public GrGLEffect {
   128 public:
   129     GLCircularRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
   131     virtual void emitCode(GrGLShaderBuilder* builder,
   132                           const GrDrawEffect& drawEffect,
   133                           EffectKey key,
   134                           const char* outputColor,
   135                           const char* inputColor,
   136                           const TransformedCoordsArray&,
   137                           const TextureSamplerArray&) SK_OVERRIDE;
   139     static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
   141     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
   143 private:
   144     GrGLUniformManager::UniformHandle   fInnerRectUniform;
   145     GrGLUniformManager::UniformHandle   fRadiusPlusHalfUniform;
   146     SkRRect                             fPrevRRect;
   147     typedef GrGLEffect INHERITED;
   148 };
   150 GLCircularRRectEffect::GLCircularRRectEffect(const GrBackendEffectFactory& factory,
   151                              const GrDrawEffect& drawEffect)
   152     : INHERITED (factory) {
   153     fPrevRRect.setEmpty();
   154 }
   156 void GLCircularRRectEffect::emitCode(GrGLShaderBuilder* builder,
   157                              const GrDrawEffect& drawEffect,
   158                              EffectKey key,
   159                              const char* outputColor,
   160                              const char* inputColor,
   161                              const TransformedCoordsArray&,
   162                              const TextureSamplerArray& samplers) {
   163     const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
   164     const char *rectName;
   165     const char *radiusPlusHalfName;
   166     // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom
   167     // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has
   168     // only rectangular corners, that side's value corresponds to the rect edge's value outset by
   169     // half a pixel.
   170     fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
   171                                             kVec4f_GrSLType,
   172                                             "innerRect",
   173                                             &rectName);
   174     fRadiusPlusHalfUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
   175                                                  kFloat_GrSLType,
   176                                                  "radiusPlusHalf",
   177                                                  &radiusPlusHalfName);
   178     const char* fragmentPos = builder->fragmentPosition();
   179     // At each quarter-circle corner we compute a vector that is the offset of the fragment position
   180     // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant
   181     // to that corner. This means that points near the interior near the rrect top edge will have
   182     // a vector that points straight up for both the TL left and TR corners. Computing an
   183     // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
   184     // fragments near the other three edges will get the correct AA. Fragments in the interior of
   185     // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will
   186     // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
   187     // The code below is a simplified version of the above that performs maxs on the vector
   188     // components before computing distances and alpha values so that only one distance computation
   189     // need be computed to determine the min alpha.
   190     //
   191     // For the cases where one half of the rrect is rectangular we drop one of the x or y
   192     // computations, compute a separate rect edge alpha for the rect side, and mul the two computed
   193     // alphas together.
   194     switch (crre.getCircularCornerFlags()) {
   195         case CircularRRectEffect::kAll_CornerFlags:
   196             builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
   197             builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
   198             builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
   199             builder->fsCodeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n",
   200                                    radiusPlusHalfName);
   201             break;
   202         case CircularRRectEffect::kTopLeft_CornerFlag:
   203             builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n",
   204                                    rectName, fragmentPos);
   205             builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
   206                                     rectName, fragmentPos);
   207             builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
   208                                     rectName, fragmentPos);
   209             builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
   210                                    radiusPlusHalfName);
   211             break;
   212         case CircularRRectEffect::kTopRight_CornerFlag:
   213             builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n",
   214                                    fragmentPos, rectName, rectName, fragmentPos);
   215             builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
   216                                    fragmentPos, rectName);
   217             builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
   218                                     rectName, fragmentPos);
   219             builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
   220                                    radiusPlusHalfName);
   221             break;
   222         case CircularRRectEffect::kBottomRight_CornerFlag:
   223             builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n",
   224                                    fragmentPos, rectName);
   225             builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
   226                                    fragmentPos, rectName);
   227             builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
   228                                    fragmentPos, rectName);
   229             builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
   230                                    radiusPlusHalfName);
   231             break;
   232         case CircularRRectEffect::kBottomLeft_CornerFlag:
   233             builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n",
   234                                    rectName, fragmentPos, fragmentPos, rectName);
   235             builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
   236                                     rectName, fragmentPos);
   237             builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
   238                                    fragmentPos, rectName);
   239             builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
   240                                    radiusPlusHalfName);
   241             break;
   242         case CircularRRectEffect::kLeft_CornerFlags:
   243             builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
   244             builder->fsCodeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName);
   245             builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n");
   246             builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
   247                                     rectName, fragmentPos);
   248             builder->fsCodeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
   249                                    radiusPlusHalfName);
   250             break;
   251         case CircularRRectEffect::kTop_CornerFlags:
   252             builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
   253             builder->fsCodeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName);
   254             builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n");
   255             builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
   256                                    rectName, fragmentPos);
   257             builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
   258                                    radiusPlusHalfName);
   259             break;
   260         case CircularRRectEffect::kRight_CornerFlags:
   261             builder->fsCodeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos);
   262             builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
   263             builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n");
   264             builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
   265                                    fragmentPos, rectName);
   266             builder->fsCodeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
   267                                    radiusPlusHalfName);
   268             break;
   269         case CircularRRectEffect::kBottom_CornerFlags:
   270             builder->fsCodeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos);
   271             builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
   272             builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n");
   273             builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
   274                                    fragmentPos, rectName);
   275             builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
   276                                    radiusPlusHalfName);
   277             break;
   278     }
   280     if (kInverseFillAA_GrEffectEdgeType == crre.getEdgeType()) {
   281         builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n");
   282     }
   284     builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
   285                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
   286 }
   288 GrGLEffect::EffectKey GLCircularRRectEffect::GenKey(const GrDrawEffect& drawEffect,
   289                                                     const GrGLCaps&) {
   290     const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
   291     GR_STATIC_ASSERT(kGrEffectEdgeTypeCnt <= 8);
   292     return (crre.getCircularCornerFlags() << 3) | crre.getEdgeType();
   293 }
   295 void GLCircularRRectEffect::setData(const GrGLUniformManager& uman,
   296                                     const GrDrawEffect& drawEffect) {
   297     const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
   298     const SkRRect& rrect = crre.getRRect();
   299     if (rrect != fPrevRRect) {
   300         SkRect rect = rrect.getBounds();
   301         SkScalar radius = 0;
   302         switch (crre.getCircularCornerFlags()) {
   303             case CircularRRectEffect::kAll_CornerFlags:
   304                 SkASSERT(rrect.isSimpleCircular());
   305                 radius = rrect.getSimpleRadii().fX;
   306                 SkASSERT(radius >= CircularRRectEffect::kRadiusMin);
   307                 rect.inset(radius, radius);
   308                 break;
   309             case CircularRRectEffect::kTopLeft_CornerFlag:
   310                 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
   311                 rect.fLeft += radius;
   312                 rect.fTop += radius;
   313                 rect.fRight += 0.5f;
   314                 rect.fBottom += 0.5f;
   315                 break;
   316             case CircularRRectEffect::kTopRight_CornerFlag:
   317                 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
   318                 rect.fLeft -= 0.5f;
   319                 rect.fTop += radius;
   320                 rect.fRight -= radius;
   321                 rect.fBottom += 0.5f;
   322                 break;
   323             case CircularRRectEffect::kBottomRight_CornerFlag:
   324                 radius = rrect.radii(SkRRect::kLowerRight_Corner).fX;
   325                 rect.fLeft -= 0.5f;
   326                 rect.fTop -= 0.5f;
   327                 rect.fRight -= radius;
   328                 rect.fBottom -= radius;
   329                 break;
   330             case CircularRRectEffect::kBottomLeft_CornerFlag:
   331                 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
   332                 rect.fLeft += radius;
   333                 rect.fTop -= 0.5f;
   334                 rect.fRight += 0.5f;
   335                 rect.fBottom -= radius;
   336                 break;
   337             case CircularRRectEffect::kLeft_CornerFlags:
   338                 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
   339                 rect.fLeft += radius;
   340                 rect.fTop += radius;
   341                 rect.fRight += 0.5f;
   342                 rect.fBottom -= radius;
   343                 break;
   344             case CircularRRectEffect::kTop_CornerFlags:
   345                 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
   346                 rect.fLeft += radius;
   347                 rect.fTop += radius;
   348                 rect.fRight -= radius;
   349                 rect.fBottom += 0.5f;
   350                 break;
   351             case CircularRRectEffect::kRight_CornerFlags:
   352                 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
   353                 rect.fLeft -= 0.5f;
   354                 rect.fTop += radius;
   355                 rect.fRight -= radius;
   356                 rect.fBottom -= radius;
   357                 break;
   358             case CircularRRectEffect::kBottom_CornerFlags:
   359                 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
   360                 rect.fLeft += radius;
   361                 rect.fTop -= 0.5f;
   362                 rect.fRight -= radius;
   363                 rect.fBottom -= radius;
   364                 break;
   365             default:
   366                 GrCrash("Should have been one of the above cases.");
   367         }
   368         uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
   369         uman.set1f(fRadiusPlusHalfUniform, radius + 0.5f);
   370         fPrevRRect = rrect;
   371     }
   372 }
   374 //////////////////////////////////////////////////////////////////////////////
   376 class GLEllipticalRRectEffect;
   378 class EllipticalRRectEffect : public GrEffect {
   379 public:
   380     // This effect currently works for these two classifications of SkRRects
   381     enum RRectType {
   382         kSimple_RRectType,       // SkRRect::kSimple_Type
   383         kNinePatch_RRectType,    // The two left x radii are the same, the two
   384                                  // top y radii are the same, etc.
   385     };
   387     // This effect only supports rrects where the radii are >= kRadiusMin.
   388     static const SkScalar kRadiusMin;
   390     static GrEffectRef* Create(GrEffectEdgeType, RRectType, const SkRRect&);
   392     virtual ~EllipticalRRectEffect() {};
   393     static const char* Name() { return "EllipticalRRect"; }
   395     const SkRRect& getRRect() const { return fRRect; }
   397     RRectType getRRectType() const { return fRRectType; }
   399     GrEffectEdgeType getEdgeType() const { return fEdgeType; }
   401     typedef GLEllipticalRRectEffect GLEffect;
   403     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
   405     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
   407 private:
   408     EllipticalRRectEffect(GrEffectEdgeType, RRectType, const SkRRect&);
   410     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
   412     SkRRect             fRRect;
   413     RRectType           fRRectType;
   414     GrEffectEdgeType    fEdgeType;
   416     GR_DECLARE_EFFECT_TEST;
   418     typedef GrEffect INHERITED;
   419 };
   421 const SkScalar EllipticalRRectEffect::kRadiusMin = 0.5f;
   423 GrEffectRef* EllipticalRRectEffect::Create(GrEffectEdgeType edgeType,
   424                                            RRectType rrType,
   425                                            const SkRRect& rrect) {
   426     SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdgeType == edgeType);
   427     return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipticalRRectEffect, (edgeType, rrType,
   428                                                                               rrect))));
   429 }
   431 void EllipticalRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
   432     *validFlags = 0;
   433 }
   435 const GrBackendEffectFactory& EllipticalRRectEffect::getFactory() const {
   436     return GrTBackendEffectFactory<EllipticalRRectEffect>::getInstance();
   437 }
   439 EllipticalRRectEffect::EllipticalRRectEffect(GrEffectEdgeType edgeType, RRectType rrType,
   440                                              const SkRRect& rrect)
   441     : fRRect(rrect)
   442     , fRRectType(rrType)
   443     , fEdgeType(edgeType){
   444     this->setWillReadFragmentPosition();
   445 }
   447 bool EllipticalRRectEffect::onIsEqual(const GrEffect& other) const {
   448     const EllipticalRRectEffect& erre = CastEffect<EllipticalRRectEffect>(other);
   449     // No need to check fRRectType as it is derived from fRRect.
   450     return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect;
   451 }
   453 //////////////////////////////////////////////////////////////////////////////
   455 GR_DEFINE_EFFECT_TEST(EllipticalRRectEffect);
   457 GrEffectRef* EllipticalRRectEffect::TestCreate(SkRandom* random,
   458                                                GrContext*,
   459                                                const GrDrawTargetCaps& caps,
   460                                                GrTexture*[]) {
   461     SkScalar w = random->nextRangeScalar(20.f, 1000.f);
   462     SkScalar h = random->nextRangeScalar(20.f, 1000.f);
   463     SkVector r[4];
   464     r[SkRRect::kUpperLeft_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
   465     // ensure at least one corner really is elliptical
   466     do {
   467         r[SkRRect::kUpperLeft_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
   468     } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX);
   470     SkRRect rrect;
   471     if (random->nextBool()) {
   472         // half the time create a four-radii rrect.
   473         r[SkRRect::kLowerRight_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
   474         r[SkRRect::kLowerRight_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
   476         r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX;
   477         r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY;
   479         r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX;
   480         r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY;
   482         rrect.setRectRadii(SkRect::MakeWH(w, h), r);
   483     } else {
   484         rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX,
   485                                               r[SkRRect::kUpperLeft_Corner].fY);
   486     }
   487     GrEffectRef* effect;
   488     do {
   489         GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
   490         effect = GrRRectEffect::Create(et, rrect);
   491     } while (NULL == effect);
   492     return effect;
   493 }
   495 //////////////////////////////////////////////////////////////////////////////
   497 class GLEllipticalRRectEffect : public GrGLEffect {
   498 public:
   499     GLEllipticalRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
   501     virtual void emitCode(GrGLShaderBuilder* builder,
   502                           const GrDrawEffect& drawEffect,
   503                           EffectKey key,
   504                           const char* outputColor,
   505                           const char* inputColor,
   506                           const TransformedCoordsArray&,
   507                           const TextureSamplerArray&) SK_OVERRIDE;
   509     static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
   511     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
   513 private:
   514     GrGLUniformManager::UniformHandle   fInnerRectUniform;
   515     GrGLUniformManager::UniformHandle   fInvRadiiSqdUniform;
   516     SkRRect                             fPrevRRect;
   517     typedef GrGLEffect INHERITED;
   518 };
   520 GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrBackendEffectFactory& factory,
   521                              const GrDrawEffect& drawEffect)
   522     : INHERITED (factory) {
   523     fPrevRRect.setEmpty();
   524 }
   526 void GLEllipticalRRectEffect::emitCode(GrGLShaderBuilder* builder,
   527                                        const GrDrawEffect& drawEffect,
   528                                        EffectKey key,
   529                                        const char* outputColor,
   530                                        const char* inputColor,
   531                                        const TransformedCoordsArray&,
   532                                        const TextureSamplerArray& samplers) {
   533     const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
   534     const char *rectName;
   535     // The inner rect is the rrect bounds inset by the x/y radii
   536     fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
   537                                             kVec4f_GrSLType,
   538                                             "innerRect",
   539                                             &rectName);
   540     const char* fragmentPos = builder->fragmentPosition();
   541     // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos
   542     // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant
   543     // to that corner. This means that points near the interior near the rrect top edge will have
   544     // a vector that points straight up for both the TL left and TR corners. Computing an
   545     // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
   546     // fragments near the other three edges will get the correct AA. Fragments in the interior of
   547     // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will
   548     // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
   549     // The code below is a simplified version of the above that performs maxs on the vector
   550     // components before computing distances and alpha values so that only one distance computation
   551     // need be computed to determine the min alpha.
   552     builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
   553     builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
   554     switch (erre.getRRectType()) {
   555         case EllipticalRRectEffect::kSimple_RRectType: {
   556             const char *invRadiiXYSqdName;
   557             fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
   558                                                       kVec2f_GrSLType,
   559                                                       "invRadiiXY",
   560                                                       &invRadiiXYSqdName);
   561             builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
   562             // Z is the x/y offsets divided by squared radii.
   563             builder->fsCodeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName);
   564             break;
   565         }
   566         case EllipticalRRectEffect::kNinePatch_RRectType: {
   567             const char *invRadiiLTRBSqdName;
   568             fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
   569                                                       kVec4f_GrSLType,
   570                                                       "invRadiiLTRB",
   571                                                       &invRadiiLTRBSqdName);
   572             builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
   573             // Z is the x/y offsets divided by squared radii. We only care about the (at most) one
   574             // corner where both the x and y offsets are positive, hence the maxes. (The inverse
   575             // squared radii will always be positive.)
   576             builder->fsCodeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n",
   577                                    invRadiiLTRBSqdName, invRadiiLTRBSqdName);
   578             break;
   579        }
   580     }
   581     // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1.
   582     builder->fsCodeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n");
   583     // grad_dot is the squared length of the gradient of the implicit.
   584     builder->fsCodeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
   585     builder->fsCodeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
   586     builder->fsCodeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
   588     if (kFillAA_GrEffectEdgeType == erre.getEdgeType()) {
   589         builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
   590     } else {
   591         builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
   592     }
   594     builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
   595                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
   596 }
   598 GrGLEffect::EffectKey GLEllipticalRRectEffect::GenKey(const GrDrawEffect& drawEffect,
   599                                                       const GrGLCaps&) {
   600     const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
   601     GR_STATIC_ASSERT(kLast_GrEffectEdgeType < (1 << 3));
   602     return erre.getRRectType() | erre.getEdgeType() << 3;
   603 }
   605 void GLEllipticalRRectEffect::setData(const GrGLUniformManager& uman,
   606                                       const GrDrawEffect& drawEffect) {
   607     const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
   608     const SkRRect& rrect = erre.getRRect();
   609     if (rrect != fPrevRRect) {
   610         SkRect rect = rrect.getBounds();
   611         const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
   612         SkASSERT(r0.fX >= EllipticalRRectEffect::kRadiusMin);
   613         SkASSERT(r0.fY >= EllipticalRRectEffect::kRadiusMin);
   614         switch (erre.getRRectType()) {
   615             case EllipticalRRectEffect::kSimple_RRectType:
   616                 rect.inset(r0.fX, r0.fY);
   617                 uman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
   618                                                 1.f / (r0.fY * r0.fY));
   619                 break;
   620             case EllipticalRRectEffect::kNinePatch_RRectType: {
   621                 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
   622                 SkASSERT(r1.fX >= EllipticalRRectEffect::kRadiusMin);
   623                 SkASSERT(r1.fY >= EllipticalRRectEffect::kRadiusMin);
   624                 rect.fLeft += r0.fX;
   625                 rect.fTop += r0.fY;
   626                 rect.fRight -= r1.fX;
   627                 rect.fBottom -= r1.fY;
   628                 uman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
   629                                                 1.f / (r0.fY * r0.fY),
   630                                                 1.f / (r1.fX * r1.fX),
   631                                                 1.f / (r1.fY * r1.fY));
   632                 break;
   633             }
   634         }
   635         uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
   636         fPrevRRect = rrect;
   637     }
   638 }
   640 //////////////////////////////////////////////////////////////////////////////
   642 GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) {
   643     if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) {
   644         return NULL;
   645     }
   646     uint32_t cornerFlags;
   647     if (rrect.isSimple()) {
   648         if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) {
   649             if (rrect.getSimpleRadii().fX < CircularRRectEffect::kRadiusMin) {
   650                 return NULL;
   651             }
   652             cornerFlags = CircularRRectEffect::kAll_CornerFlags;
   653         } else {
   654             if (rrect.getSimpleRadii().fX < EllipticalRRectEffect::kRadiusMin ||
   655                 rrect.getSimpleRadii().fY < EllipticalRRectEffect::kRadiusMin) {
   656                 return NULL;
   657             }
   658             return EllipticalRRectEffect::Create(edgeType,
   659                                                  EllipticalRRectEffect::kSimple_RRectType, rrect);
   660         }
   661     } else if (rrect.isComplex()) {
   662         // Check for the "tab" cases - two adjacent circular corners and two square corners.
   663         SkScalar radius = 0;
   664         cornerFlags = 0;
   665         for (int c = 0; c < 4; ++c) {
   666             const SkVector& r = rrect.radii((SkRRect::Corner)c);
   667             SkASSERT((0 == r.fX) == (0 == r.fY));
   668             if (0 == r.fX) {
   669                 continue;
   670             }
   671             if (r.fX != r.fY) {
   672                 cornerFlags = ~0U;
   673                 break;
   674             }
   675             if (!cornerFlags) {
   676                 radius = r.fX;
   677                 if (radius < CircularRRectEffect::kRadiusMin) {
   678                     cornerFlags = ~0U;
   679                     break;
   680                 }
   681                 cornerFlags = 1 << c;
   682             } else {
   683                 if (r.fX != radius) {
   684                    cornerFlags = ~0U;
   685                    break;
   686                 }
   687                 cornerFlags |= 1 << c;
   688             }
   689         }
   691         switch (cornerFlags) {
   692             case CircularRRectEffect::kTopLeft_CornerFlag:
   693             case CircularRRectEffect::kTopRight_CornerFlag:
   694             case CircularRRectEffect::kBottomRight_CornerFlag:
   695             case CircularRRectEffect::kBottomLeft_CornerFlag:
   696             case CircularRRectEffect::kLeft_CornerFlags:
   697             case CircularRRectEffect::kTop_CornerFlags:
   698             case CircularRRectEffect::kRight_CornerFlags:
   699             case CircularRRectEffect::kBottom_CornerFlags:
   700             case CircularRRectEffect::kAll_CornerFlags:
   701                 break;
   702             default:
   703                 if (rrect.isNinePatch()) {
   704                     const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
   705                     const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
   706                     if (r0.fX >= EllipticalRRectEffect::kRadiusMin &&
   707                         r0.fY >= EllipticalRRectEffect::kRadiusMin &&
   708                         r1.fX >= EllipticalRRectEffect::kRadiusMin &&
   709                         r1.fY >= EllipticalRRectEffect::kRadiusMin) {
   710                         return EllipticalRRectEffect::Create(edgeType,
   711                                                         EllipticalRRectEffect::kNinePatch_RRectType,
   712                                                         rrect);
   713                     }
   714                 }
   715                 return NULL;
   716         }
   717     } else {
   718         return NULL;
   719     }
   720     return CircularRRectEffect::Create(edgeType, cornerFlags, rrect);
   721 }

mercurial