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 "gm.h" 9 #include "SkGradientShader.h" 10 11 namespace skiagm { 12 13 struct GradData { 14 int fCount; 15 const SkColor* fColors; 16 const SkScalar* fPos; 17 }; 18 19 constexpr SkColor gColors[] = { 20 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK 21 }; 22 constexpr SkScalar gPos0[] = { 0, SK_Scalar1 }; 23 constexpr SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 }; 24 constexpr SkScalar gPos2[] = { 25 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1 26 }; 27 28 constexpr SkScalar gPosClamp[] = {0.0f, 0.0f, 1.0f, 1.0f}; 29 constexpr SkColor gColorClamp[] = { 30 SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLUE 31 }; 32 33 constexpr GradData gGradData[] = { 34 { 2, gColors, gPos0 }, 35 { 2, gColors, gPos1 }, 36 { 5, gColors, gPos2 }, 37 { 4, gColorClamp, gPosClamp } 38 }; 39 40 static sk_sp<SkShader> Make2ConicalOutside(const SkPoint pts[2], const GradData& data, 41 SkShader::TileMode tm, const SkMatrix& localMatrix) { 42 SkPoint center0, center1; 43 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10; 44 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3; 45 center0.set(pts[0].fX + radius0, pts[0].fY + radius0); 46 center1.set(pts[1].fX - radius1, pts[1].fY - radius1); 47 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors, 48 data.fPos, data.fCount, tm, 0, &localMatrix); 49 } 50 51 static sk_sp<SkShader> Make2ConicalOutsideStrip(const SkPoint pts[2], const GradData& data, 52 SkShader::TileMode tm, const SkMatrix& localMatrix) { 53 SkPoint center0, center1; 54 SkScalar radius = (pts[1].fX - pts[0].fX) / 3; 55 center0.set(pts[0].fX, pts[0].fY); 56 center1.set(pts[1].fX, pts[1].fY); 57 return SkGradientShader::MakeTwoPointConical(center0, radius, center1, radius, data.fColors, 58 data.fPos, data.fCount, tm, 0, &localMatrix); 59 } 60 61 static sk_sp<SkShader> Make2ConicalOutsideFlip(const SkPoint pts[2], const GradData& data, 62 SkShader::TileMode tm, const SkMatrix& localMatrix) { 63 SkPoint center0, center1; 64 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10; 65 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3; 66 center0.set(pts[0].fX + radius0, pts[0].fY + radius0); 67 center1.set(pts[1].fX - radius1, pts[1].fY - radius1); 68 return SkGradientShader::MakeTwoPointConical(center1, radius1, center0, radius0, data.fColors, 69 data.fPos, data.fCount, tm, 0, &localMatrix); 70 } 71 72 static sk_sp<SkShader> Make2ConicalInside(const SkPoint pts[2], const GradData& data, 73 SkShader::TileMode tm, const SkMatrix& localMatrix) { 74 SkPoint center0, center1; 75 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 76 SkScalarAve(pts[0].fY, pts[1].fY)); 77 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 78 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 79 return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7, 80 center0, (pts[1].fX - pts[0].fX) / 2, 81 data.fColors, data.fPos, data.fCount, tm, 82 0, &localMatrix); 83 } 84 85 static sk_sp<SkShader> Make2ConicalInsideFlip(const SkPoint pts[2], const GradData& data, 86 SkShader::TileMode tm, const SkMatrix& localMatrix) { 87 SkPoint center0, center1; 88 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 89 SkScalarAve(pts[0].fY, pts[1].fY)); 90 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 91 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 92 return SkGradientShader::MakeTwoPointConical(center0, (pts[1].fX - pts[0].fX) / 2, 93 center1, (pts[1].fX - pts[0].fX) / 7, 94 data.fColors, data.fPos, data.fCount, tm, 95 0, &localMatrix); 96 } 97 98 static sk_sp<SkShader> Make2ConicalInsideCenter(const SkPoint pts[2], const GradData& data, 99 SkShader::TileMode tm, const SkMatrix& localMatrix) { 100 SkPoint center0; 101 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 102 SkScalarAve(pts[0].fY, pts[1].fY)); 103 return SkGradientShader::MakeTwoPointConical(center0, (pts[1].fX - pts[0].fX) / 7, 104 center0, (pts[1].fX - pts[0].fX) / 2, 105 data.fColors, data.fPos, data.fCount, tm, 106 0, &localMatrix); 107 } 108 109 static sk_sp<SkShader> Make2ConicalInsideCenterReversed(const SkPoint pts[2], const GradData& data, 110 SkShader::TileMode tm, const SkMatrix& localMatrix) { 111 SkPoint center0; 112 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 113 SkScalarAve(pts[0].fY, pts[1].fY)); 114 return SkGradientShader::MakeTwoPointConical(center0, (pts[1].fX - pts[0].fX) / 2, 115 center0, (pts[1].fX - pts[0].fX) / 7, 116 data.fColors, data.fPos, data.fCount, tm, 117 0, &localMatrix); 118 } 119 120 static sk_sp<SkShader> Make2ConicalZeroRad(const SkPoint pts[2], const GradData& data, 121 SkShader::TileMode tm, const SkMatrix& localMatrix) { 122 SkPoint center0, center1; 123 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 124 SkScalarAve(pts[0].fY, pts[1].fY)); 125 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 126 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 127 return SkGradientShader::MakeTwoPointConical(center1, 0.f, 128 center0, (pts[1].fX - pts[0].fX) / 2, 129 data.fColors, data.fPos, data.fCount, tm, 130 0, &localMatrix); 131 } 132 133 static sk_sp<SkShader> Make2ConicalZeroRadFlip(const SkPoint pts[2], const GradData& data, 134 SkShader::TileMode tm, const SkMatrix& localMatrix) { 135 SkPoint center0, center1; 136 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 137 SkScalarAve(pts[0].fY, pts[1].fY)); 138 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 139 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 140 return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 2, 141 center0, 0.f, 142 data.fColors, data.fPos, data.fCount, tm, 143 0, &localMatrix); 144 } 145 146 static sk_sp<SkShader> Make2ConicalZeroRadCenter(const SkPoint pts[2], const GradData& data, 147 SkShader::TileMode tm, const SkMatrix& localMatrix) { 148 SkPoint center0, center1; 149 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 150 SkScalarAve(pts[0].fY, pts[1].fY)); 151 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 152 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 153 return SkGradientShader::MakeTwoPointConical(center0, 0.f, center0, (pts[1].fX - pts[0].fX) / 2, 154 data.fColors, data.fPos, data.fCount, tm, 155 0, &localMatrix); 156 } 157 158 static sk_sp<SkShader> Make2ConicalZeroRadOutside(const SkPoint pts[2], const GradData& data, 159 SkShader::TileMode tm, 160 const SkMatrix& localMatrix) { 161 SkPoint center0, center1; 162 SkScalar radius0 = 0.f; 163 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3; 164 center0.set(pts[0].fX + radius0, pts[0].fY + radius0); 165 center1.set(pts[1].fX - radius1, pts[1].fY - radius1); 166 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, 167 data.fColors, data.fPos, 168 data.fCount, tm, 0, &localMatrix); 169 } 170 171 static sk_sp<SkShader> Make2ConicalZeroRadFlipOutside(const SkPoint pts[2], const GradData& data, 172 SkShader::TileMode tm, 173 const SkMatrix& localMatrix) { 174 SkPoint center0, center1; 175 SkScalar radius0 = 0.f; 176 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3; 177 center0.set(pts[0].fX + radius0, pts[0].fY + radius0); 178 center1.set(pts[1].fX - radius1, pts[1].fY - radius1); 179 return SkGradientShader::MakeTwoPointConical(center1, radius1, center0, radius0, data.fColors, 180 data.fPos, data.fCount, tm, 0, &localMatrix); 181 } 182 183 static sk_sp<SkShader> Make2ConicalEdgeX(const SkPoint pts[2], const GradData& data, 184 SkShader::TileMode tm, const SkMatrix& localMatrix) { 185 SkPoint center0, center1; 186 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 7; 187 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3; 188 center1.set(SkScalarAve(pts[0].fX, pts[1].fX), 189 SkScalarAve(pts[0].fY, pts[1].fY)); 190 center0.set(center1.fX + radius1, center1.fY); 191 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors, 192 data.fPos, data.fCount, tm, 0, &localMatrix); 193 } 194 195 static sk_sp<SkShader> Make2ConicalEdgeY(const SkPoint pts[2], const GradData& data, 196 SkShader::TileMode tm, const SkMatrix& localMatrix) { 197 SkPoint center0, center1; 198 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 7; 199 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3; 200 center1.set(SkScalarAve(pts[0].fX, pts[1].fX), 201 SkScalarAve(pts[0].fY, pts[1].fY)); 202 center0.set(center1.fX, center1.fY + radius1); 203 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors, 204 data.fPos, data.fCount, tm, 0, &localMatrix); 205 } 206 207 static sk_sp<SkShader> Make2ConicalZeroRadEdgeX(const SkPoint pts[2], const GradData& data, 208 SkShader::TileMode tm, 209 const SkMatrix& localMatrix) { 210 SkPoint center0, center1; 211 SkScalar radius0 = 0.f; 212 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3; 213 center1.set(SkScalarAve(pts[0].fX, pts[1].fX), 214 SkScalarAve(pts[0].fY, pts[1].fY)); 215 center0.set(center1.fX + radius1, center1.fY); 216 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors, 217 data.fPos, data.fCount, tm, 0, &localMatrix); 218 } 219 220 static sk_sp<SkShader> Make2ConicalZeroRadEdgeY(const SkPoint pts[2], const GradData& data, 221 SkShader::TileMode tm, const SkMatrix& localMatrix) { 222 SkPoint center0, center1; 223 SkScalar radius0 = 0.f; 224 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3; 225 center1.set(SkScalarAve(pts[0].fX, pts[1].fX), 226 SkScalarAve(pts[0].fY, pts[1].fY)); 227 center0.set(center1.fX, center1.fY + radius1); 228 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors, 229 data.fPos, data.fCount, tm, 0, &localMatrix); 230 } 231 232 static sk_sp<SkShader> Make2ConicalTouchX(const SkPoint pts[2], const GradData& data, 233 SkShader::TileMode tm, const SkMatrix& localMatrix) { 234 SkPoint center0, center1; 235 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 7; 236 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3; 237 center1.set(SkScalarAve(pts[0].fX, pts[1].fX), 238 SkScalarAve(pts[0].fY, pts[1].fY)); 239 center0.set(center1.fX - radius1 + radius0, center1.fY); 240 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors, 241 data.fPos, data.fCount, tm, 0, &localMatrix); 242 } 243 244 static sk_sp<SkShader> Make2ConicalTouchY(const SkPoint pts[2], const GradData& data, 245 SkShader::TileMode tm, const SkMatrix& localMatrix) { 246 SkPoint center0, center1; 247 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 7; 248 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3; 249 center1.set(SkScalarAve(pts[0].fX, pts[1].fX), 250 SkScalarAve(pts[0].fY, pts[1].fY)); 251 center0.set(center1.fX, center1.fY + radius1 - radius0); 252 return SkGradientShader::MakeTwoPointConical(center0, radius0, center1, radius1, data.fColors, 253 data.fPos, data.fCount, tm, 0, &localMatrix); 254 } 255 256 static sk_sp<SkShader> Make2ConicalInsideSmallRad(const SkPoint pts[2], const GradData& data, 257 SkShader::TileMode tm, const SkMatrix& localMatrix) { 258 SkPoint center0, center1; 259 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 260 SkScalarAve(pts[0].fY, pts[1].fY)); 261 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 262 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 263 return SkGradientShader::MakeTwoPointConical(center0, 0.0000000000000000001f, 264 center0, (pts[1].fX - pts[0].fX) / 2, 265 data.fColors, data.fPos, data.fCount, tm, 266 0, &localMatrix); 267 } 268 269 typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data, 270 SkShader::TileMode tm, const SkMatrix& localMatrix); 271 272 constexpr GradMaker gGradMakersOutside[] = { 273 Make2ConicalOutside, Make2ConicalOutsideFlip, 274 Make2ConicalZeroRadOutside, Make2ConicalZeroRadFlipOutside, 275 Make2ConicalOutsideStrip 276 }; 277 278 constexpr GradMaker gGradMakersInside[] = { 279 Make2ConicalInside, Make2ConicalInsideFlip, Make2ConicalInsideCenter, 280 Make2ConicalZeroRad, Make2ConicalZeroRadFlip, Make2ConicalZeroRadCenter, 281 Make2ConicalInsideCenterReversed 282 }; 283 284 constexpr GradMaker gGradMakersEdgeCases[] = { 285 Make2ConicalEdgeX, Make2ConicalEdgeY, 286 Make2ConicalZeroRadEdgeX, Make2ConicalZeroRadEdgeY, 287 Make2ConicalTouchX, Make2ConicalTouchY, 288 Make2ConicalInsideSmallRad 289 }; 290 291 292 constexpr struct { 293 const GradMaker* fMaker; 294 const int fCount; 295 const char* fName; 296 } gGradCases[] = { 297 { gGradMakersOutside, SK_ARRAY_COUNT(gGradMakersOutside), "outside" }, 298 { gGradMakersInside, SK_ARRAY_COUNT(gGradMakersInside), "inside" }, 299 { gGradMakersEdgeCases, SK_ARRAY_COUNT(gGradMakersEdgeCases), "edge" }, 300 }; 301 302 enum GradCaseType { // these must match the order in gGradCases 303 kOutside_GradCaseType, 304 kInside_GradCaseType, 305 kEdge_GradCaseType, 306 }; 307 308 /////////////////////////////////////////////////////////////////////////////// 309 310 class ConicalGradientsGM : public GM { 311 public: 312 ConicalGradientsGM(GradCaseType gradCaseType, bool dither, 313 SkShader::TileMode mode = SkShader::kClamp_TileMode) 314 : fGradCaseType(gradCaseType) 315 , fDither(dither) 316 , fMode(mode) { 317 this->setBGColor(0xFFDDDDDD); 318 fName.printf("gradients_2pt_conical_%s%s", gGradCases[gradCaseType].fName, 319 fDither ? "" : "_nodither"); 320 switch (mode) { 321 case SkShader::kRepeat_TileMode: 322 fName.appendf("_repeat"); 323 break; 324 case SkShader::kMirror_TileMode: 325 fName.appendf("_mirror"); 326 break; 327 default: 328 break; 329 } 330 } 331 332 protected: 333 SkString onShortName() { 334 return fName; 335 } 336 337 virtual SkISize onISize() { return SkISize::Make(840, 815); } 338 339 virtual void onDraw(SkCanvas* canvas) { 340 341 SkPoint pts[2] = { 342 { 0, 0 }, 343 { SkIntToScalar(100), SkIntToScalar(100) } 344 }; 345 SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) }; 346 SkPaint paint; 347 paint.setAntiAlias(true); 348 paint.setDither(fDither); 349 350 canvas->translate(SkIntToScalar(20), SkIntToScalar(20)); 351 352 const GradMaker* gradMaker = gGradCases[fGradCaseType].fMaker; 353 const int count = gGradCases[fGradCaseType].fCount; 354 355 for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) { 356 canvas->save(); 357 for (int j = 0; j < count; j++) { 358 SkMatrix scale = SkMatrix::I(); 359 360 if (i == 3) { // if the clamp case 361 scale.setScale(0.5f, 0.5f); 362 scale.postTranslate(25.f, 25.f); 363 } 364 365 paint.setShader(gradMaker[j](pts, gGradData[i], fMode, scale)); 366 canvas->drawRect(r, paint); 367 canvas->translate(0, SkIntToScalar(120)); 368 } 369 canvas->restore(); 370 canvas->translate(SkIntToScalar(120), 0); 371 } 372 } 373 374 private: 375 typedef GM INHERITED; 376 377 GradCaseType fGradCaseType; 378 SkString fName; 379 bool fDither; 380 SkShader::TileMode fMode; 381 }; 382 /////////////////////////////////////////////////////////////////////////////// 383 384 DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, true); ) 385 DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, true); ) 386 DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, true); ) 387 388 DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, true, SkShader::kRepeat_TileMode); ) 389 DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, true, SkShader::kRepeat_TileMode); ) 390 DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, true, SkShader::kRepeat_TileMode); ) 391 392 DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, true, SkShader::kMirror_TileMode); ) 393 DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, true, SkShader::kMirror_TileMode); ) 394 DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, true, SkShader::kMirror_TileMode); ) 395 396 DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, false); ) 397 DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, false); ) 398 DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, false); ) 399 400 } 401