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