Home | History | Annotate | Download | only in gm
      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