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