Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Side by Side Diff: src/gpu/GrOvalRenderer.cpp

Issue 14938004: Better method for rendering ellipses (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Some perf tweaks Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "GrOvalRenderer.h" 8 #include "GrOvalRenderer.h"
9 9
10 #include "GrEffect.h" 10 #include "GrEffect.h"
(...skipping 14 matching lines...) Expand all
25 25
26 struct CircleVertex { 26 struct CircleVertex {
27 GrPoint fPos; 27 GrPoint fPos;
28 GrPoint fOffset; 28 GrPoint fOffset;
29 SkScalar fOuterRadius; 29 SkScalar fOuterRadius;
30 SkScalar fInnerRadius; 30 SkScalar fInnerRadius;
31 }; 31 };
32 32
33 struct EllipseVertex { 33 struct EllipseVertex {
34 GrPoint fPos; 34 GrPoint fPos;
35 SkScalar fOuterXRadius;
36 SkScalar fInnerXRadius;
37 GrPoint fOuterOffset;
38 GrPoint fInnerOffset;
39 };
40
41 struct RRectVertex {
42 GrPoint fPos;
43 GrPoint fOffset; 35 GrPoint fOffset;
44 GrPoint fOuterRadii; 36 GrPoint fOuterRadii;
45 GrPoint fInnerRadii; 37 GrPoint fInnerRadii;
46 }; 38 };
47 39
48 inline bool circle_stays_circle(const SkMatrix& m) { 40 inline bool circle_stays_circle(const SkMatrix& m) {
49 return m.isSimilarity(); 41 return m.isSimilarity();
50 } 42 }
51 43
52 } 44 }
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 GrContext* context, 148 GrContext* context,
157 const GrDrawTargetCaps&, 149 const GrDrawTargetCaps&,
158 GrTexture* textures[]) { 150 GrTexture* textures[]) {
159 return CircleEdgeEffect::Create(random->nextBool()); 151 return CircleEdgeEffect::Create(random->nextBool());
160 } 152 }
161 153
162 /////////////////////////////////////////////////////////////////////////////// 154 ///////////////////////////////////////////////////////////////////////////////
163 155
164 /** 156 /**
165 * The output of this effect is a modulation of the input color and coverage for an axis-aligned 157 * The output of this effect is a modulation of the input color and coverage for an axis-aligned
166 * ellipse, specified as outer and inner radii, and outer and inner offsets fro m center. 158 * ellipse, specified as a 2D offset from center, and the reciprocals of the out er and inner radii,
159 * in both x and y directions.
160 *
161 * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0.
167 */ 162 */
168 163
169 class EllipseEdgeEffect : public GrEffect { 164 class EllipseEdgeEffect : public GrEffect {
170 public: 165 public:
171 static GrEffectRef* Create(bool stroke) { 166 static GrEffectRef* Create(bool stroke) {
172 GR_CREATE_STATIC_EFFECT(gEllipseStrokeEdge, EllipseEdgeEffect, (true)); 167 GR_CREATE_STATIC_EFFECT(gEllipseStrokeEdge, EllipseEdgeEffect, (true));
173 GR_CREATE_STATIC_EFFECT(gEllipseFillEdge, EllipseEdgeEffect, (false)); 168 GR_CREATE_STATIC_EFFECT(gEllipseFillEdge, EllipseEdgeEffect, (false));
174 169
175 if (stroke) { 170 if (stroke) {
176 gEllipseStrokeEdge->ref(); 171 gEllipseStrokeEdge->ref();
(...skipping 25 matching lines...) Expand all
202 : INHERITED (factory) {} 197 : INHERITED (factory) {}
203 198
204 virtual void emitCode(GrGLShaderBuilder* builder, 199 virtual void emitCode(GrGLShaderBuilder* builder,
205 const GrDrawEffect& drawEffect, 200 const GrDrawEffect& drawEffect,
206 EffectKey key, 201 EffectKey key,
207 const char* outputColor, 202 const char* outputColor,
208 const char* inputColor, 203 const char* inputColor,
209 const TextureSamplerArray& samplers) SK_OVERRIDE { 204 const TextureSamplerArray& samplers) SK_OVERRIDE {
210 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip seEdgeEffect>(); 205 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip seEdgeEffect>();
211 206
207 const char *vsOffsetName, *fsOffsetName;
212 const char *vsRadiiName, *fsRadiiName; 208 const char *vsRadiiName, *fsRadiiName;
213 const char *vsOffsetsName, *fsOffsetsName;
214 209
215 builder->addVarying(kVec2f_GrSLType, "EllipseRadii", &vsRadiiName, & fsRadiiName); 210 builder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName , &fsOffsetName);
216 const SkString* attr0Name = 211 const SkString* attr0Name =
217 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); 212 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]);
218 builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr0Name->c_str ()); 213 builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name->c_st r());
219 214
220 builder->addVarying(kVec4f_GrSLType, "EllipseOffsets", &vsOffsetsNam e, &fsOffsetsName); 215 builder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, & fsRadiiName);
221 const SkString* attr1Name = 216 const SkString* attr1Name =
222 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[1]); 217 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[1]);
223 builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetsName, attr1Name->c_s tr()); 218 builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr1Name->c_str ());
224 219
225 // get length of offset 220 // for outer curve
226 builder->fsCodeAppendf("\tfloat dOuter = length(%s.xy);\n", fsOffset sName); 221 builder->fsCodeAppendf("\tvec2 scaledOffset = %s*%s.xy;\n", fsOffset Name, fsRadiiName);
227 // compare outer lengths against xOuterRadius 222 builder->fsCodeAppend("\tfloat test = dot(scaledOffset, scaledOffset ) - 1.0;\n");
228 builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0, 1.0);\n", 223 builder->fsCodeAppendf("\tvec2 grad = 2.0*scaledOffset*%s.xy;\n", fs RadiiName);
229 fsRadiiName); 224 builder->fsCodeAppend("\tfloat invlen = inversesqrt(dot(grad, grad)) ;\n");
225 builder->fsCodeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen, 0. 0, 1.0);\n");
230 226
227 // for inner curve
231 if (ellipseEffect.isStroked()) { 228 if (ellipseEffect.isStroked()) {
232 builder->fsCodeAppendf("\tfloat dInner = length(%s.zw);\n", fsOf fsetsName); 229 builder->fsCodeAppendf("\tscaledOffset = %s*%s.zw;\n", fsOffsetN ame, fsRadiiName);
233 230 builder->fsCodeAppend("\ttest = dot(scaledOffset, scaledOffset) - 1.0;\n");
234 // compare inner lengths against xInnerRadius 231 builder->fsCodeAppendf("\tgrad = 2.0*scaledOffset*%s.zw;\n", fsR adiiName);
235 builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.y, 0.0, 1.0);\n", 232 builder->fsCodeAppend("\tinvlen = inversesqrt(dot(grad, grad));\ n");
236 fsRadiiName); 233 builder->fsCodeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0 , 1.0);\n");
237 builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
238 } 234 }
239 235
240 SkString modulate; 236 SkString modulate;
241 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); 237 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
242 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() ); 238 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() );
243 } 239 }
244 240
245 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { 241 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) {
246 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip seEdgeEffect>(); 242 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip seEdgeEffect>();
247 243
(...skipping 30 matching lines...) Expand all
278 274
279 GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random, 275 GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random,
280 GrContext* context, 276 GrContext* context,
281 const GrDrawTargetCaps&, 277 const GrDrawTargetCaps&,
282 GrTexture* textures[]) { 278 GrTexture* textures[]) {
283 return EllipseEdgeEffect::Create(random->nextBool()); 279 return EllipseEdgeEffect::Create(random->nextBool());
284 } 280 }
285 281
286 /////////////////////////////////////////////////////////////////////////////// 282 ///////////////////////////////////////////////////////////////////////////////
287 283
288 /**
289 * The output of this effect is a modulation of the input color and coverage for an axis-aligned
290 * ellipse, specified as an offset vector from center and reciprocals of outer a nd inner radii in
291 * both x and y directions.
292 *
293 * This uses a slightly different algorithm than the EllipseEdgeEffect, above. R ather than
294 * scaling an ellipse to be a circle, it attempts to find the distance from the offset point to the
295 * ellipse by determining where the line through the origin and offset point wou ld cross the
296 * ellipse, and computing the distance to that. This is slower but works better for roundrects
297 * because the straight edges will be more accurate.
298 */
299
300 class AltEllipseEdgeEffect : public GrEffect {
301 public:
302 static GrEffectRef* Create(bool stroke) {
303 // we go through this so we only have one copy of each effect (stroked/f illed)
304 GR_CREATE_STATIC_EFFECT(gAltEllipseStrokeEdge, AltEllipseEdgeEffect, (tr ue));
305 GR_CREATE_STATIC_EFFECT(gAltEllipseFillEdge, AltEllipseEdgeEffect, (fals e));
306
307 if (stroke) {
308 gAltEllipseStrokeEdge->ref();
309 return gAltEllipseStrokeEdge;
310 } else {
311 gAltEllipseFillEdge->ref();
312 return gAltEllipseFillEdge;
313 }
314 }
315
316 virtual void getConstantColorComponents(GrColor* color,
317 uint32_t* validFlags) const SK_OVERR IDE {
318 *validFlags = 0;
319 }
320
321 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
322 return GrTBackendEffectFactory<AltEllipseEdgeEffect>::getInstance();
323 }
324
325 virtual ~AltEllipseEdgeEffect() {}
326
327 static const char* Name() { return "RRectEdge"; }
328
329 inline bool isStroked() const { return fStroke; }
330
331 class GLEffect : public GrGLEffect {
332 public:
333 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
334 : INHERITED (factory) {}
335
336 virtual void emitCode(GrGLShaderBuilder* builder,
337 const GrDrawEffect& drawEffect,
338 EffectKey key,
339 const char* outputColor,
340 const char* inputColor,
341 const TextureSamplerArray& samplers) SK_OVERRIDE {
342 const AltEllipseEdgeEffect& rrectEffect = drawEffect.castEffect<AltE llipseEdgeEffect>();
343
344 const char *vsOffsetName, *fsOffsetName;
345 const char *vsRadiiName, *fsRadiiName;
346
347 builder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName , &fsOffsetName);
348 const SkString* attr0Name =
349 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]);
350 builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name->c_st r());
351
352 builder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, & fsRadiiName);
353 const SkString* attr1Name =
354 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[1]);
355 builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr1Name->c_str ());
356
357 builder->fsCodeAppend("\tfloat edgeAlpha;\n");
358 // get length of offset
359 builder->fsCodeAppendf("\tfloat len = length(%s.xy);\n", fsOffsetNam e);
360
361 // for outer curve
362 builder->fsCodeAppendf("\tvec2 offset = %s.xy*%s.xy;\n",
363 fsOffsetName, fsRadiiName);
364 builder->fsCodeAppendf("\tfloat t = inversesqrt(dot(offset.xy, offse t.xy));\n");
365 builder->fsCodeAppend("\tedgeAlpha = clamp(len*t - len, 0.0, 1.0);\n ");
366
367 // for inner curve
368 if (rrectEffect.isStroked()) {
369 builder->fsCodeAppendf("\toffset = %s.xy*%s.zw;\n",
370 fsOffsetName, fsRadiiName);
371 builder->fsCodeAppendf("\tt = inversesqrt(dot(offset.xy, offset. xy));\n");
372 builder->fsCodeAppend("\tedgeAlpha *= clamp(len - len*t, 0.0, 1. 0);\n");
373 }
374
375 SkString modulate;
376 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
377 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() );
378 }
379
380 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) {
381 const AltEllipseEdgeEffect& rrectEffect = drawEffect.castEffect<AltE llipseEdgeEffect>();
382
383 return rrectEffect.isStroked() ? 0x1 : 0x0;
384 }
385
386 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_ OVERRIDE {
387 }
388
389 private:
390 typedef GrGLEffect INHERITED;
391 };
392
393 private:
394 AltEllipseEdgeEffect(bool stroke) : GrEffect() {
395 this->addVertexAttrib(kVec2f_GrSLType);
396 this->addVertexAttrib(kVec4f_GrSLType);
397 fStroke = stroke;
398 }
399
400 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
401 const AltEllipseEdgeEffect& aeee = CastEffect<AltEllipseEdgeEffect>(othe r);
402 return aeee.fStroke == fStroke;
403 }
404
405 bool fStroke;
406
407 GR_DECLARE_EFFECT_TEST;
408
409 typedef GrEffect INHERITED;
410 };
411
412 GR_DEFINE_EFFECT_TEST(AltEllipseEdgeEffect);
413
414 GrEffectRef* AltEllipseEdgeEffect::TestCreate(SkMWCRandom* random,
415 GrContext* context,
416 const GrDrawTargetCaps&,
417 GrTexture* textures[]) {
418 return AltEllipseEdgeEffect::Create(random->nextBool());
419 }
420
421 ///////////////////////////////////////////////////////////////////////////////
422
423 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, bo ol useAA, 284 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, bo ol useAA,
424 const GrRect& oval, const SkStrokeRec& stroke) 285 const GrRect& oval, const SkStrokeRec& stroke)
425 { 286 {
426 if (!useAA) { 287 if (!useAA) {
427 return false; 288 return false;
428 } 289 }
429 290
430 const SkMatrix& vm = context->getMatrix(); 291 const SkMatrix& vm = context->getMatrix();
431 292
432 // we can draw circles 293 // we can draw circles
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 SkScalar halfWidth = 0; 365 SkScalar halfWidth = 0;
505 if (style != SkStrokeRec::kFill_Style) { 366 if (style != SkStrokeRec::kFill_Style) {
506 if (SkScalarNearlyZero(strokeWidth)) { 367 if (SkScalarNearlyZero(strokeWidth)) {
507 halfWidth = SK_ScalarHalf; 368 halfWidth = SK_ScalarHalf;
508 } else { 369 } else {
509 halfWidth = SkScalarHalf(strokeWidth); 370 halfWidth = SkScalarHalf(strokeWidth);
510 } 371 }
511 372
512 outerRadius += halfWidth; 373 outerRadius += halfWidth;
513 if (isStroked) { 374 if (isStroked) {
514 innerRadius = SkMaxScalar(0, radius - halfWidth); 375 innerRadius = radius - halfWidth;
376 isStroked = (innerRadius > 0);
515 } 377 }
516 } 378 }
517 379
518 // The radii are outset for two reasons. First, it allows the shader to simp ly perform 380 // The radii are outset for two reasons. First, it allows the shader to simp ly perform
519 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is use d to compute the 381 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is use d to compute the
520 // verts of the bounding box that is rendered and the outset ensures the box will cover all 382 // verts of the bounding box that is rendered and the outset ensures the box will cover all
521 // pixels partially covered by the circle. 383 // pixels partially covered by the circle.
522 outerRadius += SK_ScalarHalf; 384 outerRadius += SK_ScalarHalf;
523 innerRadius -= SK_ScalarHalf; 385 innerRadius -= SK_ScalarHalf;
524 386
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 // do any matrix crunching before we reset the draw state for device coords 444 // do any matrix crunching before we reset the draw state for device coords
583 const SkMatrix& vm = drawState->getViewMatrix(); 445 const SkMatrix& vm = drawState->getViewMatrix();
584 GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY()); 446 GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY());
585 vm.mapPoints(&center, 1); 447 vm.mapPoints(&center, 1);
586 SkScalar ellipseXRadius = SkScalarHalf(ellipse.width()); 448 SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
587 SkScalar ellipseYRadius = SkScalarHalf(ellipse.height()); 449 SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
588 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*ellipseXRadius + 450 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*ellipseXRadius +
589 vm[SkMatrix::kMSkewY]*ellipseYRadius); 451 vm[SkMatrix::kMSkewY]*ellipseYRadius);
590 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*ellipseXRadius + 452 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*ellipseXRadius +
591 vm[SkMatrix::kMScaleY]*ellipseYRadius); 453 vm[SkMatrix::kMScaleY]*ellipseYRadius);
592 if (SkScalarDiv(xRadius, yRadius) > 2 || SkScalarDiv(yRadius, xRadius) > 2) {
593 return false;
594 }
595 454
596 // do (potentially) anisotropic mapping of stroke 455 // do (potentially) anisotropic mapping of stroke
597 SkVector scaledStroke; 456 SkVector scaledStroke;
598 SkScalar strokeWidth = stroke.getWidth(); 457 SkScalar strokeWidth = stroke.getWidth();
599 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat rix::kMSkewY])); 458 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat rix::kMSkewY]));
600 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr ix::kMScaleY])); 459 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr ix::kMScaleY]));
601 460
461 SkStrokeRec::Style style = stroke.getStyle();
462 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style);
463
464 SkScalar innerXRadius = 0.0f;
465 SkScalar innerYRadius = 0.0f;
466 if (SkStrokeRec::kFill_Style != style) {
467 if (SkScalarNearlyZero(scaledStroke.length())) {
468 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
469 } else {
470 scaledStroke.scale(SK_ScalarHalf);
471 }
472
473 // we only handle thick strokes for near-circular ellipses
474 if (scaledStroke.length() > SK_ScalarHalf &&
475 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius) ) {
476 return false;
477 }
478
479 // we don't handle it if curvature of the stroke is less than curvature of the ellipse
480 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY )*xRadius ||
481 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX )*yRadius) {
482 return false;
483 }
484
485 // this is legit only if scale & translation (which should be the case a t the moment)
486 if (isStroked) {
487 innerXRadius = xRadius - scaledStroke.fX;
488 innerYRadius = yRadius - scaledStroke.fY;
489 isStroked = (innerXRadius > 0 && innerYRadius > 0);
490 }
491
492 xRadius += scaledStroke.fX;
493 yRadius += scaledStroke.fY;
494 }
495
602 GrDrawState::AutoDeviceCoordDraw adcd(drawState); 496 GrDrawState::AutoDeviceCoordDraw adcd(drawState);
603 if (!adcd.succeeded()) { 497 if (!adcd.succeeded()) {
604 return false; 498 return false;
605 } 499 }
606 500
607 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVe rtexAttribs)); 501 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVe rtexAttribs));
608 GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize()); 502 GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize());
609 503
610 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); 504 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
611 if (!geo.succeeded()) { 505 if (!geo.succeeded()) {
612 GrPrintf("Failed to get space for vertices!\n"); 506 GrPrintf("Failed to get space for vertices!\n");
613 return false; 507 return false;
614 } 508 }
615 509
616 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); 510 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
617 511
618 SkStrokeRec::Style style = stroke.getStyle();
619 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style);
620 enum { 512 enum {
621 // the edge effects share this stage with glyph rendering 513 // the edge effects share this stage with glyph rendering
622 // (kGlyphMaskStage in GrTextContext) && SW path rendering 514 // (kGlyphMaskStage in GrTextContext) && SW path rendering
623 // (kPathMaskStage in GrSWMaskHelper) 515 // (kPathMaskStage in GrSWMaskHelper)
624 kEdgeEffectStage = GrPaint::kTotalStages, 516 kEdgeEffectStage = GrPaint::kTotalStages,
625 }; 517 };
518 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked);
626 519
627 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked);
628 static const int kEllipseCenterAttrIndex = 1; 520 static const int kEllipseCenterAttrIndex = 1;
629 static const int kEllipseEdgeAttrIndex = 2; 521 static const int kEllipseEdgeAttrIndex = 2;
630 drawState->setEffect(kEdgeEffectStage, effect, 522 drawState->setEffect(kEdgeEffectStage, effect,
631 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref( ); 523 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref( );
632 524
633 SkScalar innerXRadius = 0.0f; 525 // Compute the reciprocals of the radii here to save time in the shader
634 SkScalar innerRatio = 1.0f; 526 SkScalar xRadRecip = SkScalarInvert(xRadius);
635 527 SkScalar yRadRecip = SkScalarInvert(yRadius);
636 if (SkStrokeRec::kFill_Style != style) { 528 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius);
637 if (SkScalarNearlyZero(scaledStroke.length())) { 529 SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius);
638 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
639 } else {
640 scaledStroke.scale(0.5f);
641 }
642
643 // this is legit only if scale & translation (which should be the case a t the moment)
644 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) {
645 SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY);
646 if (innerYRadius > SK_ScalarNearlyZero) {
647 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX);
648 innerRatio = innerXRadius/innerYRadius;
649 }
650 }
651 xRadius += scaledStroke.fX;
652 yRadius += scaledStroke.fY;
653 }
654
655 SkScalar outerRatio = SkScalarDiv(xRadius, yRadius);
656 530
657 // We've extended the outer x radius out half a pixel to antialias. 531 // We've extended the outer x radius out half a pixel to antialias.
658 // This will also expand the rect so all the pixels will be captured. 532 // This will also expand the rect so all the pixels will be captured.
533 // TODO: Consider if we should use sqrt(2)/2 instead
659 xRadius += SK_ScalarHalf; 534 xRadius += SK_ScalarHalf;
660 yRadius += SK_ScalarHalf; 535 yRadius += SK_ScalarHalf;
661 innerXRadius -= SK_ScalarHalf;
662 536
663 SkRect bounds = SkRect::MakeLTRB( 537 SkRect bounds = SkRect::MakeLTRB(
664 center.fX - xRadius, 538 center.fX - xRadius,
665 center.fY - yRadius, 539 center.fY - yRadius,
666 center.fX + xRadius, 540 center.fX + xRadius,
667 center.fY + yRadius 541 center.fY + yRadius
668 ); 542 );
669 543
670 // The offsets are created by scaling the y radius by the appropriate ratio. This way we end up
671 // with a circle equation which can be checked quickly in the shader. We nee d one offset for
672 // outer and one for inner because they have different scale factors -- othe rwise we end up with
673 // non-uniform strokes.
674 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); 544 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
675 verts[0].fOuterXRadius = xRadius; 545 verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius);
676 verts[0].fInnerXRadius = innerXRadius; 546 verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
677 verts[0].fOuterOffset = SkPoint::Make(-xRadius, -outerRatio*yRadius); 547 verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
678 verts[0].fInnerOffset = SkPoint::Make(-xRadius, -innerRatio*yRadius);
679 548
680 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); 549 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
681 verts[1].fOuterXRadius = xRadius; 550 verts[1].fOffset = SkPoint::Make(xRadius, -yRadius);
682 verts[1].fInnerXRadius = innerXRadius; 551 verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
683 verts[1].fOuterOffset = SkPoint::Make(xRadius, -outerRatio*yRadius); 552 verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
684 verts[1].fInnerOffset = SkPoint::Make(xRadius, -innerRatio*yRadius);
685 553
686 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); 554 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
687 verts[2].fOuterXRadius = xRadius; 555 verts[2].fOffset = SkPoint::Make(-xRadius, yRadius);
688 verts[2].fInnerXRadius = innerXRadius; 556 verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
689 verts[2].fOuterOffset = SkPoint::Make(-xRadius, outerRatio*yRadius); 557 verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
690 verts[2].fInnerOffset = SkPoint::Make(-xRadius, innerRatio*yRadius);
691 558
692 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); 559 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
693 verts[3].fOuterXRadius = xRadius; 560 verts[3].fOffset = SkPoint::Make(xRadius, yRadius);
694 verts[3].fInnerXRadius = innerXRadius; 561 verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
695 verts[3].fOuterOffset = SkPoint::Make(xRadius, outerRatio*yRadius); 562 verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
696 verts[3].fInnerOffset = SkPoint::Make(xRadius, innerRatio*yRadius);
697 563
698 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); 564 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
699 565
700 return true; 566 return true;
701 } 567 }
702 568
703 /////////////////////////////////////////////////////////////////////////////// 569 ///////////////////////////////////////////////////////////////////////////////
704 570
705 static const uint16_t gRRectIndices[] = { 571 static const uint16_t gRRectIndices[] = {
706 // corners 572 // corners
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
756 // do any matrix crunching before we reset the draw state for device coords 622 // do any matrix crunching before we reset the draw state for device coords
757 const SkRect& rrectBounds = rrect.getBounds(); 623 const SkRect& rrectBounds = rrect.getBounds();
758 SkRect bounds; 624 SkRect bounds;
759 vm.mapRect(&bounds, rrectBounds); 625 vm.mapRect(&bounds, rrectBounds);
760 626
761 SkVector radii = rrect.getSimpleRadii(); 627 SkVector radii = rrect.getSimpleRadii();
762 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX + 628 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX +
763 vm[SkMatrix::kMSkewY]*radii.fY); 629 vm[SkMatrix::kMSkewY]*radii.fY);
764 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX + 630 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX +
765 vm[SkMatrix::kMScaleY]*radii.fY); 631 vm[SkMatrix::kMScaleY]*radii.fY);
766 // tall or wide quarter-ellipse corners aren't handled 632
767 if (SkScalarDiv(xRadius, yRadius) > 2 || SkScalarDiv(yRadius, xRadius) > 2) {
768 return false;
769 }
770 // if hairline stroke is greater than radius, we don't handle that right now 633 // if hairline stroke is greater than radius, we don't handle that right now
771 SkStrokeRec::Style style = stroke.getStyle(); 634 SkStrokeRec::Style style = stroke.getStyle();
772 if (SkStrokeRec::kHairline_Style == style && 635 if (SkStrokeRec::kHairline_Style == style &&
773 (SK_ScalarHalf >= xRadius || SK_ScalarHalf >= yRadius)) { 636 (SK_ScalarHalf >= xRadius || SK_ScalarHalf >= yRadius)) {
774 return false; 637 return false;
775 } 638 }
776 639
777 // do (potentially) anisotropic mapping of stroke 640 // do (potentially) anisotropic mapping of stroke
778 SkVector scaledStroke; 641 SkVector scaledStroke;
779 SkScalar strokeWidth = stroke.getWidth(); 642 SkScalar strokeWidth = stroke.getWidth();
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
812 drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircle VertexAttribs)); 675 drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircle VertexAttribs));
813 GrAssert(sizeof(CircleVertex) == drawState->getVertexSize()); 676 GrAssert(sizeof(CircleVertex) == drawState->getVertexSize());
814 677
815 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); 678 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
816 if (!geo.succeeded()) { 679 if (!geo.succeeded()) {
817 GrPrintf("Failed to get space for vertices!\n"); 680 GrPrintf("Failed to get space for vertices!\n");
818 return false; 681 return false;
819 } 682 }
820 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); 683 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
821 684
822 GrEffectRef* effect = CircleEdgeEffect::Create(isStroked);
823 static const int kCircleEdgeAttrIndex = 1;
824 drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->un ref();
825
826 SkScalar innerRadius = 0.0f; 685 SkScalar innerRadius = 0.0f;
827 SkScalar outerRadius = xRadius; 686 SkScalar outerRadius = xRadius;
828 SkScalar halfWidth = 0; 687 SkScalar halfWidth = 0;
829 if (style != SkStrokeRec::kFill_Style) { 688 if (style != SkStrokeRec::kFill_Style) {
830 if (SkScalarNearlyZero(scaledStroke.fX)) { 689 if (SkScalarNearlyZero(scaledStroke.fX)) {
831 halfWidth = SK_ScalarHalf; 690 halfWidth = SK_ScalarHalf;
832 } else { 691 } else {
833 halfWidth = SkScalarHalf(scaledStroke.fX); 692 halfWidth = SkScalarHalf(scaledStroke.fX);
834 } 693 }
835 694
836 if (isStroked) { 695 if (isStroked) {
837 innerRadius = SkMaxScalar(0, xRadius - halfWidth); 696 innerRadius = xRadius - halfWidth;
697 isStroked = (innerRadius > 0);
838 } 698 }
839 outerRadius += halfWidth; 699 outerRadius += halfWidth;
840 bounds.outset(halfWidth, halfWidth); 700 bounds.outset(halfWidth, halfWidth);
841 } 701 }
842 702
703 GrEffectRef* effect = CircleEdgeEffect::Create(isStroked);
704 static const int kCircleEdgeAttrIndex = 1;
705 drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->un ref();
706
843 // The radii are outset for two reasons. First, it allows the shader to simply perform 707 // The radii are outset for two reasons. First, it allows the shader to simply perform
844 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the 708 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the
845 // verts of the bounding box that is rendered and the outset ensures the box will cover all 709 // verts of the bounding box that is rendered and the outset ensures the box will cover all
846 // pixels partially covered by the circle. 710 // pixels partially covered by the circle.
847 outerRadius += SK_ScalarHalf; 711 outerRadius += SK_ScalarHalf;
848 innerRadius -= SK_ScalarHalf; 712 innerRadius -= SK_ScalarHalf;
849 713
850 // Expand the rect so all the pixels will be captured. 714 // Expand the rect so all the pixels will be captured.
851 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); 715 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
852 716
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
886 verts->fOuterRadius = outerRadius; 750 verts->fOuterRadius = outerRadius;
887 verts->fInnerRadius = innerRadius; 751 verts->fInnerRadius = innerRadius;
888 verts++; 752 verts++;
889 } 753 }
890 754
891 // drop out the middle quad if we're stroked 755 // drop out the middle quad if we're stroked
892 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO UNT(gRRectIndices); 756 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO UNT(gRRectIndices);
893 target->setIndexSourceToBuffer(indexBuffer); 757 target->setIndexSourceToBuffer(indexBuffer);
894 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds); 758 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds);
895 759
896 // otherwise we use the special ellipse renderer 760 // otherwise we use the ellipse renderer
897 } else { 761 } else {
762 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllip seVertexAttribs));
763 GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize());
898 764
899 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllip seVertexAttribs)); 765 SkScalar innerXRadius = 0.0f;
900 GrAssert(sizeof(RRectVertex) == drawState->getVertexSize()); 766 SkScalar innerYRadius = 0.0f;
767 if (SkStrokeRec::kFill_Style != style) {
768 if (SkScalarNearlyZero(scaledStroke.length())) {
769 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
770 } else {
771 scaledStroke.scale(SK_ScalarHalf);
772 }
773
774 // we only handle thick strokes for near-circular ellipses
775 if (scaledStroke.length() > SK_ScalarHalf &&
776 (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRad ius)) {
777 return false;
778 }
779
780 // we don't handle it if curvature of the stroke is less than curvat ure of the ellipse
781 if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStrok e.fY)*xRadius ||
782 scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStrok e.fX)*yRadius) {
783 return false;
784 }
785
786 // this is legit only if scale & translation (which should be the ca se at the moment)
787 if (isStroked) {
788 innerXRadius = xRadius - scaledStroke.fX;
789 innerYRadius = yRadius - scaledStroke.fY;
790 isStroked = (innerXRadius > 0 && innerYRadius > 0);
791 }
792
793 xRadius += scaledStroke.fX;
794 yRadius += scaledStroke.fY;
795 bounds.outset(scaledStroke.fX, scaledStroke.fY);
796 }
901 797
902 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); 798 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
903 if (!geo.succeeded()) { 799 if (!geo.succeeded()) {
904 GrPrintf("Failed to get space for vertices!\n"); 800 GrPrintf("Failed to get space for vertices!\n");
905 return false; 801 return false;
906 } 802 }
907 RRectVertex* verts = reinterpret_cast<RRectVertex*>(geo.vertices()); 803 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
908 804
909 GrEffectRef* effect = AltEllipseEdgeEffect::Create(isStroked); 805 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked);
910 static const int kEllipseOffsetAttrIndex = 1; 806 static const int kEllipseOffsetAttrIndex = 1;
911 static const int kEllipseRadiiAttrIndex = 2; 807 static const int kEllipseRadiiAttrIndex = 2;
912 drawState->setEffect(kEdgeEffectStage, effect, 808 drawState->setEffect(kEdgeEffectStage, effect,
913 kEllipseOffsetAttrIndex, kEllipseRadiiAttrIndex)->u nref(); 809 kEllipseOffsetAttrIndex, kEllipseRadiiAttrIndex)->u nref();
914 810
915 SkScalar innerXRadius = 0.0f; 811 // Compute the reciprocals of the radii here to save time in the shader
916 SkScalar innerYRadius = 0.0f; 812 SkScalar xRadRecip = SkScalarInvert(xRadius);
917 813 SkScalar yRadRecip = SkScalarInvert(yRadius);
918 if (SkStrokeRec::kFill_Style != style) { 814 SkScalar xInnerRadRecip = SkScalarInvert(innerXRadius);
919 if (SkScalarNearlyZero(scaledStroke.length())) { 815 SkScalar yInnerRadRecip = SkScalarInvert(innerYRadius);
920 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
921 } else {
922 scaledStroke.scale(0.5f);
923 }
924
925 // this is legit only if scale & translation (which should be the ca se at the moment)
926 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_St yle == style) {
927 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX);
928 innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY);
929 }
930 xRadius += scaledStroke.fX;
931 yRadius += scaledStroke.fY;
932 bounds.outset(scaledStroke.fX, scaledStroke.fY);
933 }
934 816
935 // Extend the radii out half a pixel to antialias. 817 // Extend the radii out half a pixel to antialias.
936 SkScalar xOuterRadius = xRadius + SK_ScalarHalf; 818 SkScalar xOuterRadius = xRadius + SK_ScalarHalf;
937 SkScalar yOuterRadius = yRadius + SK_ScalarHalf; 819 SkScalar yOuterRadius = yRadius + SK_ScalarHalf;
938 SkScalar xInnerRadius = SkMaxScalar(innerXRadius - SK_ScalarHalf, 0);
939 SkScalar yInnerRadius = SkMaxScalar(innerYRadius - SK_ScalarHalf, 0);
940 820
941 // Expand the rect so all the pixels will be captured. 821 // Expand the rect so all the pixels will be captured.
942 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); 822 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
943 823
944 SkScalar yCoords[4] = { 824 SkScalar yCoords[4] = {
945 bounds.fTop, 825 bounds.fTop,
946 bounds.fTop + yOuterRadius, 826 bounds.fTop + yOuterRadius,
947 bounds.fBottom - yOuterRadius, 827 bounds.fBottom - yOuterRadius,
948 bounds.fBottom 828 bounds.fBottom
949 }; 829 };
950 SkScalar yOuterOffsets[4] = { 830 SkScalar yOuterOffsets[4] = {
951 -yOuterRadius, 831 -yOuterRadius,
952 SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so can't be exactly 0 832 SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so can't be exactly 0
953 SK_ScalarNearlyZero, 833 SK_ScalarNearlyZero,
954 yOuterRadius 834 yOuterRadius
955 }; 835 };
956 836
957 SkScalar recipOuterX = SK_Scalar1/xOuterRadius;
958 SkScalar recipOuterY = SK_Scalar1/yOuterRadius;
959 SkScalar recipInnerX = SK_Scalar1/xInnerRadius;
960 SkScalar recipInnerY = SK_Scalar1/yInnerRadius;
961
962 for (int i = 0; i < 4; ++i) { 837 for (int i = 0; i < 4; ++i) {
963 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); 838 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
964 verts->fOffset = SkPoint::Make(-xOuterRadius, yOuterOffsets[i]); 839 verts->fOffset = SkPoint::Make(-xOuterRadius, yOuterOffsets[i]);
965 verts->fOuterRadii = SkPoint::Make(recipOuterX, recipOuterY); 840 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
966 verts->fInnerRadii = SkPoint::Make(recipInnerX, recipInnerY); 841 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
967 verts++; 842 verts++;
968 843
969 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]) ; 844 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]) ;
970 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] ); 845 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] );
971 verts->fOuterRadii = SkPoint::Make(recipOuterX, recipOuterY); 846 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
972 verts->fInnerRadii = SkPoint::Make(recipInnerX, recipInnerY); 847 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
973 verts++; 848 verts++;
974 849
975 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i] ); 850 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i] );
976 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] ); 851 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] );
977 verts->fOuterRadii = SkPoint::Make(recipOuterX, recipOuterY); 852 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
978 verts->fInnerRadii = SkPoint::Make(recipInnerX, recipInnerY); 853 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
979 verts++; 854 verts++;
980 855
981 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); 856 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
982 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]); 857 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
983 verts->fOuterRadii = SkPoint::Make(recipOuterX, recipOuterY); 858 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip);
984 verts->fInnerRadii = SkPoint::Make(recipInnerX, recipInnerY); 859 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip);
985 verts++; 860 verts++;
986 } 861 }
987 862
988 // drop out the middle quad if we're stroked 863 // drop out the middle quad if we're stroked
989 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO UNT(gRRectIndices); 864 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO UNT(gRRectIndices);
990 target->setIndexSourceToBuffer(indexBuffer); 865 target->setIndexSourceToBuffer(indexBuffer);
991 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds); 866 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds);
992 } 867 }
993 868
994 return true; 869 return true;
995 } 870 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698