1e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger/*
2e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger * Copyright 2013 Google Inc.
3e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger *
4e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger * Use of this source code is governed by a BSD-style license that can be
5e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger * found in the LICENSE file.
6e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger */
7e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
8e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger#include "GrOvalRenderer.h"
9e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
107839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#include "GrEffect.h"
117839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#include "gl/GrGLEffect.h"
127839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#include "gl/GrGLSL.h"
137839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#include "GrTBackendEffectFactory.h"
14e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
15e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger#include "GrDrawState.h"
16e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger#include "GrDrawTarget.h"
177839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#include "GrGpu.h"
187839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
197839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#include "SkRRect.h"
20e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger#include "SkStrokeRec.h"
21e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
22e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek SollenbergerSK_DEFINE_INST_COUNT(GrOvalRenderer)
23e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
24e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenbergernamespace {
25e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
26e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenbergerstruct CircleVertex {
277839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    GrPoint  fPos;
287839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    GrPoint  fOffset;
29e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    SkScalar fOuterRadius;
30e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    SkScalar fInnerRadius;
31e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger};
32e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
33e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenbergerstruct EllipseVertex {
347839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    GrPoint  fPos;
357839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    GrPoint  fOffset;
367839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    GrPoint  fOuterRadii;
377839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    GrPoint  fInnerRadii;
38e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger};
39e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
40e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenbergerinline bool circle_stays_circle(const SkMatrix& m) {
41e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    return m.isSimilarity();
42e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger}
43e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
44e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger}
45e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
467839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
477839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
487839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger/**
497839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger * The output of this effect is a modulation of the input color and coverage for a circle,
507839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger * specified as offset_x, offset_y (both from center point), outer radius and inner radius.
517839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger */
527839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
537839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerclass CircleEdgeEffect : public GrEffect {
547839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerpublic:
557839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    static GrEffectRef* Create(bool stroke) {
567839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GR_CREATE_STATIC_EFFECT(gCircleStrokeEdge, CircleEdgeEffect, (true));
577839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GR_CREATE_STATIC_EFFECT(gCircleFillEdge, CircleEdgeEffect, (false));
587839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
597839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        if (stroke) {
607839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            gCircleStrokeEdge->ref();
617839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            return gCircleStrokeEdge;
627839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        } else {
637839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            gCircleFillEdge->ref();
647839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            return gCircleFillEdge;
657839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
667839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
677839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
687839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    virtual void getConstantColorComponents(GrColor* color,
697839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                            uint32_t* validFlags) const SK_OVERRIDE {
707839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        *validFlags = 0;
717839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
727839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
737839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
747839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        return GrTBackendEffectFactory<CircleEdgeEffect>::getInstance();
757839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
767839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
777839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    virtual ~CircleEdgeEffect() {}
787839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
797839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    static const char* Name() { return "CircleEdge"; }
807839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
817839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    inline bool isStroked() const { return fStroke; }
827839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
837839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    class GLEffect : public GrGLEffect {
847839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    public:
857839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
867839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        : INHERITED (factory) {}
877839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
887839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        virtual void emitCode(GrGLShaderBuilder* builder,
897839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                              const GrDrawEffect& drawEffect,
907839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                              EffectKey key,
917839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                              const char* outputColor,
927839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                              const char* inputColor,
937839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                              const TextureSamplerArray& samplers) SK_OVERRIDE {
947839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleEdgeEffect>();
957839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            const char *vsName, *fsName;
967839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName);
977839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
987839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            const SkString* attrName =
997839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
1007839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
1017839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1027839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->fsCodeAppendf("\tfloat d = length(%s.xy);\n", fsName);
1037839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName);
1047839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            if (circleEffect.isStroked()) {
1057839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                builder->fsCodeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0, 1.0);\n", fsName);
1067839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
1077839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            }
1087839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1097839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            SkString modulate;
1107839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
1117839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
1127839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
1137839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1147839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
1157839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleEdgeEffect>();
1167839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1177839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            return circleEffect.isStroked() ? 0x1 : 0x0;
1187839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
1197839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1207839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
1217839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1227839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    private:
1237839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        typedef GrGLEffect INHERITED;
1247839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    };
1257839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1267839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1277839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerprivate:
1287839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    CircleEdgeEffect(bool stroke) : GrEffect() {
1297839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        this->addVertexAttrib(kVec4f_GrSLType);
1307839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        fStroke = stroke;
1317839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
1327839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1337839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
1347839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        const CircleEdgeEffect& cee = CastEffect<CircleEdgeEffect>(other);
1357839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        return cee.fStroke == fStroke;
1367839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
1377839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1387839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    bool fStroke;
1397839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1407839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    GR_DECLARE_EFFECT_TEST;
1417839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1427839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    typedef GrEffect INHERITED;
1437839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger};
1447839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1457839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek SollenbergerGR_DEFINE_EFFECT_TEST(CircleEdgeEffect);
1467839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1477839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek SollenbergerGrEffectRef* CircleEdgeEffect::TestCreate(SkMWCRandom* random,
1487839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                          GrContext* context,
1497839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                          const GrDrawTargetCaps&,
1507839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                          GrTexture* textures[]) {
1517839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    return CircleEdgeEffect::Create(random->nextBool());
1527839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger}
1537839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1547839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
1557839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1567839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger/**
1577839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger * The output of this effect is a modulation of the input color and coverage for an axis-aligned
1587839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger * ellipse, specified as a 2D offset from center, and the reciprocals of the outer and inner radii,
1597839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger * in both x and y directions.
1607839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger *
1617839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0.
1627839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger */
1637839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1647839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerclass EllipseEdgeEffect : public GrEffect {
1657839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerpublic:
1667839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    static GrEffectRef* Create(bool stroke) {
1677839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GR_CREATE_STATIC_EFFECT(gEllipseStrokeEdge, EllipseEdgeEffect, (true));
1687839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GR_CREATE_STATIC_EFFECT(gEllipseFillEdge, EllipseEdgeEffect, (false));
1697839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1707839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        if (stroke) {
1717839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            gEllipseStrokeEdge->ref();
1727839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            return gEllipseStrokeEdge;
1737839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        } else {
1747839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            gEllipseFillEdge->ref();
1757839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            return gEllipseFillEdge;
1767839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
1777839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
1787839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1797839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    virtual void getConstantColorComponents(GrColor* color,
1807839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                            uint32_t* validFlags) const SK_OVERRIDE {
1817839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        *validFlags = 0;
1827839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
1837839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1847839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
1857839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        return GrTBackendEffectFactory<EllipseEdgeEffect>::getInstance();
1867839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
1877839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1887839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    virtual ~EllipseEdgeEffect() {}
1897839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1907839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    static const char* Name() { return "EllipseEdge"; }
1917839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1927839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    inline bool isStroked() const { return fStroke; }
1937839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1947839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    class GLEffect : public GrGLEffect {
1957839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    public:
1967839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
1977839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        : INHERITED (factory) {}
1987839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
1997839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        virtual void emitCode(GrGLShaderBuilder* builder,
2007839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                              const GrDrawEffect& drawEffect,
2017839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                              EffectKey key,
2027839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                              const char* outputColor,
2037839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                              const char* inputColor,
2047839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                              const TextureSamplerArray& samplers) SK_OVERRIDE {
2057839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<EllipseEdgeEffect>();
2067839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2077839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            const char *vsOffsetName, *fsOffsetName;
2087839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            const char *vsRadiiName, *fsRadiiName;
2097839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2107839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName, &fsOffsetName);
2117839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            const SkString* attr0Name =
2127839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
2137839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name->c_str());
2147839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2157839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, &fsRadiiName);
2167839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            const SkString* attr1Name =
2177839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
2187839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr1Name->c_str());
2197839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2207839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            // for outer curve
2217839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->fsCodeAppendf("\tvec2 scaledOffset = %s*%s.xy;\n", fsOffsetName, fsRadiiName);
2227839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->fsCodeAppend("\tfloat test = dot(scaledOffset, scaledOffset) - 1.0;\n");
2237839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->fsCodeAppendf("\tvec2 grad = 2.0*scaledOffset*%s.xy;\n", fsRadiiName);
22458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            builder->fsCodeAppend("\tfloat grad_dot = dot(grad, grad);\n");
22558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            // we need to clamp the length^2 of the gradiant vector to a non-zero value, because
22658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            // on the Nexus 4 the undefined result of inversesqrt(0) drops out an entire tile
22758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            // TODO: restrict this to Adreno-only
22858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            builder->fsCodeAppend("\tgrad_dot = max(grad_dot, 1.0e-4);\n");
22958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            builder->fsCodeAppend("\tfloat invlen = inversesqrt(grad_dot);\n");
2307839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->fsCodeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);\n");
2317839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2327839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            // for inner curve
2337839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            if (ellipseEffect.isStroked()) {
2347839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                builder->fsCodeAppendf("\tscaledOffset = %s*%s.zw;\n", fsOffsetName, fsRadiiName);
2357839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                builder->fsCodeAppend("\ttest = dot(scaledOffset, scaledOffset) - 1.0;\n");
2367839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                builder->fsCodeAppendf("\tgrad = 2.0*scaledOffset*%s.zw;\n", fsRadiiName);
2377839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                builder->fsCodeAppend("\tinvlen = inversesqrt(dot(grad, grad));\n");
2387839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                builder->fsCodeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);\n");
2397839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            }
2407839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2417839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            SkString modulate;
2427839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
2437839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
2447839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
2457839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2467839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
2477839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<EllipseEdgeEffect>();
2487839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2497839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            return ellipseEffect.isStroked() ? 0x1 : 0x0;
2507839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
2517839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2527839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {
2537839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
2547839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2557839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    private:
2567839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        typedef GrGLEffect INHERITED;
2577839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    };
2587839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2597839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerprivate:
2607839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    EllipseEdgeEffect(bool stroke) : GrEffect() {
2617839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        this->addVertexAttrib(kVec2f_GrSLType);
2627839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        this->addVertexAttrib(kVec4f_GrSLType);
2637839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        fStroke = stroke;
2647839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
2657839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2667839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
2677839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        const EllipseEdgeEffect& eee = CastEffect<EllipseEdgeEffect>(other);
2687839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        return eee.fStroke == fStroke;
2697839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
2707839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2717839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    bool fStroke;
2727839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2737839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    GR_DECLARE_EFFECT_TEST;
2747839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2757839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    typedef GrEffect INHERITED;
2767839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger};
2777839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2787839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek SollenbergerGR_DEFINE_EFFECT_TEST(EllipseEdgeEffect);
2797839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2807839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek SollenbergerGrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random,
2817839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                           GrContext* context,
2827839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                           const GrDrawTargetCaps&,
2837839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                           GrTexture* textures[]) {
2847839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    return EllipseEdgeEffect::Create(random->nextBool());
2857839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger}
2867839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
2877839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
2887839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
28958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergervoid GrOvalRenderer::reset() {
29058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    GrSafeSetNull(fRRectIndexBuffer);
29158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger}
29258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
2937839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerbool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, bool useAA,
29458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                              const SkRect& oval, const SkStrokeRec& stroke)
295e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger{
2967839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    if (!useAA) {
297e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        return false;
298e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    }
299e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
300e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    const SkMatrix& vm = context->getMatrix();
301e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
302e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    // we can draw circles
303e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    if (SkScalarNearlyEqual(oval.width(), oval.height())
304e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        && circle_stays_circle(vm)) {
3057839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        this->drawCircle(target, useAA, oval, stroke);
306e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
307e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    // and axis-aligned ellipses only
308e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    } else if (vm.rectStaysRect()) {
3097839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        return this->drawEllipse(target, useAA, oval, stroke);
310e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
311e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    } else {
312e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        return false;
313e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    }
314e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
315e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    return true;
316e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger}
317e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
3187839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergernamespace {
3197839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
3207839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
3217839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
3227839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger// position + edge
3237839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerextern const GrVertexAttrib gCircleVertexAttribs[] = {
3247839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
3257839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
3267839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger};
3277839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
3287839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger};
3297839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
330e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenbergervoid GrOvalRenderer::drawCircle(GrDrawTarget* target,
3317839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                bool useAA,
33258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                                const SkRect& circle,
333e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger                                const SkStrokeRec& stroke)
334e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger{
335e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    GrDrawState* drawState = target->drawState();
336e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
337e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    const SkMatrix& vm = drawState->getViewMatrix();
338e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    GrPoint center = GrPoint::Make(circle.centerX(), circle.centerY());
339e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    vm.mapPoints(&center, 1);
340e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    SkScalar radius = vm.mapRadius(SkScalarHalf(circle.width()));
341e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    SkScalar strokeWidth = vm.mapRadius(stroke.getWidth());
342e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
34358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    GrDrawState::AutoViewMatrixRestore avmr;
34458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    if (!avmr.setIdentity(drawState)) {
345e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        return;
346e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    }
347e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
3487839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircleVertexAttribs));
349e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    GrAssert(sizeof(CircleVertex) == drawState->getVertexSize());
350e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
351e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
352e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    if (!geo.succeeded()) {
353e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        GrPrintf("Failed to get space for vertices!\n");
354e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        return;
355e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    }
356e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
357e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
358e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
359e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    SkStrokeRec::Style style = stroke.getStyle();
360e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
361e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
3627839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    GrEffectRef* effect = CircleEdgeEffect::Create(isStroked);
363e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    static const int kCircleEdgeAttrIndex = 1;
36458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref();
365e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
366e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    SkScalar innerRadius = 0.0f;
367e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    SkScalar outerRadius = radius;
368e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    SkScalar halfWidth = 0;
369e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    if (style != SkStrokeRec::kFill_Style) {
370e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        if (SkScalarNearlyZero(strokeWidth)) {
371e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger            halfWidth = SK_ScalarHalf;
372e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        } else {
373e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger            halfWidth = SkScalarHalf(strokeWidth);
374e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        }
375e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
376e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        outerRadius += halfWidth;
377e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        if (isStroked) {
3787839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            innerRadius = radius - halfWidth;
3797839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            isStroked = (innerRadius > 0);
380e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        }
381e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    }
382e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
3837839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // The radii are outset for two reasons. First, it allows the shader to simply perform
3847839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the
3857839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // verts of the bounding box that is rendered and the outset ensures the box will cover all
3867839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // pixels partially covered by the circle.
3877839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    outerRadius += SK_ScalarHalf;
3887839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    innerRadius -= SK_ScalarHalf;
3897839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
3907839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkRect bounds = SkRect::MakeLTRB(
3917839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        center.fX - outerRadius,
3927839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        center.fY - outerRadius,
3937839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        center.fX + outerRadius,
3947839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        center.fY + outerRadius
3957839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    );
3967839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
3977839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[0].fPos = SkPoint::Make(bounds.fLeft,  bounds.fTop);
3987839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[0].fOffset = SkPoint::Make(-outerRadius, -outerRadius);
3997839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[0].fOuterRadius = outerRadius;
4007839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[0].fInnerRadius = innerRadius;
4017839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
4027839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
4037839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[1].fOffset = SkPoint::Make(outerRadius, -outerRadius);
4047839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[1].fOuterRadius = outerRadius;
4057839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[1].fInnerRadius = innerRadius;
4067839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
4077839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[2].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
4087839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[2].fOffset = SkPoint::Make(-outerRadius, outerRadius);
4097839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[2].fOuterRadius = outerRadius;
4107839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[2].fInnerRadius = innerRadius;
4117839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
4127839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
4137839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[3].fOffset = SkPoint::Make(outerRadius, outerRadius);
4147839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[3].fOuterRadius = outerRadius;
4157839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[3].fInnerRadius = innerRadius;
4167839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
4177839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
4187839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger}
419e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
4207839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
421e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
4227839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergernamespace {
423e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
4247839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger// position + edge
4257839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerextern const GrVertexAttrib gEllipseVertexAttribs[] = {
4267839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    {kVec2f_GrVertexAttribType, 0,                 kPosition_GrVertexAttribBinding},
4277839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    {kVec2f_GrVertexAttribType, sizeof(GrPoint),   kEffect_GrVertexAttribBinding},
4287839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint), kEffect_GrVertexAttribBinding}
4297839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger};
430e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
4317839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger};
432e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
4337839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerbool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
4347839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                 bool useAA,
43558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                                 const SkRect& ellipse,
436e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger                                 const SkStrokeRec& stroke)
437e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger{
438e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    GrDrawState* drawState = target->drawState();
439e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger#ifdef SK_DEBUG
440e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    {
441e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        // we should have checked for this previously
442e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        bool isAxisAlignedEllipse = drawState->getViewMatrix().rectStaysRect();
4437839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkASSERT(useAA && isAxisAlignedEllipse);
444e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    }
445e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger#endif
446e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
4477839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // do any matrix crunching before we reset the draw state for device coords
448e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    const SkMatrix& vm = drawState->getViewMatrix();
449e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY());
450e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    vm.mapPoints(&center, 1);
4517839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
4527839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
4537839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*ellipseXRadius +
4547839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                   vm[SkMatrix::kMSkewY]*ellipseYRadius);
4557839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*ellipseXRadius +
4567839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                   vm[SkMatrix::kMScaleY]*ellipseYRadius);
4577839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
4587839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // do (potentially) anisotropic mapping of stroke
4597839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkVector scaledStroke;
4607839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar strokeWidth = stroke.getWidth();
4617839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMatrix::kMSkewY]));
4627839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatrix::kMScaleY]));
4637839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
4647839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkStrokeRec::Style style = stroke.getStyle();
4657839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
4667839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
4677839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar innerXRadius = 0.0f;
4687839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar innerYRadius = 0.0f;
4697839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    if (SkStrokeRec::kFill_Style != style) {
4707839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        if (SkScalarNearlyZero(scaledStroke.length())) {
4717839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
4727839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        } else {
4737839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            scaledStroke.scale(SK_ScalarHalf);
4747839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
4757839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
4767839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // we only handle thick strokes for near-circular ellipses
4777839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        if (scaledStroke.length() > SK_ScalarHalf &&
4787839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
4797839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            return false;
4807839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
4817839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
4827839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // we don't handle it if curvature of the stroke is less than curvature of the ellipse
4837839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
4847839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
4857839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            return false;
4867839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
4877839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
4887839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // this is legit only if scale & translation (which should be the case at the moment)
4897839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        if (isStroked) {
4907839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            innerXRadius = xRadius - scaledStroke.fX;
4917839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            innerYRadius = yRadius - scaledStroke.fY;
4927839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            isStroked = (innerXRadius > 0 && innerYRadius > 0);
4937839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
4947839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
4957839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        xRadius += scaledStroke.fX;
4967839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        yRadius += scaledStroke.fY;
4977839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
498e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
49958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    GrDrawState::AutoViewMatrixRestore avmr;
50058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    if (!avmr.setIdentity(drawState)) {
5017839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        return false;
502e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    }
503e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
5047839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVertexAttribs));
505e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize());
506e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
507e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
508e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    if (!geo.succeeded()) {
509e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        GrPrintf("Failed to get space for vertices!\n");
5107839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        return false;
511e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    }
512e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
513e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
514e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
5157839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked);
516e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
517e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    static const int kEllipseCenterAttrIndex = 1;
518e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    static const int kEllipseEdgeAttrIndex = 2;
51958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    drawState->addCoverageEffect(effect, kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref();
520e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
5217839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // Compute the reciprocals of the radii here to save time in the shader
5227839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar xRadRecip = SkScalarInvert(xRadius);
5237839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar yRadRecip = SkScalarInvert(yRadius);
5247839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius);
5257839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius);
526e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
5277839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // We've extended the outer x radius out half a pixel to antialias.
5287839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // This will also expand the rect so all the pixels will be captured.
5297839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // TODO: Consider if we should use sqrt(2)/2 instead
5307839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    xRadius += SK_ScalarHalf;
5317839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    yRadius += SK_ScalarHalf;
5327839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
5337839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkRect bounds = SkRect::MakeLTRB(
5347839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        center.fX - xRadius,
5357839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        center.fY - yRadius,
5367839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        center.fX + xRadius,
5377839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        center.fY + yRadius
5387839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    );
5397839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
5407839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[0].fPos = SkPoint::Make(bounds.fLeft,  bounds.fTop);
5417839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius);
5427839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
5437839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
5447839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
5457839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
5467839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[1].fOffset = SkPoint::Make(xRadius, -yRadius);
5477839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
5487839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
5497839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
5507839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[2].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
5517839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[2].fOffset = SkPoint::Make(-xRadius, yRadius);
5527839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
5537839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
5547839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
5557839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
5567839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[3].fOffset = SkPoint::Make(xRadius, yRadius);
5577839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
5587839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
5597839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
5607839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
561e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
5627839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    return true;
5637839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger}
564e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
5657839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
566e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
5677839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerstatic const uint16_t gRRectIndices[] = {
5687839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // corners
5697839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    0, 1, 5, 0, 5, 4,
5707839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    2, 3, 7, 2, 7, 6,
5717839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    8, 9, 13, 8, 13, 12,
5727839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    10, 11, 15, 10, 15, 14,
5737839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
5747839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // edges
5757839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    1, 2, 6, 1, 6, 5,
5767839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    4, 5, 9, 4, 9, 8,
5777839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    6, 7, 11, 6, 11, 10,
5787839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    9, 10, 14, 9, 14, 13,
5797839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
5807839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // center
5817839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // we place this at the end so that we can ignore these indices when rendering stroke-only
5827839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    5, 6, 10, 5, 10, 9
5837839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger};
5847839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
5857839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
5867839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek SollenbergerGrIndexBuffer* GrOvalRenderer::rRectIndexBuffer(GrGpu* gpu) {
5877839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    if (NULL == fRRectIndexBuffer) {
5887839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        fRRectIndexBuffer =
5897839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        gpu->createIndexBuffer(sizeof(gRRectIndices), false);
5907839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        if (NULL != fRRectIndexBuffer) {
5917839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#if GR_DEBUG
5927839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            bool updated =
5937839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#endif
5947839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            fRRectIndexBuffer->updateData(gRRectIndices,
5957839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                          sizeof(gRRectIndices));
5967839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            GR_DEBUGASSERT(updated);
597e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger        }
598e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    }
5997839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    return fRRectIndexBuffer;
6007839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger}
601e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
6027839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenbergerbool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context, bool useAA,
6037839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                     const SkRRect& rrect, const SkStrokeRec& stroke)
6047839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger{
6057839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // only anti-aliased rrects for now
6067839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    if (!useAA) {
6077839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        return false;
6087839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
609e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
6107839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    const SkMatrix& vm = context->getMatrix();
6117839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#ifdef SK_DEBUG
6127839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    {
6137839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // we should have checked for this previously
6147839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkASSERT(useAA && vm.rectStaysRect() && rrect.isSimple());
615e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    }
6167839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger#endif
617e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
6187839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // do any matrix crunching before we reset the draw state for device coords
6197839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    const SkRect& rrectBounds = rrect.getBounds();
6207839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkRect bounds;
6217839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    vm.mapRect(&bounds, rrectBounds);
622e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger
6237839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkVector radii = rrect.getSimpleRadii();
6247839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX +
6257839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                   vm[SkMatrix::kMSkewY]*radii.fY);
6267839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX +
6277839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                   vm[SkMatrix::kMScaleY]*radii.fY);
6287839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
6297839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // if hairline stroke is greater than radius, we don't handle that right now
6307839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkStrokeRec::Style style = stroke.getStyle();
6317839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    if (SkStrokeRec::kHairline_Style == style &&
6327839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        (SK_ScalarHalf >= xRadius || SK_ScalarHalf >= yRadius)) {
6337839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        return false;
6347839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
6357839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
6367839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // do (potentially) anisotropic mapping of stroke
6377839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkVector scaledStroke;
6387839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    SkScalar strokeWidth = stroke.getWidth();
6397839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMatrix::kMSkewY]));
6407839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatrix::kMScaleY]));
6417839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
6427839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // if half of strokewidth is greater than radius, we don't handle that right now
6437839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    if (SK_ScalarHalf*scaledStroke.fX >= xRadius || SK_ScalarHalf*scaledStroke.fY >= yRadius) {
6447839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        return false;
6457839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
6467839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
6477839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // reset to device coordinates
6487839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    GrDrawState* drawState = target->drawState();
64958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    GrDrawState::AutoViewMatrixRestore avmr;
65058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    if (!avmr.setIdentity(drawState)) {
6517839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        return false;
6527839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
6537839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
6547839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
6557839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
6567839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(context->getGpu());
6577839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    if (NULL == indexBuffer) {
6587839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GrPrintf("Failed to create index buffer!\n");
6597839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        return false;
6607839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
6617839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
6627839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // if the corners are circles, use the circle renderer
6637839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    if ((!isStroked || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) {
6647839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircleVertexAttribs));
6657839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GrAssert(sizeof(CircleVertex) == drawState->getVertexSize());
6667839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
6677839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
6687839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        if (!geo.succeeded()) {
6697839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            GrPrintf("Failed to get space for vertices!\n");
6707839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            return false;
6717839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
6727839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
6737839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
6747839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar innerRadius = 0.0f;
6757839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar outerRadius = xRadius;
6767839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar halfWidth = 0;
6777839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        if (style != SkStrokeRec::kFill_Style) {
6787839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            if (SkScalarNearlyZero(scaledStroke.fX)) {
6797839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                halfWidth = SK_ScalarHalf;
6807839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            } else {
6817839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                halfWidth = SkScalarHalf(scaledStroke.fX);
6827839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            }
6837839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
6847839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            if (isStroked) {
6857839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                innerRadius = xRadius - halfWidth;
6867839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                isStroked = (innerRadius > 0);
6877839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            }
6887839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            outerRadius += halfWidth;
6897839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            bounds.outset(halfWidth, halfWidth);
6907839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
6917839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
6927839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GrEffectRef* effect = CircleEdgeEffect::Create(isStroked);
6937839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        static const int kCircleEdgeAttrIndex = 1;
69458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        drawState->addCoverageEffect(effect, kCircleEdgeAttrIndex)->unref();
6957839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
6967839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // The radii are outset for two reasons. First, it allows the shader to simply perform
6977839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the
6987839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // verts of the bounding box that is rendered and the outset ensures the box will cover all
6997839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // pixels partially covered by the circle.
7007839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        outerRadius += SK_ScalarHalf;
7017839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        innerRadius -= SK_ScalarHalf;
7027839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7037839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // Expand the rect so all the pixels will be captured.
7047839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
7057839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7067839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar yCoords[4] = {
7077839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            bounds.fTop,
7087839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            bounds.fTop + outerRadius,
7097839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            bounds.fBottom - outerRadius,
7107839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            bounds.fBottom
7117839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        };
7127839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar yOuterRadii[4] = {
7137839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            -outerRadius,
7147839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            0,
7157839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            0,
7167839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            outerRadius
7177839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        };
7187839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        for (int i = 0; i < 4; ++i) {
7197839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
7207839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOffset = SkPoint::Make(-outerRadius, yOuterRadii[i]);
7217839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOuterRadius = outerRadius;
7227839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fInnerRadius = innerRadius;
7237839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts++;
7247839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7257839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
7267839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
7277839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOuterRadius = outerRadius;
7287839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fInnerRadius = innerRadius;
7297839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts++;
7307839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7317839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
7327839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
7337839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOuterRadius = outerRadius;
7347839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fInnerRadius = innerRadius;
7357839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts++;
7367839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7377839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
7387839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOffset = SkPoint::Make(outerRadius, yOuterRadii[i]);
7397839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOuterRadius = outerRadius;
7407839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fInnerRadius = innerRadius;
7417839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts++;
7427839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
7437839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7447839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // drop out the middle quad if we're stroked
7457839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_COUNT(gRRectIndices);
7467839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        target->setIndexSourceToBuffer(indexBuffer);
7477839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bounds);
7487839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7497839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    // otherwise we use the ellipse renderer
7507839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    } else {
7517839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVertexAttribs));
7527839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize());
7537839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7547839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar innerXRadius = 0.0f;
7557839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar innerYRadius = 0.0f;
7567839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        if (SkStrokeRec::kFill_Style != style) {
7577839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            if (SkScalarNearlyZero(scaledStroke.length())) {
7587839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
7597839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            } else {
7607839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                scaledStroke.scale(SK_ScalarHalf);
7617839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            }
7627839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7637839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            // we only handle thick strokes for near-circular ellipses
7647839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            if (scaledStroke.length() > SK_ScalarHalf &&
7657839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
7667839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                return false;
7677839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            }
7687839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7697839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            // we don't handle it if curvature of the stroke is less than curvature of the ellipse
7707839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
7717839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
7727839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                return false;
7737839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            }
7747839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7757839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            // this is legit only if scale & translation (which should be the case at the moment)
7767839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            if (isStroked) {
7777839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                innerXRadius = xRadius - scaledStroke.fX;
7787839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                innerYRadius = yRadius - scaledStroke.fY;
7797839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                isStroked = (innerXRadius > 0 && innerYRadius > 0);
7807839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            }
7817839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7827839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            xRadius += scaledStroke.fX;
7837839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            yRadius += scaledStroke.fY;
7847839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            bounds.outset(scaledStroke.fX, scaledStroke.fY);
7857839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
7867839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7877839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
7887839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        if (!geo.succeeded()) {
7897839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            GrPrintf("Failed to get space for vertices!\n");
7907839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            return false;
7917839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
7927839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
7937839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
7947839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked);
7957839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        static const int kEllipseOffsetAttrIndex = 1;
7967839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        static const int kEllipseRadiiAttrIndex = 2;
79758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        drawState->addCoverageEffect(effect,
79858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                                     kEllipseOffsetAttrIndex, kEllipseRadiiAttrIndex)->unref();
7997839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
8007839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // Compute the reciprocals of the radii here to save time in the shader
8017839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar xRadRecip = SkScalarInvert(xRadius);
8027839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar yRadRecip = SkScalarInvert(yRadius);
8037839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius);
8047839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius);
8057839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
8067839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // Extend the radii out half a pixel to antialias.
8077839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar xOuterRadius = xRadius + SK_ScalarHalf;
8087839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar yOuterRadius = yRadius + SK_ScalarHalf;
8097839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
8107839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // Expand the rect so all the pixels will be captured.
8117839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
8127839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
8137839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar yCoords[4] = {
8147839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            bounds.fTop,
8157839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            bounds.fTop + yOuterRadius,
8167839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            bounds.fBottom - yOuterRadius,
8177839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            bounds.fBottom
8187839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        };
8197839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        SkScalar yOuterOffsets[4] = {
82058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            yOuterRadius,
8217839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so can't be exactly 0
8227839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            SK_ScalarNearlyZero,
8237839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            yOuterRadius
8247839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        };
8257839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
8267839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        for (int i = 0; i < 4; ++i) {
8277839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
82858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
8297839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
8307839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
8317839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts++;
8327839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
8337839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]);
8347839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
8357839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
8367839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
8377839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts++;
8387839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
8397839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]);
8407839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
8417839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
8427839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
8437839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts++;
8447839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
8457839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
8467839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
8477839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
8487839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
8497839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger            verts++;
8507839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        }
8517839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
8527839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        // drop out the middle quad if we're stroked
8537839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_COUNT(gRRectIndices);
8547839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        target->setIndexSourceToBuffer(indexBuffer);
8557839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger        target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bounds);
8567839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    }
8577839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger
8587839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger    return true;
859e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger}
860