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 = SkScalarDiv(pts[1].fX - pts[0].fX, 10);
     44     SkScalar radius1 = SkScalarDiv(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 = SkScalarDiv(pts[1].fX - pts[0].fX, 10);
     57     SkScalar radius1 = SkScalarDiv(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 = SkScalarDiv(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 = SkScalarDiv(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 = SkScalarDiv(pts[1].fX - pts[0].fX, 7);
    174     SkScalar radius1 = SkScalarDiv(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 = SkScalarDiv(pts[1].fX - pts[0].fX, 7);
    188     SkScalar radius1 = SkScalarDiv(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 = SkScalarDiv(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 = SkScalarDiv(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 = SkScalarDiv(pts[1].fX - pts[0].fX, 7);
    230     SkScalar radius1 = SkScalarDiv(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 = SkScalarDiv(pts[1].fX - pts[0].fX, 7);
    244     SkScalar radius1 = SkScalarDiv(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) {
    309         this->setBGColor(0xFFDDDDDD);
    310         fName.printf("gradients_2pt_conical_%s", gGradCases[gradCaseType].fName);
    311         fGradCaseType = gradCaseType;
    312     }
    313 
    314 protected:
    315     virtual uint32_t onGetFlags() const SK_OVERRIDE {
    316         if (fGradCaseType != kInside_GradCaseType) {
    317             return kSkipTiled_Flag;
    318         }
    319         return 0;
    320     }
    321 
    322     SkString onShortName() {
    323         return fName;
    324     }
    325 
    326     virtual SkISize onISize() { return SkISize::Make(840, 815); }
    327 
    328     virtual void onDraw(SkCanvas* canvas) {
    329 
    330         SkPoint pts[2] = {
    331             { 0, 0 },
    332             { SkIntToScalar(100), SkIntToScalar(100) }
    333         };
    334         SkShader::TileMode tm = SkShader::kClamp_TileMode;
    335         SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
    336         SkPaint paint;
    337         paint.setAntiAlias(true);
    338 
    339         canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
    340 
    341         const GradMaker* gradMaker = gGradCases[fGradCaseType].fMaker;
    342         const int count = gGradCases[fGradCaseType].fCount;
    343 
    344         for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
    345             canvas->save();
    346             for (int j = 0; j < count; j++) {
    347                 SkMatrix scale = SkMatrix::I();
    348 
    349                 if (i == 3) { // if the clamp case
    350                     scale.setScale(0.5f, 0.5f);
    351                     scale.postTranslate(25.f, 25.f);
    352                 }
    353 
    354                 SkShader* shader = gradMaker[j](pts, gGradData[i], tm, scale);
    355                 paint.setShader(shader);
    356                 canvas->drawRect(r, paint);
    357                 shader->unref();
    358                 canvas->translate(0, SkIntToScalar(120));
    359             }
    360             canvas->restore();
    361             canvas->translate(SkIntToScalar(120), 0);
    362         }
    363     }
    364 
    365 private:
    366     typedef GM INHERITED;
    367 
    368     GradCaseType fGradCaseType;
    369     SkString fName;
    370 };
    371 ///////////////////////////////////////////////////////////////////////////////
    372 
    373 static GM* MyFactory1(void*) { return new ConicalGradientsGM(kInside_GradCaseType); }
    374 static GMRegistry reg1(MyFactory1);
    375 
    376 static GM* MyFactory2(void*) { return new ConicalGradientsGM(kOutside_GradCaseType); }
    377 static GMRegistry reg2(MyFactory2);
    378 
    379 static GM* MyFactory3(void*) { return new ConicalGradientsGM(kEdge_GradCaseType); }
    380 static GMRegistry reg3(MyFactory3);
    381 }
    382