| 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 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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(¢er, 1); | 447 vm.mapPoints(¢er, 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |