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(¢er, 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(¢er, 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