Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2013 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 #include "gm.h"
      8 #include "SkGradientShader.h"
      9 
     10 using namespace skiagm;
     11 
     12 struct GradData {
     13     int             fCount;
     14     const SkColor*  fColors;
     15     const SkScalar* fPos;
     16 };
     17 
     18 constexpr SkColor gColors[] = {
     19     SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE,
     20 };
     21 
     22 constexpr GradData gGradData[] = {
     23     { 1, gColors, nullptr },
     24     { 2, gColors, nullptr },
     25     { 3, gColors, nullptr },
     26     { 4, gColors, nullptr },
     27 };
     28 
     29 static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
     30     return SkGradientShader::MakeLinear(pts, data.fColors, data.fPos, data.fCount, tm);
     31 }
     32 
     33 static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
     34     SkPoint center;
     35     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
     36                SkScalarAve(pts[0].fY, pts[1].fY));
     37     return SkGradientShader::MakeRadial(center, center.fX, data.fColors, data.fPos, data.fCount, tm);
     38 }
     39 
     40 static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode) {
     41     SkPoint center;
     42     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
     43                SkScalarAve(pts[0].fY, pts[1].fY));
     44     return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
     45 }
     46 
     47 static sk_sp<SkShader> Make2Radial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
     48     SkPoint center0, center1;
     49     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
     50                 SkScalarAve(pts[0].fY, pts[1].fY));
     51     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
     52                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     53     return SkGradientShader::MakeTwoPointConical(
     54         center1, (pts[1].fX - pts[0].fX) / 7,
     55         center0, (pts[1].fX - pts[0].fX) / 2,
     56         data.fColors, data.fPos, data.fCount, tm);
     57 }
     58 
     59 static sk_sp<SkShader> Make2Conical(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
     60     SkPoint center0, center1;
     61     SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
     62     SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
     63     center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
     64     center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
     65     return SkGradientShader::MakeTwoPointConical(center1, radius1,
     66                                                    center0, radius0,
     67                                                    data.fColors, data.fPos,
     68                                                    data.fCount, tm);
     69 }
     70 
     71 
     72 typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
     73 
     74 constexpr GradMaker gGradMakers[] = {
     75     MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical,
     76 };
     77 
     78 ///////////////////////////////////////////////////////////////////////////////
     79 
     80 class GradientsNoTextureGM : public GM {
     81 public:
     82     GradientsNoTextureGM(bool dither) : fDither(dither) {
     83         this->setBGColor(0xFFDDDDDD);
     84     }
     85 
     86 protected:
     87 
     88     SkString onShortName() override {
     89         return SkString(fDither ? "gradients_no_texture" : "gradients_no_texture_nodither");
     90     }
     91 
     92     SkISize onISize() override { return SkISize::Make(640, 615); }
     93 
     94     void onDraw(SkCanvas* canvas) override {
     95         constexpr SkPoint kPts[2] = { { 0, 0 },
     96                                          { SkIntToScalar(50), SkIntToScalar(50) } };
     97         constexpr SkShader::TileMode kTM = SkShader::kClamp_TileMode;
     98         SkRect kRect = { 0, 0, SkIntToScalar(50), SkIntToScalar(50) };
     99         SkPaint paint;
    100         paint.setAntiAlias(true);
    101         paint.setDither(fDither);
    102 
    103         canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
    104         constexpr uint8_t kAlphas[] = { 0xff, 0x40 };
    105         for (size_t a = 0; a < SK_ARRAY_COUNT(kAlphas); ++a) {
    106             for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); ++i) {
    107                 canvas->save();
    108                 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); ++j) {
    109                     paint.setShader(gGradMakers[j](kPts, gGradData[i], kTM));
    110                     paint.setAlpha(kAlphas[a]);
    111                     canvas->drawRect(kRect, paint);
    112                     canvas->translate(0, SkIntToScalar(kRect.height() + 20));
    113                 }
    114                 canvas->restore();
    115                 canvas->translate(SkIntToScalar(kRect.width() + 20), 0);
    116             }
    117         }
    118     }
    119 
    120 private:
    121     bool fDither;
    122 
    123     typedef GM INHERITED;
    124 };
    125 
    126 ///////////////////////////////////////////////////////////////////////////////
    127 
    128 struct ColorPos {
    129     SkColor*    fColors;
    130     SkScalar*   fPos;
    131     int         fCount;
    132 
    133     ColorPos() : fColors(nullptr), fPos(nullptr), fCount(0) {}
    134     ~ColorPos() {
    135         delete[] fColors;
    136         delete[] fPos;
    137     }
    138 
    139     void construct(const SkColor colors[], const SkScalar pos[], int count) {
    140         fColors = new SkColor[count];
    141         memcpy(fColors, colors, count * sizeof(SkColor));
    142         if (pos) {
    143             fPos = new SkScalar[count];
    144             memcpy(fPos, pos, count * sizeof(SkScalar));
    145             fPos[0] = 0;
    146             fPos[count - 1] = 1;
    147         }
    148         fCount = count;
    149     }
    150 };
    151 
    152 static void make0(ColorPos* rec) {
    153 #if 0
    154     From http://jsfiddle.net/3fe2a/
    155 
    156 background-image: -webkit-linear-gradient(left, #22d1cd 1%, #22d1cd 0.9510157507590116%, #df4b37 2.9510157507590113%, #df4b37 23.695886056604927%, #22d1cd 25.695886056604927%, #22d1cd 25.39321881940624%, #e6de36 27.39321881940624%, #e6de36 31.849399922570655%, #3267ff 33.849399922570655%, #3267ff 44.57735802921938%, #9d47d1 46.57735802921938%, #9d47d1 53.27185850805876%, #3267ff 55.27185850805876%, #3267ff 61.95718972227316%, #5cdd9d 63.95718972227316%, #5cdd9d 69.89166004442%, #3267ff 71.89166004442%, #3267ff 74.45795382765857%, #9d47d1 76.45795382765857%, #9d47d1 82.78364610713776%, #3267ff 84.78364610713776%, #3267ff 94.52743647737229%, #e3d082 96.52743647737229%, #e3d082 96.03934633331295%);
    157 height: 30px;
    158 #endif
    159 
    160     const SkColor colors[] = {
    161         0xFF22d1cd, 0xFF22d1cd, 0xFFdf4b37, 0xFFdf4b37, 0xFF22d1cd, 0xFF22d1cd, 0xFFe6de36, 0xFFe6de36,
    162         0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFF5cdd9d, 0xFF5cdd9d,
    163         0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFFe3d082, 0xFFe3d082
    164     };
    165     const double percent[] = {
    166         1, 0.9510157507590116, 2.9510157507590113, 23.695886056604927,
    167         25.695886056604927, 25.39321881940624, 27.39321881940624, 31.849399922570655,
    168         33.849399922570655, 44.57735802921938, 46.57735802921938, 53.27185850805876,
    169         55.27185850805876, 61.95718972227316, 63.95718972227316, 69.89166004442,
    170         71.89166004442, 74.45795382765857, 76.45795382765857, 82.78364610713776,
    171         84.78364610713776, 94.52743647737229, 96.52743647737229, 96.03934633331295,
    172     };
    173     const int N = SK_ARRAY_COUNT(percent);
    174     SkScalar pos[N];
    175     for (int i = 0; i < N; ++i) {
    176         pos[i] = SkDoubleToScalar(percent[i] / 100);
    177     }
    178     rec->construct(colors, pos, N);
    179 }
    180 
    181 static void make1(ColorPos* rec) {
    182     const SkColor colors[] = {
    183         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
    184         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
    185         SK_ColorBLACK,
    186     };
    187     rec->construct(colors, nullptr, SK_ARRAY_COUNT(colors));
    188 }
    189 
    190 static void make2(ColorPos* rec) {
    191     const SkColor colors[] = {
    192         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
    193         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
    194         SK_ColorBLACK,
    195     };
    196     const int N = SK_ARRAY_COUNT(colors);
    197     SkScalar pos[N];
    198     for (int i = 0; i < N; ++i) {
    199         pos[i] = SK_Scalar1 * i / (N - 1);
    200     }
    201     rec->construct(colors, pos, N);
    202 }
    203 
    204 static void make3(ColorPos* rec) {
    205     const SkColor colors[] = {
    206         SK_ColorRED, SK_ColorBLUE, SK_ColorBLUE, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLACK,
    207     };
    208     const SkScalar pos[] = {
    209         0, 0, 0.5f, 0.5, 1, 1,
    210     };
    211     rec->construct(colors, pos, SK_ARRAY_COUNT(colors));
    212 }
    213 
    214 class GradientsManyColorsGM : public GM {
    215     enum {
    216         W = 800,
    217     };
    218     sk_sp<SkShader> fShader;
    219 
    220     typedef void (*Proc)(ColorPos*);
    221 public:
    222     GradientsManyColorsGM(bool dither) : fDither(dither) {}
    223 
    224 protected:
    225 
    226     SkString onShortName() override {
    227         return SkString(fDither ? "gradients_many" : "gradients_many_nodither");
    228     }
    229 
    230     SkISize onISize() override { return SkISize::Make(880, 400); }
    231 
    232     void onDraw(SkCanvas* canvas) override {
    233         const Proc procs[] = {
    234             make0, make1, make2, make3,
    235         };
    236         const SkPoint pts[] = {
    237             { 0, 0 },
    238             { SkIntToScalar(W), 0 },
    239         };
    240         const SkRect r = SkRect::MakeWH(SkIntToScalar(W), 30);
    241 
    242         SkPaint paint;
    243         paint.setDither(fDither);
    244 
    245         canvas->translate(40, 20);
    246 
    247         for (int i = 0; i <= 8; ++i) {
    248             SkScalar x = r.width() * i / 8;
    249             canvas->drawLine(x, 0, x, 10000, paint);
    250         }
    251 
    252         // expand the drawing rect so we exercise clampping in the gradients
    253         const SkRect drawR = r.makeOutset(20, 0);
    254         for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
    255             ColorPos rec;
    256             procs[i](&rec);
    257             paint.setShader(SkGradientShader::MakeLinear(pts, rec.fColors, rec.fPos, rec.fCount,
    258                                                          SkShader::kClamp_TileMode));
    259             canvas->drawRect(drawR, paint);
    260 
    261             canvas->save();
    262             canvas->translate(r.centerX(), r.height() + 4);
    263             canvas->scale(-1, 1);
    264             canvas->translate(-r.centerX(), 0);
    265             canvas->drawRect(drawR, paint);
    266             canvas->restore();
    267 
    268             canvas->translate(0, r.height() + 2*r.height() + 8);
    269         }
    270     }
    271 
    272 private:
    273     bool fDither;
    274 
    275     typedef GM INHERITED;
    276 };
    277 
    278 ///////////////////////////////////////////////////////////////////////////////
    279 
    280 DEF_GM(return new GradientsNoTextureGM(true);)
    281 DEF_GM(return new GradientsNoTextureGM(false);)
    282 DEF_GM(return new GradientsManyColorsGM(true);)
    283 DEF_GM(return new GradientsManyColorsGM(false);)
    284