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 
      8 #include "gm.h"
      9 #include "sk_tool_utils.h"
     10 #include "SkArithmeticImageFilter.h"
     11 #include "SkImage.h"
     12 #include "SkImageSource.h"
     13 #include "SkOffsetImageFilter.h"
     14 #include "SkXfermodeImageFilter.h"
     15 
     16 #define WIDTH 600
     17 #define HEIGHT 700
     18 #define MARGIN 12
     19 
     20 namespace skiagm {
     21 
     22 class XfermodeImageFilterGM : public GM {
     23 public:
     24     XfermodeImageFilterGM(){
     25         this->setBGColor(0xFF000000);
     26     }
     27 
     28 protected:
     29     SkString onShortName() override {
     30         return SkString("xfermodeimagefilter");
     31     }
     32 
     33     SkISize onISize() override {
     34         return SkISize::Make(WIDTH, HEIGHT);
     35     }
     36 
     37     void onOnceBeforeDraw() override {
     38         fBitmap = sk_tool_utils::create_string_bitmap(80, 80, 0xD000D000, 15, 65, 96, "e");
     39 
     40         fCheckerboard = SkImage::MakeFromBitmap(
     41             sk_tool_utils::create_checkerboard_bitmap(80, 80,
     42                                                       sk_tool_utils::color_to_565(0xFFA0A0A0),
     43                                                       sk_tool_utils::color_to_565(0xFF404040),
     44                                                       8));
     45     }
     46 
     47     void onDraw(SkCanvas* canvas) override {
     48         canvas->clear(SK_ColorBLACK);
     49         SkPaint paint;
     50 
     51         const SkBlendMode gModes[] = {
     52             SkBlendMode::kClear,
     53             SkBlendMode::kSrc,
     54             SkBlendMode::kDst,
     55             SkBlendMode::kSrcOver,
     56             SkBlendMode::kDstOver,
     57             SkBlendMode::kSrcIn,
     58             SkBlendMode::kDstIn,
     59             SkBlendMode::kSrcOut,
     60             SkBlendMode::kDstOut,
     61             SkBlendMode::kSrcATop,
     62             SkBlendMode::kDstATop,
     63             SkBlendMode::kXor,
     64 
     65             SkBlendMode::kPlus,
     66             SkBlendMode::kModulate,
     67             SkBlendMode::kScreen,
     68             SkBlendMode::kOverlay,
     69             SkBlendMode::kDarken,
     70             SkBlendMode::kLighten,
     71             SkBlendMode::kColorDodge,
     72             SkBlendMode::kColorBurn,
     73             SkBlendMode::kHardLight,
     74             SkBlendMode::kSoftLight,
     75             SkBlendMode::kDifference,
     76             SkBlendMode::kExclusion,
     77             SkBlendMode::kMultiply,
     78             SkBlendMode::kHue,
     79             SkBlendMode::kSaturation,
     80             SkBlendMode::kColor,
     81             SkBlendMode::kLuminosity,
     82         };
     83 
     84         int x = 0, y = 0;
     85         sk_sp<SkImageFilter> background(SkImageSource::Make(fCheckerboard));
     86         for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
     87             paint.setImageFilter(SkXfermodeImageFilter::Make(gModes[i], background));
     88             DrawClippedBitmap(canvas, fBitmap, paint, x, y);
     89             x += fBitmap.width() + MARGIN;
     90             if (x + fBitmap.width() > WIDTH) {
     91                 x = 0;
     92                 y += fBitmap.height() + MARGIN;
     93             }
     94         }
     95         // Test arithmetic mode as image filter
     96         paint.setImageFilter(SkArithmeticImageFilter::Make(0, 1, 1, 0, true, background,
     97                                                            nullptr, nullptr));
     98         DrawClippedBitmap(canvas, fBitmap, paint, x, y);
     99         x += fBitmap.width() + MARGIN;
    100         if (x + fBitmap.width() > WIDTH) {
    101             x = 0;
    102             y += fBitmap.height() + MARGIN;
    103         }
    104         // Test nullptr mode
    105         paint.setImageFilter(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, background));
    106         DrawClippedBitmap(canvas, fBitmap, paint, x, y);
    107         x += fBitmap.width() + MARGIN;
    108         if (x + fBitmap.width() > WIDTH) {
    109             x = 0;
    110             y += fBitmap.height() + MARGIN;
    111         }
    112         SkRect clipRect = SkRect::MakeWH(SkIntToScalar(fBitmap.width() + 4),
    113                                          SkIntToScalar(fBitmap.height() + 4));
    114         // Test offsets on SrcMode (uses fixed-function blend)
    115         sk_sp<SkImage> bitmapImage(SkImage::MakeFromBitmap(fBitmap));
    116         sk_sp<SkImageFilter> foreground(SkImageSource::Make(std::move(bitmapImage)));
    117         sk_sp<SkImageFilter> offsetForeground(SkOffsetImageFilter::Make(SkIntToScalar(4),
    118                                                                         SkIntToScalar(-4),
    119                                                                         foreground));
    120         sk_sp<SkImageFilter> offsetBackground(SkOffsetImageFilter::Make(SkIntToScalar(4),
    121                                                                         SkIntToScalar(4),
    122                                                                         background));
    123         paint.setImageFilter(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver,
    124                                                          offsetBackground,
    125                                                          offsetForeground,
    126                                                          nullptr));
    127         DrawClippedPaint(canvas, clipRect, paint, x, y);
    128         x += fBitmap.width() + MARGIN;
    129         if (x + fBitmap.width() > WIDTH) {
    130             x = 0;
    131             y += fBitmap.height() + MARGIN;
    132         }
    133         // Test offsets on Darken (uses shader blend)
    134         paint.setImageFilter(SkXfermodeImageFilter::Make(SkBlendMode::kDarken,
    135                                                          offsetBackground,
    136                                                          offsetForeground,
    137                                                          nullptr));
    138         DrawClippedPaint(canvas, clipRect, paint, x, y);
    139         x += fBitmap.width() + MARGIN;
    140         if (x + fBitmap.width() > WIDTH) {
    141             x = 0;
    142             y += fBitmap.height() + MARGIN;
    143         }
    144         // Test cropping
    145         constexpr size_t nbSamples = 3;
    146         const SkBlendMode sampledModes[nbSamples] = {
    147             SkBlendMode::kOverlay, SkBlendMode::kSrcOver, SkBlendMode::kPlus
    148         };
    149         int offsets[nbSamples][4] = {{ 10,  10, -16, -16},
    150                                      { 10,  10,  10,  10},
    151                                      {-10, -10,  -6,  -6}};
    152         for (size_t i = 0; i < nbSamples; ++i) {
    153             SkIRect cropRect = SkIRect::MakeXYWH(offsets[i][0],
    154                                                  offsets[i][1],
    155                                                  fBitmap.width()  + offsets[i][2],
    156                                                  fBitmap.height() + offsets[i][3]);
    157             SkImageFilter::CropRect rect(SkRect::Make(cropRect));
    158             paint.setImageFilter(SkXfermodeImageFilter::Make(sampledModes[i],
    159                                                              offsetBackground,
    160                                                              offsetForeground,
    161                                                              &rect));
    162             DrawClippedPaint(canvas, clipRect, paint, x, y);
    163             x += fBitmap.width() + MARGIN;
    164             if (x + fBitmap.width() > WIDTH) {
    165                 x = 0;
    166                 y += fBitmap.height() + MARGIN;
    167             }
    168         }
    169         // Test small bg, large fg with Screen (uses shader blend)
    170         SkBlendMode mode = SkBlendMode::kScreen;
    171         SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(10, 10, 60, 60));
    172         sk_sp<SkImageFilter> cropped(SkOffsetImageFilter::Make(0, 0, foreground, &cropRect));
    173         paint.setImageFilter(SkXfermodeImageFilter::Make(mode, cropped, background, nullptr));
    174         DrawClippedPaint(canvas, clipRect, paint, x, y);
    175         x += fBitmap.width() + MARGIN;
    176         if (x + fBitmap.width() > WIDTH) {
    177             x = 0;
    178             y += fBitmap.height() + MARGIN;
    179         }
    180         // Test small fg, large bg with Screen (uses shader blend)
    181         paint.setImageFilter(SkXfermodeImageFilter::Make(mode, background, cropped, nullptr));
    182         DrawClippedPaint(canvas, clipRect, paint, x, y);
    183         x += fBitmap.width() + MARGIN;
    184         if (x + fBitmap.width() > WIDTH) {
    185             x = 0;
    186             y += fBitmap.height() + MARGIN;
    187         }
    188         // Test small fg, large bg with SrcIn with a crop that forces it to full size.
    189         // This tests that SkXfermodeImageFilter correctly applies the compositing mode to
    190         // the region outside the foreground.
    191         mode = SkBlendMode::kSrcIn;
    192         SkImageFilter::CropRect cropRectFull(SkRect::MakeXYWH(0, 0, 80, 80));
    193         paint.setImageFilter(SkXfermodeImageFilter::Make(mode, background,
    194                                                          cropped, &cropRectFull));
    195         DrawClippedPaint(canvas, clipRect, paint, x, y);
    196         x += fBitmap.width() + MARGIN;
    197         if (x + fBitmap.width() > WIDTH) {
    198             x = 0;
    199             y += fBitmap.height() + MARGIN;
    200         }
    201     }
    202 
    203 private:
    204     static void DrawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint,
    205                                   int x, int y) {
    206         canvas->save();
    207         canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
    208         canvas->clipRect(SkRect::MakeIWH(bitmap.width(), bitmap.height()));
    209         canvas->drawBitmap(bitmap, 0, 0, &paint);
    210         canvas->restore();
    211     }
    212 
    213     static void DrawClippedPaint(SkCanvas* canvas, const SkRect& rect, const SkPaint& paint,
    214                                  int x, int y) {
    215         canvas->save();
    216         canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
    217         canvas->clipRect(rect);
    218         canvas->drawPaint(paint);
    219         canvas->restore();
    220     }
    221 
    222     SkBitmap        fBitmap;
    223     sk_sp<SkImage>  fCheckerboard;
    224 
    225     typedef GM INHERITED;
    226 };
    227 
    228 //////////////////////////////////////////////////////////////////////////////
    229 
    230 DEF_GM( return new XfermodeImageFilterGM; );
    231 
    232 }
    233