1 /* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "GrRRectEffect.h" 9 10 #include "gl/GrGLEffect.h" 11 #include "gl/GrGLSL.h" 12 #include "GrConvexPolyEffect.h" 13 #include "GrOvalEffect.h" 14 #include "GrTBackendEffectFactory.h" 15 16 #include "SkRRect.h" 17 18 // The effects defined here only handle rrect radii >= kRadiusMin. 19 static const SkScalar kRadiusMin = SK_ScalarHalf; 20 21 ////////////////////////////////////////////////////////////////////////////// 22 23 class GLCircularRRectEffect; 24 25 class CircularRRectEffect : public GrEffect { 26 public: 27 28 enum CornerFlags { 29 kTopLeft_CornerFlag = (1 << SkRRect::kUpperLeft_Corner), 30 kTopRight_CornerFlag = (1 << SkRRect::kUpperRight_Corner), 31 kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner), 32 kBottomLeft_CornerFlag = (1 << SkRRect::kLowerLeft_Corner), 33 34 kLeft_CornerFlags = kTopLeft_CornerFlag | kBottomLeft_CornerFlag, 35 kTop_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag, 36 kRight_CornerFlags = kTopRight_CornerFlag | kBottomRight_CornerFlag, 37 kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag, 38 39 kAll_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag | 40 kBottomLeft_CornerFlag | kBottomRight_CornerFlag, 41 42 kNone_CornerFlags = 0 43 }; 44 45 // The flags are used to indicate which corners are circluar (unflagged corners are assumed to 46 // be square). 47 static GrEffectRef* Create(GrEffectEdgeType, uint32_t circularCornerFlags, const SkRRect&); 48 49 virtual ~CircularRRectEffect() {}; 50 static const char* Name() { return "CircularRRect"; } 51 52 const SkRRect& getRRect() const { return fRRect; } 53 54 uint32_t getCircularCornerFlags() const { return fCircularCornerFlags; } 55 56 GrEffectEdgeType getEdgeType() const { return fEdgeType; } 57 58 typedef GLCircularRRectEffect GLEffect; 59 60 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; 61 62 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; 63 64 private: 65 CircularRRectEffect(GrEffectEdgeType, uint32_t circularCornerFlags, const SkRRect&); 66 67 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE; 68 69 SkRRect fRRect; 70 GrEffectEdgeType fEdgeType; 71 uint32_t fCircularCornerFlags; 72 73 GR_DECLARE_EFFECT_TEST; 74 75 typedef GrEffect INHERITED; 76 }; 77 78 GrEffectRef* CircularRRectEffect::Create(GrEffectEdgeType edgeType, 79 uint32_t circularCornerFlags, 80 const SkRRect& rrect) { 81 if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) { 82 return NULL; 83 } 84 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircularRRectEffect, 85 (edgeType, circularCornerFlags, rrect)))); 86 } 87 88 void CircularRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { 89 *validFlags = 0; 90 } 91 92 const GrBackendEffectFactory& CircularRRectEffect::getFactory() const { 93 return GrTBackendEffectFactory<CircularRRectEffect>::getInstance(); 94 } 95 96 CircularRRectEffect::CircularRRectEffect(GrEffectEdgeType edgeType, uint32_t circularCornerFlags, 97 const SkRRect& rrect) 98 : fRRect(rrect) 99 , fEdgeType(edgeType) 100 , fCircularCornerFlags(circularCornerFlags) { 101 this->setWillReadFragmentPosition(); 102 } 103 104 bool CircularRRectEffect::onIsEqual(const GrEffect& other) const { 105 const CircularRRectEffect& crre = CastEffect<CircularRRectEffect>(other); 106 // The corner flags are derived from fRRect, so no need to check them. 107 return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect; 108 } 109 110 ////////////////////////////////////////////////////////////////////////////// 111 112 GR_DEFINE_EFFECT_TEST(CircularRRectEffect); 113 114 GrEffectRef* CircularRRectEffect::TestCreate(SkRandom* random, 115 GrContext*, 116 const GrDrawTargetCaps& caps, 117 GrTexture*[]) { 118 SkScalar w = random->nextRangeScalar(20.f, 1000.f); 119 SkScalar h = random->nextRangeScalar(20.f, 1000.f); 120 SkScalar r = random->nextRangeF(kRadiusMin, 9.f); 121 SkRRect rrect; 122 rrect.setRectXY(SkRect::MakeWH(w, h), r, r); 123 GrEffectRef* effect; 124 do { 125 GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt); 126 effect = GrRRectEffect::Create(et, rrect); 127 } while (NULL == effect); 128 return effect; 129 } 130 131 ////////////////////////////////////////////////////////////////////////////// 132 133 class GLCircularRRectEffect : public GrGLEffect { 134 public: 135 GLCircularRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&); 136 137 virtual void emitCode(GrGLShaderBuilder* builder, 138 const GrDrawEffect& drawEffect, 139 EffectKey key, 140 const char* outputColor, 141 const char* inputColor, 142 const TransformedCoordsArray&, 143 const TextureSamplerArray&) SK_OVERRIDE; 144 145 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); 146 147 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; 148 149 private: 150 GrGLUniformManager::UniformHandle fInnerRectUniform; 151 GrGLUniformManager::UniformHandle fRadiusPlusHalfUniform; 152 SkRRect fPrevRRect; 153 typedef GrGLEffect INHERITED; 154 }; 155 156 GLCircularRRectEffect::GLCircularRRectEffect(const GrBackendEffectFactory& factory, 157 const GrDrawEffect& drawEffect) 158 : INHERITED (factory) { 159 fPrevRRect.setEmpty(); 160 } 161 162 void GLCircularRRectEffect::emitCode(GrGLShaderBuilder* builder, 163 const GrDrawEffect& drawEffect, 164 EffectKey key, 165 const char* outputColor, 166 const char* inputColor, 167 const TransformedCoordsArray&, 168 const TextureSamplerArray& samplers) { 169 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>(); 170 const char *rectName; 171 const char *radiusPlusHalfName; 172 // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom 173 // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has 174 // only rectangular corners, that side's value corresponds to the rect edge's value outset by 175 // half a pixel. 176 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 177 kVec4f_GrSLType, 178 "innerRect", 179 &rectName); 180 fRadiusPlusHalfUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 181 kFloat_GrSLType, 182 "radiusPlusHalf", 183 &radiusPlusHalfName); 184 const char* fragmentPos = builder->fragmentPosition(); 185 // At each quarter-circle corner we compute a vector that is the offset of the fragment position 186 // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant 187 // to that corner. This means that points near the interior near the rrect top edge will have 188 // a vector that points straight up for both the TL left and TR corners. Computing an 189 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly, 190 // fragments near the other three edges will get the correct AA. Fragments in the interior of 191 // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will 192 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas. 193 // The code below is a simplified version of the above that performs maxs on the vector 194 // components before computing distances and alpha values so that only one distance computation 195 // need be computed to determine the min alpha. 196 // 197 // For the cases where one half of the rrect is rectangular we drop one of the x or y 198 // computations, compute a separate rect edge alpha for the rect side, and mul the two computed 199 // alphas together. 200 switch (crre.getCircularCornerFlags()) { 201 case CircularRRectEffect::kAll_CornerFlags: 202 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s;\n", rectName, fragmentPos); 203 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s - %s.zw;\n", fragmentPos, rectName); 204 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); 205 builder->fsCodeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n", 206 radiusPlusHalfName); 207 break; 208 case CircularRRectEffect::kTopLeft_CornerFlag: 209 builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n", 210 rectName, fragmentPos); 211 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n", 212 rectName, fragmentPos); 213 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n", 214 rectName, fragmentPos); 215 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 216 radiusPlusHalfName); 217 break; 218 case CircularRRectEffect::kTopRight_CornerFlag: 219 builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n", 220 fragmentPos, rectName, rectName, fragmentPos); 221 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n", 222 fragmentPos, rectName); 223 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n", 224 rectName, fragmentPos); 225 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 226 radiusPlusHalfName); 227 break; 228 case CircularRRectEffect::kBottomRight_CornerFlag: 229 builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n", 230 fragmentPos, rectName); 231 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n", 232 fragmentPos, rectName); 233 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", 234 fragmentPos, rectName); 235 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 236 radiusPlusHalfName); 237 break; 238 case CircularRRectEffect::kBottomLeft_CornerFlag: 239 builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n", 240 rectName, fragmentPos, fragmentPos, rectName); 241 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n", 242 rectName, fragmentPos); 243 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", 244 fragmentPos, rectName); 245 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 246 radiusPlusHalfName); 247 break; 248 case CircularRRectEffect::kLeft_CornerFlags: 249 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos); 250 builder->fsCodeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName); 251 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n"); 252 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n", 253 rectName, fragmentPos); 254 builder->fsCodeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 255 radiusPlusHalfName); 256 break; 257 case CircularRRectEffect::kTop_CornerFlags: 258 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos); 259 builder->fsCodeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName); 260 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n"); 261 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n", 262 rectName, fragmentPos); 263 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 264 radiusPlusHalfName); 265 break; 266 case CircularRRectEffect::kRight_CornerFlags: 267 builder->fsCodeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos); 268 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName); 269 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n"); 270 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n", 271 fragmentPos, rectName); 272 builder->fsCodeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 273 radiusPlusHalfName); 274 break; 275 case CircularRRectEffect::kBottom_CornerFlags: 276 builder->fsCodeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos); 277 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName); 278 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n"); 279 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", 280 fragmentPos, rectName); 281 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 282 radiusPlusHalfName); 283 break; 284 } 285 286 if (kInverseFillAA_GrEffectEdgeType == crre.getEdgeType()) { 287 builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n"); 288 } 289 290 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor, 291 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str()); 292 } 293 294 GrGLEffect::EffectKey GLCircularRRectEffect::GenKey(const GrDrawEffect& drawEffect, 295 const GrGLCaps&) { 296 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>(); 297 GR_STATIC_ASSERT(kGrEffectEdgeTypeCnt <= 8); 298 return (crre.getCircularCornerFlags() << 3) | crre.getEdgeType(); 299 } 300 301 void GLCircularRRectEffect::setData(const GrGLUniformManager& uman, 302 const GrDrawEffect& drawEffect) { 303 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>(); 304 const SkRRect& rrect = crre.getRRect(); 305 if (rrect != fPrevRRect) { 306 SkRect rect = rrect.getBounds(); 307 SkScalar radius = 0; 308 switch (crre.getCircularCornerFlags()) { 309 case CircularRRectEffect::kAll_CornerFlags: 310 SkASSERT(rrect.isSimpleCircular()); 311 radius = rrect.getSimpleRadii().fX; 312 SkASSERT(radius >= kRadiusMin); 313 rect.inset(radius, radius); 314 break; 315 case CircularRRectEffect::kTopLeft_CornerFlag: 316 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 317 rect.fLeft += radius; 318 rect.fTop += radius; 319 rect.fRight += 0.5f; 320 rect.fBottom += 0.5f; 321 break; 322 case CircularRRectEffect::kTopRight_CornerFlag: 323 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX; 324 rect.fLeft -= 0.5f; 325 rect.fTop += radius; 326 rect.fRight -= radius; 327 rect.fBottom += 0.5f; 328 break; 329 case CircularRRectEffect::kBottomRight_CornerFlag: 330 radius = rrect.radii(SkRRect::kLowerRight_Corner).fX; 331 rect.fLeft -= 0.5f; 332 rect.fTop -= 0.5f; 333 rect.fRight -= radius; 334 rect.fBottom -= radius; 335 break; 336 case CircularRRectEffect::kBottomLeft_CornerFlag: 337 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX; 338 rect.fLeft += radius; 339 rect.fTop -= 0.5f; 340 rect.fRight += 0.5f; 341 rect.fBottom -= radius; 342 break; 343 case CircularRRectEffect::kLeft_CornerFlags: 344 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 345 rect.fLeft += radius; 346 rect.fTop += radius; 347 rect.fRight += 0.5f; 348 rect.fBottom -= radius; 349 break; 350 case CircularRRectEffect::kTop_CornerFlags: 351 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 352 rect.fLeft += radius; 353 rect.fTop += radius; 354 rect.fRight -= radius; 355 rect.fBottom += 0.5f; 356 break; 357 case CircularRRectEffect::kRight_CornerFlags: 358 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX; 359 rect.fLeft -= 0.5f; 360 rect.fTop += radius; 361 rect.fRight -= radius; 362 rect.fBottom -= radius; 363 break; 364 case CircularRRectEffect::kBottom_CornerFlags: 365 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX; 366 rect.fLeft += radius; 367 rect.fTop -= 0.5f; 368 rect.fRight -= radius; 369 rect.fBottom -= radius; 370 break; 371 default: 372 SkFAIL("Should have been one of the above cases."); 373 } 374 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); 375 uman.set1f(fRadiusPlusHalfUniform, radius + 0.5f); 376 fPrevRRect = rrect; 377 } 378 } 379 380 ////////////////////////////////////////////////////////////////////////////// 381 382 class GLEllipticalRRectEffect; 383 384 class EllipticalRRectEffect : public GrEffect { 385 public: 386 static GrEffectRef* Create(GrEffectEdgeType, const SkRRect&); 387 388 virtual ~EllipticalRRectEffect() {}; 389 static const char* Name() { return "EllipticalRRect"; } 390 391 const SkRRect& getRRect() const { return fRRect; } 392 393 394 GrEffectEdgeType getEdgeType() const { return fEdgeType; } 395 396 typedef GLEllipticalRRectEffect GLEffect; 397 398 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; 399 400 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; 401 402 private: 403 EllipticalRRectEffect(GrEffectEdgeType, const SkRRect&); 404 405 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE; 406 407 SkRRect fRRect; 408 GrEffectEdgeType fEdgeType; 409 410 GR_DECLARE_EFFECT_TEST; 411 412 typedef GrEffect INHERITED; 413 }; 414 415 GrEffectRef* EllipticalRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) { 416 if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) { 417 return NULL; 418 } 419 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipticalRRectEffect, (edgeType, rrect)))); 420 } 421 422 void EllipticalRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { 423 *validFlags = 0; 424 } 425 426 const GrBackendEffectFactory& EllipticalRRectEffect::getFactory() const { 427 return GrTBackendEffectFactory<EllipticalRRectEffect>::getInstance(); 428 } 429 430 EllipticalRRectEffect::EllipticalRRectEffect(GrEffectEdgeType edgeType, const SkRRect& rrect) 431 : fRRect(rrect) 432 , fEdgeType(edgeType){ 433 this->setWillReadFragmentPosition(); 434 } 435 436 bool EllipticalRRectEffect::onIsEqual(const GrEffect& other) const { 437 const EllipticalRRectEffect& erre = CastEffect<EllipticalRRectEffect>(other); 438 return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect; 439 } 440 441 ////////////////////////////////////////////////////////////////////////////// 442 443 GR_DEFINE_EFFECT_TEST(EllipticalRRectEffect); 444 445 GrEffectRef* EllipticalRRectEffect::TestCreate(SkRandom* random, 446 GrContext*, 447 const GrDrawTargetCaps& caps, 448 GrTexture*[]) { 449 SkScalar w = random->nextRangeScalar(20.f, 1000.f); 450 SkScalar h = random->nextRangeScalar(20.f, 1000.f); 451 SkVector r[4]; 452 r[SkRRect::kUpperLeft_Corner].fX = random->nextRangeF(kRadiusMin, 9.f); 453 // ensure at least one corner really is elliptical 454 do { 455 r[SkRRect::kUpperLeft_Corner].fY = random->nextRangeF(kRadiusMin, 9.f); 456 } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX); 457 458 SkRRect rrect; 459 if (random->nextBool()) { 460 // half the time create a four-radii rrect. 461 r[SkRRect::kLowerRight_Corner].fX = random->nextRangeF(kRadiusMin, 9.f); 462 r[SkRRect::kLowerRight_Corner].fY = random->nextRangeF(kRadiusMin, 9.f); 463 464 r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX; 465 r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY; 466 467 r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX; 468 r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY; 469 470 rrect.setRectRadii(SkRect::MakeWH(w, h), r); 471 } else { 472 rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX, 473 r[SkRRect::kUpperLeft_Corner].fY); 474 } 475 GrEffectRef* effect; 476 do { 477 GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt); 478 effect = GrRRectEffect::Create(et, rrect); 479 } while (NULL == effect); 480 return effect; 481 } 482 483 ////////////////////////////////////////////////////////////////////////////// 484 485 class GLEllipticalRRectEffect : public GrGLEffect { 486 public: 487 GLEllipticalRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&); 488 489 virtual void emitCode(GrGLShaderBuilder* builder, 490 const GrDrawEffect& drawEffect, 491 EffectKey key, 492 const char* outputColor, 493 const char* inputColor, 494 const TransformedCoordsArray&, 495 const TextureSamplerArray&) SK_OVERRIDE; 496 497 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); 498 499 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; 500 501 private: 502 GrGLUniformManager::UniformHandle fInnerRectUniform; 503 GrGLUniformManager::UniformHandle fInvRadiiSqdUniform; 504 SkRRect fPrevRRect; 505 typedef GrGLEffect INHERITED; 506 }; 507 508 GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrBackendEffectFactory& factory, 509 const GrDrawEffect& drawEffect) 510 : INHERITED (factory) { 511 fPrevRRect.setEmpty(); 512 } 513 514 void GLEllipticalRRectEffect::emitCode(GrGLShaderBuilder* builder, 515 const GrDrawEffect& drawEffect, 516 EffectKey key, 517 const char* outputColor, 518 const char* inputColor, 519 const TransformedCoordsArray&, 520 const TextureSamplerArray& samplers) { 521 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>(); 522 const char *rectName; 523 // The inner rect is the rrect bounds inset by the x/y radii 524 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 525 kVec4f_GrSLType, 526 "innerRect", 527 &rectName); 528 const char* fragmentPos = builder->fragmentPosition(); 529 // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos 530 // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant 531 // to that corner. This means that points near the interior near the rrect top edge will have 532 // a vector that points straight up for both the TL left and TR corners. Computing an 533 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly, 534 // fragments near the other three edges will get the correct AA. Fragments in the interior of 535 // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will 536 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas. 537 // The code below is a simplified version of the above that performs maxs on the vector 538 // components before computing distances and alpha values so that only one distance computation 539 // need be computed to determine the min alpha. 540 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s;\n", rectName, fragmentPos); 541 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s - %s.zw;\n", fragmentPos, rectName); 542 switch (erre.getRRect().getType()) { 543 case SkRRect::kSimple_Type: { 544 const char *invRadiiXYSqdName; 545 fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 546 kVec2f_GrSLType, 547 "invRadiiXY", 548 &invRadiiXYSqdName); 549 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); 550 // Z is the x/y offsets divided by squared radii. 551 builder->fsCodeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName); 552 break; 553 } 554 case SkRRect::kNinePatch_Type: { 555 const char *invRadiiLTRBSqdName; 556 fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 557 kVec4f_GrSLType, 558 "invRadiiLTRB", 559 &invRadiiLTRBSqdName); 560 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); 561 // Z is the x/y offsets divided by squared radii. We only care about the (at most) one 562 // corner where both the x and y offsets are positive, hence the maxes. (The inverse 563 // squared radii will always be positive.) 564 builder->fsCodeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n", 565 invRadiiLTRBSqdName, invRadiiLTRBSqdName); 566 break; 567 } 568 default: 569 SkFAIL("RRect should always be simple or nine-patch."); 570 } 571 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1. 572 builder->fsCodeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n"); 573 // grad_dot is the squared length of the gradient of the implicit. 574 builder->fsCodeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n"); 575 // avoid calling inversesqrt on zero. 576 builder->fsCodeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n"); 577 builder->fsCodeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n"); 578 579 if (kFillAA_GrEffectEdgeType == erre.getEdgeType()) { 580 builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n"); 581 } else { 582 builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n"); 583 } 584 585 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor, 586 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str()); 587 } 588 589 GrGLEffect::EffectKey GLEllipticalRRectEffect::GenKey(const GrDrawEffect& drawEffect, 590 const GrGLCaps&) { 591 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>(); 592 GR_STATIC_ASSERT(kLast_GrEffectEdgeType < (1 << 3)); 593 return erre.getRRect().getType() | erre.getEdgeType() << 3; 594 } 595 596 void GLEllipticalRRectEffect::setData(const GrGLUniformManager& uman, 597 const GrDrawEffect& drawEffect) { 598 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>(); 599 const SkRRect& rrect = erre.getRRect(); 600 if (rrect != fPrevRRect) { 601 SkRect rect = rrect.getBounds(); 602 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); 603 SkASSERT(r0.fX >= kRadiusMin); 604 SkASSERT(r0.fY >= kRadiusMin); 605 switch (erre.getRRect().getType()) { 606 case SkRRect::kSimple_Type: 607 rect.inset(r0.fX, r0.fY); 608 uman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 609 1.f / (r0.fY * r0.fY)); 610 break; 611 case SkRRect::kNinePatch_Type: { 612 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); 613 SkASSERT(r1.fX >= kRadiusMin); 614 SkASSERT(r1.fY >= kRadiusMin); 615 rect.fLeft += r0.fX; 616 rect.fTop += r0.fY; 617 rect.fRight -= r1.fX; 618 rect.fBottom -= r1.fY; 619 uman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 620 1.f / (r0.fY * r0.fY), 621 1.f / (r1.fX * r1.fX), 622 1.f / (r1.fY * r1.fY)); 623 break; 624 } 625 default: 626 SkFAIL("RRect should always be simple or nine-patch."); 627 } 628 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); 629 fPrevRRect = rrect; 630 } 631 } 632 633 ////////////////////////////////////////////////////////////////////////////// 634 635 GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) { 636 if (rrect.isRect()) { 637 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds()); 638 } 639 640 if (rrect.isOval()) { 641 return GrOvalEffect::Create(edgeType, rrect.getBounds()); 642 } 643 644 if (rrect.isSimple()) { 645 if (rrect.getSimpleRadii().fX < kRadiusMin || rrect.getSimpleRadii().fY < kRadiusMin) { 646 // In this case the corners are extremely close to rectangular and we collapse the 647 // clip to a rectangular clip. 648 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds()); 649 } 650 if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) { 651 return CircularRRectEffect::Create(edgeType, CircularRRectEffect::kAll_CornerFlags, 652 rrect); 653 } else { 654 return EllipticalRRectEffect::Create(edgeType, rrect); 655 } 656 } 657 658 if (rrect.isComplex() || rrect.isNinePatch()) { 659 // Check for the "tab" cases - two adjacent circular corners and two square corners. 660 SkScalar circularRadius = 0; 661 uint32_t cornerFlags = 0; 662 663 SkVector radii[4]; 664 bool squashedRadii = false; 665 for (int c = 0; c < 4; ++c) { 666 radii[c] = rrect.radii((SkRRect::Corner)c); 667 SkASSERT((0 == radii[c].fX) == (0 == radii[c].fY)); 668 if (0 == radii[c].fX) { 669 // The corner is square, so no need to squash or flag as circular. 670 continue; 671 } 672 if (radii[c].fX < kRadiusMin || radii[c].fY < kRadiusMin) { 673 radii[c].set(0, 0); 674 squashedRadii = true; 675 continue; 676 } 677 if (radii[c].fX != radii[c].fY) { 678 cornerFlags = ~0U; 679 break; 680 } 681 if (!cornerFlags) { 682 circularRadius = radii[c].fX; 683 cornerFlags = 1 << c; 684 } else { 685 if (radii[c].fX != circularRadius) { 686 cornerFlags = ~0U; 687 break; 688 } 689 cornerFlags |= 1 << c; 690 } 691 } 692 693 switch (cornerFlags) { 694 case CircularRRectEffect::kAll_CornerFlags: 695 // This rrect should have been caught in the simple case above. Though, it would 696 // be correctly handled in the fallthrough code. 697 SkASSERT(false); 698 case CircularRRectEffect::kTopLeft_CornerFlag: 699 case CircularRRectEffect::kTopRight_CornerFlag: 700 case CircularRRectEffect::kBottomRight_CornerFlag: 701 case CircularRRectEffect::kBottomLeft_CornerFlag: 702 case CircularRRectEffect::kLeft_CornerFlags: 703 case CircularRRectEffect::kTop_CornerFlags: 704 case CircularRRectEffect::kRight_CornerFlags: 705 case CircularRRectEffect::kBottom_CornerFlags: { 706 SkTCopyOnFirstWrite<SkRRect> rr(rrect); 707 if (squashedRadii) { 708 rr.writable()->setRectRadii(rrect.getBounds(), radii); 709 } 710 return CircularRRectEffect::Create(edgeType, cornerFlags, *rr); 711 } 712 case CircularRRectEffect::kNone_CornerFlags: 713 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds()); 714 default: { 715 if (squashedRadii) { 716 // If we got here then we squashed some but not all the radii to zero. (If all 717 // had been squashed cornerFlags would be 0.) The elliptical effect doesn't 718 // support some rounded and some square corners. 719 return NULL; 720 } 721 if (rrect.isNinePatch()) { 722 return EllipticalRRectEffect::Create(edgeType, rrect); 723 } 724 return NULL; 725 } 726 } 727 } 728 729 return NULL; 730 } 731