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 "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