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