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 static const SkColor gColors[] = {
     20     SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
     21 };
     22 static const SkScalar gPos0[] = { 0, SK_Scalar1 };
     23 static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
     24 static const SkScalar gPos2[] = {
     25     0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
     26 };
     27 
     28 static const SkScalar gPosClamp[]   = {0.0f, 0.0f, 1.0f, 1.0f};
     29 static const SkColor  gColorClamp[] = {
     30     SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLUE
     31 };
     32 
     33 static const GradData gGradData[] = {
     34     { 2, gColors, gPos0 },
     35     { 2, gColors, gPos1 },
     36     { 5, gColors, gPos2 },
     37     { 4, gColorClamp, gPosClamp }
     38 };
     39 
     40 static 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::CreateTwoPointConical(center0, radius0,
     48                                                    center1, radius1,
     49                                                    data.fColors, data.fPos,
     50                                                    data.fCount, tm, 0, &localMatrix);
     51 }
     52 
     53 static SkShader* Make2ConicalOutsideFlip(const SkPoint pts[2], const GradData& data,
     54                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
     55     SkPoint center0, center1;
     56     SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
     57     SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
     58     center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
     59     center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
     60     return SkGradientShader::CreateTwoPointConical(center1, radius1,
     61                                                    center0, radius0,
     62                                                    data.fColors, data.fPos,
     63                                                    data.fCount, tm, 0, &localMatrix);
     64 }
     65 
     66 static SkShader* Make2ConicalInside(const SkPoint pts[2], const GradData& data,
     67                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
     68     SkPoint center0, center1;
     69     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
     70                 SkScalarAve(pts[0].fY, pts[1].fY));
     71     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
     72                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     73     return SkGradientShader::CreateTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
     74                                                    center0, (pts[1].fX - pts[0].fX) / 2,
     75                                                    data.fColors, data.fPos, data.fCount, tm,
     76                                                    0, &localMatrix);
     77 }
     78 
     79 static SkShader* Make2ConicalInsideFlip(const SkPoint pts[2], const GradData& data,
     80                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
     81     SkPoint center0, center1;
     82     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
     83                 SkScalarAve(pts[0].fY, pts[1].fY));
     84     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
     85                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     86     return SkGradientShader::CreateTwoPointConical(center0, (pts[1].fX - pts[0].fX) / 2,
     87                                                    center1, (pts[1].fX - pts[0].fX) / 7,
     88                                                    data.fColors, data.fPos, data.fCount, tm,
     89                                                    0, &localMatrix);
     90 }
     91 
     92 static SkShader* Make2ConicalInsideCenter(const SkPoint pts[2], const GradData& data,
     93                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
     94     SkPoint center0, center1;
     95     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
     96                 SkScalarAve(pts[0].fY, pts[1].fY));
     97     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
     98                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     99     return SkGradientShader::CreateTwoPointConical(center0, (pts[1].fX - pts[0].fX) / 7,
    100                                                    center0, (pts[1].fX - pts[0].fX) / 2,
    101                                                    data.fColors, data.fPos, data.fCount, tm,
    102                                                    0, &localMatrix);
    103 }
    104 
    105 static SkShader* Make2ConicalZeroRad(const SkPoint pts[2], const GradData& data,
    106                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
    107     SkPoint center0, center1;
    108     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
    109                 SkScalarAve(pts[0].fY, pts[1].fY));
    110     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
    111                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
    112     return SkGradientShader::CreateTwoPointConical(center1, 0.f,
    113                                                    center0, (pts[1].fX - pts[0].fX) / 2,
    114                                                    data.fColors, data.fPos, data.fCount, tm,
    115                                                    0, &localMatrix);
    116 }
    117 
    118 static SkShader* Make2ConicalZeroRadFlip(const SkPoint pts[2], const GradData& data,
    119                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
    120     SkPoint center0, center1;
    121     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
    122                 SkScalarAve(pts[0].fY, pts[1].fY));
    123     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
    124                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
    125     return SkGradientShader::CreateTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 2,
    126                                                    center0, 0.f,
    127                                                    data.fColors, data.fPos, data.fCount, tm,
    128                                                    0, &localMatrix);
    129 }
    130 
    131 static SkShader* Make2ConicalZeroRadCenter(const SkPoint pts[2], const GradData& data,
    132                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
    133     SkPoint center0, center1;
    134     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
    135                 SkScalarAve(pts[0].fY, pts[1].fY));
    136     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
    137                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
    138     return SkGradientShader::CreateTwoPointConical(center0, 0.f,
    139                                                    center0, (pts[1].fX - pts[0].fX) / 2,
    140                                                    data.fColors, data.fPos, data.fCount, tm,
    141                                                    0, &localMatrix);
    142 }
    143 
    144 static SkShader* Make2ConicalZeroRadOutside(const SkPoint pts[2], const GradData& data,
    145                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
    146     SkPoint center0, center1;
    147     SkScalar radius0 = 0.f;
    148     SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
    149     center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
    150     center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
    151     return SkGradientShader::CreateTwoPointConical(center0, radius0,
    152                                                    center1, radius1,
    153                                                    data.fColors, data.fPos,
    154                                                    data.fCount, tm, 0, &localMatrix);
    155 }
    156 
    157 static SkShader* Make2ConicalZeroRadFlipOutside(const SkPoint pts[2], const GradData& data,
    158                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
    159     SkPoint center0, center1;
    160     SkScalar radius0 = 0.f;
    161     SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
    162     center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
    163     center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
    164     return SkGradientShader::CreateTwoPointConical(center1, radius1,
    165                                                    center0, radius0,
    166                                                    data.fColors, data.fPos,
    167                                                    data.fCount, tm, 0, &localMatrix);
    168 }
    169 
    170 static SkShader* Make2ConicalEdgeX(const SkPoint pts[2], const GradData& data,
    171                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
    172     SkPoint center0, center1;
    173     SkScalar radius0 = (pts[1].fX - pts[0].fX) / 7;
    174     SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
    175     center1.set(SkScalarAve(pts[0].fX, pts[1].fX),
    176                 SkScalarAve(pts[0].fY, pts[1].fY));
    177     center0.set(center1.fX + radius1, center1.fY);
    178     return SkGradientShader::CreateTwoPointConical(center0, radius0,
    179                                                    center1, radius1,
    180                                                    data.fColors, data.fPos,
    181                                                    data.fCount, tm, 0, &localMatrix);
    182 }
    183 
    184 static SkShader* Make2ConicalEdgeY(const SkPoint pts[2], const GradData& data,
    185                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
    186     SkPoint center0, center1;
    187     SkScalar radius0 = (pts[1].fX - pts[0].fX) / 7;
    188     SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
    189     center1.set(SkScalarAve(pts[0].fX, pts[1].fX),
    190                 SkScalarAve(pts[0].fY, pts[1].fY));
    191     center0.set(center1.fX, center1.fY + radius1);
    192     return SkGradientShader::CreateTwoPointConical(center0, radius0,
    193                                                    center1, radius1,
    194                                                    data.fColors, data.fPos,
    195                                                    data.fCount, tm, 0, &localMatrix);
    196 }
    197 
    198 static SkShader* Make2ConicalZeroRadEdgeX(const SkPoint pts[2], const GradData& data,
    199                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
    200     SkPoint center0, center1;
    201     SkScalar radius0 = 0.f;
    202     SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
    203     center1.set(SkScalarAve(pts[0].fX, pts[1].fX),
    204                 SkScalarAve(pts[0].fY, pts[1].fY));
    205     center0.set(center1.fX + radius1, center1.fY);
    206     return SkGradientShader::CreateTwoPointConical(center0, radius0,
    207                                                    center1, radius1,
    208                                                    data.fColors, data.fPos,
    209                                                    data.fCount, tm, 0, &localMatrix);
    210 }
    211 
    212 static SkShader* Make2ConicalZeroRadEdgeY(const SkPoint pts[2], const GradData& data,
    213                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
    214     SkPoint center0, center1;
    215     SkScalar radius0 = 0.f;
    216     SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
    217     center1.set(SkScalarAve(pts[0].fX, pts[1].fX),
    218                 SkScalarAve(pts[0].fY, pts[1].fY));
    219     center0.set(center1.fX, center1.fY + radius1);
    220     return SkGradientShader::CreateTwoPointConical(center0, radius0,
    221                                                    center1, radius1,
    222                                                    data.fColors, data.fPos,
    223                                                    data.fCount, tm, 0, &localMatrix);
    224 }
    225 
    226 static SkShader* Make2ConicalTouchX(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 - radius1 + radius0, center1.fY);
    234     return SkGradientShader::CreateTwoPointConical(center0, radius0,
    235                                                    center1, radius1,
    236                                                    data.fColors, data.fPos,
    237                                                    data.fCount, tm, 0, &localMatrix);
    238 }
    239 
    240 static SkShader* Make2ConicalTouchY(const SkPoint pts[2], const GradData& data,
    241                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
    242     SkPoint center0, center1;
    243     SkScalar radius0 = (pts[1].fX - pts[0].fX) / 7;
    244     SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
    245     center1.set(SkScalarAve(pts[0].fX, pts[1].fX),
    246                 SkScalarAve(pts[0].fY, pts[1].fY));
    247     center0.set(center1.fX, center1.fY + radius1 - radius0);
    248     return SkGradientShader::CreateTwoPointConical(center0, radius0,
    249                                                    center1, radius1,
    250                                                    data.fColors, data.fPos,
    251                                                    data.fCount, tm, 0, &localMatrix);
    252 }
    253 
    254 static SkShader* Make2ConicalInsideSmallRad(const SkPoint pts[2], const GradData& data,
    255                              SkShader::TileMode tm, const SkMatrix& localMatrix) {
    256     SkPoint center0, center1;
    257     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
    258                 SkScalarAve(pts[0].fY, pts[1].fY));
    259     center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
    260                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
    261     return SkGradientShader::CreateTwoPointConical(center0, 0.0000000000000000001f,
    262                                                    center0, (pts[1].fX - pts[0].fX) / 2,
    263                                                    data.fColors, data.fPos, data.fCount, tm,
    264                                                    0, &localMatrix);
    265 }
    266 
    267 typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
    268                                SkShader::TileMode tm, const SkMatrix& localMatrix);
    269 
    270 static const GradMaker gGradMakersOutside[] = {
    271     Make2ConicalOutside, Make2ConicalOutsideFlip,
    272     Make2ConicalZeroRadOutside, Make2ConicalZeroRadFlipOutside
    273 };
    274 
    275 static const GradMaker gGradMakersInside[] = {
    276     Make2ConicalInside, Make2ConicalInsideFlip, Make2ConicalInsideCenter,
    277     Make2ConicalZeroRad, Make2ConicalZeroRadFlip, Make2ConicalZeroRadCenter,
    278 };
    279 
    280 static const GradMaker gGradMakersEdgeCases[] = {
    281     Make2ConicalEdgeX, Make2ConicalEdgeY,
    282     Make2ConicalZeroRadEdgeX, Make2ConicalZeroRadEdgeY,
    283     Make2ConicalTouchX, Make2ConicalTouchY,
    284     Make2ConicalInsideSmallRad
    285 };
    286 
    287 
    288 static const struct {
    289     const GradMaker*   fMaker;
    290     const int fCount;
    291     const char* fName;
    292 } gGradCases[] = {
    293     { gGradMakersOutside,   SK_ARRAY_COUNT(gGradMakersOutside),     "outside"  },
    294     { gGradMakersInside,    SK_ARRAY_COUNT(gGradMakersInside),      "inside"  },
    295     { gGradMakersEdgeCases, SK_ARRAY_COUNT(gGradMakersEdgeCases),   "edge"  },
    296 };
    297 
    298 enum GradCaseType { // these must match the order in gGradCases
    299     kOutside_GradCaseType,
    300     kInside_GradCaseType,
    301     kEdge_GradCaseType,
    302 };
    303 
    304 ///////////////////////////////////////////////////////////////////////////////
    305 
    306 class ConicalGradientsGM : public GM {
    307 public:
    308     ConicalGradientsGM(GradCaseType gradCaseType, bool dither)
    309         : fGradCaseType(gradCaseType)
    310         , fDither(dither) {
    311         this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
    312         fName.printf("gradients_2pt_conical_%s%s", gGradCases[gradCaseType].fName,
    313                      fDither ? "" : "_nodither");
    314     }
    315 
    316 protected:
    317     SkString onShortName() {
    318         return fName;
    319     }
    320 
    321     virtual SkISize onISize() { return SkISize::Make(840, 815); }
    322 
    323     virtual void onDraw(SkCanvas* canvas) {
    324 
    325         SkPoint pts[2] = {
    326             { 0, 0 },
    327             { SkIntToScalar(100), SkIntToScalar(100) }
    328         };
    329         SkShader::TileMode tm = SkShader::kClamp_TileMode;
    330         SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
    331         SkPaint paint;
    332         paint.setAntiAlias(true);
    333         paint.setDither(fDither);
    334 
    335         canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
    336 
    337         const GradMaker* gradMaker = gGradCases[fGradCaseType].fMaker;
    338         const int count = gGradCases[fGradCaseType].fCount;
    339 
    340         for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
    341             canvas->save();
    342             for (int j = 0; j < count; j++) {
    343                 SkMatrix scale = SkMatrix::I();
    344 
    345                 if (i == 3) { // if the clamp case
    346                     scale.setScale(0.5f, 0.5f);
    347                     scale.postTranslate(25.f, 25.f);
    348                 }
    349 
    350                 SkShader* shader = gradMaker[j](pts, gGradData[i], tm, scale);
    351                 paint.setShader(shader);
    352                 canvas->drawRect(r, paint);
    353                 shader->unref();
    354                 canvas->translate(0, SkIntToScalar(120));
    355             }
    356             canvas->restore();
    357             canvas->translate(SkIntToScalar(120), 0);
    358         }
    359     }
    360 
    361 private:
    362     typedef GM INHERITED;
    363 
    364     GradCaseType fGradCaseType;
    365     SkString fName;
    366     bool fDither;
    367 };
    368 ///////////////////////////////////////////////////////////////////////////////
    369 
    370 DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, true); )
    371 DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, true); )
    372 DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, true); )
    373 
    374 DEF_GM( return new ConicalGradientsGM(kInside_GradCaseType, false); )
    375 DEF_GM( return new ConicalGradientsGM(kOutside_GradCaseType, false); )
    376 DEF_GM( return new ConicalGradientsGM(kEdge_GradCaseType, false); )
    377 
    378 }
    379