Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 582 // do any matrix crunching before we reset the draw state for device coords | 443 // do any matrix crunching before we reset the draw state for device coords |
| 583 const SkMatrix& vm = drawState->getViewMatrix(); | 444 const SkMatrix& vm = drawState->getViewMatrix(); |
| 584 GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY()); | 445 GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY()); |
| 585 vm.mapPoints(¢er, 1); | 446 vm.mapPoints(¢er, 1); |
| 586 SkScalar ellipseXRadius = SkScalarHalf(ellipse.width()); | 447 SkScalar ellipseXRadius = SkScalarHalf(ellipse.width()); |
| 587 SkScalar ellipseYRadius = SkScalarHalf(ellipse.height()); | 448 SkScalar ellipseYRadius = SkScalarHalf(ellipse.height()); |
| 588 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*ellipseXRadius + | 449 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*ellipseXRadius + |
| 589 vm[SkMatrix::kMSkewY]*ellipseYRadius); | 450 vm[SkMatrix::kMSkewY]*ellipseYRadius); |
| 590 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*ellipseXRadius + | 451 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*ellipseXRadius + |
| 591 vm[SkMatrix::kMScaleY]*ellipseYRadius); | 452 vm[SkMatrix::kMScaleY]*ellipseYRadius); |
| 592 if (SkScalarDiv(xRadius, yRadius) > 2 || SkScalarDiv(yRadius, xRadius) > 2) { | |
| 593 return false; | |
| 594 } | |
| 595 | 453 |
| 596 // do (potentially) anisotropic mapping of stroke | 454 // do (potentially) anisotropic mapping of stroke |
| 597 SkVector scaledStroke; | 455 SkVector scaledStroke; |
| 598 SkScalar strokeWidth = stroke.getWidth(); | 456 SkScalar strokeWidth = stroke.getWidth(); |
| 599 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat rix::kMSkewY])); | 457 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat rix::kMSkewY])); |
| 600 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr ix::kMScaleY])); | 458 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr ix::kMScaleY])); |
| 601 | 459 |
| 460 SkStrokeRec::Style style = stroke.getStyle(); | |
| 461 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style); | |
| 462 | |
| 463 SkScalar innerXRadius = 0.0f; | |
| 464 SkScalar innerYRadius = 0.0f; | |
| 465 if (SkStrokeRec::kFill_Style != style) { | |
| 466 if (SkScalarNearlyZero(scaledStroke.length())) { | |
| 467 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); | |
| 468 } else { | |
| 469 scaledStroke.scale(0.5f); | |
| 470 } | |
| 471 | |
| 472 // we only handle thick strokes for near-circular ellipses | |
| 473 if (scaledStroke.length() > SK_ScalarHalf && (xRadius/yRadius > 2 || yRa dius/xRadius > 2)) { | |
| 474 return false; | |
| 475 } | |
| 476 | |
| 477 // we don't handle it if curvature of the stroke is less than curvature of the ellipse | |
|
robertphillips
2013/05/14 22:44:30
The compiler should do this - but rejigger to remo
jvanverth1
2013/05/15 18:34:12
Good catch, thanks.
| |
| 478 if (scaledStroke.fX/(scaledStroke.fY*scaledStroke.fY) < xRadius/(yRadius *yRadius) || | |
| 479 scaledStroke.fY/(scaledStroke.fX*scaledStroke.fX) < yRadius/(xRadius *xRadius)) { | |
| 480 return false; | |
| 481 } | |
| 482 | |
| 483 // this is legit only if scale & translation (which should be the case a t the moment) | |
|
robertphillips
2013/05/14 22:44:30
isn't this if test redundant since we're in this b
jvanverth1
2013/05/15 18:34:12
No, because it could also be stroked and filled. H
| |
| 484 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) { | |
|
robertphillips
2013/05/14 22:44:30
Do innerXRadius first to match xRadius/yRadius ord
jvanverth1
2013/05/15 18:34:12
Done.
| |
| 485 innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); | |
| 486 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX); | |
| 487 } | |
| 488 | |
| 489 xRadius += scaledStroke.fX; | |
| 490 yRadius += scaledStroke.fY; | |
| 491 } | |
| 492 | |
| 602 GrDrawState::AutoDeviceCoordDraw adcd(drawState); | 493 GrDrawState::AutoDeviceCoordDraw adcd(drawState); |
| 603 if (!adcd.succeeded()) { | 494 if (!adcd.succeeded()) { |
| 604 return false; | 495 return false; |
| 605 } | 496 } |
| 606 | 497 |
| 607 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVe rtexAttribs)); | 498 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllipseVe rtexAttribs)); |
| 608 GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize()); | 499 GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize()); |
| 609 | 500 |
| 610 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); | 501 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); |
| 611 if (!geo.succeeded()) { | 502 if (!geo.succeeded()) { |
| 612 GrPrintf("Failed to get space for vertices!\n"); | 503 GrPrintf("Failed to get space for vertices!\n"); |
| 613 return false; | 504 return false; |
| 614 } | 505 } |
| 615 | 506 |
| 616 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); | 507 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); |
| 617 | 508 |
| 618 SkStrokeRec::Style style = stroke.getStyle(); | |
| 619 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style); | |
| 620 enum { | 509 enum { |
| 621 // the edge effects share this stage with glyph rendering | 510 // the edge effects share this stage with glyph rendering |
| 622 // (kGlyphMaskStage in GrTextContext) && SW path rendering | 511 // (kGlyphMaskStage in GrTextContext) && SW path rendering |
| 623 // (kPathMaskStage in GrSWMaskHelper) | 512 // (kPathMaskStage in GrSWMaskHelper) |
| 624 kEdgeEffectStage = GrPaint::kTotalStages, | 513 kEdgeEffectStage = GrPaint::kTotalStages, |
| 625 }; | 514 }; |
| 515 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked && | |
| 516 innerXRadius > 0.0 && innerY Radius > 0.0); | |
| 626 | 517 |
| 627 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked); | |
| 628 static const int kEllipseCenterAttrIndex = 1; | 518 static const int kEllipseCenterAttrIndex = 1; |
| 629 static const int kEllipseEdgeAttrIndex = 2; | 519 static const int kEllipseEdgeAttrIndex = 2; |
| 630 drawState->setEffect(kEdgeEffectStage, effect, | 520 drawState->setEffect(kEdgeEffectStage, effect, |
| 631 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref( ); | 521 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref( ); |
| 632 | 522 |
| 633 SkScalar innerXRadius = 0.0f; | 523 // Compute the reciprocals of the squares of the radii here to save time in the shader |
|
robertphillips
2013/05/14 22:44:30
I think there is a scalar macro for this
jvanverth1
2013/05/15 18:34:12
Done.
| |
| 634 SkScalar innerRatio = 1.0f; | 524 SkScalar xRadRecip = SK_Scalar1/xRadius; |
| 635 | 525 SkScalar yRadRecip = SK_Scalar1/yRadius; |
|
robertphillips
2013/05/14 22:44:30
What happens when innerXRadius is zero?
jvanverth1
2013/05/15 18:34:12
Added a check above. If it's zero, then we'll use
| |
| 636 if (SkStrokeRec::kFill_Style != style) { | 526 SkScalar xInnerRadRecip = SK_Scalar1/innerXRadius; |
| 637 if (SkScalarNearlyZero(scaledStroke.length())) { | 527 SkScalar yInnerRadRecip = SK_Scalar1/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 | 528 |
| 657 // We've extended the outer x radius out half a pixel to antialias. | 529 // 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. | 530 // This will also expand the rect so all the pixels will be captured. |
| 531 // TODO: Consider if we should use sqrt(2)/2 instead | |
| 659 xRadius += SK_ScalarHalf; | 532 xRadius += SK_ScalarHalf; |
| 660 yRadius += SK_ScalarHalf; | 533 yRadius += SK_ScalarHalf; |
| 661 innerXRadius -= SK_ScalarHalf; | |
| 662 | 534 |
| 663 SkRect bounds = SkRect::MakeLTRB( | 535 SkRect bounds = SkRect::MakeLTRB( |
| 664 center.fX - xRadius, | 536 center.fX - xRadius, |
| 665 center.fY - yRadius, | 537 center.fY - yRadius, |
| 666 center.fX + xRadius, | 538 center.fX + xRadius, |
| 667 center.fY + yRadius | 539 center.fY + yRadius |
| 668 ); | 540 ); |
| 669 | 541 |
| 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); | 542 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); |
| 675 verts[0].fOuterXRadius = xRadius; | 543 verts[0].fOffset = SkPoint::Make(-xRadius, -yRadius); |
| 676 verts[0].fInnerXRadius = innerXRadius; | 544 verts[0].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
| 677 verts[0].fOuterOffset = SkPoint::Make(-xRadius, -outerRatio*yRadius); | 545 verts[0].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
| 678 verts[0].fInnerOffset = SkPoint::Make(-xRadius, -innerRatio*yRadius); | |
| 679 | 546 |
| 680 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); | 547 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); |
| 681 verts[1].fOuterXRadius = xRadius; | 548 verts[1].fOffset = SkPoint::Make(xRadius, -yRadius); |
| 682 verts[1].fInnerXRadius = innerXRadius; | 549 verts[1].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
| 683 verts[1].fOuterOffset = SkPoint::Make(xRadius, -outerRatio*yRadius); | 550 verts[1].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
| 684 verts[1].fInnerOffset = SkPoint::Make(xRadius, -innerRatio*yRadius); | |
| 685 | 551 |
| 686 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); | 552 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); |
| 687 verts[2].fOuterXRadius = xRadius; | 553 verts[2].fOffset = SkPoint::Make(-xRadius, yRadius); |
| 688 verts[2].fInnerXRadius = innerXRadius; | 554 verts[2].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
| 689 verts[2].fOuterOffset = SkPoint::Make(-xRadius, outerRatio*yRadius); | 555 verts[2].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
| 690 verts[2].fInnerOffset = SkPoint::Make(-xRadius, innerRatio*yRadius); | |
| 691 | 556 |
| 692 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); | 557 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); |
| 693 verts[3].fOuterXRadius = xRadius; | 558 verts[3].fOffset = SkPoint::Make(xRadius, yRadius); |
| 694 verts[3].fInnerXRadius = innerXRadius; | 559 verts[3].fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
| 695 verts[3].fOuterOffset = SkPoint::Make(xRadius, outerRatio*yRadius); | 560 verts[3].fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
| 696 verts[3].fInnerOffset = SkPoint::Make(xRadius, innerRatio*yRadius); | |
| 697 | 561 |
| 698 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); | 562 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); |
| 699 | 563 |
| 700 return true; | 564 return true; |
| 701 } | 565 } |
| 702 | 566 |
| 703 /////////////////////////////////////////////////////////////////////////////// | 567 /////////////////////////////////////////////////////////////////////////////// |
| 704 | 568 |
| 705 static const uint16_t gRRectIndices[] = { | 569 static const uint16_t gRRectIndices[] = { |
| 706 // corners | 570 // corners |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 // do any matrix crunching before we reset the draw state for device coords | 620 // do any matrix crunching before we reset the draw state for device coords |
| 757 const SkRect& rrectBounds = rrect.getBounds(); | 621 const SkRect& rrectBounds = rrect.getBounds(); |
| 758 SkRect bounds; | 622 SkRect bounds; |
| 759 vm.mapRect(&bounds, rrectBounds); | 623 vm.mapRect(&bounds, rrectBounds); |
| 760 | 624 |
| 761 SkVector radii = rrect.getSimpleRadii(); | 625 SkVector radii = rrect.getSimpleRadii(); |
| 762 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX + | 626 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX + |
| 763 vm[SkMatrix::kMSkewY]*radii.fY); | 627 vm[SkMatrix::kMSkewY]*radii.fY); |
| 764 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX + | 628 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX + |
| 765 vm[SkMatrix::kMScaleY]*radii.fY); | 629 vm[SkMatrix::kMScaleY]*radii.fY); |
| 766 // tall or wide quarter-ellipse corners aren't handled | 630 |
| 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 | 631 // if hairline stroke is greater than radius, we don't handle that right now |
| 771 SkStrokeRec::Style style = stroke.getStyle(); | 632 SkStrokeRec::Style style = stroke.getStyle(); |
| 772 if (SkStrokeRec::kHairline_Style == style && | 633 if (SkStrokeRec::kHairline_Style == style && |
| 773 (SK_ScalarHalf >= xRadius || SK_ScalarHalf >= yRadius)) { | 634 (SK_ScalarHalf >= xRadius || SK_ScalarHalf >= yRadius)) { |
| 774 return false; | 635 return false; |
| 775 } | 636 } |
| 776 | 637 |
| 777 // do (potentially) anisotropic mapping of stroke | 638 // do (potentially) anisotropic mapping of stroke |
| 778 SkVector scaledStroke; | 639 SkVector scaledStroke; |
| 779 SkScalar strokeWidth = stroke.getWidth(); | 640 SkScalar strokeWidth = stroke.getWidth(); |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 886 verts->fOuterRadius = outerRadius; | 747 verts->fOuterRadius = outerRadius; |
| 887 verts->fInnerRadius = innerRadius; | 748 verts->fInnerRadius = innerRadius; |
| 888 verts++; | 749 verts++; |
| 889 } | 750 } |
| 890 | 751 |
| 891 // drop out the middle quad if we're stroked | 752 // drop out the middle quad if we're stroked |
| 892 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO UNT(gRRectIndices); | 753 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO UNT(gRRectIndices); |
| 893 target->setIndexSourceToBuffer(indexBuffer); | 754 target->setIndexSourceToBuffer(indexBuffer); |
| 894 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds); | 755 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds); |
| 895 | 756 |
| 896 // otherwise we use the special ellipse renderer | 757 // otherwise we use the ellipse renderer |
| 897 } else { | 758 } else { |
| 898 | |
| 899 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllip seVertexAttribs)); | 759 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllip seVertexAttribs)); |
| 900 GrAssert(sizeof(RRectVertex) == drawState->getVertexSize()); | 760 GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize()); |
| 901 | |
| 902 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); | |
| 903 if (!geo.succeeded()) { | |
| 904 GrPrintf("Failed to get space for vertices!\n"); | |
| 905 return false; | |
| 906 } | |
| 907 RRectVertex* verts = reinterpret_cast<RRectVertex*>(geo.vertices()); | |
| 908 | |
| 909 GrEffectRef* effect = AltEllipseEdgeEffect::Create(isStroked); | |
| 910 static const int kEllipseOffsetAttrIndex = 1; | |
| 911 static const int kEllipseRadiiAttrIndex = 2; | |
| 912 drawState->setEffect(kEdgeEffectStage, effect, | |
| 913 kEllipseOffsetAttrIndex, kEllipseRadiiAttrIndex)->u nref(); | |
| 914 | 761 |
| 915 SkScalar innerXRadius = 0.0f; | 762 SkScalar innerXRadius = 0.0f; |
| 916 SkScalar innerYRadius = 0.0f; | 763 SkScalar innerYRadius = 0.0f; |
| 917 | |
| 918 if (SkStrokeRec::kFill_Style != style) { | 764 if (SkStrokeRec::kFill_Style != style) { |
| 919 if (SkScalarNearlyZero(scaledStroke.length())) { | 765 if (SkScalarNearlyZero(scaledStroke.length())) { |
| 920 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); | 766 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); |
| 921 } else { | 767 } else { |
| 922 scaledStroke.scale(0.5f); | 768 scaledStroke.scale(0.5f); |
| 923 } | 769 } |
| 924 | 770 |
| 771 // we only handle thick strokes for near-circular ellipses | |
| 772 if (scaledStroke.length() > SK_ScalarHalf && | |
| 773 (xRadius/yRadius > 2 || yRadius/xRadius > 2)) { | |
| 774 return false; | |
| 775 } | |
| 776 | |
| 777 // we don't handle it if curvature of the stroke is less than curvat ure of the ellipse | |
| 778 if (scaledStroke.fX/(scaledStroke.fY*scaledStroke.fY) < xRadius/(yRa dius*yRadius) || | |
| 779 scaledStroke.fY/(scaledStroke.fX*scaledStroke.fX) < yRadius/(xRa dius*xRadius)) { | |
| 780 return false; | |
| 781 } | |
| 782 | |
| 925 // this is legit only if scale & translation (which should be the ca se at the moment) | 783 // 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) { | 784 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_St yle == style) { |
| 927 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX); | 785 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX); |
| 928 innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); | 786 innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); |
| 929 } | 787 } |
| 930 xRadius += scaledStroke.fX; | 788 xRadius += scaledStroke.fX; |
| 931 yRadius += scaledStroke.fY; | 789 yRadius += scaledStroke.fY; |
| 932 bounds.outset(scaledStroke.fX, scaledStroke.fY); | 790 bounds.outset(scaledStroke.fX, scaledStroke.fY); |
| 933 } | 791 } |
| 934 | 792 |
| 793 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); | |
| 794 if (!geo.succeeded()) { | |
| 795 GrPrintf("Failed to get space for vertices!\n"); | |
| 796 return false; | |
| 797 } | |
| 798 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); | |
| 799 | |
| 800 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked); | |
| 801 static const int kEllipseOffsetAttrIndex = 1; | |
| 802 static const int kEllipseRadiiAttrIndex = 2; | |
| 803 drawState->setEffect(kEdgeEffectStage, effect, | |
| 804 kEllipseOffsetAttrIndex, kEllipseRadiiAttrIndex)->u nref(); | |
| 805 | |
| 806 // Compute the reciprocals of the radii here to save time in the shader | |
| 807 SkScalar xRadRecip = SK_Scalar1/xRadius; | |
| 808 SkScalar yRadRecip = SK_Scalar1/yRadius; | |
| 809 SkScalar xInnerRadRecip = SK_Scalar1/innerXRadius; | |
| 810 SkScalar yInnerRadRecip = SK_Scalar1/innerYRadius; | |
| 811 | |
| 935 // Extend the radii out half a pixel to antialias. | 812 // Extend the radii out half a pixel to antialias. |
| 936 SkScalar xOuterRadius = xRadius + SK_ScalarHalf; | 813 SkScalar xOuterRadius = xRadius + SK_ScalarHalf; |
| 937 SkScalar yOuterRadius = yRadius + SK_ScalarHalf; | 814 SkScalar yOuterRadius = yRadius + SK_ScalarHalf; |
| 938 SkScalar xInnerRadius = SkMaxScalar(innerXRadius - SK_ScalarHalf, 0); | |
| 939 SkScalar yInnerRadius = SkMaxScalar(innerYRadius - SK_ScalarHalf, 0); | |
| 940 | 815 |
| 941 // Expand the rect so all the pixels will be captured. | 816 // Expand the rect so all the pixels will be captured. |
| 942 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); | 817 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); |
| 943 | 818 |
| 944 SkScalar yCoords[4] = { | 819 SkScalar yCoords[4] = { |
| 945 bounds.fTop, | 820 bounds.fTop, |
| 946 bounds.fTop + yOuterRadius, | 821 bounds.fTop + yOuterRadius, |
| 947 bounds.fBottom - yOuterRadius, | 822 bounds.fBottom - yOuterRadius, |
| 948 bounds.fBottom | 823 bounds.fBottom |
| 949 }; | 824 }; |
| 950 SkScalar yOuterOffsets[4] = { | 825 SkScalar yOuterOffsets[4] = { |
| 951 -yOuterRadius, | 826 -yOuterRadius, |
| 952 SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so can't be exactly 0 | 827 SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so can't be exactly 0 |
| 953 SK_ScalarNearlyZero, | 828 SK_ScalarNearlyZero, |
| 954 yOuterRadius | 829 yOuterRadius |
| 955 }; | 830 }; |
| 956 | 831 |
| 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) { | 832 for (int i = 0; i < 4; ++i) { |
| 963 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); | 833 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); |
| 964 verts->fOffset = SkPoint::Make(-xOuterRadius, yOuterOffsets[i]); | 834 verts->fOffset = SkPoint::Make(-xOuterRadius, yOuterOffsets[i]); |
| 965 verts->fOuterRadii = SkPoint::Make(recipOuterX, recipOuterY); | 835 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
| 966 verts->fInnerRadii = SkPoint::Make(recipInnerX, recipInnerY); | 836 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
| 967 verts++; | 837 verts++; |
| 968 | 838 |
| 969 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]) ; | 839 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]) ; |
| 970 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] ); | 840 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] ); |
| 971 verts->fOuterRadii = SkPoint::Make(recipOuterX, recipOuterY); | 841 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
| 972 verts->fInnerRadii = SkPoint::Make(recipInnerX, recipInnerY); | 842 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
| 973 verts++; | 843 verts++; |
| 974 | 844 |
| 975 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i] ); | 845 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i] ); |
| 976 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] ); | 846 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] ); |
| 977 verts->fOuterRadii = SkPoint::Make(recipOuterX, recipOuterY); | 847 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
| 978 verts->fInnerRadii = SkPoint::Make(recipInnerX, recipInnerY); | 848 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
| 979 verts++; | 849 verts++; |
| 980 | 850 |
| 981 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); | 851 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); |
| 982 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]); | 852 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]); |
| 983 verts->fOuterRadii = SkPoint::Make(recipOuterX, recipOuterY); | 853 verts->fOuterRadii = SkPoint::Make(xRadRecip, yRadRecip); |
| 984 verts->fInnerRadii = SkPoint::Make(recipInnerX, recipInnerY); | 854 verts->fInnerRadii = SkPoint::Make(xInnerRadRecip, yInnerRadRecip); |
| 985 verts++; | 855 verts++; |
| 986 } | 856 } |
| 987 | 857 |
| 988 // drop out the middle quad if we're stroked | 858 // drop out the middle quad if we're stroked |
| 989 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO UNT(gRRectIndices); | 859 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO UNT(gRRectIndices); |
| 990 target->setIndexSourceToBuffer(indexBuffer); | 860 target->setIndexSourceToBuffer(indexBuffer); |
| 991 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds); | 861 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds); |
| 992 } | 862 } |
| 993 | 863 |
| 994 return true; | 864 return true; |
| 995 } | 865 } |
| OLD | NEW |