Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2011 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 "sk_tool_utils.h"
     10 #include "SkBitmap.h"
     11 #include "SkShader.h"
     12 #include "SkPM4f.h"
     13 
     14 enum SrcType {
     15     //! A WxH image with a rectangle in the lower right.
     16     kRectangleImage_SrcType               = 0x01,
     17     //! kRectangleImage_SrcType with an alpha of 34.5%.
     18     kRectangleImageWithAlpha_SrcType      = 0x02,
     19     //! kRectnagleImageWithAlpha_SrcType scaled down by half.
     20     kSmallRectangleImageWithAlpha_SrcType = 0x04,
     21     //! kRectangleImage_SrcType drawn directly instead in an image.
     22     kRectangle_SrcType                    = 0x08,
     23     //! Two rectangles, first on the right half, second on the bottom half.
     24     kQuarterClear_SrcType                 = 0x10,
     25     //! kQuarterClear_SrcType in a layer.
     26     kQuarterClearInLayer_SrcType          = 0x20,
     27     //! A W/2xH/2 transparent image.
     28     kSmallTransparentImage_SrcType        = 0x40,
     29     //! kRectangleImage_SrcType drawn directly with a mask.
     30     kRectangleWithMask_SrcType            = 0x80,
     31 
     32     kAll_SrcType                          = 0xFF, //!< All the source types.
     33     kBasic_SrcType                        = 0x03, //!< Just basic source types.
     34 };
     35 
     36 const struct {
     37     SkBlendMode fMode;
     38     int         fSourceTypeMask;  // The source types to use this
     39     // mode with. See draw_mode for
     40     // an explanation of each type.
     41     // PDF has to play some tricks
     42     // to support the base modes,
     43     // test those more extensively.
     44 } gModes[] = {
     45     { SkBlendMode::kClear,        kAll_SrcType   },
     46     { SkBlendMode::kSrc,          kAll_SrcType   },
     47     { SkBlendMode::kDst,          kAll_SrcType   },
     48     { SkBlendMode::kSrcOver,      kAll_SrcType   },
     49     { SkBlendMode::kDstOver,      kAll_SrcType   },
     50     { SkBlendMode::kSrcIn,        kAll_SrcType   },
     51     { SkBlendMode::kDstIn,        kAll_SrcType   },
     52     { SkBlendMode::kSrcOut,       kAll_SrcType   },
     53     { SkBlendMode::kDstOut,       kAll_SrcType   },
     54     { SkBlendMode::kSrcATop,      kAll_SrcType   },
     55     { SkBlendMode::kDstATop,      kAll_SrcType   },
     56 
     57     { SkBlendMode::kXor,          kBasic_SrcType },
     58     { SkBlendMode::kPlus,         kBasic_SrcType },
     59     { SkBlendMode::kModulate,     kAll_SrcType   },
     60     { SkBlendMode::kScreen,       kBasic_SrcType },
     61     { SkBlendMode::kOverlay,      kBasic_SrcType },
     62     { SkBlendMode::kDarken,       kBasic_SrcType },
     63     { SkBlendMode::kLighten,      kBasic_SrcType },
     64     { SkBlendMode::kColorDodge,   kBasic_SrcType },
     65     { SkBlendMode::kColorBurn,    kBasic_SrcType },
     66     { SkBlendMode::kHardLight,    kBasic_SrcType },
     67     { SkBlendMode::kSoftLight,    kBasic_SrcType },
     68     { SkBlendMode::kDifference,   kBasic_SrcType },
     69     { SkBlendMode::kExclusion,    kBasic_SrcType },
     70     { SkBlendMode::kMultiply,     kAll_SrcType   },
     71     { SkBlendMode::kHue,          kBasic_SrcType },
     72     { SkBlendMode::kSaturation,   kBasic_SrcType },
     73     { SkBlendMode::kColor,        kBasic_SrcType },
     74     { SkBlendMode::kLuminosity,   kBasic_SrcType },
     75 };
     76 
     77 static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst,
     78                          SkBitmap* transparent) {
     79     src->allocN32Pixels(w, h);
     80     src->eraseColor(SK_ColorTRANSPARENT);
     81 
     82     SkPaint p;
     83     p.setAntiAlias(true);
     84 
     85     SkRect r;
     86     SkScalar ww = SkIntToScalar(w);
     87     SkScalar hh = SkIntToScalar(h);
     88 
     89     {
     90         SkCanvas c(*src);
     91         p.setColor(sk_tool_utils::color_to_565(0xFFFFCC44));
     92         r.set(0, 0, ww*3/4, hh*3/4);
     93         c.drawOval(r, p);
     94     }
     95 
     96     dst->allocN32Pixels(w, h);
     97     dst->eraseColor(SK_ColorTRANSPARENT);
     98 
     99     {
    100         SkCanvas c(*dst);
    101         p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
    102         r.set(ww/3, hh/3, ww*19/20, hh*19/20);
    103         c.drawRect(r, p);
    104     }
    105 
    106     transparent->allocN32Pixels(w, h);
    107     transparent->eraseColor(SK_ColorTRANSPARENT);
    108 }
    109 
    110 static uint16_t gData[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
    111 
    112 class XfermodesGM : public skiagm::GM {
    113     SkBitmap    fBG;
    114     SkBitmap    fSrcB, fDstB, fTransparent;
    115 
    116     /* The srcType argument indicates what to draw for the source part. Skia
    117      * uses the implied shape of the drawing command and these modes
    118      * demonstrate that.
    119      */
    120     void draw_mode(SkCanvas* canvas, SkBlendMode mode, SrcType srcType, SkScalar x, SkScalar y) {
    121         SkPaint p;
    122         SkMatrix m;
    123         bool restoreNeeded = false;
    124         m.setTranslate(x, y);
    125 
    126         canvas->drawBitmap(fSrcB, x, y, &p);
    127         p.setBlendMode(mode);
    128         switch (srcType) {
    129             case kSmallTransparentImage_SrcType: {
    130                 m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y);
    131 
    132                 SkAutoCanvasRestore acr(canvas, true);
    133                 canvas->concat(m);
    134                 canvas->drawBitmap(fTransparent, 0, 0, &p);
    135                 break;
    136             }
    137             case kQuarterClearInLayer_SrcType: {
    138                 SkRect bounds = SkRect::MakeXYWH(x, y, SkIntToScalar(W),
    139                                                  SkIntToScalar(H));
    140                 canvas->saveLayer(&bounds, &p);
    141                 restoreNeeded = true;
    142                 p.setBlendMode(SkBlendMode::kSrcOver);
    143                 // Fall through.
    144             }
    145             case kQuarterClear_SrcType: {
    146                 SkScalar halfW = SkIntToScalar(W) / 2;
    147                 SkScalar halfH = SkIntToScalar(H) / 2;
    148                 p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
    149                 SkRect r = SkRect::MakeXYWH(x + halfW, y, halfW,
    150                                             SkIntToScalar(H));
    151                 canvas->drawRect(r, p);
    152                 p.setColor(sk_tool_utils::color_to_565(0xFFAA66FF));
    153                 r = SkRect::MakeXYWH(x, y + halfH, SkIntToScalar(W), halfH);
    154                 canvas->drawRect(r, p);
    155                 break;
    156             }
    157             case kRectangleWithMask_SrcType: {
    158                 canvas->save();
    159                 restoreNeeded = true;
    160                 SkScalar w = SkIntToScalar(W);
    161                 SkScalar h = SkIntToScalar(H);
    162                 SkRect r = SkRect::MakeXYWH(x, y + h / 4, w, h * 23 / 60);
    163                 canvas->clipRect(r);
    164                 // Fall through.
    165             }
    166             case kRectangle_SrcType: {
    167                 SkScalar w = SkIntToScalar(W);
    168                 SkScalar h = SkIntToScalar(H);
    169                 SkRect r = SkRect::MakeXYWH(x + w / 3, y + h / 3,
    170                                             w * 37 / 60, h * 37 / 60);
    171                 p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
    172                 canvas->drawRect(r, p);
    173                 break;
    174             }
    175             case kSmallRectangleImageWithAlpha_SrcType:
    176                 m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y);
    177                 // Fall through.
    178             case kRectangleImageWithAlpha_SrcType:
    179                 p.setAlpha(0x88);
    180                 // Fall through.
    181             case kRectangleImage_SrcType: {
    182                 SkAutoCanvasRestore acr(canvas, true);
    183                 canvas->concat(m);
    184                 canvas->drawBitmap(fDstB, 0, 0, &p);
    185                 break;
    186             }
    187             default:
    188                 break;
    189         }
    190 
    191         if (restoreNeeded) {
    192             canvas->restore();
    193         }
    194     }
    195 
    196     void onOnceBeforeDraw() override {
    197         fBG.installPixels(SkImageInfo::Make(2, 2, kARGB_4444_SkColorType,
    198                                             kOpaque_SkAlphaType),
    199                           gData, 4);
    200 
    201         make_bitmaps(W, H, &fSrcB, &fDstB, &fTransparent);
    202     }
    203 
    204 public:
    205     const static int W = 64;
    206     const static int H = 64;
    207     XfermodesGM() {}
    208 
    209 protected:
    210     SkString onShortName() override {
    211         return SkString("xfermodes");
    212     }
    213 
    214     SkISize onISize() override {
    215         return SkISize::Make(1990, 570);
    216     }
    217 
    218     void onDraw(SkCanvas* canvas) override {
    219         canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
    220 
    221         const SkScalar w = SkIntToScalar(W);
    222         const SkScalar h = SkIntToScalar(H);
    223         SkMatrix m;
    224         m.setScale(SkIntToScalar(6), SkIntToScalar(6));
    225         auto s = SkShader::MakeBitmapShader(fBG, SkShader::kRepeat_TileMode,
    226                                             SkShader::kRepeat_TileMode, &m);
    227 
    228         SkPaint labelP;
    229         labelP.setAntiAlias(true);
    230         sk_tool_utils::set_portable_typeface(&labelP);
    231         labelP.setTextAlign(SkPaint::kCenter_Align);
    232 
    233         const int W = 5;
    234 
    235         SkScalar x0 = 0;
    236         SkScalar y0 = 0;
    237         for (int sourceType = 1; sourceType & kAll_SrcType; sourceType <<= 1) {
    238             SkScalar x = x0, y = y0;
    239             for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
    240                 if ((gModes[i].fSourceTypeMask & sourceType) == 0) {
    241                     continue;
    242                 }
    243                 SkRect r{ x, y, x+w, y+h };
    244 
    245                 SkPaint p;
    246                 p.setStyle(SkPaint::kFill_Style);
    247                 p.setShader(s);
    248                 canvas->drawRect(r, p);
    249 
    250                 canvas->saveLayer(&r, nullptr);
    251                 draw_mode(canvas, gModes[i].fMode, static_cast<SrcType>(sourceType),
    252                           r.fLeft, r.fTop);
    253                 canvas->restore();
    254 
    255                 r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
    256                 p.setStyle(SkPaint::kStroke_Style);
    257                 p.setShader(nullptr);
    258                 canvas->drawRect(r, p);
    259 
    260 #if 1
    261                 const char* label = SkBlendMode_Name(gModes[i].fMode);
    262                 canvas->drawString(label,
    263                                  x + w/2, y - labelP.getTextSize()/2, labelP);
    264 #endif
    265                 x += w + SkIntToScalar(10);
    266                 if ((i % W) == W - 1) {
    267                     x = x0;
    268                     y += h + SkIntToScalar(30);
    269                 }
    270             }
    271             if (y < 320) {
    272                 if (x > x0) {
    273                     y += h + SkIntToScalar(30);
    274                 }
    275                 y0 = y;
    276             } else {
    277                 x0 += SkIntToScalar(400);
    278                 y0 = 0;
    279             }
    280         }
    281     }
    282 
    283 private:
    284     typedef GM INHERITED;
    285 };
    286 DEF_GM( return new XfermodesGM; )
    287