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