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         DrawClippedBitmap(canvas, fBitmap, paint, x, y);
     98         x += fBitmap.width() + MARGIN;
     99         if (x + fBitmap.width() > WIDTH) {
    100             x = 0;
    101             y += fBitmap.height() + MARGIN;
    102         }
    103         // Test nullptr mode
    104         paint.setImageFilter(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, background));
    105         DrawClippedBitmap(canvas, fBitmap, paint, x, y);
    106         x += fBitmap.width() + MARGIN;
    107         if (x + fBitmap.width() > WIDTH) {
    108             x = 0;
    109             y += fBitmap.height() + MARGIN;
    110         }
    111         SkRect clipRect = SkRect::MakeWH(SkIntToScalar(fBitmap.width() + 4),
    112                                          SkIntToScalar(fBitmap.height() + 4));
    113         // Test offsets on SrcMode (uses fixed-function blend)
    114         sk_sp<SkImage> bitmapImage(SkImage::MakeFromBitmap(fBitmap));
    115         sk_sp<SkImageFilter> foreground(SkImageSource::Make(std::move(bitmapImage)));
    116         sk_sp<SkImageFilter> offsetForeground(SkOffsetImageFilter::Make(SkIntToScalar(4),
    117                                                                         SkIntToScalar(-4),
    118                                                                         foreground));
    119         sk_sp<SkImageFilter> offsetBackground(SkOffsetImageFilter::Make(SkIntToScalar(4),
    120                                                                         SkIntToScalar(4),
    121                                                                         background));
    122         paint.setImageFilter(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver,
    123                                                          offsetBackground,
    124                                                          offsetForeground,
    125                                                          nullptr));
    126         DrawClippedPaint(canvas, clipRect, paint, x, y);
    127         x += fBitmap.width() + MARGIN;
    128         if (x + fBitmap.width() > WIDTH) {
    129             x = 0;
    130             y += fBitmap.height() + MARGIN;
    131         }
    132         // Test offsets on Darken (uses shader blend)
    133         paint.setImageFilter(SkXfermodeImageFilter::Make(SkBlendMode::kDarken,
    134                                                          offsetBackground,
    135                                                          offsetForeground,
    136                                                          nullptr));
    137         DrawClippedPaint(canvas, clipRect, paint, x, y);
    138         x += fBitmap.width() + MARGIN;
    139         if (x + fBitmap.width() > WIDTH) {
    140             x = 0;
    141             y += fBitmap.height() + MARGIN;
    142         }
    143         // Test cropping
    144         constexpr size_t nbSamples = 3;
    145         const SkBlendMode sampledModes[nbSamples] = {
    146             SkBlendMode::kOverlay, SkBlendMode::kSrcOver, SkBlendMode::kPlus
    147         };
    148         int offsets[nbSamples][4] = {{ 10,  10, -16, -16},
    149                                      { 10,  10,  10,  10},
    150                                      {-10, -10,  -6,  -6}};
    151         for (size_t i = 0; i < nbSamples; ++i) {
    152             SkIRect cropRect = SkIRect::MakeXYWH(offsets[i][0],
    153                                                  offsets[i][1],
    154                                                  fBitmap.width()  + offsets[i][2],
    155                                                  fBitmap.height() + offsets[i][3]);
    156             SkImageFilter::CropRect rect(SkRect::Make(cropRect));
    157             paint.setImageFilter(SkXfermodeImageFilter::Make(sampledModes[i],
    158                                                              offsetBackground,
    159                                                              offsetForeground,
    160                                                              &rect));
    161             DrawClippedPaint(canvas, clipRect, paint, x, y);
    162             x += fBitmap.width() + MARGIN;
    163             if (x + fBitmap.width() > WIDTH) {
    164                 x = 0;
    165                 y += fBitmap.height() + MARGIN;
    166             }
    167         }
    168         // Test small bg, large fg with Screen (uses shader blend)
    169         SkBlendMode mode = SkBlendMode::kScreen;
    170         SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(10, 10, 60, 60));
    171         sk_sp<SkImageFilter> cropped(SkOffsetImageFilter::Make(0, 0, foreground, &cropRect));
    172         paint.setImageFilter(SkXfermodeImageFilter::Make(mode, cropped, background, nullptr));
    173         DrawClippedPaint(canvas, clipRect, paint, x, y);
    174         x += fBitmap.width() + MARGIN;
    175         if (x + fBitmap.width() > WIDTH) {
    176             x = 0;
    177             y += fBitmap.height() + MARGIN;
    178         }
    179         // Test small fg, large bg with Screen (uses shader blend)
    180         paint.setImageFilter(SkXfermodeImageFilter::Make(mode, background, cropped, nullptr));
    181         DrawClippedPaint(canvas, clipRect, paint, x, y);
    182         x += fBitmap.width() + MARGIN;
    183         if (x + fBitmap.width() > WIDTH) {
    184             x = 0;
    185             y += fBitmap.height() + MARGIN;
    186         }
    187         // Test small fg, large bg with SrcIn with a crop that forces it to full size.
    188         // This tests that SkXfermodeImageFilter correctly applies the compositing mode to
    189         // the region outside the foreground.
    190         mode = SkBlendMode::kSrcIn;
    191         SkImageFilter::CropRect cropRectFull(SkRect::MakeXYWH(0, 0, 80, 80));
    192         paint.setImageFilter(SkXfermodeImageFilter::Make(mode, background,
    193                                                          cropped, &cropRectFull));
    194         DrawClippedPaint(canvas, clipRect, paint, x, y);
    195         x += fBitmap.width() + MARGIN;
    196         if (x + fBitmap.width() > WIDTH) {
    197             x = 0;
    198             y += fBitmap.height() + MARGIN;
    199         }
    200     }
    201 
    202 private:
    203     static void DrawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint,
    204                            int x, int y) {
    205         canvas->save();
    206         canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
    207         canvas->clipRect(SkRect::MakeWH(
    208             SkIntToScalar(bitmap.width()), SkIntToScalar(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