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