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