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 12namespace skiagm { 13 14struct GradData { 15 int fCount; 16 const SkColor* fColors; 17 const SkScalar* fPos; 18}; 19 20constexpr SkColor gColors[] = { 21 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK 22}; 23constexpr SkScalar gPos0[] = { 0, SK_Scalar1 }; 24constexpr SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 }; 25constexpr SkScalar gPos2[] = { 26 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1 27}; 28 29constexpr SkScalar gPosClamp[] = {0.0f, 0.0f, 1.0f, 1.0f}; 30constexpr SkColor gColorClamp[] = { 31 SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLUE 32}; 33 34constexpr GradData gGradData[] = { 35 { 2, gColors, gPos0 }, 36 { 2, gColors, gPos1 }, 37 { 5, gColors, gPos2 }, 38 { 4, gColorClamp, gPosClamp } 39}; 40 41static 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 52static 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 63static 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 76static 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 89static 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 102static 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 115static 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 128static 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 140static 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 153static 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 165static 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 177static 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 189static 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 202static 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 214static 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 226static 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 238static 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 251typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data, 252 SkShader::TileMode tm, const SkMatrix& localMatrix); 253 254constexpr GradMaker gGradMakersOutside[] = { 255 Make2ConicalOutside, Make2ConicalOutsideFlip, 256 Make2ConicalZeroRadOutside, Make2ConicalZeroRadFlipOutside 257}; 258 259constexpr GradMaker gGradMakersInside[] = { 260 Make2ConicalInside, Make2ConicalInsideFlip, Make2ConicalInsideCenter, 261 Make2ConicalZeroRad, Make2ConicalZeroRadFlip, Make2ConicalZeroRadCenter, 262}; 263 264constexpr GradMaker gGradMakersEdgeCases[] = { 265 Make2ConicalEdgeX, Make2ConicalEdgeY, 266 Make2ConicalZeroRadEdgeX, Make2ConicalZeroRadEdgeY, 267 Make2ConicalTouchX, Make2ConicalTouchY, 268 Make2ConicalInsideSmallRad 269}; 270 271 272constexpr 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 282enum GradCaseType { // these must match the order in gGradCases 283 kOutside_GradCaseType, 284 kInside_GradCaseType, 285 kEdge_GradCaseType, 286}; 287 288/////////////////////////////////////////////////////////////////////////////// 289 290class ConicalGradientsGM : public GM { 291public: 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 312protected: 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 354private: 355 typedef GM INHERITED; 356 357 GradCaseType fGradCaseType; 358 SkString fName; 359 bool fDither; 360 SkShader::TileMode fMode; 361}; 362/////////////////////////////////////////////////////////////////////////////// 363 364DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, true); ) 365DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, true); ) 366DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, true); ) 367 368DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, true, SkShader::kRepeat_TileMode); ) 369DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, true, SkShader::kRepeat_TileMode); ) 370DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, true, SkShader::kRepeat_TileMode); ) 371 372DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, true, SkShader::kMirror_TileMode); ) 373DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, true, SkShader::kMirror_TileMode); ) 374DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, true, SkShader::kMirror_TileMode); ) 375 376DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, false); ) 377DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, false); ) 378DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, false); ) 379 380} 381