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