Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2013 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 "GrOvalRenderer.h"
      9 
     10 #include "gl/builders/GrGLFullProgramBuilder.h"
     11 #include "gl/GrGLProcessor.h"
     12 #include "gl/GrGLSL.h"
     13 #include "gl/GrGLGeometryProcessor.h"
     14 #include "GrProcessor.h"
     15 #include "GrTBackendProcessorFactory.h"
     16 
     17 #include "GrDrawState.h"
     18 #include "GrDrawTarget.h"
     19 #include "GrGpu.h"
     20 
     21 #include "SkRRect.h"
     22 #include "SkStrokeRec.h"
     23 #include "SkTLazy.h"
     24 
     25 #include "GrGeometryProcessor.h"
     26 #include "effects/GrRRectEffect.h"
     27 
     28 namespace {
     29 
     30 struct CircleVertex {
     31     SkPoint  fPos;
     32     SkPoint  fOffset;
     33     SkScalar fOuterRadius;
     34     SkScalar fInnerRadius;
     35 };
     36 
     37 struct EllipseVertex {
     38     SkPoint  fPos;
     39     SkPoint  fOffset;
     40     SkPoint  fOuterRadii;
     41     SkPoint  fInnerRadii;
     42 };
     43 
     44 struct DIEllipseVertex {
     45     SkPoint  fPos;
     46     SkPoint  fOuterOffset;
     47     SkPoint  fInnerOffset;
     48 };
     49 
     50 inline bool circle_stays_circle(const SkMatrix& m) {
     51     return m.isSimilarity();
     52 }
     53 
     54 }
     55 
     56 ///////////////////////////////////////////////////////////////////////////////
     57 
     58 /**
     59  * The output of this effect is a modulation of the input color and coverage for a circle,
     60  * specified as offset_x, offset_y (both from center point), outer radius and inner radius.
     61  */
     62 
     63 class CircleEdgeEffect : public GrGeometryProcessor {
     64 public:
     65     static GrGeometryProcessor* Create(bool stroke) {
     66         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gCircleStrokeEdge, CircleEdgeEffect, (true));
     67         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gCircleFillEdge, CircleEdgeEffect, (false));
     68 
     69         if (stroke) {
     70             gCircleStrokeEdge->ref();
     71             return gCircleStrokeEdge;
     72         } else {
     73             gCircleFillEdge->ref();
     74             return gCircleFillEdge;
     75         }
     76     }
     77 
     78     virtual void getConstantColorComponents(GrColor* color,
     79                                             uint32_t* validFlags) const SK_OVERRIDE {
     80         *validFlags = 0;
     81     }
     82 
     83     const GrShaderVar& inCircleEdge() const { return fInCircleEdge; }
     84 
     85     virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE {
     86         return GrTBackendGeometryProcessorFactory<CircleEdgeEffect>::getInstance();
     87     }
     88 
     89     virtual ~CircleEdgeEffect() {}
     90 
     91     static const char* Name() { return "CircleEdge"; }
     92 
     93     inline bool isStroked() const { return fStroke; }
     94 
     95     class GLProcessor : public GrGLGeometryProcessor {
     96     public:
     97         GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&)
     98         : INHERITED (factory) {}
     99 
    100         virtual void emitCode(GrGLFullProgramBuilder* builder,
    101                               const GrGeometryProcessor& geometryProcessor,
    102                               const GrProcessorKey& key,
    103                               const char* outputColor,
    104                               const char* inputColor,
    105                               const TransformedCoordsArray&,
    106                               const TextureSamplerArray& samplers) SK_OVERRIDE {
    107             const CircleEdgeEffect& circleEffect = geometryProcessor.cast<CircleEdgeEffect>();
    108             const char *vsName, *fsName;
    109             builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName);
    110 
    111             GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();;
    112             vsBuilder->codeAppendf("\t%s = %s;\n", vsName, circleEffect.inCircleEdge().c_str());
    113 
    114             GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
    115             fsBuilder->codeAppendf("\tfloat d = length(%s.xy);\n", fsName);
    116             fsBuilder->codeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName);
    117             if (circleEffect.isStroked()) {
    118                 fsBuilder->codeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0, 1.0);\n", fsName);
    119                 fsBuilder->codeAppend("\tedgeAlpha *= innerAlpha;\n");
    120             }
    121 
    122             fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
    123                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
    124         }
    125 
    126         static void GenKey(const GrProcessor& processor, const GrGLCaps&,
    127                            GrProcessorKeyBuilder* b) {
    128             const CircleEdgeEffect& circleEffect = processor.cast<CircleEdgeEffect>();
    129             b->add32(circleEffect.isStroked());
    130         }
    131 
    132         virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {}
    133 
    134     private:
    135         typedef GrGLGeometryProcessor INHERITED;
    136     };
    137 
    138 
    139 private:
    140     CircleEdgeEffect(bool stroke)
    141         : fInCircleEdge(this->addVertexAttrib(
    142                 GrShaderVar("inCircleEdge",
    143                             kVec4f_GrSLType,
    144                             GrShaderVar::kAttribute_TypeModifier))) {
    145         fStroke = stroke;
    146     }
    147 
    148     virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE {
    149         const CircleEdgeEffect& cee = other.cast<CircleEdgeEffect>();
    150         return cee.fStroke == fStroke;
    151     }
    152 
    153     const GrShaderVar& fInCircleEdge;
    154     bool fStroke;
    155 
    156     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
    157 
    158     typedef GrGeometryProcessor INHERITED;
    159 };
    160 
    161 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleEdgeEffect);
    162 
    163 GrGeometryProcessor* CircleEdgeEffect::TestCreate(SkRandom* random,
    164                                                   GrContext* context,
    165                                                   const GrDrawTargetCaps&,
    166                                                   GrTexture* textures[]) {
    167     return CircleEdgeEffect::Create(random->nextBool());
    168 }
    169 
    170 ///////////////////////////////////////////////////////////////////////////////
    171 
    172 /**
    173  * The output of this effect is a modulation of the input color and coverage for an axis-aligned
    174  * ellipse, specified as a 2D offset from center, and the reciprocals of the outer and inner radii,
    175  * in both x and y directions.
    176  *
    177  * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0.
    178  */
    179 
    180 class EllipseEdgeEffect : public GrGeometryProcessor {
    181 public:
    182     static GrGeometryProcessor* Create(bool stroke) {
    183         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gEllipseStrokeEdge, EllipseEdgeEffect, (true));
    184         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gEllipseFillEdge, EllipseEdgeEffect, (false));
    185 
    186         if (stroke) {
    187             gEllipseStrokeEdge->ref();
    188             return gEllipseStrokeEdge;
    189         } else {
    190             gEllipseFillEdge->ref();
    191             return gEllipseFillEdge;
    192         }
    193     }
    194 
    195     virtual void getConstantColorComponents(GrColor* color,
    196                                             uint32_t* validFlags) const SK_OVERRIDE {
    197         *validFlags = 0;
    198     }
    199 
    200     virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE {
    201         return GrTBackendGeometryProcessorFactory<EllipseEdgeEffect>::getInstance();
    202     }
    203 
    204     virtual ~EllipseEdgeEffect() {}
    205 
    206     static const char* Name() { return "EllipseEdge"; }
    207 
    208     const GrShaderVar& inEllipseOffset() const { return fInEllipseOffset; }
    209     const GrShaderVar& inEllipseRadii() const { return fInEllipseRadii; }
    210 
    211     inline bool isStroked() const { return fStroke; }
    212 
    213     class GLProcessor : public GrGLGeometryProcessor {
    214     public:
    215         GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&)
    216         : INHERITED (factory) {}
    217 
    218         virtual void emitCode(GrGLFullProgramBuilder* builder,
    219                               const GrGeometryProcessor& geometryProcessor,
    220                               const GrProcessorKey& key,
    221                               const char* outputColor,
    222                               const char* inputColor,
    223                               const TransformedCoordsArray&,
    224                               const TextureSamplerArray& samplers) SK_OVERRIDE {
    225             const EllipseEdgeEffect& ellipseEffect = geometryProcessor.cast<EllipseEdgeEffect>();
    226 
    227             const char *vsOffsetName, *fsOffsetName;
    228             const char *vsRadiiName, *fsRadiiName;
    229 
    230             builder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName, &fsOffsetName);
    231 
    232             GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
    233             vsBuilder->codeAppendf("%s = %s;", vsOffsetName,
    234                                    ellipseEffect.inEllipseOffset().c_str());
    235 
    236             builder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, &fsRadiiName);
    237             vsBuilder->codeAppendf("%s = %s;", vsRadiiName, ellipseEffect.inEllipseRadii().c_str());
    238 
    239             // for outer curve
    240             GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
    241             fsBuilder->codeAppendf("\tvec2 scaledOffset = %s*%s.xy;\n", fsOffsetName, fsRadiiName);
    242             fsBuilder->codeAppend("\tfloat test = dot(scaledOffset, scaledOffset) - 1.0;\n");
    243             fsBuilder->codeAppendf("\tvec2 grad = 2.0*scaledOffset*%s.xy;\n", fsRadiiName);
    244             fsBuilder->codeAppend("\tfloat grad_dot = dot(grad, grad);\n");
    245             // avoid calling inversesqrt on zero.
    246             fsBuilder->codeAppend("\tgrad_dot = max(grad_dot, 1.0e-4);\n");
    247             fsBuilder->codeAppend("\tfloat invlen = inversesqrt(grad_dot);\n");
    248             fsBuilder->codeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);\n");
    249 
    250             // for inner curve
    251             if (ellipseEffect.isStroked()) {
    252                 fsBuilder->codeAppendf("\tscaledOffset = %s*%s.zw;\n", fsOffsetName, fsRadiiName);
    253                 fsBuilder->codeAppend("\ttest = dot(scaledOffset, scaledOffset) - 1.0;\n");
    254                 fsBuilder->codeAppendf("\tgrad = 2.0*scaledOffset*%s.zw;\n", fsRadiiName);
    255                 fsBuilder->codeAppend("\tinvlen = inversesqrt(dot(grad, grad));\n");
    256                 fsBuilder->codeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);\n");
    257             }
    258 
    259             fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
    260                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
    261         }
    262 
    263         static void GenKey(const GrProcessor& processor, const GrGLCaps&,
    264                            GrProcessorKeyBuilder* b) {
    265             const EllipseEdgeEffect& ellipseEffect = processor.cast<EllipseEdgeEffect>();
    266             b->add32(ellipseEffect.isStroked());
    267         }
    268 
    269         virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {
    270         }
    271 
    272     private:
    273         typedef GrGLGeometryProcessor INHERITED;
    274     };
    275 
    276 private:
    277     EllipseEdgeEffect(bool stroke)
    278         : fInEllipseOffset(this->addVertexAttrib(
    279                 GrShaderVar("inEllipseOffset",
    280                             kVec2f_GrSLType,
    281                             GrShaderVar::kAttribute_TypeModifier)))
    282         , fInEllipseRadii(this->addVertexAttrib(
    283                 GrShaderVar("inEllipseRadii",
    284                             kVec4f_GrSLType,
    285                             GrShaderVar::kAttribute_TypeModifier))) {
    286         fStroke = stroke;
    287     }
    288 
    289     virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE {
    290         const EllipseEdgeEffect& eee = other.cast<EllipseEdgeEffect>();
    291         return eee.fStroke == fStroke;
    292     }
    293 
    294     const GrShaderVar& fInEllipseOffset;
    295     const GrShaderVar& fInEllipseRadii;
    296     bool fStroke;
    297 
    298     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
    299 
    300     typedef GrGeometryProcessor INHERITED;
    301 };
    302 
    303 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(EllipseEdgeEffect);
    304 
    305 GrGeometryProcessor* EllipseEdgeEffect::TestCreate(SkRandom* random,
    306                                                    GrContext* context,
    307                                                    const GrDrawTargetCaps&,
    308                                                    GrTexture* textures[]) {
    309     return EllipseEdgeEffect::Create(random->nextBool());
    310 }
    311 
    312 ///////////////////////////////////////////////////////////////////////////////
    313 
    314 /**
    315  * The output of this effect is a modulation of the input color and coverage for an ellipse,
    316  * specified as a 2D offset from center for both the outer and inner paths (if stroked). The
    317  * implict equation used is for a unit circle (x^2 + y^2 - 1 = 0) and the edge corrected by
    318  * using differentials.
    319  *
    320  * The result is device-independent and can be used with any affine matrix.
    321  */
    322 
    323 class DIEllipseEdgeEffect : public GrGeometryProcessor {
    324 public:
    325     enum Mode { kStroke = 0, kHairline, kFill };
    326 
    327     static GrGeometryProcessor* Create(Mode mode) {
    328         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gEllipseStrokeEdge, DIEllipseEdgeEffect, (kStroke));
    329         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gEllipseHairlineEdge, DIEllipseEdgeEffect, (kHairline));
    330         GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gEllipseFillEdge, DIEllipseEdgeEffect, (kFill));
    331 
    332         if (kStroke == mode) {
    333             gEllipseStrokeEdge->ref();
    334             return gEllipseStrokeEdge;
    335         } else if (kHairline == mode) {
    336             gEllipseHairlineEdge->ref();
    337             return gEllipseHairlineEdge;
    338         } else {
    339             gEllipseFillEdge->ref();
    340             return gEllipseFillEdge;
    341         }
    342     }
    343 
    344     virtual void getConstantColorComponents(GrColor* color,
    345                                             uint32_t* validFlags) const SK_OVERRIDE {
    346         *validFlags = 0;
    347     }
    348 
    349     virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE {
    350         return GrTBackendGeometryProcessorFactory<DIEllipseEdgeEffect>::getInstance();
    351     }
    352 
    353     virtual ~DIEllipseEdgeEffect() {}
    354 
    355     static const char* Name() { return "DIEllipseEdge"; }
    356 
    357     const GrShaderVar& inEllipseOffsets0() const { return fInEllipseOffsets0; }
    358     const GrShaderVar& inEllipseOffsets1() const { return fInEllipseOffsets1; }
    359 
    360     inline Mode getMode() const { return fMode; }
    361 
    362     class GLProcessor : public GrGLGeometryProcessor {
    363     public:
    364         GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&)
    365         : INHERITED (factory) {}
    366 
    367         virtual void emitCode(GrGLFullProgramBuilder* builder,
    368                               const GrGeometryProcessor& geometryProcessor,
    369                               const GrProcessorKey& key,
    370                               const char* outputColor,
    371                               const char* inputColor,
    372                               const TransformedCoordsArray&,
    373                               const TextureSamplerArray& samplers) SK_OVERRIDE {
    374             const DIEllipseEdgeEffect& ellipseEffect =
    375                     geometryProcessor.cast<DIEllipseEdgeEffect>();
    376 
    377             const char *vsOffsetName0, *fsOffsetName0;
    378             builder->addVarying(kVec2f_GrSLType, "EllipseOffsets0",
    379                                       &vsOffsetName0, &fsOffsetName0);
    380 
    381             GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
    382             vsBuilder->codeAppendf("%s = %s;", vsOffsetName0,
    383                                    ellipseEffect.inEllipseOffsets0().c_str());
    384             const char *vsOffsetName1, *fsOffsetName1;
    385             builder->addVarying(kVec2f_GrSLType, "EllipseOffsets1",
    386                                       &vsOffsetName1, &fsOffsetName1);
    387             vsBuilder->codeAppendf("\t%s = %s;\n", vsOffsetName1,
    388                                    ellipseEffect.inEllipseOffsets1().c_str());
    389 
    390             GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
    391             SkAssertResult(fsBuilder->enableFeature(
    392                     GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
    393             // for outer curve
    394             fsBuilder->codeAppendf("\tvec2 scaledOffset = %s.xy;\n", fsOffsetName0);
    395             fsBuilder->codeAppend("\tfloat test = dot(scaledOffset, scaledOffset) - 1.0;\n");
    396             fsBuilder->codeAppendf("\tvec2 duvdx = dFdx(%s);\n", fsOffsetName0);
    397             fsBuilder->codeAppendf("\tvec2 duvdy = dFdy(%s);\n", fsOffsetName0);
    398             fsBuilder->codeAppendf("\tvec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,\n"
    399                                    "\t                 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);\n",
    400                                    fsOffsetName0, fsOffsetName0, fsOffsetName0, fsOffsetName0);
    401 
    402             fsBuilder->codeAppend("\tfloat grad_dot = dot(grad, grad);\n");
    403             // avoid calling inversesqrt on zero.
    404             fsBuilder->codeAppend("\tgrad_dot = max(grad_dot, 1.0e-4);\n");
    405             fsBuilder->codeAppend("\tfloat invlen = inversesqrt(grad_dot);\n");
    406             if (kHairline == ellipseEffect.getMode()) {
    407                 // can probably do this with one step
    408                 fsBuilder->codeAppend("\tfloat edgeAlpha = clamp(1.0-test*invlen, 0.0, 1.0);\n");
    409                 fsBuilder->codeAppend("\tedgeAlpha *= clamp(1.0+test*invlen, 0.0, 1.0);\n");
    410             } else {
    411                 fsBuilder->codeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);\n");
    412             }
    413 
    414             // for inner curve
    415             if (kStroke == ellipseEffect.getMode()) {
    416                 fsBuilder->codeAppendf("\tscaledOffset = %s.xy;\n", fsOffsetName1);
    417                 fsBuilder->codeAppend("\ttest = dot(scaledOffset, scaledOffset) - 1.0;\n");
    418                 fsBuilder->codeAppendf("\tduvdx = dFdx(%s);\n", fsOffsetName1);
    419                 fsBuilder->codeAppendf("\tduvdy = dFdy(%s);\n", fsOffsetName1);
    420                 fsBuilder->codeAppendf("\tgrad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,\n"
    421                                        "\t            2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);\n",
    422                                        fsOffsetName1, fsOffsetName1, fsOffsetName1, fsOffsetName1);
    423                 fsBuilder->codeAppend("\tinvlen = inversesqrt(dot(grad, grad));\n");
    424                 fsBuilder->codeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);\n");
    425             }
    426 
    427             fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
    428                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
    429         }
    430 
    431         static void GenKey(const GrProcessor& processor, const GrGLCaps&,
    432                            GrProcessorKeyBuilder* b) {
    433             const DIEllipseEdgeEffect& ellipseEffect = processor.cast<DIEllipseEdgeEffect>();
    434 
    435             b->add32(ellipseEffect.getMode());
    436         }
    437 
    438         virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {
    439         }
    440 
    441     private:
    442         typedef GrGLGeometryProcessor INHERITED;
    443     };
    444 
    445 private:
    446     DIEllipseEdgeEffect(Mode mode)
    447         : fInEllipseOffsets0(this->addVertexAttrib(
    448                 GrShaderVar("inEllipseOffsets0",
    449                             kVec2f_GrSLType,
    450                             GrShaderVar::kAttribute_TypeModifier)))
    451         , fInEllipseOffsets1(this->addVertexAttrib(
    452                 GrShaderVar("inEllipseOffsets1",
    453                             kVec2f_GrSLType,
    454                             GrShaderVar::kAttribute_TypeModifier))) {
    455         fMode = mode;
    456     }
    457 
    458     virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE {
    459         const DIEllipseEdgeEffect& eee = other.cast<DIEllipseEdgeEffect>();
    460         return eee.fMode == fMode;
    461     }
    462 
    463     const GrShaderVar& fInEllipseOffsets0;
    464     const GrShaderVar& fInEllipseOffsets1;
    465     Mode fMode;
    466 
    467     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
    468 
    469     typedef GrGeometryProcessor INHERITED;
    470 };
    471 
    472 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseEdgeEffect);
    473 
    474 GrGeometryProcessor* DIEllipseEdgeEffect::TestCreate(SkRandom* random,
    475                                                      GrContext* context,
    476                                                      const GrDrawTargetCaps&,
    477                                                      GrTexture* textures[]) {
    478     return DIEllipseEdgeEffect::Create((Mode)(random->nextRangeU(0,2)));
    479 }
    480 
    481 ///////////////////////////////////////////////////////////////////////////////
    482 
    483 void GrOvalRenderer::reset() {
    484     SkSafeSetNull(fRRectIndexBuffer);
    485 }
    486 
    487 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, bool useAA,
    488                               const SkRect& oval, const SkStrokeRec& stroke)
    489 {
    490     bool useCoverageAA = useAA &&
    491         !target->getDrawState().getRenderTarget()->isMultisampled() &&
    492         !target->shouldDisableCoverageAAForBlend();
    493 
    494     if (!useCoverageAA) {
    495         return false;
    496     }
    497 
    498     const SkMatrix& vm = context->getMatrix();
    499 
    500     // we can draw circles
    501     if (SkScalarNearlyEqual(oval.width(), oval.height())
    502         && circle_stays_circle(vm)) {
    503         this->drawCircle(target, useCoverageAA, oval, stroke);
    504     // if we have shader derivative support, render as device-independent
    505     } else if (target->caps()->shaderDerivativeSupport()) {
    506         return this->drawDIEllipse(target, useCoverageAA, oval, stroke);
    507     // otherwise axis-aligned ellipses only
    508     } else if (vm.rectStaysRect()) {
    509         return this->drawEllipse(target, useCoverageAA, oval, stroke);
    510     } else {
    511         return false;
    512     }
    513 
    514     return true;
    515 }
    516 
    517 ///////////////////////////////////////////////////////////////////////////////
    518 
    519 // position + edge
    520 extern const GrVertexAttrib gCircleVertexAttribs[] = {
    521     {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
    522     {kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding}
    523 };
    524 
    525 void GrOvalRenderer::drawCircle(GrDrawTarget* target,
    526                                 bool useCoverageAA,
    527                                 const SkRect& circle,
    528                                 const SkStrokeRec& stroke)
    529 {
    530     GrDrawState* drawState = target->drawState();
    531 
    532     const SkMatrix& vm = drawState->getViewMatrix();
    533     SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY());
    534     vm.mapPoints(&center, 1);
    535     SkScalar radius = vm.mapRadius(SkScalarHalf(circle.width()));
    536     SkScalar strokeWidth = vm.mapRadius(stroke.getWidth());
    537 
    538     GrDrawState::AutoViewMatrixRestore avmr;
    539     if (!avmr.setIdentity(drawState)) {
    540         return;
    541     }
    542 
    543     drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircleVertexAttribs),
    544                                                       sizeof(CircleVertex));
    545 
    546     GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
    547     if (!geo.succeeded()) {
    548         GrPrintf("Failed to get space for vertices!\n");
    549         return;
    550     }
    551 
    552     CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
    553 
    554     SkStrokeRec::Style style = stroke.getStyle();
    555     bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
    556                         SkStrokeRec::kHairline_Style == style;
    557     bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
    558 
    559     SkScalar innerRadius = 0.0f;
    560     SkScalar outerRadius = radius;
    561     SkScalar halfWidth = 0;
    562     if (hasStroke) {
    563         if (SkScalarNearlyZero(strokeWidth)) {
    564             halfWidth = SK_ScalarHalf;
    565         } else {
    566             halfWidth = SkScalarHalf(strokeWidth);
    567         }
    568 
    569         outerRadius += halfWidth;
    570         if (isStrokeOnly) {
    571             innerRadius = radius - halfWidth;
    572         }
    573     }
    574 
    575     GrGeometryProcessor* gp = CircleEdgeEffect::Create(isStrokeOnly && innerRadius > 0);
    576     drawState->setGeometryProcessor(gp)->unref();
    577 
    578     // The radii are outset for two reasons. First, it allows the shader to simply perform
    579     // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the
    580     // verts of the bounding box that is rendered and the outset ensures the box will cover all
    581     // pixels partially covered by the circle.
    582     outerRadius += SK_ScalarHalf;
    583     innerRadius -= SK_ScalarHalf;
    584 
    585     SkRect bounds = SkRect::MakeLTRB(
    586         center.fX - outerRadius,
    587         center.fY - outerRadius,
    588         center.fX + outerRadius,
    589         center.fY + outerRadius
    590     );
    591 
    592     verts[0].fPos = SkPoint::Make(bounds.fLeft,  bounds.fTop);
    593     verts[0].fOffset = SkPoint::Make(-outerRadius, -outerRadius);
    594     verts[0].fOuterRadius = outerRadius;
    595     verts[0].fInnerRadius = innerRadius;
    596 
    597     verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
    598     verts[1].fOffset = SkPoint::Make(outerRadius, -outerRadius);
    599     verts[1].fOuterRadius = outerRadius;
    600     verts[1].fInnerRadius = innerRadius;
    601 
    602     verts[2].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
    603     verts[2].fOffset = SkPoint::Make(-outerRadius, outerRadius);
    604     verts[2].fOuterRadius = outerRadius;
    605     verts[2].fInnerRadius = innerRadius;
    606 
    607     verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
    608     verts[3].fOffset = SkPoint::Make(outerRadius, outerRadius);
    609     verts[3].fOuterRadius = outerRadius;
    610     verts[3].fInnerRadius = innerRadius;
    611 
    612     target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
    613 }
    614 
    615 ///////////////////////////////////////////////////////////////////////////////
    616 
    617 // position + offset + 1/radii
    618 extern const GrVertexAttrib gEllipseVertexAttribs[] = {
    619     {kVec2f_GrVertexAttribType, 0,                 kPosition_GrVertexAttribBinding},
    620     {kVec2f_GrVertexAttribType, sizeof(SkPoint),   kGeometryProcessor_GrVertexAttribBinding},
    621     {kVec4f_GrVertexAttribType, 2*sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding}
    622 };
    623 
    624 // position + offsets
    625 extern const GrVertexAttrib gDIEllipseVertexAttribs[] = {
    626     {kVec2f_GrVertexAttribType, 0,                 kPosition_GrVertexAttribBinding},
    627     {kVec2f_GrVertexAttribType, sizeof(SkPoint),   kGeometryProcessor_GrVertexAttribBinding},
    628     {kVec2f_GrVertexAttribType, 2*sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding},
    629 };
    630 
    631 bool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
    632                                  bool useCoverageAA,
    633                                  const SkRect& ellipse,
    634                                  const SkStrokeRec& stroke)
    635 {
    636     GrDrawState* drawState = target->drawState();
    637 #ifdef SK_DEBUG
    638     {
    639         // we should have checked for this previously
    640         bool isAxisAlignedEllipse = drawState->getViewMatrix().rectStaysRect();
    641         SkASSERT(useCoverageAA && isAxisAlignedEllipse);
    642     }
    643 #endif
    644 
    645     // do any matrix crunching before we reset the draw state for device coords
    646     const SkMatrix& vm = drawState->getViewMatrix();
    647     SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
    648     vm.mapPoints(&center, 1);
    649     SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
    650     SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
    651     SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*ellipseXRadius +
    652                                    vm[SkMatrix::kMSkewY]*ellipseYRadius);
    653     SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*ellipseXRadius +
    654                                    vm[SkMatrix::kMScaleY]*ellipseYRadius);
    655 
    656     // do (potentially) anisotropic mapping of stroke
    657     SkVector scaledStroke;
    658     SkScalar strokeWidth = stroke.getWidth();
    659     scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMatrix::kMSkewY]));
    660     scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatrix::kMScaleY]));
    661 
    662     SkStrokeRec::Style style = stroke.getStyle();
    663     bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
    664                         SkStrokeRec::kHairline_Style == style;
    665     bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
    666 
    667     SkScalar innerXRadius = 0;
    668     SkScalar innerYRadius = 0;
    669     if (hasStroke) {
    670         if (SkScalarNearlyZero(scaledStroke.length())) {
    671             scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
    672         } else {
    673             scaledStroke.scale(SK_ScalarHalf);
    674         }
    675 
    676         // we only handle thick strokes for near-circular ellipses
    677         if (scaledStroke.length() > SK_ScalarHalf &&
    678             (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
    679             return false;
    680         }
    681 
    682         // we don't handle it if curvature of the stroke is less than curvature of the ellipse
    683         if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
    684             scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
    685             return false;
    686         }
    687 
    688         // this is legit only if scale & translation (which should be the case at the moment)
    689         if (isStrokeOnly) {
    690             innerXRadius = xRadius - scaledStroke.fX;
    691             innerYRadius = yRadius - scaledStroke.fY;
    692         }
    693 
    694         xRadius += scaledStroke.fX;
    695         yRadius += scaledStroke.fY;
    696     }
    697 
    698     GrDrawState::AutoViewMatrixRestore avmr;
    699     if (!avmr.setIdentity(drawState)) {
    700         return false;
    701     }
    702 
    703     drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVertexAttribs),
    704                                                        sizeof(EllipseVertex));
    705 
    706     GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
    707     if (!geo.succeeded()) {
    708         GrPrintf("Failed to get space for vertices!\n");
    709         return false;
    710     }
    711 
    712     EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
    713 
    714     GrGeometryProcessor* gp = EllipseEdgeEffect::Create(isStrokeOnly &&
    715                                                         innerXRadius > 0 && innerYRadius > 0);
    716 
    717     drawState->setGeometryProcessor(gp)->unref();
    718 
    719     // Compute the reciprocals of the radii here to save time in the shader
    720     SkScalar xRadRecip = SkScalarInvert(xRadius);
    721     SkScalar yRadRecip = SkScalarInvert(yRadius);
    722     SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius);
    723     SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius);
    724 
    725     // We've extended the outer x radius out half a pixel to antialias.
    726     // This will also expand the rect so all the pixels will be captured.
    727     // TODO: Consider if we should use sqrt(2)/2 instead
    728     xRadius += SK_ScalarHalf;
    729     yRadius += SK_ScalarHalf;
    730 
    731     SkRect bounds = SkRect::MakeLTRB(
    732         center.fX - xRadius,
    733         center.fY - yRadius,
    734         center.fX + xRadius,
    735         center.fY + yRadius
    736     );
    737 
    738     verts[0].fPos = SkPoint::Make(bounds.fLeft,  bounds.fTop);
    739     verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius);
    740     verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
    741     verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
    742 
    743     verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
    744     verts[1].fOffset = SkPoint::Make(xRadius, -yRadius);
    745     verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
    746     verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
    747 
    748     verts[2].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
    749     verts[2].fOffset = SkPoint::Make(-xRadius, yRadius);
    750     verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
    751     verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
    752 
    753     verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
    754     verts[3].fOffset = SkPoint::Make(xRadius, yRadius);
    755     verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
    756     verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
    757 
    758     target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
    759 
    760     return true;
    761 }
    762 
    763 bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target,
    764                                    bool useCoverageAA,
    765                                    const SkRect& ellipse,
    766                                    const SkStrokeRec& stroke)
    767 {
    768     GrDrawState* drawState = target->drawState();
    769     const SkMatrix& vm = drawState->getViewMatrix();
    770 
    771     SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
    772     SkScalar xRadius = SkScalarHalf(ellipse.width());
    773     SkScalar yRadius = SkScalarHalf(ellipse.height());
    774 
    775     SkStrokeRec::Style style = stroke.getStyle();
    776     DIEllipseEdgeEffect::Mode mode = (SkStrokeRec::kStroke_Style == style) ?
    777                                     DIEllipseEdgeEffect::kStroke :
    778                                     (SkStrokeRec::kHairline_Style == style) ?
    779                                     DIEllipseEdgeEffect::kHairline : DIEllipseEdgeEffect::kFill;
    780 
    781     SkScalar innerXRadius = 0;
    782     SkScalar innerYRadius = 0;
    783     if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
    784         SkScalar strokeWidth = stroke.getWidth();
    785 
    786         if (SkScalarNearlyZero(strokeWidth)) {
    787             strokeWidth = SK_ScalarHalf;
    788         } else {
    789             strokeWidth *= SK_ScalarHalf;
    790         }
    791 
    792         // we only handle thick strokes for near-circular ellipses
    793         if (strokeWidth > SK_ScalarHalf &&
    794             (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
    795             return false;
    796         }
    797 
    798         // we don't handle it if curvature of the stroke is less than curvature of the ellipse
    799         if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius ||
    800             strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) {
    801             return false;
    802         }
    803 
    804         // set inner radius (if needed)
    805         if (SkStrokeRec::kStroke_Style == style) {
    806             innerXRadius = xRadius - strokeWidth;
    807             innerYRadius = yRadius - strokeWidth;
    808         }
    809 
    810         xRadius += strokeWidth;
    811         yRadius += strokeWidth;
    812     }
    813     if (DIEllipseEdgeEffect::kStroke == mode) {
    814         mode = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseEdgeEffect::kStroke :
    815                                                         DIEllipseEdgeEffect::kFill;
    816     }
    817     SkScalar innerRatioX = SkScalarDiv(xRadius, innerXRadius);
    818     SkScalar innerRatioY = SkScalarDiv(yRadius, innerYRadius);
    819 
    820     drawState->setVertexAttribs<gDIEllipseVertexAttribs>(SK_ARRAY_COUNT(gDIEllipseVertexAttribs),
    821                                                          sizeof(DIEllipseVertex));
    822 
    823     GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
    824     if (!geo.succeeded()) {
    825         GrPrintf("Failed to get space for vertices!\n");
    826         return false;
    827     }
    828 
    829     DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(geo.vertices());
    830 
    831     GrGeometryProcessor* gp = DIEllipseEdgeEffect::Create(mode);
    832 
    833     drawState->setGeometryProcessor(gp)->unref();
    834 
    835     // This expands the outer rect so that after CTM we end up with a half-pixel border
    836     SkScalar a = vm[SkMatrix::kMScaleX];
    837     SkScalar b = vm[SkMatrix::kMSkewX];
    838     SkScalar c = vm[SkMatrix::kMSkewY];
    839     SkScalar d = vm[SkMatrix::kMScaleY];
    840     SkScalar geoDx = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(a*a + c*c));
    841     SkScalar geoDy = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(b*b + d*d));
    842     // This adjusts the "radius" to include the half-pixel border
    843     SkScalar offsetDx = SkScalarDiv(geoDx, xRadius);
    844     SkScalar offsetDy = SkScalarDiv(geoDy, yRadius);
    845 
    846     SkRect bounds = SkRect::MakeLTRB(
    847         center.fX - xRadius - geoDx,
    848         center.fY - yRadius - geoDy,
    849         center.fX + xRadius + geoDx,
    850         center.fY + yRadius + geoDy
    851     );
    852 
    853     verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
    854     verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy);
    855     verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy);
    856 
    857     verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
    858     verts[1].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy);
    859     verts[1].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
    860 
    861     verts[2].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
    862     verts[2].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy);
    863     verts[2].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy);
    864 
    865     verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
    866     verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy);
    867     verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy);
    868 
    869     target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
    870 
    871     return true;
    872 }
    873 
    874 ///////////////////////////////////////////////////////////////////////////////
    875 
    876 static const uint16_t gRRectIndices[] = {
    877     // corners
    878     0, 1, 5, 0, 5, 4,
    879     2, 3, 7, 2, 7, 6,
    880     8, 9, 13, 8, 13, 12,
    881     10, 11, 15, 10, 15, 14,
    882 
    883     // edges
    884     1, 2, 6, 1, 6, 5,
    885     4, 5, 9, 4, 9, 8,
    886     6, 7, 11, 6, 11, 10,
    887     9, 10, 14, 9, 14, 13,
    888 
    889     // center
    890     // we place this at the end so that we can ignore these indices when rendering stroke-only
    891     5, 6, 10, 5, 10, 9
    892 };
    893 
    894 
    895 GrIndexBuffer* GrOvalRenderer::rRectIndexBuffer(GrGpu* gpu) {
    896     if (NULL == fRRectIndexBuffer) {
    897         fRRectIndexBuffer =
    898         gpu->createIndexBuffer(sizeof(gRRectIndices), false);
    899         if (fRRectIndexBuffer) {
    900 #ifdef SK_DEBUG
    901             bool updated =
    902 #endif
    903             fRRectIndexBuffer->updateData(gRRectIndices,
    904                                           sizeof(gRRectIndices));
    905             GR_DEBUGASSERT(updated);
    906         }
    907     }
    908     return fRRectIndexBuffer;
    909 }
    910 
    911 bool GrOvalRenderer::drawDRRect(GrDrawTarget* target, GrContext* context, bool useAA,
    912                                 const SkRRect& origOuter, const SkRRect& origInner) {
    913     bool applyAA = useAA &&
    914                    !target->getDrawState().getRenderTarget()->isMultisampled() &&
    915                    !target->shouldDisableCoverageAAForBlend();
    916     GrDrawState::AutoRestoreEffects are;
    917     if (!origInner.isEmpty()) {
    918         SkTCopyOnFirstWrite<SkRRect> inner(origInner);
    919         if (!context->getMatrix().isIdentity()) {
    920             if (!origInner.transform(context->getMatrix(), inner.writable())) {
    921                 return false;
    922             }
    923         }
    924         GrPrimitiveEdgeType edgeType = applyAA ?
    925                 kInverseFillAA_GrProcessorEdgeType :
    926                 kInverseFillBW_GrProcessorEdgeType;
    927         GrFragmentProcessor* fp = GrRRectEffect::Create(edgeType, *inner);
    928         if (NULL == fp) {
    929             return false;
    930         }
    931         are.set(target->drawState());
    932         target->drawState()->addCoverageProcessor(fp)->unref();
    933     }
    934 
    935     SkStrokeRec fillRec(SkStrokeRec::kFill_InitStyle);
    936     if (this->drawRRect(target, context, useAA, origOuter, fillRec)) {
    937         return true;
    938     }
    939 
    940     SkASSERT(!origOuter.isEmpty());
    941     SkTCopyOnFirstWrite<SkRRect> outer(origOuter);
    942     if (!context->getMatrix().isIdentity()) {
    943         if (!origOuter.transform(context->getMatrix(), outer.writable())) {
    944             return false;
    945         }
    946     }
    947     GrPrimitiveEdgeType edgeType = applyAA ? kFillAA_GrProcessorEdgeType :
    948                                           kFillBW_GrProcessorEdgeType;
    949     GrFragmentProcessor* effect = GrRRectEffect::Create(edgeType, *outer);
    950     if (NULL == effect) {
    951         return false;
    952     }
    953     if (!are.isSet()) {
    954         are.set(target->drawState());
    955     }
    956     GrDrawState::AutoViewMatrixRestore avmr;
    957     if (!avmr.setIdentity(target->drawState())) {
    958         return false;
    959     }
    960     target->drawState()->addCoverageProcessor(effect)->unref();
    961     SkRect bounds = outer->getBounds();
    962     if (applyAA) {
    963         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
    964     }
    965     target->drawRect(bounds, NULL, NULL);
    966     return true;
    967 }
    968 
    969 bool GrOvalRenderer::drawRRect(GrDrawTarget* target, GrContext* context, bool useAA,
    970                                const SkRRect& rrect, const SkStrokeRec& stroke) {
    971     if (rrect.isOval()) {
    972         return this->drawOval(target, context, useAA, rrect.getBounds(), stroke);
    973     }
    974 
    975     bool useCoverageAA = useAA &&
    976         !target->getDrawState().getRenderTarget()->isMultisampled() &&
    977         !target->shouldDisableCoverageAAForBlend();
    978 
    979     // only anti-aliased rrects for now
    980     if (!useCoverageAA) {
    981         return false;
    982     }
    983 
    984     const SkMatrix& vm = context->getMatrix();
    985 
    986     if (!vm.rectStaysRect() || !rrect.isSimple()) {
    987         return false;
    988     }
    989 
    990     // do any matrix crunching before we reset the draw state for device coords
    991     const SkRect& rrectBounds = rrect.getBounds();
    992     SkRect bounds;
    993     vm.mapRect(&bounds, rrectBounds);
    994 
    995     SkVector radii = rrect.getSimpleRadii();
    996     SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX +
    997                                    vm[SkMatrix::kMSkewY]*radii.fY);
    998     SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX +
    999                                    vm[SkMatrix::kMScaleY]*radii.fY);
   1000 
   1001     SkStrokeRec::Style style = stroke.getStyle();
   1002 
   1003     // do (potentially) anisotropic mapping of stroke
   1004     SkVector scaledStroke;
   1005     SkScalar strokeWidth = stroke.getWidth();
   1006 
   1007     bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
   1008                         SkStrokeRec::kHairline_Style == style;
   1009     bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
   1010 
   1011     if (hasStroke) {
   1012         if (SkStrokeRec::kHairline_Style == style) {
   1013             scaledStroke.set(1, 1);
   1014         } else {
   1015             scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] +
   1016                                                        vm[SkMatrix::kMSkewY]));
   1017             scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] +
   1018                                                        vm[SkMatrix::kMScaleY]));
   1019         }
   1020 
   1021         // if half of strokewidth is greater than radius, we don't handle that right now
   1022         if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStroke.fY > yRadius) {
   1023             return false;
   1024         }
   1025     }
   1026 
   1027     // The way the effect interpolates the offset-to-ellipse/circle-center attribute only works on
   1028     // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner rect of the nine-
   1029     // patch will have fractional coverage. This only matters when the interior is actually filled.
   1030     // We could consider falling back to rect rendering here, since a tiny radius is
   1031     // indistinguishable from a square corner.
   1032     if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
   1033         return false;
   1034     }
   1035 
   1036     // reset to device coordinates
   1037     GrDrawState* drawState = target->drawState();
   1038     GrDrawState::AutoViewMatrixRestore avmr;
   1039     if (!avmr.setIdentity(drawState)) {
   1040         return false;
   1041     }
   1042 
   1043     GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(context->getGpu());
   1044     if (NULL == indexBuffer) {
   1045         GrPrintf("Failed to create index buffer!\n");
   1046         return false;
   1047     }
   1048 
   1049     // if the corners are circles, use the circle renderer
   1050     if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) {
   1051         drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircleVertexAttribs),
   1052                                                           sizeof(CircleVertex));
   1053 
   1054         GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
   1055         if (!geo.succeeded()) {
   1056             GrPrintf("Failed to get space for vertices!\n");
   1057             return false;
   1058         }
   1059         CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
   1060 
   1061         SkScalar innerRadius = 0.0f;
   1062         SkScalar outerRadius = xRadius;
   1063         SkScalar halfWidth = 0;
   1064         if (hasStroke) {
   1065             if (SkScalarNearlyZero(scaledStroke.fX)) {
   1066                 halfWidth = SK_ScalarHalf;
   1067             } else {
   1068                 halfWidth = SkScalarHalf(scaledStroke.fX);
   1069             }
   1070 
   1071             if (isStrokeOnly) {
   1072                 innerRadius = xRadius - halfWidth;
   1073             }
   1074             outerRadius += halfWidth;
   1075             bounds.outset(halfWidth, halfWidth);
   1076         }
   1077 
   1078         isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
   1079 
   1080         GrGeometryProcessor* effect = CircleEdgeEffect::Create(isStrokeOnly);
   1081         drawState->setGeometryProcessor(effect)->unref();
   1082 
   1083         // The radii are outset for two reasons. First, it allows the shader to simply perform
   1084         // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the
   1085         // verts of the bounding box that is rendered and the outset ensures the box will cover all
   1086         // pixels partially covered by the circle.
   1087         outerRadius += SK_ScalarHalf;
   1088         innerRadius -= SK_ScalarHalf;
   1089 
   1090         // Expand the rect so all the pixels will be captured.
   1091         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
   1092 
   1093         SkScalar yCoords[4] = {
   1094             bounds.fTop,
   1095             bounds.fTop + outerRadius,
   1096             bounds.fBottom - outerRadius,
   1097             bounds.fBottom
   1098         };
   1099         SkScalar yOuterRadii[4] = {
   1100             -outerRadius,
   1101             0,
   1102             0,
   1103             outerRadius
   1104         };
   1105         for (int i = 0; i < 4; ++i) {
   1106             verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
   1107             verts->fOffset = SkPoint::Make(-outerRadius, yOuterRadii[i]);
   1108             verts->fOuterRadius = outerRadius;
   1109             verts->fInnerRadius = innerRadius;
   1110             verts++;
   1111 
   1112             verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
   1113             verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
   1114             verts->fOuterRadius = outerRadius;
   1115             verts->fInnerRadius = innerRadius;
   1116             verts++;
   1117 
   1118             verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
   1119             verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
   1120             verts->fOuterRadius = outerRadius;
   1121             verts->fInnerRadius = innerRadius;
   1122             verts++;
   1123 
   1124             verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
   1125             verts->fOffset = SkPoint::Make(outerRadius, yOuterRadii[i]);
   1126             verts->fOuterRadius = outerRadius;
   1127             verts->fInnerRadius = innerRadius;
   1128             verts++;
   1129         }
   1130 
   1131         // drop out the middle quad if we're stroked
   1132         int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
   1133                                       SK_ARRAY_COUNT(gRRectIndices);
   1134         target->setIndexSourceToBuffer(indexBuffer);
   1135         target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bounds);
   1136 
   1137     // otherwise we use the ellipse renderer
   1138     } else {
   1139         drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVertexAttribs),
   1140                                                            sizeof(EllipseVertex));
   1141 
   1142         SkScalar innerXRadius = 0.0f;
   1143         SkScalar innerYRadius = 0.0f;
   1144         if (hasStroke) {
   1145             if (SkScalarNearlyZero(scaledStroke.length())) {
   1146                 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
   1147             } else {
   1148                 scaledStroke.scale(SK_ScalarHalf);
   1149             }
   1150 
   1151             // we only handle thick strokes for near-circular ellipses
   1152             if (scaledStroke.length() > SK_ScalarHalf &&
   1153                 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
   1154                 return false;
   1155             }
   1156 
   1157             // we don't handle it if curvature of the stroke is less than curvature of the ellipse
   1158             if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
   1159                 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
   1160                 return false;
   1161             }
   1162 
   1163             // this is legit only if scale & translation (which should be the case at the moment)
   1164             if (isStrokeOnly) {
   1165                 innerXRadius = xRadius - scaledStroke.fX;
   1166                 innerYRadius = yRadius - scaledStroke.fY;
   1167             }
   1168 
   1169             xRadius += scaledStroke.fX;
   1170             yRadius += scaledStroke.fY;
   1171             bounds.outset(scaledStroke.fX, scaledStroke.fY);
   1172         }
   1173 
   1174         isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
   1175 
   1176         GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
   1177         if (!geo.succeeded()) {
   1178             GrPrintf("Failed to get space for vertices!\n");
   1179             return false;
   1180         }
   1181         EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
   1182 
   1183         GrGeometryProcessor* effect = EllipseEdgeEffect::Create(isStrokeOnly);
   1184         drawState->setGeometryProcessor(effect)->unref();
   1185 
   1186         // Compute the reciprocals of the radii here to save time in the shader
   1187         SkScalar xRadRecip = SkScalarInvert(xRadius);
   1188         SkScalar yRadRecip = SkScalarInvert(yRadius);
   1189         SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius);
   1190         SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius);
   1191 
   1192         // Extend the radii out half a pixel to antialias.
   1193         SkScalar xOuterRadius = xRadius + SK_ScalarHalf;
   1194         SkScalar yOuterRadius = yRadius + SK_ScalarHalf;
   1195 
   1196         // Expand the rect so all the pixels will be captured.
   1197         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
   1198 
   1199         SkScalar yCoords[4] = {
   1200             bounds.fTop,
   1201             bounds.fTop + yOuterRadius,
   1202             bounds.fBottom - yOuterRadius,
   1203             bounds.fBottom
   1204         };
   1205         SkScalar yOuterOffsets[4] = {
   1206             yOuterRadius,
   1207             SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so can't be exactly 0
   1208             SK_ScalarNearlyZero,
   1209             yOuterRadius
   1210         };
   1211 
   1212         for (int i = 0; i < 4; ++i) {
   1213             verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
   1214             verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
   1215             verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
   1216             verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
   1217             verts++;
   1218 
   1219             verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]);
   1220             verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
   1221             verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
   1222             verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
   1223             verts++;
   1224 
   1225             verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]);
   1226             verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
   1227             verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
   1228             verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
   1229             verts++;
   1230 
   1231             verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
   1232             verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
   1233             verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
   1234             verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
   1235             verts++;
   1236         }
   1237 
   1238         // drop out the middle quad if we're stroked
   1239         int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
   1240                                       SK_ARRAY_COUNT(gRRectIndices);
   1241         target->setIndexSourceToBuffer(indexBuffer);
   1242         target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bounds);
   1243     }
   1244 
   1245     return true;
   1246 }
   1247