Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2015 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 "SkBlurImageFilter.h"
     10 #include "SkColorMatrixFilter.h"
     11 #include "SkImage.h"
     12 #include "SkImageFilter.h"
     13 #include "SkSurface.h"
     14 #include "sk_tool_utils.h"
     15 
     16 /**
     17  *  Test drawing a primitive w/ an imagefilter (in this case, just matrix w/ identity) to see
     18  *  that we apply the xfermode *after* the image has been created and filtered, and not during
     19  *  the creation step (i.e. before it is filtered).
     20  *
     21  *  see https://bug.skia.org/3741
     22  */
     23 static void do_draw(SkCanvas* canvas, SkBlendMode mode, sk_sp<SkImageFilter> imf) {
     24         SkAutoCanvasRestore acr(canvas, true);
     25         canvas->clipRect(SkRect::MakeWH(220, 220));
     26 
     27         // want to force a layer, so modes like DstIn can combine meaningfully, but the final
     28         // image can still be shown against our default (opaque) background. non-opaque GMs
     29         // are a lot more trouble to compare/triage.
     30         canvas->saveLayer(nullptr, nullptr);
     31         canvas->drawColor(SK_ColorGREEN);
     32 
     33         SkPaint paint;
     34         paint.setAntiAlias(true);
     35 
     36         SkRect r0 = SkRect::MakeXYWH(10, 60, 200, 100);
     37         SkRect r1 = SkRect::MakeXYWH(60, 10, 100, 200);
     38 
     39         paint.setColor(SK_ColorRED);
     40         canvas->drawOval(r0, paint);
     41 
     42         paint.setColor(0x660000FF);
     43         paint.setImageFilter(std::move(imf));
     44         paint.setBlendMode(mode);
     45         canvas->drawOval(r1, paint);
     46 }
     47 
     48 DEF_SIMPLE_GM(imagefilters_xfermodes, canvas, 480, 480) {
     49         canvas->translate(10, 10);
     50 
     51         // just need an imagefilter to trigger the code-path (which creates a tmp layer)
     52         sk_sp<SkImageFilter> imf(SkImageFilter::MakeMatrixFilter(SkMatrix::I(),
     53                                                                  kNone_SkFilterQuality,
     54                                                                  nullptr));
     55 
     56         const SkBlendMode modes[] = {
     57             SkBlendMode::kSrcATop, SkBlendMode::kDstIn
     58         };
     59 
     60         for (size_t i = 0; i < SK_ARRAY_COUNT(modes); ++i) {
     61             canvas->save();
     62             do_draw(canvas, modes[i], nullptr);
     63             canvas->translate(240, 0);
     64             do_draw(canvas, modes[i], imf);
     65             canvas->restore();
     66 
     67             canvas->translate(0, 240);
     68         }
     69 }
     70 
     71 static sk_sp<SkImage> make_image(SkCanvas* canvas) {
     72     const SkImageInfo info = SkImageInfo::MakeS32(100, 100, kPremul_SkAlphaType);
     73     auto surface(sk_tool_utils::makeSurface(canvas, info));
     74     surface->getCanvas()->drawRect(SkRect::MakeXYWH(25, 25, 50, 50), SkPaint());
     75     return surface->makeImageSnapshot();
     76 }
     77 
     78 // Compare blurs when we're tightly clipped (fast) and not as tightly (slower)
     79 //
     80 // Expect the two to draw the same (modulo the extra border of pixels when the clip is larger)
     81 //
     82 DEF_SIMPLE_GM(fast_slow_blurimagefilter, canvas, 620, 260) {
     83     sk_sp<SkImage> image(make_image(canvas));
     84     const SkRect r = SkRect::MakeIWH(image->width(), image->height());
     85 
     86     canvas->translate(10, 10);
     87     for (SkScalar sigma = 8; sigma <= 128; sigma *= 2) {
     88         SkPaint paint;
     89         paint.setImageFilter(SkBlurImageFilter::Make(sigma, sigma, nullptr));
     90 
     91         canvas->save();
     92         // we outset the clip by 1, to fall out of the fast-case in drawImage
     93         // i.e. the clip is larger than the image
     94         for (SkScalar outset = 0; outset <= 1; ++outset) {
     95             canvas->save();
     96             canvas->clipRect(r.makeOutset(outset, outset));
     97             canvas->drawImage(image, 0, 0, &paint);
     98             canvas->restore();
     99             canvas->translate(0, r.height() + 20);
    100         }
    101         canvas->restore();
    102         canvas->translate(r.width() + 20, 0);
    103     }
    104 }
    105 
    106 ///////////////////////////////////////////////////////////////////////////////////////////////////
    107 #include "Resources.h"
    108 #include "SkBlurImageFilter.h"
    109 #include "SkMatrixConvolutionImageFilter.h"
    110 #include "SkMorphologyImageFilter.h"
    111 #include "SkColorMatrixFilter.h"
    112 #include "SkColorFilterImageFilter.h"
    113 #include "SkRRect.h"
    114 
    115 static void draw_set(SkCanvas* canvas, sk_sp<SkImageFilter> filters[], int count) {
    116     const SkRect r = SkRect::MakeXYWH(30, 30, 200, 200);
    117     const SkScalar offset = 250;
    118     SkScalar dx = 0, dy = 0;
    119 
    120     for (int i = 0; i < count; ++i) {
    121         canvas->save();
    122         SkRRect rr = SkRRect::MakeRectXY(r.makeOffset(dx, dy), 20, 20);
    123         canvas->clipRRect(rr, true);
    124         canvas->saveLayer({ &rr.getBounds(), nullptr, filters[i].get(), nullptr, nullptr, 0 });
    125         canvas->drawColor(0x40FFFFFF);
    126         canvas->restore();
    127         canvas->restore();
    128 
    129         if (0 == dx) {
    130             dx = offset;
    131         } else {
    132             dx = 0;
    133             dy = offset;
    134         }
    135     }
    136 }
    137 
    138 DEF_SIMPLE_GM(savelayer_with_backdrop, canvas, 830, 550) {
    139     SkColorMatrix cm;
    140     cm.setSaturation(10);
    141     sk_sp<SkColorFilter> cf(SkColorFilter::MakeMatrixFilterRowMajor255(cm.fMat));
    142     const SkScalar kernel[] = { 4, 0, 4, 0, -15, 0, 4, 0, 4 };
    143     sk_sp<SkImageFilter> filters[] = {
    144         SkBlurImageFilter::Make(10, 10, nullptr),
    145         SkDilateImageFilter::Make(8, 8, nullptr),
    146         SkMatrixConvolutionImageFilter::Make(
    147                                            { 3, 3 }, kernel, 1, 0, { 0, 0 },
    148                                            SkMatrixConvolutionImageFilter::kClampToBlack_TileMode,
    149                                            true, nullptr),
    150         SkColorFilterImageFilter::Make(std::move(cf), nullptr),
    151     };
    152 
    153     const struct {
    154         SkScalar    fSx, fSy, fTx, fTy;
    155     } xforms[] = {
    156         { 1, 1, 0, 0 },
    157         { 0.5f, 0.5f, 530, 0 },
    158         { 0.25f, 0.25f, 530, 275 },
    159         { 0.125f, 0.125f, 530, 420 },
    160     };
    161 
    162     SkPaint paint;
    163     paint.setFilterQuality(kMedium_SkFilterQuality);
    164     sk_sp<SkImage> image(GetResourceAsImage("images/mandrill_512.png"));
    165 
    166     canvas->translate(20, 20);
    167     for (const auto& xform : xforms) {
    168         canvas->save();
    169         canvas->translate(xform.fTx, xform.fTy);
    170         canvas->scale(xform.fSx, xform.fSy);
    171         canvas->drawImage(image, 0, 0, &paint);
    172         draw_set(canvas, filters, SK_ARRAY_COUNT(filters));
    173         canvas->restore();
    174     }
    175 }
    176