GrOvalRenderer.cpp revision 66beaf0a7386a1281dc63632a740d20a725358f9
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
25namespace {
26
27struct CircleVertex {
28    GrPoint  fPos;
29    GrPoint  fOffset;
30    SkScalar fOuterRadius;
31    SkScalar fInnerRadius;
32};
33
34struct EllipseVertex {
35    GrPoint  fPos;
36    GrPoint  fOffset;
37    GrPoint  fOuterRadii;
38    GrPoint  fInnerRadii;
39};
40
41struct DIEllipseVertex {
42    GrPoint  fPos;
43    GrPoint  fOuterOffset;
44    GrPoint  fInnerOffset;
45};
46
47inline 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
60class CircleEdgeEffect : public GrVertexEffect {
61public:
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
134private:
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
152GR_DEFINE_EFFECT_TEST(CircleEdgeEffect);
153
154GrEffectRef* 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
171class EllipseEdgeEffect : public GrVertexEffect {
172public:
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
266private:
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
285GR_DEFINE_EFFECT_TEST(EllipseEdgeEffect);
286
287GrEffectRef* 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
305class DIEllipseEdgeEffect : public GrVertexEffect {
306public:
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
424private:
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
443GR_DEFINE_EFFECT_TEST(DIEllipseEdgeEffect);
444
445GrEffectRef* 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
454void GrOvalRenderer::reset() {
455    SkSafeSetNull(fRRectIndexBuffer);
456}
457
458bool 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
491extern const GrVertexAttrib gCircleVertexAttribs[] = {
492    {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
493    {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
494};
495
496void 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
588extern 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
595extern 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
601bool 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
733bool 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
849static 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
868GrIndexBuffer* 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
884bool 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