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 "SkBitmap.h"
     10 #include "SkShader.h"
     11 #include "SkXfermode.h"
     12 #include "SkPM4f.h"
     13 
     14 #include "SkArithmeticMode.h"
     15 #include "SkPixelXorXfermode.h"
     16 #include "SkAvoidXfermode.h"
     17 
     18 #define kCustomShift    16
     19 #define kCustomMask     (~0xFFFF)
     20 
     21 enum CustomModes {
     22     kArithmetic_CustomMode  = 1 << kCustomShift,
     23     kPixelXor_CustomMode    = 2 << kCustomShift,
     24     kAvoid_CustomMode       = 3 << kCustomShift,
     25 };
     26 
     27 static SkXfermode* make_custom(int customMode) {
     28     switch (customMode) {
     29         case kArithmetic_CustomMode: {
     30             const SkScalar k1 = 0.25;
     31             const SkScalar k2 = 0.75;
     32             const SkScalar k3 = 0.75;
     33             const SkScalar k4 = -0.25;
     34             return SkArithmeticMode::Create(k1, k2, k3, k4);
     35         }
     36         case kPixelXor_CustomMode:
     37             return SkPixelXorXfermode::Create(0xFF88CC44);
     38         case kAvoid_CustomMode:
     39             return SkAvoidXfermode::Create(0xFFFF0000, 0x44, SkAvoidXfermode::kAvoidColor_Mode);
     40         default:
     41             break;
     42     }
     43     SkASSERT(false);
     44     return nullptr;
     45 }
     46 
     47 enum SrcType {
     48     //! A WxH image with a rectangle in the lower right.
     49     kRectangleImage_SrcType               = 0x01,
     50     //! kRectangleImage_SrcType with an alpha of 34.5%.
     51     kRectangleImageWithAlpha_SrcType      = 0x02,
     52     //! kRectnagleImageWithAlpha_SrcType scaled down by half.
     53     kSmallRectangleImageWithAlpha_SrcType = 0x04,
     54     //! kRectangleImage_SrcType drawn directly instead in an image.
     55     kRectangle_SrcType                    = 0x08,
     56     //! Two rectangles, first on the right half, second on the bottom half.
     57     kQuarterClear_SrcType                 = 0x10,
     58     //! kQuarterClear_SrcType in a layer.
     59     kQuarterClearInLayer_SrcType          = 0x20,
     60     //! A W/2xH/2 transparent image.
     61     kSmallTransparentImage_SrcType        = 0x40,
     62     //! kRectangleImage_SrcType drawn directly with a mask.
     63     kRectangleWithMask_SrcType            = 0x80,
     64 
     65     kAll_SrcType                          = 0xFF, //!< All the source types.
     66     kBasic_SrcType                        = 0x03, //!< Just basic source types.
     67 };
     68 
     69 const struct {
     70     SkXfermode::Mode  fMode;
     71     const char*       fLabel;
     72     int               fSourceTypeMask;  // The source types to use this
     73     // mode with. See draw_mode for
     74     // an explanation of each type.
     75     // PDF has to play some tricks
     76     // to support the base modes,
     77     // test those more extensively.
     78 } gModes[] = {
     79     { SkXfermode::kClear_Mode,        "Clear",        kAll_SrcType   },
     80     { SkXfermode::kSrc_Mode,          "Src",          kAll_SrcType   },
     81     { SkXfermode::kDst_Mode,          "Dst",          kAll_SrcType   },
     82     { SkXfermode::kSrcOver_Mode,      "SrcOver",      kAll_SrcType   },
     83     { SkXfermode::kDstOver_Mode,      "DstOver",      kAll_SrcType   },
     84     { SkXfermode::kSrcIn_Mode,        "SrcIn",        kAll_SrcType   },
     85     { SkXfermode::kDstIn_Mode,        "DstIn",        kAll_SrcType   },
     86     { SkXfermode::kSrcOut_Mode,       "SrcOut",       kAll_SrcType   },
     87     { SkXfermode::kDstOut_Mode,       "DstOut",       kAll_SrcType   },
     88     { SkXfermode::kSrcATop_Mode,      "SrcATop",      kAll_SrcType   },
     89     { SkXfermode::kDstATop_Mode,      "DstATop",      kAll_SrcType   },
     90 
     91     { SkXfermode::kXor_Mode,          "Xor",          kBasic_SrcType },
     92     { SkXfermode::kPlus_Mode,         "Plus",         kBasic_SrcType },
     93     { SkXfermode::kModulate_Mode,     "Modulate",     kAll_SrcType   },
     94     { SkXfermode::kScreen_Mode,       "Screen",       kBasic_SrcType },
     95     { SkXfermode::kOverlay_Mode,      "Overlay",      kBasic_SrcType },
     96     { SkXfermode::kDarken_Mode,       "Darken",       kBasic_SrcType },
     97     { SkXfermode::kLighten_Mode,      "Lighten",      kBasic_SrcType },
     98     { SkXfermode::kColorDodge_Mode,   "ColorDodge",   kBasic_SrcType },
     99     { SkXfermode::kColorBurn_Mode,    "ColorBurn",    kBasic_SrcType },
    100     { SkXfermode::kHardLight_Mode,    "HardLight",    kBasic_SrcType },
    101     { SkXfermode::kSoftLight_Mode,    "SoftLight",    kBasic_SrcType },
    102     { SkXfermode::kDifference_Mode,   "Difference",   kBasic_SrcType },
    103     { SkXfermode::kExclusion_Mode,    "Exclusion",    kBasic_SrcType },
    104     { SkXfermode::kMultiply_Mode,     "Multiply",     kAll_SrcType   },
    105     { SkXfermode::kHue_Mode,          "Hue",          kBasic_SrcType },
    106     { SkXfermode::kSaturation_Mode,   "Saturation",   kBasic_SrcType },
    107     { SkXfermode::kColor_Mode,        "Color",        kBasic_SrcType },
    108     { SkXfermode::kLuminosity_Mode,   "Luminosity",   kBasic_SrcType },
    109 
    110     { SkXfermode::Mode(0xFFFF),       "Arithmetic",   kBasic_SrcType + kArithmetic_CustomMode   },
    111     { SkXfermode::Mode(0xFFFF),       "PixelXor",     kBasic_SrcType + kPixelXor_CustomMode     },
    112     { SkXfermode::Mode(0xFFFF),       "Avoid",        kBasic_SrcType + kAvoid_CustomMode        },
    113 };
    114 
    115 static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst,
    116                          SkBitmap* transparent) {
    117     src->allocN32Pixels(w, h);
    118     src->eraseColor(SK_ColorTRANSPARENT);
    119 
    120     SkPaint p;
    121     p.setAntiAlias(true);
    122 
    123     SkRect r;
    124     SkScalar ww = SkIntToScalar(w);
    125     SkScalar hh = SkIntToScalar(h);
    126 
    127     {
    128         SkCanvas c(*src);
    129         p.setColor(sk_tool_utils::color_to_565(0xFFFFCC44));
    130         r.set(0, 0, ww*3/4, hh*3/4);
    131         c.drawOval(r, p);
    132     }
    133 
    134     dst->allocN32Pixels(w, h);
    135     dst->eraseColor(SK_ColorTRANSPARENT);
    136 
    137     {
    138         SkCanvas c(*dst);
    139         p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
    140         r.set(ww/3, hh/3, ww*19/20, hh*19/20);
    141         c.drawRect(r, p);
    142     }
    143 
    144     transparent->allocN32Pixels(w, h);
    145     transparent->eraseColor(SK_ColorTRANSPARENT);
    146 }
    147 
    148 static uint16_t gData[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
    149 
    150 class XfermodesGM : public skiagm::GM {
    151     SkBitmap    fBG;
    152     SkBitmap    fSrcB, fDstB, fTransparent;
    153 
    154     /* The srcType argument indicates what to draw for the source part. Skia
    155      * uses the implied shape of the drawing command and these modes
    156      * demonstrate that.
    157      */
    158     void draw_mode(SkCanvas* canvas, SkXfermode* mode, SrcType srcType,
    159                    SkScalar x, SkScalar y) {
    160         SkPaint p;
    161         SkMatrix m;
    162         bool restoreNeeded = false;
    163         m.setTranslate(x, y);
    164 
    165         canvas->drawBitmap(fSrcB, x, y, &p);
    166         p.setXfermode(mode);
    167         switch (srcType) {
    168             case kSmallTransparentImage_SrcType: {
    169                 m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y);
    170 
    171                 SkAutoCanvasRestore acr(canvas, true);
    172                 canvas->concat(m);
    173                 canvas->drawBitmap(fTransparent, 0, 0, &p);
    174                 break;
    175             }
    176             case kQuarterClearInLayer_SrcType: {
    177                 SkRect bounds = SkRect::MakeXYWH(x, y, SkIntToScalar(W),
    178                                                  SkIntToScalar(H));
    179                 canvas->saveLayer(&bounds, &p);
    180                 restoreNeeded = true;
    181                 p.setXfermodeMode(SkXfermode::kSrcOver_Mode);
    182                 // Fall through.
    183             }
    184             case kQuarterClear_SrcType: {
    185                 SkScalar halfW = SkIntToScalar(W) / 2;
    186                 SkScalar halfH = SkIntToScalar(H) / 2;
    187                 p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
    188                 SkRect r = SkRect::MakeXYWH(x + halfW, y, halfW,
    189                                             SkIntToScalar(H));
    190                 canvas->drawRect(r, p);
    191                 p.setColor(sk_tool_utils::color_to_565(0xFFAA66FF));
    192                 r = SkRect::MakeXYWH(x, y + halfH, SkIntToScalar(W), halfH);
    193                 canvas->drawRect(r, p);
    194                 break;
    195             }
    196             case kRectangleWithMask_SrcType: {
    197                 canvas->save();
    198                 restoreNeeded = true;
    199                 SkScalar w = SkIntToScalar(W);
    200                 SkScalar h = SkIntToScalar(H);
    201                 SkRect r = SkRect::MakeXYWH(x, y + h / 4, w, h * 23 / 60);
    202                 canvas->clipRect(r);
    203                 // Fall through.
    204             }
    205             case kRectangle_SrcType: {
    206                 SkScalar w = SkIntToScalar(W);
    207                 SkScalar h = SkIntToScalar(H);
    208                 SkRect r = SkRect::MakeXYWH(x + w / 3, y + h / 3,
    209                                             w * 37 / 60, h * 37 / 60);
    210                 p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
    211                 canvas->drawRect(r, p);
    212                 break;
    213             }
    214             case kSmallRectangleImageWithAlpha_SrcType:
    215                 m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y);
    216                 // Fall through.
    217             case kRectangleImageWithAlpha_SrcType:
    218                 p.setAlpha(0x88);
    219                 // Fall through.
    220             case kRectangleImage_SrcType: {
    221                 SkAutoCanvasRestore acr(canvas, true);
    222                 canvas->concat(m);
    223                 canvas->drawBitmap(fDstB, 0, 0, &p);
    224                 break;
    225             }
    226             default:
    227                 break;
    228         }
    229 
    230         if (restoreNeeded) {
    231             canvas->restore();
    232         }
    233     }
    234 
    235     void onOnceBeforeDraw() override {
    236         fBG.installPixels(SkImageInfo::Make(2, 2, kARGB_4444_SkColorType,
    237                                             kOpaque_SkAlphaType),
    238                           gData, 4);
    239 
    240         make_bitmaps(W, H, &fSrcB, &fDstB, &fTransparent);
    241     }
    242 
    243 public:
    244     const static int W = 64;
    245     const static int H = 64;
    246     XfermodesGM() {}
    247 
    248 protected:
    249     SkString onShortName() override {
    250         return SkString("xfermodes");
    251     }
    252 
    253     SkISize onISize() override {
    254         return SkISize::Make(1990, 660);
    255     }
    256 
    257     void onDraw(SkCanvas* canvas) override {
    258         canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
    259 
    260         const SkScalar w = SkIntToScalar(W);
    261         const SkScalar h = SkIntToScalar(H);
    262         SkMatrix m;
    263         m.setScale(SkIntToScalar(6), SkIntToScalar(6));
    264         SkShader* s = SkShader::CreateBitmapShader(fBG,
    265                                                    SkShader::kRepeat_TileMode,
    266                                                    SkShader::kRepeat_TileMode,
    267                                                    &m);
    268 
    269         SkPaint labelP;
    270         labelP.setAntiAlias(true);
    271         sk_tool_utils::set_portable_typeface(&labelP);
    272         labelP.setTextAlign(SkPaint::kCenter_Align);
    273 
    274         const int W = 5;
    275 
    276         SkScalar x0 = 0;
    277         SkScalar y0 = 0;
    278         for (int sourceType = 1; sourceType & kAll_SrcType; sourceType <<= 1) {
    279             SkScalar x = x0, y = y0;
    280             for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
    281                 if ((gModes[i].fSourceTypeMask & sourceType) == 0) {
    282                     continue;
    283                 }
    284                 SkAutoTUnref<SkXfermode> mode;
    285                 if (gModes[i].fSourceTypeMask & kCustomMask) {
    286                     mode.reset(make_custom(gModes[i].fSourceTypeMask & kCustomMask));
    287                 } else {
    288                     mode.reset(SkXfermode::Create(gModes[i].fMode));
    289                 }
    290                 SkRect r;
    291                 r.set(x, y, x+w, y+h);
    292 
    293                 SkPaint p;
    294                 p.setStyle(SkPaint::kFill_Style);
    295                 p.setShader(s);
    296                 canvas->drawRect(r, p);
    297 
    298                 canvas->saveLayer(&r, nullptr);
    299                 draw_mode(canvas, mode, static_cast<SrcType>(sourceType),
    300                           r.fLeft, r.fTop);
    301                 canvas->restore();
    302 
    303                 r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
    304                 p.setStyle(SkPaint::kStroke_Style);
    305                 p.setShader(nullptr);
    306                 canvas->drawRect(r, p);
    307 
    308 #if 1
    309                 canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
    310                                  x + w/2, y - labelP.getTextSize()/2, labelP);
    311 #endif
    312                 x += w + SkIntToScalar(10);
    313                 if ((i % W) == W - 1) {
    314                     x = x0;
    315                     y += h + SkIntToScalar(30);
    316                 }
    317             }
    318             if (y < 320) {
    319                 if (x > x0) {
    320                     y += h + SkIntToScalar(30);
    321                 }
    322                 y0 = y;
    323             } else {
    324                 x0 += SkIntToScalar(400);
    325                 y0 = 0;
    326             }
    327         }
    328         s->unref();
    329     }
    330 
    331 private:
    332     typedef GM INHERITED;
    333 };
    334 DEF_GM( return new XfermodesGM; )
    335