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