20ae77cb5244a258bec1de34730772d4f2f2d33f
[platform/upstream/libSkiaSharp.git] / src / gpu / GrOvalRenderer.cpp
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 "GrBatch.h"
11 #include "GrBatchTarget.h"
12 #include "GrBufferAllocPool.h"
13 #include "GrDrawTarget.h"
14 #include "GrGeometryProcessor.h"
15 #include "GrGpu.h"
16 #include "GrInvariantOutput.h"
17 #include "GrPipelineBuilder.h"
18 #include "GrProcessor.h"
19 #include "SkRRect.h"
20 #include "SkStrokeRec.h"
21 #include "SkTLazy.h"
22 #include "effects/GrRRectEffect.h"
23 #include "gl/GrGLProcessor.h"
24 #include "gl/GrGLSL.h"
25 #include "gl/GrGLGeometryProcessor.h"
26 #include "gl/builders/GrGLProgramBuilder.h"
27
28 // TODO(joshualitt) - Break this file up during GrBatch post implementation cleanup
29
30 namespace {
31 // TODO(joshualitt) add per vertex colors
32 struct CircleVertex {
33     SkPoint  fPos;
34     SkPoint  fOffset;
35     SkScalar fOuterRadius;
36     SkScalar fInnerRadius;
37 };
38
39 struct EllipseVertex {
40     SkPoint  fPos;
41     SkPoint  fOffset;
42     SkPoint  fOuterRadii;
43     SkPoint  fInnerRadii;
44 };
45
46 struct DIEllipseVertex {
47     SkPoint  fPos;
48     SkPoint  fOuterOffset;
49     SkPoint  fInnerOffset;
50 };
51
52 inline bool circle_stays_circle(const SkMatrix& m) {
53     return m.isSimilarity();
54 }
55
56 }
57
58 ///////////////////////////////////////////////////////////////////////////////
59
60 /**
61  * The output of this effect is a modulation of the input color and coverage for a circle. It
62  * operates in a space normalized by the circle radius (outer radius in the case of a stroke)
63  * with origin at the circle center. Two   vertex attributes are used:
64  *    vec2f : position in device space of the bounding geometry vertices
65  *    vec4f : (p.xy, outerRad, innerRad)
66  *             p is the position in the normalized space.
67  *             outerRad is the outerRadius in device space.
68  *             innerRad is the innerRadius in normalized space (ignored if not stroking).
69  */
70
71 class CircleEdgeEffect : public GrGeometryProcessor {
72 public:
73     static GrGeometryProcessor* Create(GrColor color, bool stroke, const SkMatrix& localMatrix) {
74         return SkNEW_ARGS(CircleEdgeEffect, (color, stroke, localMatrix));
75     }
76
77     const Attribute* inPosition() const { return fInPosition; }
78     const Attribute* inCircleEdge() const { return fInCircleEdge; }
79     virtual ~CircleEdgeEffect() {}
80
81     const char* name() const SK_OVERRIDE { return "CircleEdge"; }
82
83     inline bool isStroked() const { return fStroke; }
84
85     class GLProcessor : public GrGLGeometryProcessor {
86     public:
87         GLProcessor(const GrGeometryProcessor&,
88                     const GrBatchTracker&)
89             : fColor(GrColor_ILLEGAL) {}
90
91         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) SK_OVERRIDE{
92             const CircleEdgeEffect& ce = args.fGP.cast<CircleEdgeEffect>();
93             GrGLGPBuilder* pb = args.fPB;
94             const BatchTracker& local = args.fBT.cast<BatchTracker>();
95             GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
96
97             // emit attributes
98             vsBuilder->emitAttributes(ce);
99
100             GrGLVertToFrag v(kVec4f_GrSLType);
101             args.fPB->addVarying("CircleEdge", &v);
102             vsBuilder->codeAppendf("%s = %s;", v.vsOut(), ce.inCircleEdge()->fName);
103
104             // Setup pass through color
105             this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
106                                         &fColorUniform);
107
108             // Setup position
109             this->setupPosition(pb, gpArgs, ce.inPosition()->fName, ce.viewMatrix());
110
111             // emit transforms
112             this->emitTransforms(args.fPB, gpArgs->fPositionVar, ce.inPosition()->fName,
113                                  ce.localMatrix(), args.fTransformsIn, args.fTransformsOut);;
114
115             GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
116             fsBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn());
117             fsBuilder->codeAppendf("float edgeAlpha = clamp(%s.z * (1.0 - d), 0.0, 1.0);", v.fsIn());
118             if (ce.isStroked()) {
119                 fsBuilder->codeAppendf("float innerAlpha = clamp(%s.z * (d - %s.w), 0.0, 1.0);",
120                                        v.fsIn(), v.fsIn());
121                 fsBuilder->codeAppend("edgeAlpha *= innerAlpha;");
122             }
123
124             fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
125         }
126
127         static void GenKey(const GrGeometryProcessor& gp,
128                            const GrBatchTracker& bt,
129                            const GrGLCaps&,
130                            GrProcessorKeyBuilder* b) {
131             const BatchTracker& local = bt.cast<BatchTracker>();
132             const CircleEdgeEffect& circleEffect = gp.cast<CircleEdgeEffect>();
133             uint16_t key = circleEffect.isStroked() ? 0x1 : 0x0;
134             key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x2 : 0x0;
135             key |= ComputePosKey(gp.viewMatrix()) << 2;
136             b->add32(key << 16 | local.fInputColorType);
137         }
138
139         virtual void setData(const GrGLProgramDataManager& pdman,
140                              const GrPrimitiveProcessor& gp,
141                              const GrBatchTracker& bt) SK_OVERRIDE {
142             this->setUniformViewMatrix(pdman, gp.viewMatrix());
143
144             const BatchTracker& local = bt.cast<BatchTracker>();
145             if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
146                 GrGLfloat c[4];
147                 GrColorToRGBAFloat(local.fColor, c);
148                 pdman.set4fv(fColorUniform, 1, c);
149                 fColor = local.fColor;
150             }
151         }
152
153     private:
154         GrColor fColor;
155         UniformHandle fColorUniform;
156         typedef GrGLGeometryProcessor INHERITED;
157     };
158
159     virtual void getGLProcessorKey(const GrBatchTracker& bt,
160                                    const GrGLCaps& caps,
161                                    GrProcessorKeyBuilder* b) const SK_OVERRIDE {
162         GLProcessor::GenKey(*this, bt, caps, b);
163     }
164
165     virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
166                                                      const GrGLCaps&) const SK_OVERRIDE {
167         return SkNEW_ARGS(GLProcessor, (*this, bt));
168     }
169
170     void initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const SK_OVERRIDE {
171         BatchTracker* local = bt->cast<BatchTracker>();
172         local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
173         local->fUsesLocalCoords = init.fUsesLocalCoords;
174     }
175
176     bool onCanMakeEqual(const GrBatchTracker& m,
177                         const GrGeometryProcessor& that,
178                         const GrBatchTracker& t) const SK_OVERRIDE {
179         const BatchTracker& mine = m.cast<BatchTracker>();
180         const BatchTracker& theirs = t.cast<BatchTracker>();
181         return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
182                                        that, theirs.fUsesLocalCoords) &&
183                CanCombineOutput(mine.fInputColorType, mine.fColor,
184                                 theirs.fInputColorType, theirs.fColor);
185     }
186
187 private:
188     CircleEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix)
189         : INHERITED(color, SkMatrix::I(), localMatrix) {
190         this->initClassID<CircleEdgeEffect>();
191         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
192         fInCircleEdge = &this->addVertexAttrib(Attribute("inCircleEdge",
193                                                            kVec4f_GrVertexAttribType));
194         fStroke = stroke;
195     }
196
197     bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE {
198         const CircleEdgeEffect& cee = other.cast<CircleEdgeEffect>();
199         return cee.fStroke == fStroke;
200     }
201
202     void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
203         out->setUnknownSingleComponent();
204     }
205
206     struct BatchTracker {
207         GrGPInput fInputColorType;
208         GrColor fColor;
209         bool fUsesLocalCoords;
210     };
211
212     const Attribute* fInPosition;
213     const Attribute* fInCircleEdge;
214     bool fStroke;
215
216     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
217
218     typedef GrGeometryProcessor INHERITED;
219 };
220
221 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleEdgeEffect);
222
223 GrGeometryProcessor* CircleEdgeEffect::TestCreate(SkRandom* random,
224                                                   GrContext* context,
225                                                   const GrDrawTargetCaps&,
226                                                   GrTexture* textures[]) {
227     return CircleEdgeEffect::Create(GrRandomColor(random),
228                                     random->nextBool(),
229                                     GrProcessorUnitTest::TestMatrix(random));
230 }
231
232 ///////////////////////////////////////////////////////////////////////////////
233
234 /**
235  * The output of this effect is a modulation of the input color and coverage for an axis-aligned
236  * ellipse, specified as a 2D offset from center, and the reciprocals of the outer and inner radii,
237  * in both x and y directions.
238  *
239  * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0.
240  */
241
242 class EllipseEdgeEffect : public GrGeometryProcessor {
243 public:
244     static GrGeometryProcessor* Create(GrColor color, bool stroke, const SkMatrix& localMatrix) {
245         return SkNEW_ARGS(EllipseEdgeEffect, (color, stroke, localMatrix));
246     }
247
248     virtual ~EllipseEdgeEffect() {}
249
250     const char* name() const SK_OVERRIDE { return "EllipseEdge"; }
251
252     const Attribute* inPosition() const { return fInPosition; }
253     const Attribute* inEllipseOffset() const { return fInEllipseOffset; }
254     const Attribute* inEllipseRadii() const { return fInEllipseRadii; }
255
256     inline bool isStroked() const { return fStroke; }
257
258     class GLProcessor : public GrGLGeometryProcessor {
259     public:
260         GLProcessor(const GrGeometryProcessor&,
261                     const GrBatchTracker&)
262             : fColor(GrColor_ILLEGAL) {}
263
264         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) SK_OVERRIDE{
265             const EllipseEdgeEffect& ee = args.fGP.cast<EllipseEdgeEffect>();
266             GrGLGPBuilder* pb = args.fPB;
267             const BatchTracker& local = args.fBT.cast<BatchTracker>();
268             GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
269
270             // emit attributes
271             vsBuilder->emitAttributes(ee);
272
273             GrGLVertToFrag ellipseOffsets(kVec2f_GrSLType);
274             args.fPB->addVarying("EllipseOffsets", &ellipseOffsets);
275             vsBuilder->codeAppendf("%s = %s;", ellipseOffsets.vsOut(),
276                                    ee.inEllipseOffset()->fName);
277
278             GrGLVertToFrag ellipseRadii(kVec4f_GrSLType);
279             args.fPB->addVarying("EllipseRadii", &ellipseRadii);
280             vsBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(),
281                                    ee.inEllipseRadii()->fName);
282
283             // Setup pass through color
284             this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
285                                         &fColorUniform);
286
287             // Setup position
288             this->setupPosition(pb, gpArgs, ee.inPosition()->fName, ee.viewMatrix());
289
290             // emit transforms
291             this->emitTransforms(args.fPB, gpArgs->fPositionVar, ee.inPosition()->fName,
292                                  ee.localMatrix(), args.fTransformsIn, args.fTransformsOut);
293
294             // for outer curve
295             GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
296             fsBuilder->codeAppendf("vec2 scaledOffset = %s*%s.xy;", ellipseOffsets.fsIn(),
297                                    ellipseRadii.fsIn());
298             fsBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
299             fsBuilder->codeAppendf("vec2 grad = 2.0*scaledOffset*%s.xy;", ellipseRadii.fsIn());
300             fsBuilder->codeAppend("float grad_dot = dot(grad, grad);");
301
302             // avoid calling inversesqrt on zero.
303             fsBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
304             fsBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
305             fsBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
306
307             // for inner curve
308             if (ee.isStroked()) {
309                 fsBuilder->codeAppendf("scaledOffset = %s*%s.zw;",
310                                        ellipseOffsets.fsIn(), ellipseRadii.fsIn());
311                 fsBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
312                 fsBuilder->codeAppendf("grad = 2.0*scaledOffset*%s.zw;",
313                                        ellipseRadii.fsIn());
314                 fsBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
315                 fsBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
316             }
317
318             fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
319         }
320
321         static void GenKey(const GrGeometryProcessor& gp,
322                            const GrBatchTracker& bt,
323                            const GrGLCaps&,
324                            GrProcessorKeyBuilder* b) {
325             const BatchTracker& local = bt.cast<BatchTracker>();
326             const EllipseEdgeEffect& ellipseEffect = gp.cast<EllipseEdgeEffect>();
327             uint16_t key = ellipseEffect.isStroked() ? 0x1 : 0x0;
328             key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x2 : 0x0;
329             key |= ComputePosKey(gp.viewMatrix()) << 2;
330             b->add32(key << 16 | local.fInputColorType);
331         }
332
333         virtual void setData(const GrGLProgramDataManager& pdman,
334                              const GrPrimitiveProcessor& gp,
335                              const GrBatchTracker& bt) SK_OVERRIDE {
336             this->setUniformViewMatrix(pdman, gp.viewMatrix());
337
338             const BatchTracker& local = bt.cast<BatchTracker>();
339             if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
340                 GrGLfloat c[4];
341                 GrColorToRGBAFloat(local.fColor, c);
342                 pdman.set4fv(fColorUniform, 1, c);
343                 fColor = local.fColor;
344             }
345         }
346
347     private:
348         GrColor fColor;
349         UniformHandle fColorUniform;
350
351         typedef GrGLGeometryProcessor INHERITED;
352     };
353
354     virtual void getGLProcessorKey(const GrBatchTracker& bt,
355                                    const GrGLCaps& caps,
356                                    GrProcessorKeyBuilder* b) const SK_OVERRIDE {
357         GLProcessor::GenKey(*this, bt, caps, b);
358     }
359
360     virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
361                                                      const GrGLCaps&) const SK_OVERRIDE {
362         return SkNEW_ARGS(GLProcessor, (*this, bt));
363     }
364
365     void initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const SK_OVERRIDE {
366         BatchTracker* local = bt->cast<BatchTracker>();
367         local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
368         local->fUsesLocalCoords = init.fUsesLocalCoords;
369     }
370
371     bool onCanMakeEqual(const GrBatchTracker& m,
372                         const GrGeometryProcessor& that,
373                         const GrBatchTracker& t) const SK_OVERRIDE {
374         const BatchTracker& mine = m.cast<BatchTracker>();
375         const BatchTracker& theirs = t.cast<BatchTracker>();
376         return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
377                                        that, theirs.fUsesLocalCoords) &&
378                CanCombineOutput(mine.fInputColorType, mine.fColor,
379                                 theirs.fInputColorType, theirs.fColor);
380     }
381
382 private:
383     EllipseEdgeEffect(GrColor color, bool stroke, const SkMatrix& localMatrix)
384         : INHERITED(color, SkMatrix::I(), localMatrix) {
385         this->initClassID<EllipseEdgeEffect>();
386         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
387         fInEllipseOffset = &this->addVertexAttrib(Attribute("inEllipseOffset",
388                                                               kVec2f_GrVertexAttribType));
389         fInEllipseRadii = &this->addVertexAttrib(Attribute("inEllipseRadii",
390                                                              kVec4f_GrVertexAttribType));
391         fStroke = stroke;
392     }
393
394     bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE {
395         const EllipseEdgeEffect& eee = other.cast<EllipseEdgeEffect>();
396         return eee.fStroke == fStroke;
397     }
398
399     void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
400         out->setUnknownSingleComponent();
401     }
402
403     struct BatchTracker {
404         GrGPInput fInputColorType;
405         GrColor fColor;
406         bool fUsesLocalCoords;
407     };
408
409     const Attribute* fInPosition;
410     const Attribute* fInEllipseOffset;
411     const Attribute* fInEllipseRadii;
412     bool fStroke;
413
414     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
415
416     typedef GrGeometryProcessor INHERITED;
417 };
418
419 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(EllipseEdgeEffect);
420
421 GrGeometryProcessor* EllipseEdgeEffect::TestCreate(SkRandom* random,
422                                                    GrContext* context,
423                                                    const GrDrawTargetCaps&,
424                                                    GrTexture* textures[]) {
425     return EllipseEdgeEffect::Create(GrRandomColor(random),
426                                      random->nextBool(),
427                                      GrProcessorUnitTest::TestMatrix(random));
428 }
429
430 ///////////////////////////////////////////////////////////////////////////////
431
432 /**
433  * The output of this effect is a modulation of the input color and coverage for an ellipse,
434  * specified as a 2D offset from center for both the outer and inner paths (if stroked). The
435  * implict equation used is for a unit circle (x^2 + y^2 - 1 = 0) and the edge corrected by
436  * using differentials.
437  *
438  * The result is device-independent and can be used with any affine matrix.
439  */
440
441 class DIEllipseEdgeEffect : public GrGeometryProcessor {
442 public:
443     enum Mode { kStroke = 0, kHairline, kFill };
444
445     static GrGeometryProcessor* Create(GrColor color, const SkMatrix& viewMatrix, Mode mode) {
446         return SkNEW_ARGS(DIEllipseEdgeEffect, (color, viewMatrix, mode));
447     }
448
449     virtual ~DIEllipseEdgeEffect() {}
450
451     const char* name() const SK_OVERRIDE { return "DIEllipseEdge"; }
452
453     const Attribute* inPosition() const { return fInPosition; }
454     const Attribute* inEllipseOffsets0() const { return fInEllipseOffsets0; }
455     const Attribute* inEllipseOffsets1() const { return fInEllipseOffsets1; }
456
457     inline Mode getMode() const { return fMode; }
458
459     class GLProcessor : public GrGLGeometryProcessor {
460     public:
461         GLProcessor(const GrGeometryProcessor&,
462                     const GrBatchTracker&)
463             : fColor(GrColor_ILLEGAL) {}
464
465         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) SK_OVERRIDE{
466             const DIEllipseEdgeEffect& ee = args.fGP.cast<DIEllipseEdgeEffect>();
467             GrGLGPBuilder* pb = args.fPB;
468             const BatchTracker& local = args.fBT.cast<BatchTracker>();
469             GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
470
471             // emit attributes
472             vsBuilder->emitAttributes(ee);
473
474             GrGLVertToFrag offsets0(kVec2f_GrSLType);
475             args.fPB->addVarying("EllipseOffsets0", &offsets0);
476             vsBuilder->codeAppendf("%s = %s;", offsets0.vsOut(),
477                                    ee.inEllipseOffsets0()->fName);
478
479             GrGLVertToFrag offsets1(kVec2f_GrSLType);
480             args.fPB->addVarying("EllipseOffsets1", &offsets1);
481             vsBuilder->codeAppendf("%s = %s;", offsets1.vsOut(),
482                                    ee.inEllipseOffsets1()->fName);
483
484             // Setup pass through color
485             this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
486                                         &fColorUniform);
487
488             // Setup position
489             this->setupPosition(pb, gpArgs, ee.inPosition()->fName, ee.viewMatrix());
490
491             // emit transforms
492             this->emitTransforms(args.fPB, gpArgs->fPositionVar, ee.inPosition()->fName,
493                                  ee.localMatrix(), args.fTransformsIn, args.fTransformsOut);
494
495             GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
496             SkAssertResult(fsBuilder->enableFeature(
497                     GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
498             // for outer curve
499             fsBuilder->codeAppendf("vec2 scaledOffset = %s.xy;", offsets0.fsIn());
500             fsBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
501             fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s);", offsets0.fsIn());
502             fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s);", offsets0.fsIn());
503             fsBuilder->codeAppendf("vec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
504                                    "                 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
505                                    offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn());
506
507             fsBuilder->codeAppend("float grad_dot = dot(grad, grad);");
508             // avoid calling inversesqrt on zero.
509             fsBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
510             fsBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
511             if (kHairline == ee.getMode()) {
512                 // can probably do this with one step
513                 fsBuilder->codeAppend("float edgeAlpha = clamp(1.0-test*invlen, 0.0, 1.0);");
514                 fsBuilder->codeAppend("edgeAlpha *= clamp(1.0+test*invlen, 0.0, 1.0);");
515             } else {
516                 fsBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
517             }
518
519             // for inner curve
520             if (kStroke == ee.getMode()) {
521                 fsBuilder->codeAppendf("scaledOffset = %s.xy;", offsets1.fsIn());
522                 fsBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
523                 fsBuilder->codeAppendf("duvdx = dFdx(%s);", offsets1.fsIn());
524                 fsBuilder->codeAppendf("duvdy = dFdy(%s);", offsets1.fsIn());
525                 fsBuilder->codeAppendf("grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
526                                        "            2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
527                                        offsets1.fsIn(), offsets1.fsIn(), offsets1.fsIn(),
528                                        offsets1.fsIn());
529                 fsBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
530                 fsBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
531             }
532
533             fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
534         }
535
536         static void GenKey(const GrGeometryProcessor& gp,
537                            const GrBatchTracker& bt,
538                            const GrGLCaps&,
539                            GrProcessorKeyBuilder* b) {
540             const BatchTracker& local = bt.cast<BatchTracker>();
541             const DIEllipseEdgeEffect& ellipseEffect = gp.cast<DIEllipseEdgeEffect>();
542             uint16_t key = ellipseEffect.getMode();
543             key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 8 : 0x0;
544             key |= ComputePosKey(gp.viewMatrix()) << 9;
545             b->add32(key << 16 | local.fInputColorType);
546         }
547
548         virtual void setData(const GrGLProgramDataManager& pdman,
549                              const GrPrimitiveProcessor& gp,
550                              const GrBatchTracker& bt) SK_OVERRIDE {
551             this->setUniformViewMatrix(pdman, gp.viewMatrix());
552
553             const BatchTracker& local = bt.cast<BatchTracker>();
554             if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
555                 GrGLfloat c[4];
556                 GrColorToRGBAFloat(local.fColor, c);
557                 pdman.set4fv(fColorUniform, 1, c);
558                 fColor = local.fColor;
559             }
560         }
561
562     private:
563         GrColor fColor;
564         UniformHandle fColorUniform;
565
566         typedef GrGLGeometryProcessor INHERITED;
567     };
568
569     virtual void getGLProcessorKey(const GrBatchTracker& bt,
570                                    const GrGLCaps& caps,
571                                    GrProcessorKeyBuilder* b) const SK_OVERRIDE {
572         GLProcessor::GenKey(*this, bt, caps, b);
573     }
574
575     virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
576                                                      const GrGLCaps&) const SK_OVERRIDE {
577         return SkNEW_ARGS(GLProcessor, (*this, bt));
578     }
579
580     void initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const SK_OVERRIDE {
581         BatchTracker* local = bt->cast<BatchTracker>();
582         local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
583         local->fUsesLocalCoords = init.fUsesLocalCoords;
584     }
585
586     bool onCanMakeEqual(const GrBatchTracker& m,
587                         const GrGeometryProcessor& that,
588                         const GrBatchTracker& t) const SK_OVERRIDE {
589         const BatchTracker& mine = m.cast<BatchTracker>();
590         const BatchTracker& theirs = t.cast<BatchTracker>();
591         return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
592                                        that, theirs.fUsesLocalCoords) &&
593                CanCombineOutput(mine.fInputColorType, mine.fColor,
594                                 theirs.fInputColorType, theirs.fColor);
595     }
596
597 private:
598     DIEllipseEdgeEffect(GrColor color, const SkMatrix& viewMatrix, Mode mode)
599         : INHERITED(color, viewMatrix) {
600         this->initClassID<DIEllipseEdgeEffect>();
601         fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
602         fInEllipseOffsets0 = &this->addVertexAttrib(Attribute("inEllipseOffsets0",
603                                                                 kVec2f_GrVertexAttribType));
604         fInEllipseOffsets1 = &this->addVertexAttrib(Attribute("inEllipseOffsets1",
605                                                                 kVec2f_GrVertexAttribType));
606         fMode = mode;
607     }
608
609     bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE {
610         const DIEllipseEdgeEffect& eee = other.cast<DIEllipseEdgeEffect>();
611         return eee.fMode == fMode;
612     }
613
614     void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
615         out->setUnknownSingleComponent();
616     }
617
618     struct BatchTracker {
619         GrGPInput fInputColorType;
620         GrColor fColor;
621         bool fUsesLocalCoords;
622     };
623
624     const Attribute* fInPosition;
625     const Attribute* fInEllipseOffsets0;
626     const Attribute* fInEllipseOffsets1;
627     Mode fMode;
628
629     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
630
631     typedef GrGeometryProcessor INHERITED;
632 };
633
634 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseEdgeEffect);
635
636 GrGeometryProcessor* DIEllipseEdgeEffect::TestCreate(SkRandom* random,
637                                                      GrContext* context,
638                                                      const GrDrawTargetCaps&,
639                                                      GrTexture* textures[]) {
640     return DIEllipseEdgeEffect::Create(GrRandomColor(random),
641                                        GrProcessorUnitTest::TestMatrix(random),
642                                        (Mode)(random->nextRangeU(0,2)));
643 }
644
645 ///////////////////////////////////////////////////////////////////////////////
646
647 void GrOvalRenderer::reset() {
648     SkSafeSetNull(fRRectIndexBuffer);
649     SkSafeSetNull(fStrokeRRectIndexBuffer);
650 }
651
652 bool GrOvalRenderer::drawOval(GrDrawTarget* target,
653                               GrPipelineBuilder* pipelineBuilder,
654                               GrColor color,
655                               const SkMatrix& viewMatrix,
656                               bool useAA,
657                               const SkRect& oval,
658                               const SkStrokeRec& stroke)
659 {
660     bool useCoverageAA = useAA &&
661         !pipelineBuilder->getRenderTarget()->isMultisampled();
662
663     if (!useCoverageAA) {
664         return false;
665     }
666
667     // we can draw circles
668     if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle(viewMatrix)) {
669         this->drawCircle(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval, stroke);
670     // if we have shader derivative support, render as device-independent
671     } else if (target->caps()->shaderDerivativeSupport()) {
672         return this->drawDIEllipse(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval,
673                                    stroke);
674     // otherwise axis-aligned ellipses only
675     } else if (viewMatrix.rectStaysRect()) {
676         return this->drawEllipse(target, pipelineBuilder, color, viewMatrix, useCoverageAA, oval,
677                                  stroke);
678     } else {
679         return false;
680     }
681
682     return true;
683 }
684
685 ///////////////////////////////////////////////////////////////////////////////
686
687 class CircleBatch : public GrBatch {
688 public:
689     struct Geometry {
690         GrColor fColor;
691         SkMatrix fViewMatrix;
692         SkScalar fInnerRadius;
693         SkScalar fOuterRadius;
694         bool fStroke;
695         SkRect fDevBounds;
696     };
697
698     static GrBatch* Create(const Geometry& geometry) {
699         return SkNEW_ARGS(CircleBatch, (geometry));
700     }
701
702     const char* name() const SK_OVERRIDE { return "CircleBatch"; }
703
704     void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
705         // When this is called on a batch, there is only one geometry bundle
706         out->setKnownFourComponents(fGeoData[0].fColor);
707     }
708
709     void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
710         out->setUnknownSingleComponent();
711     }
712
713     void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
714         // Handle any color overrides
715         if (init.fColorIgnored) {
716             fGeoData[0].fColor = GrColor_ILLEGAL;
717         } else if (GrColor_ILLEGAL != init.fOverrideColor) {
718             fGeoData[0].fColor = init.fOverrideColor;
719         }
720
721         // setup batch properties
722         fBatch.fColorIgnored = init.fColorIgnored;
723         fBatch.fColor = fGeoData[0].fColor;
724         fBatch.fStroke = fGeoData[0].fStroke;
725         fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
726         fBatch.fCoverageIgnored = init.fCoverageIgnored;
727     }
728
729     void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
730         SkMatrix invert;
731         if (!this->viewMatrix().invert(&invert)) {
732             return;
733         }
734
735         // Setup geometry processor
736         SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->color(),
737                                                                       this->stroke(),
738                                                                       invert));
739
740         batchTarget->initDraw(gp, pipeline);
741
742         // TODO this is hacky, but the only way we have to initialize the GP is to use the
743         // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
744         // everywhere we can remove this nastiness
745         GrPipelineInfo init;
746         init.fColorIgnored = fBatch.fColorIgnored;
747         init.fOverrideColor = GrColor_ILLEGAL;
748         init.fCoverageIgnored = fBatch.fCoverageIgnored;
749         init.fUsesLocalCoords = this->usesLocalCoords();
750         gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
751
752         int instanceCount = fGeoData.count();
753         int vertexCount = kVertsPerCircle * instanceCount;
754         size_t vertexStride = gp->getVertexStride();
755         SkASSERT(vertexStride == sizeof(CircleVertex));
756
757         const GrVertexBuffer* vertexBuffer;
758         int firstVertex;
759
760         void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
761                                                               vertexCount,
762                                                               &vertexBuffer,
763                                                               &firstVertex);
764
765         if (!vertices || !batchTarget->quadIndexBuffer()) {
766             SkDebugf("Could not allocate buffers\n");
767             return;
768         }
769
770         CircleVertex* verts = reinterpret_cast<CircleVertex*>(vertices);
771
772         for (int i = 0; i < instanceCount; i++) {
773             Geometry& args = fGeoData[i];
774
775             SkScalar innerRadius = args.fInnerRadius;
776             SkScalar outerRadius = args.fOuterRadius;
777
778             const SkRect& bounds = args.fDevBounds;
779
780             // The inner radius in the vertex data must be specified in normalized space.
781             innerRadius = innerRadius / outerRadius;
782             verts[0].fPos = SkPoint::Make(bounds.fLeft,  bounds.fTop);
783             verts[0].fOffset = SkPoint::Make(-1, -1);
784             verts[0].fOuterRadius = outerRadius;
785             verts[0].fInnerRadius = innerRadius;
786
787             verts[1].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
788             verts[1].fOffset = SkPoint::Make(-1, 1);
789             verts[1].fOuterRadius = outerRadius;
790             verts[1].fInnerRadius = innerRadius;
791
792             verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
793             verts[2].fOffset = SkPoint::Make(1, 1);
794             verts[2].fOuterRadius = outerRadius;
795             verts[2].fInnerRadius = innerRadius;
796
797             verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
798             verts[3].fOffset = SkPoint::Make(1, -1);
799             verts[3].fOuterRadius = outerRadius;
800             verts[3].fInnerRadius = innerRadius;
801
802             verts += kVertsPerCircle;
803         }
804
805         const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
806
807         GrDrawTarget::DrawInfo drawInfo;
808         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
809         drawInfo.setStartVertex(0);
810         drawInfo.setStartIndex(0);
811         drawInfo.setVerticesPerInstance(kVertsPerCircle);
812         drawInfo.setIndicesPerInstance(kIndicesPerCircle);
813         drawInfo.adjustStartVertex(firstVertex);
814         drawInfo.setVertexBuffer(vertexBuffer);
815         drawInfo.setIndexBuffer(quadIndexBuffer);
816
817         int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
818
819         while (instanceCount) {
820             drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
821             drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
822             drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
823
824             batchTarget->draw(drawInfo);
825
826             drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
827             instanceCount -= drawInfo.instanceCount();
828         }
829     }
830
831     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
832
833 private:
834     CircleBatch(const Geometry& geometry) {
835         this->initClassID<CircleBatch>();
836         fGeoData.push_back(geometry);
837     }
838
839     bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
840         CircleBatch* that = t->cast<CircleBatch>();
841
842         // TODO use vertex color to avoid breaking batches
843         if (this->color() != that->color()) {
844             return false;
845         }
846
847         if (this->stroke() != that->stroke()) {
848             return false;
849         }
850
851         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
852         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
853             return false;
854         }
855
856         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
857         return true;
858     }
859
860     GrColor color() const { return fBatch.fColor; }
861     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
862     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
863     bool stroke() const { return fBatch.fStroke; }
864
865     struct BatchTracker {
866         GrColor fColor;
867         bool fStroke;
868         bool fUsesLocalCoords;
869         bool fColorIgnored;
870         bool fCoverageIgnored;
871     };
872
873     static const int kVertsPerCircle = 4;
874     static const int kIndicesPerCircle = 6;
875
876     BatchTracker fBatch;
877     SkSTArray<1, Geometry, true> fGeoData;
878 };
879
880 void GrOvalRenderer::drawCircle(GrDrawTarget* target,
881                                 GrPipelineBuilder* pipelineBuilder,
882                                 GrColor color,
883                                 const SkMatrix& viewMatrix,
884                                 bool useCoverageAA,
885                                 const SkRect& circle,
886                                 const SkStrokeRec& stroke) {
887     SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY());
888     viewMatrix.mapPoints(&center, 1);
889     SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width()));
890     SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
891
892     SkStrokeRec::Style style = stroke.getStyle();
893     bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
894                         SkStrokeRec::kHairline_Style == style;
895     bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
896
897     SkScalar innerRadius = 0.0f;
898     SkScalar outerRadius = radius;
899     SkScalar halfWidth = 0;
900     if (hasStroke) {
901         if (SkScalarNearlyZero(strokeWidth)) {
902             halfWidth = SK_ScalarHalf;
903         } else {
904             halfWidth = SkScalarHalf(strokeWidth);
905         }
906
907         outerRadius += halfWidth;
908         if (isStrokeOnly) {
909             innerRadius = radius - halfWidth;
910         }
911     }
912
913     // The radii are outset for two reasons. First, it allows the shader to simply perform simpler
914     // computation because the computed alpha is zero, rather than 50%, at the radius.
915     // Second, the outer radius is used to compute the verts of the bounding box that is rendered
916     // and the outset ensures the box will cover all partially covered by the circle.
917     outerRadius += SK_ScalarHalf;
918     innerRadius -= SK_ScalarHalf;
919
920     SkRect bounds = SkRect::MakeLTRB(
921         center.fX - outerRadius,
922         center.fY - outerRadius,
923         center.fX + outerRadius,
924         center.fY + outerRadius
925     );
926
927     CircleBatch::Geometry geometry;
928     geometry.fViewMatrix = viewMatrix;
929     geometry.fColor = color;
930     geometry.fInnerRadius = innerRadius;
931     geometry.fOuterRadius = outerRadius;
932     geometry.fStroke = isStrokeOnly && innerRadius > 0;
933     geometry.fDevBounds = bounds;
934
935     SkAutoTUnref<GrBatch> batch(CircleBatch::Create(geometry));
936     target->drawBatch(pipelineBuilder, batch, &bounds);
937 }
938
939 ///////////////////////////////////////////////////////////////////////////////
940
941 class EllipseBatch : public GrBatch {
942 public:
943     struct Geometry {
944         GrColor fColor;
945         SkMatrix fViewMatrix;
946         SkScalar fXRadius;
947         SkScalar fYRadius;
948         SkScalar fInnerXRadius;
949         SkScalar fInnerYRadius;
950         bool fStroke;
951         SkRect fDevBounds;
952     };
953
954     static GrBatch* Create(const Geometry& geometry) {
955         return SkNEW_ARGS(EllipseBatch, (geometry));
956     }
957
958     const char* name() const SK_OVERRIDE { return "EllipseBatch"; }
959
960     void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
961         // When this is called on a batch, there is only one geometry bundle
962         out->setKnownFourComponents(fGeoData[0].fColor);
963     }
964     void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
965         out->setUnknownSingleComponent();
966     }
967
968     void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
969         // Handle any color overrides
970         if (init.fColorIgnored) {
971             fGeoData[0].fColor = GrColor_ILLEGAL;
972         } else if (GrColor_ILLEGAL != init.fOverrideColor) {
973             fGeoData[0].fColor = init.fOverrideColor;
974         }
975
976         // setup batch properties
977         fBatch.fColorIgnored = init.fColorIgnored;
978         fBatch.fColor = fGeoData[0].fColor;
979         fBatch.fStroke = fGeoData[0].fStroke;
980         fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
981         fBatch.fCoverageIgnored = init.fCoverageIgnored;
982     }
983
984     void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
985         SkMatrix invert;
986         if (!this->viewMatrix().invert(&invert)) {
987             return;
988         }
989
990         // Setup geometry processor
991         SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->color(),
992                                                                        this->stroke(),
993                                                                        invert));
994
995         batchTarget->initDraw(gp, pipeline);
996
997         // TODO this is hacky, but the only way we have to initialize the GP is to use the
998         // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
999         // everywhere we can remove this nastiness
1000         GrPipelineInfo init;
1001         init.fColorIgnored = fBatch.fColorIgnored;
1002         init.fOverrideColor = GrColor_ILLEGAL;
1003         init.fCoverageIgnored = fBatch.fCoverageIgnored;
1004         init.fUsesLocalCoords = this->usesLocalCoords();
1005         gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
1006
1007         int instanceCount = fGeoData.count();
1008         int vertexCount = kVertsPerEllipse * instanceCount;
1009         size_t vertexStride = gp->getVertexStride();
1010         SkASSERT(vertexStride == sizeof(EllipseVertex));
1011
1012         const GrVertexBuffer* vertexBuffer;
1013         int firstVertex;
1014
1015         void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
1016                                                               vertexCount,
1017                                                               &vertexBuffer,
1018                                                               &firstVertex);
1019
1020         if (!vertices || !batchTarget->quadIndexBuffer()) {
1021             SkDebugf("Could not allocate buffers\n");
1022             return;
1023         }
1024
1025         EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(vertices);
1026
1027         for (int i = 0; i < instanceCount; i++) {
1028             Geometry& args = fGeoData[i];
1029
1030             SkScalar xRadius = args.fXRadius;
1031             SkScalar yRadius = args.fYRadius;
1032
1033             // Compute the reciprocals of the radii here to save time in the shader
1034             SkScalar xRadRecip = SkScalarInvert(xRadius);
1035             SkScalar yRadRecip = SkScalarInvert(yRadius);
1036             SkScalar xInnerRadRecip = SkScalarInvert(args.fInnerXRadius);
1037             SkScalar yInnerRadRecip = SkScalarInvert(args.fInnerYRadius);
1038
1039             const SkRect& bounds = args.fDevBounds;
1040
1041             // The inner radius in the vertex data must be specified in normalized space.
1042             verts[0].fPos = SkPoint::Make(bounds.fLeft,  bounds.fTop);
1043             verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius);
1044             verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1045             verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1046
1047             verts[1].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
1048             verts[1].fOffset = SkPoint::Make(-xRadius, yRadius);
1049             verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1050             verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1051
1052             verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
1053             verts[2].fOffset = SkPoint::Make(xRadius, yRadius);
1054             verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1055             verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1056
1057             verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
1058             verts[3].fOffset = SkPoint::Make(xRadius, -yRadius);
1059             verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1060             verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1061
1062             verts += kVertsPerEllipse;
1063         }
1064
1065         const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
1066
1067         GrDrawTarget::DrawInfo drawInfo;
1068         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
1069         drawInfo.setStartVertex(0);
1070         drawInfo.setStartIndex(0);
1071         drawInfo.setVerticesPerInstance(kVertsPerEllipse);
1072         drawInfo.setIndicesPerInstance(kIndicesPerEllipse);
1073         drawInfo.adjustStartVertex(firstVertex);
1074         drawInfo.setVertexBuffer(vertexBuffer);
1075         drawInfo.setIndexBuffer(quadIndexBuffer);
1076
1077         int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
1078
1079         while (instanceCount) {
1080             drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
1081             drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
1082             drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
1083
1084             batchTarget->draw(drawInfo);
1085
1086             drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
1087             instanceCount -= drawInfo.instanceCount();
1088         }
1089     }
1090
1091     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1092
1093 private:
1094     EllipseBatch(const Geometry& geometry) {
1095         this->initClassID<EllipseBatch>();
1096         fGeoData.push_back(geometry);
1097     }
1098
1099     bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
1100         EllipseBatch* that = t->cast<EllipseBatch>();
1101
1102         // TODO use vertex color to avoid breaking batches
1103         if (this->color() != that->color()) {
1104             return false;
1105         }
1106
1107         if (this->stroke() != that->stroke()) {
1108             return false;
1109         }
1110
1111         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1112         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1113             return false;
1114         }
1115
1116         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
1117         return true;
1118     }
1119
1120     GrColor color() const { return fBatch.fColor; }
1121     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1122     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1123     bool stroke() const { return fBatch.fStroke; }
1124
1125     struct BatchTracker {
1126         GrColor fColor;
1127         bool fStroke;
1128         bool fUsesLocalCoords;
1129         bool fColorIgnored;
1130         bool fCoverageIgnored;
1131     };
1132
1133     static const int kVertsPerEllipse = 4;
1134     static const int kIndicesPerEllipse = 6;
1135
1136     BatchTracker fBatch;
1137     SkSTArray<1, Geometry, true> fGeoData;
1138 };
1139
1140 bool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
1141                                  GrPipelineBuilder* pipelineBuilder,
1142                                  GrColor color,
1143                                  const SkMatrix& viewMatrix,
1144                                  bool useCoverageAA,
1145                                  const SkRect& ellipse,
1146                                  const SkStrokeRec& stroke) {
1147 #ifdef SK_DEBUG
1148     {
1149         // we should have checked for this previously
1150         bool isAxisAlignedEllipse = viewMatrix.rectStaysRect();
1151         SkASSERT(useCoverageAA && isAxisAlignedEllipse);
1152     }
1153 #endif
1154
1155     // do any matrix crunching before we reset the draw state for device coords
1156     SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
1157     viewMatrix.mapPoints(&center, 1);
1158     SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
1159     SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
1160     SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*ellipseXRadius +
1161                                    viewMatrix[SkMatrix::kMSkewY]*ellipseYRadius);
1162     SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*ellipseXRadius +
1163                                    viewMatrix[SkMatrix::kMScaleY]*ellipseYRadius);
1164
1165     // do (potentially) anisotropic mapping of stroke
1166     SkVector scaledStroke;
1167     SkScalar strokeWidth = stroke.getWidth();
1168     scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
1169                                                viewMatrix[SkMatrix::kMSkewY]));
1170     scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
1171                                                viewMatrix[SkMatrix::kMScaleY]));
1172
1173     SkStrokeRec::Style style = stroke.getStyle();
1174     bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
1175                         SkStrokeRec::kHairline_Style == style;
1176     bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
1177
1178     SkScalar innerXRadius = 0;
1179     SkScalar innerYRadius = 0;
1180     if (hasStroke) {
1181         if (SkScalarNearlyZero(scaledStroke.length())) {
1182             scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
1183         } else {
1184             scaledStroke.scale(SK_ScalarHalf);
1185         }
1186
1187         // we only handle thick strokes for near-circular ellipses
1188         if (scaledStroke.length() > SK_ScalarHalf &&
1189             (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
1190             return false;
1191         }
1192
1193         // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1194         if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
1195             scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
1196             return false;
1197         }
1198
1199         // this is legit only if scale & translation (which should be the case at the moment)
1200         if (isStrokeOnly) {
1201             innerXRadius = xRadius - scaledStroke.fX;
1202             innerYRadius = yRadius - scaledStroke.fY;
1203         }
1204
1205         xRadius += scaledStroke.fX;
1206         yRadius += scaledStroke.fY;
1207     }
1208
1209     // We've extended the outer x radius out half a pixel to antialias.
1210     // This will also expand the rect so all the pixels will be captured.
1211     // TODO: Consider if we should use sqrt(2)/2 instead
1212     xRadius += SK_ScalarHalf;
1213     yRadius += SK_ScalarHalf;
1214
1215     SkRect bounds = SkRect::MakeLTRB(
1216         center.fX - xRadius,
1217         center.fY - yRadius,
1218         center.fX + xRadius,
1219         center.fY + yRadius
1220     );
1221
1222     EllipseBatch::Geometry geometry;
1223     geometry.fViewMatrix = viewMatrix;
1224     geometry.fColor = color;
1225     geometry.fXRadius = xRadius;
1226     geometry.fYRadius = yRadius;
1227     geometry.fInnerXRadius = innerXRadius;
1228     geometry.fInnerYRadius = innerYRadius;
1229     geometry.fStroke = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0;
1230     geometry.fDevBounds = bounds;
1231
1232     SkAutoTUnref<GrBatch> batch(EllipseBatch::Create(geometry));
1233     target->drawBatch(pipelineBuilder, batch, &bounds);
1234
1235     return true;
1236 }
1237
1238 /////////////////////////////////////////////////////////////////////////////////////////////////
1239
1240 class DIEllipseBatch : public GrBatch {
1241 public:
1242     struct Geometry {
1243         GrColor fColor;
1244         SkMatrix fViewMatrix;
1245         SkScalar fXRadius;
1246         SkScalar fYRadius;
1247         SkScalar fInnerXRadius;
1248         SkScalar fInnerYRadius;
1249         SkScalar fGeoDx;
1250         SkScalar fGeoDy;
1251         DIEllipseEdgeEffect::Mode fMode;
1252         SkRect fDevBounds;
1253     };
1254
1255     static GrBatch* Create(const Geometry& geometry) {
1256         return SkNEW_ARGS(DIEllipseBatch, (geometry));
1257     }
1258
1259     const char* name() const SK_OVERRIDE { return "DIEllipseBatch"; }
1260
1261     void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
1262         // When this is called on a batch, there is only one geometry bundle
1263         out->setKnownFourComponents(fGeoData[0].fColor);
1264     }
1265     void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
1266         out->setUnknownSingleComponent();
1267     }
1268
1269     void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
1270         // Handle any color overrides
1271         if (init.fColorIgnored) {
1272             fGeoData[0].fColor = GrColor_ILLEGAL;
1273         } else if (GrColor_ILLEGAL != init.fOverrideColor) {
1274             fGeoData[0].fColor = init.fOverrideColor;
1275         }
1276
1277         // setup batch properties
1278         fBatch.fColorIgnored = init.fColorIgnored;
1279         fBatch.fColor = fGeoData[0].fColor;
1280         fBatch.fMode = fGeoData[0].fMode;
1281         fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
1282         fBatch.fCoverageIgnored = init.fCoverageIgnored;
1283     }
1284
1285     void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
1286         // Setup geometry processor
1287         SkAutoTUnref<GrGeometryProcessor> gp(DIEllipseEdgeEffect::Create(this->color(),
1288                                                                          this->viewMatrix(),
1289                                                                          this->mode()));
1290
1291         batchTarget->initDraw(gp, pipeline);
1292
1293         // TODO this is hacky, but the only way we have to initialize the GP is to use the
1294         // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
1295         // everywhere we can remove this nastiness
1296         GrPipelineInfo init;
1297         init.fColorIgnored = fBatch.fColorIgnored;
1298         init.fOverrideColor = GrColor_ILLEGAL;
1299         init.fCoverageIgnored = fBatch.fCoverageIgnored;
1300         init.fUsesLocalCoords = this->usesLocalCoords();
1301         gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
1302
1303         int instanceCount = fGeoData.count();
1304         int vertexCount = kVertsPerEllipse * instanceCount;
1305         size_t vertexStride = gp->getVertexStride();
1306         SkASSERT(vertexStride == sizeof(DIEllipseVertex));
1307
1308         const GrVertexBuffer* vertexBuffer;
1309         int firstVertex;
1310
1311         void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
1312                                                               vertexCount,
1313                                                               &vertexBuffer,
1314                                                               &firstVertex);
1315
1316         if (!vertices || !batchTarget->quadIndexBuffer()) {
1317             SkDebugf("Could not allocate buffers\n");
1318             return;
1319         }
1320
1321         DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(vertices);
1322
1323         for (int i = 0; i < instanceCount; i++) {
1324             Geometry& args = fGeoData[i];
1325
1326             SkScalar xRadius = args.fXRadius;
1327             SkScalar yRadius = args.fYRadius;
1328
1329             const SkRect& bounds = args.fDevBounds;
1330
1331             // This adjusts the "radius" to include the half-pixel border
1332             SkScalar offsetDx = SkScalarDiv(args.fGeoDx, xRadius);
1333             SkScalar offsetDy = SkScalarDiv(args.fGeoDy, yRadius);
1334
1335             SkScalar innerRatioX = SkScalarDiv(xRadius, args.fInnerXRadius);
1336             SkScalar innerRatioY = SkScalarDiv(yRadius, args.fInnerYRadius);
1337
1338             verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
1339             verts[0].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, -1.0f - offsetDy);
1340             verts[0].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, -innerRatioY - offsetDy);
1341
1342             verts[1].fPos = SkPoint::Make(bounds.fLeft,  bounds.fBottom);
1343             verts[1].fOuterOffset = SkPoint::Make(-1.0f - offsetDx, 1.0f + offsetDy);
1344             verts[1].fInnerOffset = SkPoint::Make(-innerRatioX - offsetDx, innerRatioY + offsetDy);
1345
1346             verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
1347             verts[2].fOuterOffset = SkPoint::Make(1.0f + offsetDx, 1.0f + offsetDy);
1348             verts[2].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, innerRatioY + offsetDy);
1349
1350             verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
1351             verts[3].fOuterOffset = SkPoint::Make(1.0f + offsetDx, -1.0f - offsetDy);
1352             verts[3].fInnerOffset = SkPoint::Make(innerRatioX + offsetDx, -innerRatioY - offsetDy);
1353
1354             verts += kVertsPerEllipse;
1355         }
1356
1357         const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
1358
1359         GrDrawTarget::DrawInfo drawInfo;
1360         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
1361         drawInfo.setStartVertex(0);
1362         drawInfo.setStartIndex(0);
1363         drawInfo.setVerticesPerInstance(kVertsPerEllipse);
1364         drawInfo.setIndicesPerInstance(kIndicesPerEllipse);
1365         drawInfo.adjustStartVertex(firstVertex);
1366         drawInfo.setVertexBuffer(vertexBuffer);
1367         drawInfo.setIndexBuffer(quadIndexBuffer);
1368
1369         int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
1370
1371         while (instanceCount) {
1372             drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
1373             drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
1374             drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
1375
1376             batchTarget->draw(drawInfo);
1377
1378             drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
1379             instanceCount -= drawInfo.instanceCount();
1380         }
1381     }
1382
1383     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1384
1385 private:
1386     DIEllipseBatch(const Geometry& geometry) {
1387         this->initClassID<DIEllipseBatch>();
1388         fGeoData.push_back(geometry);
1389     }
1390
1391     bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
1392         DIEllipseBatch* that = t->cast<DIEllipseBatch>();
1393
1394         // TODO use vertex color to avoid breaking batches
1395         if (this->color() != that->color()) {
1396             return false;
1397         }
1398
1399         if (this->mode() != that->mode()) {
1400             return false;
1401         }
1402
1403         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1404         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1405             return false;
1406         }
1407
1408         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
1409         return true;
1410     }
1411
1412     GrColor color() const { return fBatch.fColor; }
1413     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1414     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1415     DIEllipseEdgeEffect::Mode mode() const { return fBatch.fMode; }
1416
1417     struct BatchTracker {
1418         GrColor fColor;
1419         DIEllipseEdgeEffect::Mode fMode;
1420         bool fUsesLocalCoords;
1421         bool fColorIgnored;
1422         bool fCoverageIgnored;
1423     };
1424
1425     static const int kVertsPerEllipse = 4;
1426     static const int kIndicesPerEllipse = 6;
1427
1428     BatchTracker fBatch;
1429     SkSTArray<1, Geometry, true> fGeoData;
1430 };
1431
1432 bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target,
1433                                    GrPipelineBuilder* pipelineBuilder,
1434                                    GrColor color,
1435                                    const SkMatrix& viewMatrix,
1436                                    bool useCoverageAA,
1437                                    const SkRect& ellipse,
1438                                    const SkStrokeRec& stroke) {
1439     SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
1440     SkScalar xRadius = SkScalarHalf(ellipse.width());
1441     SkScalar yRadius = SkScalarHalf(ellipse.height());
1442
1443     SkStrokeRec::Style style = stroke.getStyle();
1444     DIEllipseEdgeEffect::Mode mode = (SkStrokeRec::kStroke_Style == style) ?
1445                                     DIEllipseEdgeEffect::kStroke :
1446                                     (SkStrokeRec::kHairline_Style == style) ?
1447                                     DIEllipseEdgeEffect::kHairline : DIEllipseEdgeEffect::kFill;
1448
1449     SkScalar innerXRadius = 0;
1450     SkScalar innerYRadius = 0;
1451     if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
1452         SkScalar strokeWidth = stroke.getWidth();
1453
1454         if (SkScalarNearlyZero(strokeWidth)) {
1455             strokeWidth = SK_ScalarHalf;
1456         } else {
1457             strokeWidth *= SK_ScalarHalf;
1458         }
1459
1460         // we only handle thick strokes for near-circular ellipses
1461         if (strokeWidth > SK_ScalarHalf &&
1462             (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
1463             return false;
1464         }
1465
1466         // we don't handle it if curvature of the stroke is less than curvature of the ellipse
1467         if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius ||
1468             strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) {
1469             return false;
1470         }
1471
1472         // set inner radius (if needed)
1473         if (SkStrokeRec::kStroke_Style == style) {
1474             innerXRadius = xRadius - strokeWidth;
1475             innerYRadius = yRadius - strokeWidth;
1476         }
1477
1478         xRadius += strokeWidth;
1479         yRadius += strokeWidth;
1480     }
1481     if (DIEllipseEdgeEffect::kStroke == mode) {
1482         mode = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseEdgeEffect::kStroke :
1483                                                         DIEllipseEdgeEffect::kFill;
1484     }
1485
1486     // This expands the outer rect so that after CTM we end up with a half-pixel border
1487     SkScalar a = viewMatrix[SkMatrix::kMScaleX];
1488     SkScalar b = viewMatrix[SkMatrix::kMSkewX];
1489     SkScalar c = viewMatrix[SkMatrix::kMSkewY];
1490     SkScalar d = viewMatrix[SkMatrix::kMScaleY];
1491     SkScalar geoDx = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(a*a + c*c));
1492     SkScalar geoDy = SkScalarDiv(SK_ScalarHalf, SkScalarSqrt(b*b + d*d));
1493
1494     SkRect bounds = SkRect::MakeLTRB(
1495         center.fX - xRadius - geoDx,
1496         center.fY - yRadius - geoDy,
1497         center.fX + xRadius + geoDx,
1498         center.fY + yRadius + geoDy
1499     );
1500
1501     DIEllipseBatch::Geometry geometry;
1502     geometry.fViewMatrix = viewMatrix;
1503     geometry.fColor = color;
1504     geometry.fXRadius = xRadius;
1505     geometry.fYRadius = yRadius;
1506     geometry.fInnerXRadius = innerXRadius;
1507     geometry.fInnerYRadius = innerYRadius;
1508     geometry.fGeoDx = geoDx;
1509     geometry.fGeoDy = geoDy;
1510     geometry.fMode = mode;
1511     geometry.fDevBounds = bounds;
1512
1513     SkAutoTUnref<GrBatch> batch(DIEllipseBatch::Create(geometry));
1514     target->drawBatch(pipelineBuilder, batch, &bounds);
1515
1516     return true;
1517 }
1518
1519 ///////////////////////////////////////////////////////////////////////////////
1520
1521 static const uint16_t gRRectIndices[] = {
1522     // corners
1523     0, 1, 5, 0, 5, 4,
1524     2, 3, 7, 2, 7, 6,
1525     8, 9, 13, 8, 13, 12,
1526     10, 11, 15, 10, 15, 14,
1527
1528     // edges
1529     1, 2, 6, 1, 6, 5,
1530     4, 5, 9, 4, 9, 8,
1531     6, 7, 11, 6, 11, 10,
1532     9, 10, 14, 9, 14, 13,
1533
1534     // center
1535     // we place this at the end so that we can ignore these indices when rendering stroke-only
1536     5, 6, 10, 5, 10, 9
1537 };
1538
1539 static const int kIndicesPerStrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6;
1540 static const int kIndicesPerRRect = SK_ARRAY_COUNT(gRRectIndices);
1541 static const int kVertsPerRRect = 16;
1542 static const int kNumRRectsInIndexBuffer = 256;
1543
1544 GrIndexBuffer* GrOvalRenderer::rRectIndexBuffer(bool isStrokeOnly) {
1545     if (isStrokeOnly) {
1546         if (NULL == fStrokeRRectIndexBuffer) {
1547             fStrokeRRectIndexBuffer = fGpu->createInstancedIndexBuffer(gRRectIndices,
1548                                                                        kIndicesPerStrokeRRect,
1549                                                                        kNumRRectsInIndexBuffer,
1550                                                                        kVertsPerRRect);
1551         }
1552         return fStrokeRRectIndexBuffer;
1553     } else {
1554         if (NULL == fRRectIndexBuffer) {
1555             fRRectIndexBuffer = fGpu->createInstancedIndexBuffer(gRRectIndices,
1556                                                                  kIndicesPerRRect,
1557                                                                  kNumRRectsInIndexBuffer,
1558                                                                  kVertsPerRRect);
1559         }
1560         return fRRectIndexBuffer;
1561     }
1562 }
1563
1564 bool GrOvalRenderer::drawDRRect(GrDrawTarget* target,
1565                                 GrPipelineBuilder* pipelineBuilder,
1566                                 GrColor color,
1567                                 const SkMatrix& viewMatrix,
1568                                 bool useAA,
1569                                 const SkRRect& origOuter,
1570                                 const SkRRect& origInner) {
1571     bool applyAA = useAA &&
1572                    !pipelineBuilder->getRenderTarget()->isMultisampled();
1573     GrPipelineBuilder::AutoRestoreFragmentProcessors arfp;
1574     if (!origInner.isEmpty()) {
1575         SkTCopyOnFirstWrite<SkRRect> inner(origInner);
1576         if (!viewMatrix.isIdentity()) {
1577             if (!origInner.transform(viewMatrix, inner.writable())) {
1578                 return false;
1579             }
1580         }
1581         GrPrimitiveEdgeType edgeType = applyAA ?
1582                 kInverseFillAA_GrProcessorEdgeType :
1583                 kInverseFillBW_GrProcessorEdgeType;
1584         // TODO this needs to be a geometry processor
1585         GrFragmentProcessor* fp = GrRRectEffect::Create(edgeType, *inner);
1586         if (NULL == fp) {
1587             return false;
1588         }
1589         arfp.set(pipelineBuilder);
1590         pipelineBuilder->addCoverageProcessor(fp)->unref();
1591     }
1592
1593     SkStrokeRec fillRec(SkStrokeRec::kFill_InitStyle);
1594     if (this->drawRRect(target, pipelineBuilder, color, viewMatrix, useAA, origOuter, fillRec)) {
1595         return true;
1596     }
1597
1598     SkASSERT(!origOuter.isEmpty());
1599     SkTCopyOnFirstWrite<SkRRect> outer(origOuter);
1600     if (!viewMatrix.isIdentity()) {
1601         if (!origOuter.transform(viewMatrix, outer.writable())) {
1602             return false;
1603         }
1604     }
1605     GrPrimitiveEdgeType edgeType = applyAA ? kFillAA_GrProcessorEdgeType :
1606                                              kFillBW_GrProcessorEdgeType;
1607     GrFragmentProcessor* effect = GrRRectEffect::Create(edgeType, *outer);
1608     if (NULL == effect) {
1609         return false;
1610     }
1611     if (!arfp.isSet()) {
1612         arfp.set(pipelineBuilder);
1613     }
1614
1615     SkMatrix invert;
1616     if (!viewMatrix.invert(&invert)) {
1617         return false;
1618     }
1619
1620     pipelineBuilder->addCoverageProcessor(effect)->unref();
1621     SkRect bounds = outer->getBounds();
1622     if (applyAA) {
1623         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1624     }
1625     target->drawRect(pipelineBuilder, color, SkMatrix::I(), bounds, NULL, &invert);
1626     return true;
1627 }
1628
1629 ///////////////////////////////////////////////////////////////////////////////////////////////////
1630
1631 class RRectCircleRendererBatch : public GrBatch {
1632 public:
1633     struct Geometry {
1634         GrColor fColor;
1635         SkMatrix fViewMatrix;
1636         SkScalar fInnerRadius;
1637         SkScalar fOuterRadius;
1638         bool fStroke;
1639         SkRect fDevBounds;
1640     };
1641
1642     static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* indexBuffer) {
1643         return SkNEW_ARGS(RRectCircleRendererBatch, (geometry, indexBuffer));
1644     }
1645
1646     const char* name() const SK_OVERRIDE { return "RRectCircleBatch"; }
1647
1648     void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
1649         // When this is called on a batch, there is only one geometry bundle
1650         out->setKnownFourComponents(fGeoData[0].fColor);
1651     }
1652     void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
1653         out->setUnknownSingleComponent();
1654     }
1655
1656     void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
1657         // Handle any color overrides
1658         if (init.fColorIgnored) {
1659             fGeoData[0].fColor = GrColor_ILLEGAL;
1660         } else if (GrColor_ILLEGAL != init.fOverrideColor) {
1661             fGeoData[0].fColor = init.fOverrideColor;
1662         }
1663
1664         // setup batch properties
1665         fBatch.fColorIgnored = init.fColorIgnored;
1666         fBatch.fColor = fGeoData[0].fColor;
1667         fBatch.fStroke = fGeoData[0].fStroke;
1668         fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
1669         fBatch.fCoverageIgnored = init.fCoverageIgnored;
1670     }
1671
1672     void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
1673         // reset to device coordinates
1674         SkMatrix invert;
1675         if (!this->viewMatrix().invert(&invert)) {
1676             SkDebugf("Failed to invert\n");
1677             return;
1678         }
1679
1680         // Setup geometry processor
1681         SkAutoTUnref<GrGeometryProcessor> gp(CircleEdgeEffect::Create(this->color(),
1682                                                                       this->stroke(),
1683                                                                       invert));
1684
1685         batchTarget->initDraw(gp, pipeline);
1686
1687         // TODO this is hacky, but the only way we have to initialize the GP is to use the
1688         // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
1689         // everywhere we can remove this nastiness
1690         GrPipelineInfo init;
1691         init.fColorIgnored = fBatch.fColorIgnored;
1692         init.fOverrideColor = GrColor_ILLEGAL;
1693         init.fCoverageIgnored = fBatch.fCoverageIgnored;
1694         init.fUsesLocalCoords = this->usesLocalCoords();
1695         gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
1696
1697         int instanceCount = fGeoData.count();
1698         int vertexCount = kVertsPerRRect * instanceCount;
1699         size_t vertexStride = gp->getVertexStride();
1700         SkASSERT(vertexStride == sizeof(CircleVertex));
1701
1702         const GrVertexBuffer* vertexBuffer;
1703         int firstVertex;
1704
1705         void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
1706                                                               vertexCount,
1707                                                               &vertexBuffer,
1708                                                               &firstVertex);
1709
1710         if (!vertices) {
1711             SkDebugf("Could not allocate vertices\n");
1712             return;
1713         }
1714
1715         CircleVertex* verts = reinterpret_cast<CircleVertex*>(vertices);
1716
1717         for (int i = 0; i < instanceCount; i++) {
1718             Geometry& args = fGeoData[i];
1719
1720             SkScalar outerRadius = args.fOuterRadius;
1721
1722             const SkRect& bounds = args.fDevBounds;
1723
1724             SkScalar yCoords[4] = {
1725                 bounds.fTop,
1726                 bounds.fTop + outerRadius,
1727                 bounds.fBottom - outerRadius,
1728                 bounds.fBottom
1729             };
1730
1731             SkScalar yOuterRadii[4] = {-1, 0, 0, 1 };
1732             // The inner radius in the vertex data must be specified in normalized space.
1733             SkScalar innerRadius = args.fInnerRadius / args.fOuterRadius;
1734             for (int i = 0; i < 4; ++i) {
1735                 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
1736                 verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
1737                 verts->fOuterRadius = outerRadius;
1738                 verts->fInnerRadius = innerRadius;
1739                 verts++;
1740
1741                 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
1742                 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1743                 verts->fOuterRadius = outerRadius;
1744                 verts->fInnerRadius = innerRadius;
1745                 verts++;
1746
1747                 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]);
1748                 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1749                 verts->fOuterRadius = outerRadius;
1750                 verts->fInnerRadius = innerRadius;
1751                 verts++;
1752
1753                 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1754                 verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
1755                 verts->fOuterRadius = outerRadius;
1756                 verts->fInnerRadius = innerRadius;
1757                 verts++;
1758             }
1759         }
1760
1761         // drop out the middle quad if we're stroked
1762         int indexCnt = this->stroke() ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
1763                                         SK_ARRAY_COUNT(gRRectIndices);
1764
1765
1766         GrDrawTarget::DrawInfo drawInfo;
1767         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
1768         drawInfo.setStartVertex(0);
1769         drawInfo.setStartIndex(0);
1770         drawInfo.setVerticesPerInstance(kVertsPerRRect);
1771         drawInfo.setIndicesPerInstance(indexCnt);
1772         drawInfo.adjustStartVertex(firstVertex);
1773         drawInfo.setVertexBuffer(vertexBuffer);
1774         drawInfo.setIndexBuffer(fIndexBuffer);
1775
1776         int maxInstancesPerDraw = kNumRRectsInIndexBuffer;
1777
1778         while (instanceCount) {
1779             drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
1780             drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
1781             drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
1782
1783             batchTarget->draw(drawInfo);
1784
1785             drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
1786             instanceCount -= drawInfo.instanceCount();
1787         }
1788     }
1789
1790     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
1791
1792 private:
1793     RRectCircleRendererBatch(const Geometry& geometry, const GrIndexBuffer* indexBuffer)
1794         : fIndexBuffer(indexBuffer) {
1795         this->initClassID<RRectCircleRendererBatch>();
1796         fGeoData.push_back(geometry);
1797     }
1798
1799     bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
1800         RRectCircleRendererBatch* that = t->cast<RRectCircleRendererBatch>();
1801
1802         // TODO use vertex color to avoid breaking batches
1803         if (this->color() != that->color()) {
1804             return false;
1805         }
1806
1807         if (this->stroke() != that->stroke()) {
1808             return false;
1809         }
1810
1811         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1812         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1813             return false;
1814         }
1815
1816         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
1817         return true;
1818     }
1819
1820     GrColor color() const { return fBatch.fColor; }
1821     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1822     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
1823     bool stroke() const { return fBatch.fStroke; }
1824
1825     struct BatchTracker {
1826         GrColor fColor;
1827         bool fStroke;
1828         bool fUsesLocalCoords;
1829         bool fColorIgnored;
1830         bool fCoverageIgnored;
1831     };
1832
1833     BatchTracker fBatch;
1834     SkSTArray<1, Geometry, true> fGeoData;
1835     const GrIndexBuffer* fIndexBuffer;
1836 };
1837
1838 class RRectEllipseRendererBatch : public GrBatch {
1839 public:
1840     struct Geometry {
1841         GrColor fColor;
1842         SkMatrix fViewMatrix;
1843         SkScalar fXRadius;
1844         SkScalar fYRadius;
1845         SkScalar fInnerXRadius;
1846         SkScalar fInnerYRadius;
1847         bool fStroke;
1848         SkRect fDevBounds;
1849     };
1850
1851     static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* indexBuffer) {
1852         return SkNEW_ARGS(RRectEllipseRendererBatch, (geometry, indexBuffer));
1853     }
1854
1855     const char* name() const SK_OVERRIDE { return "RRectEllipseRendererBatch"; }
1856
1857     void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
1858         // When this is called on a batch, there is only one geometry bundle
1859         out->setKnownFourComponents(fGeoData[0].fColor);
1860     }
1861     void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
1862         out->setUnknownSingleComponent();
1863     }
1864
1865     void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
1866         // Handle any color overrides
1867         if (init.fColorIgnored) {
1868             fGeoData[0].fColor = GrColor_ILLEGAL;
1869         } else if (GrColor_ILLEGAL != init.fOverrideColor) {
1870             fGeoData[0].fColor = init.fOverrideColor;
1871         }
1872
1873         // setup batch properties
1874         fBatch.fColorIgnored = init.fColorIgnored;
1875         fBatch.fColor = fGeoData[0].fColor;
1876         fBatch.fStroke = fGeoData[0].fStroke;
1877         fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
1878         fBatch.fCoverageIgnored = init.fCoverageIgnored;
1879     }
1880
1881     void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
1882         // reset to device coordinates
1883         SkMatrix invert;
1884         if (!this->viewMatrix().invert(&invert)) {
1885             SkDebugf("Failed to invert\n");
1886             return;
1887         }
1888
1889         // Setup geometry processor
1890         SkAutoTUnref<GrGeometryProcessor> gp(EllipseEdgeEffect::Create(this->color(),
1891                                                                        this->stroke(),
1892                                                                        invert));
1893
1894         batchTarget->initDraw(gp, pipeline);
1895
1896         // TODO this is hacky, but the only way we have to initialize the GP is to use the
1897         // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
1898         // everywhere we can remove this nastiness
1899         GrPipelineInfo init;
1900         init.fColorIgnored = fBatch.fColorIgnored;
1901         init.fOverrideColor = GrColor_ILLEGAL;
1902         init.fCoverageIgnored = fBatch.fCoverageIgnored;
1903         init.fUsesLocalCoords = this->usesLocalCoords();
1904         gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
1905
1906         int instanceCount = fGeoData.count();
1907         int vertexCount = kVertsPerRRect * instanceCount;
1908         size_t vertexStride = gp->getVertexStride();
1909         SkASSERT(vertexStride == sizeof(EllipseVertex));
1910
1911         const GrVertexBuffer* vertexBuffer;
1912         int firstVertex;
1913
1914         void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
1915                                                               vertexCount,
1916                                                               &vertexBuffer,
1917                                                               &firstVertex);
1918
1919         if (!vertices) {
1920             SkDebugf("Could not allocate vertices\n");
1921             return;
1922         }
1923
1924         EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(vertices);
1925
1926         for (int i = 0; i < instanceCount; i++) {
1927             Geometry& args = fGeoData[i];
1928
1929             // Compute the reciprocals of the radii here to save time in the shader
1930             SkScalar xRadRecip = SkScalarInvert(args.fXRadius);
1931             SkScalar yRadRecip = SkScalarInvert(args.fYRadius);
1932             SkScalar xInnerRadRecip = SkScalarInvert(args.fInnerXRadius);
1933             SkScalar yInnerRadRecip = SkScalarInvert(args.fInnerYRadius);
1934
1935             // Extend the radii out half a pixel to antialias.
1936             SkScalar xOuterRadius = args.fXRadius + SK_ScalarHalf;
1937             SkScalar yOuterRadius = args.fYRadius + SK_ScalarHalf;
1938
1939             const SkRect& bounds = args.fDevBounds;
1940
1941             SkScalar yCoords[4] = {
1942                 bounds.fTop,
1943                 bounds.fTop + yOuterRadius,
1944                 bounds.fBottom - yOuterRadius,
1945                 bounds.fBottom
1946             };
1947             SkScalar yOuterOffsets[4] = {
1948                 yOuterRadius,
1949                 SK_ScalarNearlyZero, // we're using inversesqrt() in shader, so can't be exactly 0
1950                 SK_ScalarNearlyZero,
1951                 yOuterRadius
1952             };
1953
1954             for (int i = 0; i < 4; ++i) {
1955                 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
1956                 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
1957                 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1958                 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1959                 verts++;
1960
1961                 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]);
1962                 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
1963                 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1964                 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1965                 verts++;
1966
1967                 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i]);
1968                 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i]);
1969                 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1970                 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1971                 verts++;
1972
1973                 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1974                 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
1975                 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
1976                 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
1977                 verts++;
1978             }
1979         }
1980
1981         // drop out the middle quad if we're stroked
1982         int indexCnt = this->stroke() ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
1983                                         SK_ARRAY_COUNT(gRRectIndices);
1984
1985         GrDrawTarget::DrawInfo drawInfo;
1986         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
1987         drawInfo.setStartVertex(0);
1988         drawInfo.setStartIndex(0);
1989         drawInfo.setVerticesPerInstance(kVertsPerRRect);
1990         drawInfo.setIndicesPerInstance(indexCnt);
1991         drawInfo.adjustStartVertex(firstVertex);
1992         drawInfo.setVertexBuffer(vertexBuffer);
1993         drawInfo.setIndexBuffer(fIndexBuffer);
1994
1995         int maxInstancesPerDraw = kNumRRectsInIndexBuffer;
1996
1997         while (instanceCount) {
1998             drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
1999             drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
2000             drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
2001
2002             batchTarget->draw(drawInfo);
2003
2004             drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
2005             instanceCount -= drawInfo.instanceCount();
2006         }
2007     }
2008
2009     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
2010
2011 private:
2012     RRectEllipseRendererBatch(const Geometry& geometry, const GrIndexBuffer* indexBuffer)
2013         : fIndexBuffer(indexBuffer) {
2014         this->initClassID<RRectEllipseRendererBatch>();
2015         fGeoData.push_back(geometry);
2016     }
2017
2018     bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
2019         RRectEllipseRendererBatch* that = t->cast<RRectEllipseRendererBatch>();
2020
2021         // TODO use vertex color to avoid breaking batches
2022         if (this->color() != that->color()) {
2023             return false;
2024         }
2025
2026         if (this->stroke() != that->stroke()) {
2027             return false;
2028         }
2029
2030         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
2031         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
2032             return false;
2033         }
2034
2035         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
2036         return true;
2037     }
2038
2039     GrColor color() const { return fBatch.fColor; }
2040     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
2041     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
2042     bool stroke() const { return fBatch.fStroke; }
2043
2044     struct BatchTracker {
2045         GrColor fColor;
2046         bool fStroke;
2047         bool fUsesLocalCoords;
2048         bool fColorIgnored;
2049         bool fCoverageIgnored;
2050     };
2051
2052     BatchTracker fBatch;
2053     SkSTArray<1, Geometry, true> fGeoData;
2054     const GrIndexBuffer* fIndexBuffer;
2055 };
2056
2057 bool GrOvalRenderer::drawRRect(GrDrawTarget* target,
2058                                GrPipelineBuilder* pipelineBuilder,
2059                                GrColor color,
2060                                const SkMatrix& viewMatrix,
2061                                bool useAA,
2062                                const SkRRect& rrect,
2063                                const SkStrokeRec& stroke) {
2064     if (rrect.isOval()) {
2065         return this->drawOval(target, pipelineBuilder, color, viewMatrix, useAA, rrect.getBounds(),
2066                               stroke);
2067     }
2068
2069     bool useCoverageAA = useAA &&
2070         !pipelineBuilder->getRenderTarget()->isMultisampled();
2071
2072     // only anti-aliased rrects for now
2073     if (!useCoverageAA) {
2074         return false;
2075     }
2076
2077     if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) {
2078         return false;
2079     }
2080
2081     // do any matrix crunching before we reset the draw state for device coords
2082     const SkRect& rrectBounds = rrect.getBounds();
2083     SkRect bounds;
2084     viewMatrix.mapRect(&bounds, rrectBounds);
2085
2086     SkVector radii = rrect.getSimpleRadii();
2087     SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*radii.fX +
2088                                    viewMatrix[SkMatrix::kMSkewY]*radii.fY);
2089     SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*radii.fX +
2090                                    viewMatrix[SkMatrix::kMScaleY]*radii.fY);
2091
2092     SkStrokeRec::Style style = stroke.getStyle();
2093
2094     // do (potentially) anisotropic mapping of stroke
2095     SkVector scaledStroke;
2096     SkScalar strokeWidth = stroke.getWidth();
2097
2098     bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
2099                         SkStrokeRec::kHairline_Style == style;
2100     bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
2101
2102     if (hasStroke) {
2103         if (SkStrokeRec::kHairline_Style == style) {
2104             scaledStroke.set(1, 1);
2105         } else {
2106             scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
2107                                                        viewMatrix[SkMatrix::kMSkewY]));
2108             scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
2109                                                        viewMatrix[SkMatrix::kMScaleY]));
2110         }
2111
2112         // if half of strokewidth is greater than radius, we don't handle that right now
2113         if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStroke.fY > yRadius) {
2114             return false;
2115         }
2116     }
2117
2118     // The way the effect interpolates the offset-to-ellipse/circle-center attribute only works on
2119     // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner rect of the nine-
2120     // patch will have fractional coverage. This only matters when the interior is actually filled.
2121     // We could consider falling back to rect rendering here, since a tiny radius is
2122     // indistinguishable from a square corner.
2123     if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
2124         return false;
2125     }
2126
2127     GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(isStrokeOnly);
2128     if (NULL == indexBuffer) {
2129         SkDebugf("Failed to create index buffer!\n");
2130         return false;
2131     }
2132
2133     // if the corners are circles, use the circle renderer
2134     if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) {
2135         SkScalar innerRadius = 0.0f;
2136         SkScalar outerRadius = xRadius;
2137         SkScalar halfWidth = 0;
2138         if (hasStroke) {
2139             if (SkScalarNearlyZero(scaledStroke.fX)) {
2140                 halfWidth = SK_ScalarHalf;
2141             } else {
2142                 halfWidth = SkScalarHalf(scaledStroke.fX);
2143             }
2144
2145             if (isStrokeOnly) {
2146                 innerRadius = xRadius - halfWidth;
2147             }
2148             outerRadius += halfWidth;
2149             bounds.outset(halfWidth, halfWidth);
2150         }
2151
2152         isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
2153
2154         // The radii are outset for two reasons. First, it allows the shader to simply perform
2155         // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
2156         // Second, the outer radius is used to compute the verts of the bounding box that is
2157         // rendered and the outset ensures the box will cover all partially covered by the rrect
2158         // corners.
2159         outerRadius += SK_ScalarHalf;
2160         innerRadius -= SK_ScalarHalf;
2161
2162         // Expand the rect so all the pixels will be captured.
2163         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
2164
2165         RRectCircleRendererBatch::Geometry geometry;
2166         geometry.fViewMatrix = viewMatrix;
2167         geometry.fColor = color;
2168         geometry.fInnerRadius = innerRadius;
2169         geometry.fOuterRadius = outerRadius;
2170         geometry.fStroke = isStrokeOnly;
2171         geometry.fDevBounds = bounds;
2172
2173         SkAutoTUnref<GrBatch> batch(RRectCircleRendererBatch::Create(geometry, indexBuffer));
2174         target->drawBatch(pipelineBuilder, batch, &bounds);
2175
2176     // otherwise we use the ellipse renderer
2177     } else {
2178         SkScalar innerXRadius = 0.0f;
2179         SkScalar innerYRadius = 0.0f;
2180         if (hasStroke) {
2181             if (SkScalarNearlyZero(scaledStroke.length())) {
2182                 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
2183             } else {
2184                 scaledStroke.scale(SK_ScalarHalf);
2185             }
2186
2187             // we only handle thick strokes for near-circular ellipses
2188             if (scaledStroke.length() > SK_ScalarHalf &&
2189                 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
2190                 return false;
2191             }
2192
2193             // we don't handle it if curvature of the stroke is less than curvature of the ellipse
2194             if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
2195                 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
2196                 return false;
2197             }
2198
2199             // this is legit only if scale & translation (which should be the case at the moment)
2200             if (isStrokeOnly) {
2201                 innerXRadius = xRadius - scaledStroke.fX;
2202                 innerYRadius = yRadius - scaledStroke.fY;
2203             }
2204
2205             xRadius += scaledStroke.fX;
2206             yRadius += scaledStroke.fY;
2207             bounds.outset(scaledStroke.fX, scaledStroke.fY);
2208         }
2209
2210         isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
2211
2212         // Expand the rect so all the pixels will be captured.
2213         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
2214
2215         RRectEllipseRendererBatch::Geometry geometry;
2216         geometry.fViewMatrix = viewMatrix;
2217         geometry.fColor = color;
2218         geometry.fXRadius = xRadius;
2219         geometry.fYRadius = yRadius;
2220         geometry.fInnerXRadius = innerXRadius;
2221         geometry.fInnerYRadius = innerYRadius;
2222         geometry.fStroke = isStrokeOnly;
2223         geometry.fDevBounds = bounds;
2224
2225         SkAutoTUnref<GrBatch> batch(RRectEllipseRendererBatch::Create(geometry, indexBuffer));
2226         target->drawBatch(pipelineBuilder, batch, &bounds);
2227     }
2228     return true;
2229 }