gfx/skia/trunk/src/gpu/GrOvalRenderer.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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  */
     8 #include "GrOvalRenderer.h"
    10 #include "GrEffect.h"
    11 #include "gl/GrGLEffect.h"
    12 #include "gl/GrGLSL.h"
    13 #include "gl/GrGLVertexEffect.h"
    14 #include "GrTBackendEffectFactory.h"
    16 #include "GrDrawState.h"
    17 #include "GrDrawTarget.h"
    18 #include "GrGpu.h"
    20 #include "SkRRect.h"
    21 #include "SkStrokeRec.h"
    23 #include "effects/GrVertexEffect.h"
    25 namespace {
    27 struct CircleVertex {
    28     GrPoint  fPos;
    29     GrPoint  fOffset;
    30     SkScalar fOuterRadius;
    31     SkScalar fInnerRadius;
    32 };
    34 struct EllipseVertex {
    35     GrPoint  fPos;
    36     GrPoint  fOffset;
    37     GrPoint  fOuterRadii;
    38     GrPoint  fInnerRadii;
    39 };
    41 struct DIEllipseVertex {
    42     GrPoint  fPos;
    43     GrPoint  fOuterOffset;
    44     GrPoint  fInnerOffset;
    45 };
    47 inline bool circle_stays_circle(const SkMatrix& m) {
    48     return m.isSimilarity();
    49 }
    51 }
    53 ///////////////////////////////////////////////////////////////////////////////
    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  */
    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));
    66         if (stroke) {
    67             gCircleStrokeEdge->ref();
    68             return gCircleStrokeEdge;
    69         } else {
    70             gCircleFillEdge->ref();
    71             return gCircleFillEdge;
    72         }
    73     }
    75     virtual void getConstantColorComponents(GrColor* color,
    76                                             uint32_t* validFlags) const SK_OVERRIDE {
    77         *validFlags = 0;
    78     }
    80     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
    81         return GrTBackendEffectFactory<CircleEdgeEffect>::getInstance();
    82     }
    84     virtual ~CircleEdgeEffect() {}
    86     static const char* Name() { return "CircleEdge"; }
    88     inline bool isStroked() const { return fStroke; }
    90     class GLEffect : public GrGLVertexEffect {
    91     public:
    92         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
    93         : INHERITED (factory) {}
    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);
   106             const SkString* attrName =
   107                 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
   108             builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
   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             }
   117             builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
   118                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
   119         }
   121         static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
   122             const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleEdgeEffect>();
   124             return circleEffect.isStroked() ? 0x1 : 0x0;
   125         }
   127         virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
   129     private:
   130         typedef GrGLVertexEffect INHERITED;
   131     };
   134 private:
   135     CircleEdgeEffect(bool stroke) : GrVertexEffect() {
   136         this->addVertexAttrib(kVec4f_GrSLType);
   137         fStroke = stroke;
   138     }
   140     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
   141         const CircleEdgeEffect& cee = CastEffect<CircleEdgeEffect>(other);
   142         return cee.fStroke == fStroke;
   143     }
   145     bool fStroke;
   147     GR_DECLARE_EFFECT_TEST;
   149     typedef GrVertexEffect INHERITED;
   150 };
   152 GR_DEFINE_EFFECT_TEST(CircleEdgeEffect);
   154 GrEffectRef* CircleEdgeEffect::TestCreate(SkRandom* random,
   155                                           GrContext* context,
   156                                           const GrDrawTargetCaps&,
   157                                           GrTexture* textures[]) {
   158     return CircleEdgeEffect::Create(random->nextBool());
   159 }
   161 ///////////////////////////////////////////////////////////////////////////////
   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  */
   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));
   177         if (stroke) {
   178             gEllipseStrokeEdge->ref();
   179             return gEllipseStrokeEdge;
   180         } else {
   181             gEllipseFillEdge->ref();
   182             return gEllipseFillEdge;
   183         }
   184     }
   186     virtual void getConstantColorComponents(GrColor* color,
   187                                             uint32_t* validFlags) const SK_OVERRIDE {
   188         *validFlags = 0;
   189     }
   191     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
   192         return GrTBackendEffectFactory<EllipseEdgeEffect>::getInstance();
   193     }
   195     virtual ~EllipseEdgeEffect() {}
   197     static const char* Name() { return "EllipseEdge"; }
   199     inline bool isStroked() const { return fStroke; }
   201     class GLEffect : public GrGLVertexEffect {
   202     public:
   203         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
   204         : INHERITED (factory) {}
   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>();
   215             const char *vsOffsetName, *fsOffsetName;
   216             const char *vsRadiiName, *fsRadiiName;
   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());
   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());
   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");
   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             }
   249             builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
   250                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
   251         }
   253         static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
   254             const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<EllipseEdgeEffect>();
   256             return ellipseEffect.isStroked() ? 0x1 : 0x0;
   257         }
   259         virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {
   260         }
   262     private:
   263         typedef GrGLVertexEffect INHERITED;
   264     };
   266 private:
   267     EllipseEdgeEffect(bool stroke) : GrVertexEffect() {
   268         this->addVertexAttrib(kVec2f_GrSLType);
   269         this->addVertexAttrib(kVec4f_GrSLType);
   270         fStroke = stroke;
   271     }
   273     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
   274         const EllipseEdgeEffect& eee = CastEffect<EllipseEdgeEffect>(other);
   275         return eee.fStroke == fStroke;
   276     }
   278     bool fStroke;
   280     GR_DECLARE_EFFECT_TEST;
   282     typedef GrVertexEffect INHERITED;
   283 };
   285 GR_DEFINE_EFFECT_TEST(EllipseEdgeEffect);
   287 GrEffectRef* EllipseEdgeEffect::TestCreate(SkRandom* random,
   288                                            GrContext* context,
   289                                            const GrDrawTargetCaps&,
   290                                            GrTexture* textures[]) {
   291     return EllipseEdgeEffect::Create(random->nextBool());
   292 }
   294 ///////////////////////////////////////////////////////////////////////////////
   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  */
   305 class DIEllipseEdgeEffect : public GrVertexEffect {
   306 public:
   307     enum Mode { kStroke = 0, kHairline, kFill };
   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));
   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     }
   326     virtual void getConstantColorComponents(GrColor* color,
   327                                             uint32_t* validFlags) const SK_OVERRIDE {
   328         *validFlags = 0;
   329     }
   331     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
   332         return GrTBackendEffectFactory<DIEllipseEdgeEffect>::getInstance();
   333     }
   335     virtual ~DIEllipseEdgeEffect() {}
   337     static const char* Name() { return "DIEllipseEdge"; }
   339     inline Mode getMode() const { return fMode; }
   341     class GLEffect : public GrGLVertexEffect {
   342     public:
   343         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
   344         : INHERITED (factory) {}
   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>();
   355             SkAssertResult(builder->enableFeature(
   356                                               GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
   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());
   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);
   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             }
   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             }
   407             builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
   408                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
   409         }
   411         static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
   412             const DIEllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<DIEllipseEdgeEffect>();
   414             return ellipseEffect.getMode();
   415         }
   417         virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {
   418         }
   420     private:
   421         typedef GrGLVertexEffect INHERITED;
   422     };
   424 private:
   425     DIEllipseEdgeEffect(Mode mode) : GrVertexEffect() {
   426         this->addVertexAttrib(kVec2f_GrSLType);
   427         this->addVertexAttrib(kVec2f_GrSLType);
   428         fMode = mode;
   429     }
   431     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
   432         const DIEllipseEdgeEffect& eee = CastEffect<DIEllipseEdgeEffect>(other);
   433         return eee.fMode == fMode;
   434     }
   436     Mode fMode;
   438     GR_DECLARE_EFFECT_TEST;
   440     typedef GrVertexEffect INHERITED;
   441 };
   443 GR_DEFINE_EFFECT_TEST(DIEllipseEdgeEffect);
   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 }
   452 ///////////////////////////////////////////////////////////////////////////////
   454 void GrOvalRenderer::reset() {
   455     SkSafeSetNull(fRRectIndexBuffer);
   456 }
   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();
   465     if (!useCoverageAA) {
   466         return false;
   467     }
   469     const SkMatrix& vm = context->getMatrix();
   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     }
   485     return true;
   486 }
   488 ///////////////////////////////////////////////////////////////////////////////
   490 // position + edge
   491 extern const GrVertexAttrib gCircleVertexAttribs[] = {
   492     {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
   493     {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
   494 };
   496 void GrOvalRenderer::drawCircle(GrDrawTarget* target,
   497                                 bool useCoverageAA,
   498                                 const SkRect& circle,
   499                                 const SkStrokeRec& stroke)
   500 {
   501     GrDrawState* drawState = target->drawState();
   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());
   509     GrDrawState::AutoViewMatrixRestore avmr;
   510     if (!avmr.setIdentity(drawState)) {
   511         return;
   512     }
   514     drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircleVertexAttribs));
   515     SkASSERT(sizeof(CircleVertex) == drawState->getVertexSize());
   517     GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
   518     if (!geo.succeeded()) {
   519         GrPrintf("Failed to get space for vertices!\n");
   520         return;
   521     }
   523     CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
   525     SkStrokeRec::Style style = stroke.getStyle();
   526     bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
   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         }
   538         outerRadius += halfWidth;
   539         if (isStroked) {
   540             innerRadius = radius - halfWidth;
   541         }
   542     }
   544     GrEffectRef* effect = CircleEdgeEffect::Create(isStroked && innerRadius > 0);
   545     static const int kCircleEdgeAttrIndex = 1;
   546     drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref();
   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;
   555     SkRect bounds = SkRect::MakeLTRB(
   556         center.fX - outerRadius,
   557         center.fY - outerRadius,
   558         center.fX + outerRadius,
   559         center.fY + outerRadius
   560     );
   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;
   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;
   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;
   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;
   582     target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
   583 }
   585 ///////////////////////////////////////////////////////////////////////////////
   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 };
   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 };
   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
   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);
   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]));
   632     SkStrokeRec::Style style = stroke.getStyle();
   633     bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
   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         }
   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         }
   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         }
   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         }
   662         xRadius += scaledStroke.fX;
   663         yRadius += scaledStroke.fY;
   664     }
   666     GrDrawState::AutoViewMatrixRestore avmr;
   667     if (!avmr.setIdentity(drawState)) {
   668         return false;
   669     }
   671     drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVertexAttribs));
   672     SkASSERT(sizeof(EllipseVertex) == drawState->getVertexSize());
   674     GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
   675     if (!geo.succeeded()) {
   676         GrPrintf("Failed to get space for vertices!\n");
   677         return false;
   678     }
   680     EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
   682     GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked &&
   683                                                     innerXRadius > 0 && innerYRadius > 0);
   685     static const int kEllipseCenterAttrIndex = 1;
   686     static const int kEllipseEdgeAttrIndex = 2;
   687     drawState->addCoverageEffect(effect, kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref();
   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);
   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;
   701     SkRect bounds = SkRect::MakeLTRB(
   702         center.fX - xRadius,
   703         center.fY - yRadius,
   704         center.fX + xRadius,
   705         center.fY + yRadius
   706     );
   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);
   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);
   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);
   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);
   728     target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
   730     return true;
   731 }
   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();
   741     GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY());
   742     SkScalar xRadius = SkScalarHalf(ellipse.width());
   743     SkScalar yRadius = SkScalarHalf(ellipse.height());
   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;
   751     SkScalar innerXRadius = 0;
   752     SkScalar innerYRadius = 0;
   753     if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
   754         SkScalar strokeWidth = stroke.getWidth();
   756         if (SkScalarNearlyZero(strokeWidth)) {
   757             strokeWidth = SK_ScalarHalf;
   758         } else {
   759             strokeWidth *= SK_ScalarHalf;
   760         }
   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         }
   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         }
   774         // set inner radius (if needed)
   775         if (SkStrokeRec::kStroke_Style == style) {
   776             innerXRadius = xRadius - strokeWidth;
   777             innerYRadius = yRadius - strokeWidth;
   778         }
   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);
   790     drawState->setVertexAttribs<gDIEllipseVertexAttribs>(SK_ARRAY_COUNT(gDIEllipseVertexAttribs));
   791     SkASSERT(sizeof(DIEllipseVertex) == drawState->getVertexSize());
   793     GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
   794     if (!geo.succeeded()) {
   795         GrPrintf("Failed to get space for vertices!\n");
   796         return false;
   797     }
   799     DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(geo.vertices());
   801     GrEffectRef* effect = DIEllipseEdgeEffect::Create(mode);
   803     static const int kEllipseOuterOffsetAttrIndex = 1;
   804     static const int kEllipseInnerOffsetAttrIndex = 2;
   805     drawState->addCoverageEffect(effect, kEllipseOuterOffsetAttrIndex,
   806                                          kEllipseInnerOffsetAttrIndex)->unref();
   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);
   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     );
   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);
   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);
   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);
   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);
   842     target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
   844     return true;
   845 }
   847 ///////////////////////////////////////////////////////////////////////////////
   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,
   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,
   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 };
   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 }
   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();
   891     // only anti-aliased rrects for now
   892     if (!useCoverageAA) {
   893         return false;
   894     }
   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
   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);
   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);
   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     }
   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]));
   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     }
   933     // reset to device coordinates
   934     GrDrawState* drawState = target->drawState();
   935     GrDrawState::AutoViewMatrixRestore avmr;
   936     if (!avmr.setIdentity(drawState)) {
   937         return false;
   938     }
   940     bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
   942     GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(context->getGpu());
   943     if (NULL == indexBuffer) {
   944         GrPrintf("Failed to create index buffer!\n");
   945         return false;
   946     }
   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());
   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());
   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             }
   970             if (isStroked) {
   971                 innerRadius = xRadius - halfWidth;
   972             }
   973             outerRadius += halfWidth;
   974             bounds.outset(halfWidth, halfWidth);
   975         }
   977         isStroked = (isStroked && innerRadius >= 0);
   979         GrEffectRef* effect = CircleEdgeEffect::Create(isStroked);
   980         static const int kCircleEdgeAttrIndex = 1;
   981         drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref();
   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;
   990         // Expand the rect so all the pixels will be captured.
   991         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
   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++;
  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++;
  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++;
  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++;
  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);
  1036     // otherwise we use the ellipse renderer
  1037     } else {
  1038         drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVertexAttribs));
  1039         SkASSERT(sizeof(EllipseVertex) == drawState->getVertexSize());
  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);
  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;
  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;
  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;
  1068             xRadius += scaledStroke.fX;
  1069             yRadius += scaledStroke.fY;
  1070             bounds.outset(scaledStroke.fX, scaledStroke.fY);
  1073         isStroked = (isStroked && innerXRadius >= 0 && innerYRadius >= 0);
  1075         GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
  1076         if (!geo.succeeded()) {
  1077             GrPrintf("Failed to get space for vertices!\n");
  1078             return false;
  1080         EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
  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();
  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);
  1094         // Extend the radii out half a pixel to antialias.
  1095         SkScalar xOuterRadius = xRadius + SK_ScalarHalf;
  1096         SkScalar yOuterRadius = yRadius + SK_ScalarHalf;
  1098         // Expand the rect so all the pixels will be captured.
  1099         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
  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         };
  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++;
  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++;
  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++;
  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++;
  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);
  1146     return true;

mercurial