blob: 91bcbc5d0b4cefe440a0793179c0029c56751251 [file] [log] [blame]
reed7e4186a2015-04-20 07:27:15 -07001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkBlendMode.h"
10#include "include/core/SkCanvas.h"
11#include "include/core/SkColor.h"
12#include "include/core/SkColorFilter.h"
13#include "include/core/SkFilterQuality.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/core/SkImage.h"
15#include "include/core/SkImageFilter.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040016#include "include/core/SkImageInfo.h"
17#include "include/core/SkMatrix.h"
18#include "include/core/SkPaint.h"
19#include "include/core/SkRRect.h"
20#include "include/core/SkRect.h"
21#include "include/core/SkRefCnt.h"
22#include "include/core/SkScalar.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "include/core/SkSurface.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040024#include "include/core/SkTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "include/effects/SkBlurImageFilter.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040026#include "include/effects/SkColorFilterImageFilter.h"
27#include "include/effects/SkColorMatrix.h"
28#include "include/effects/SkMatrixConvolutionImageFilter.h"
29#include "include/effects/SkMorphologyImageFilter.h"
30#include "tools/Resources.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050031#include "tools/ToolUtils.h"
reed7e4186a2015-04-20 07:27:15 -070032
Ben Wagner7fde8e12019-05-01 17:28:53 -040033#include <utility>
34
reed7e4186a2015-04-20 07:27:15 -070035/**
36 * Test drawing a primitive w/ an imagefilter (in this case, just matrix w/ identity) to see
37 * that we apply the xfermode *after* the image has been created and filtered, and not during
38 * the creation step (i.e. before it is filtered).
39 *
halcanary6950de62015-11-07 05:29:00 -080040 * see https://bug.skia.org/3741
reed7e4186a2015-04-20 07:27:15 -070041 */
reed374772b2016-10-05 17:33:02 -070042static void do_draw(SkCanvas* canvas, SkBlendMode mode, sk_sp<SkImageFilter> imf) {
reed49124372015-04-20 09:10:31 -070043 SkAutoCanvasRestore acr(canvas, true);
44 canvas->clipRect(SkRect::MakeWH(220, 220));
xidachen467ddc02015-12-10 12:08:44 -080045
reed49124372015-04-20 09:10:31 -070046 // want to force a layer, so modes like DstIn can combine meaningfully, but the final
47 // image can still be shown against our default (opaque) background. non-opaque GMs
48 // are a lot more trouble to compare/triage.
halcanary96fcdcc2015-08-27 07:41:13 -070049 canvas->saveLayer(nullptr, nullptr);
reed49124372015-04-20 09:10:31 -070050 canvas->drawColor(SK_ColorGREEN);
51
reed7e4186a2015-04-20 07:27:15 -070052 SkPaint paint;
53 paint.setAntiAlias(true);
xidachen467ddc02015-12-10 12:08:44 -080054
reed7e4186a2015-04-20 07:27:15 -070055 SkRect r0 = SkRect::MakeXYWH(10, 60, 200, 100);
56 SkRect r1 = SkRect::MakeXYWH(60, 10, 100, 200);
xidachen467ddc02015-12-10 12:08:44 -080057
reed7e4186a2015-04-20 07:27:15 -070058 paint.setColor(SK_ColorRED);
59 canvas->drawOval(r0, paint);
60
reed49124372015-04-20 09:10:31 -070061 paint.setColor(0x660000FF);
robertphillipsae8c9332016-04-05 15:09:00 -070062 paint.setImageFilter(std::move(imf));
reed374772b2016-10-05 17:33:02 -070063 paint.setBlendMode(mode);
reed7e4186a2015-04-20 07:27:15 -070064 canvas->drawOval(r1, paint);
halcanary2a243382015-09-09 08:16:41 -070065}
reed7e4186a2015-04-20 07:27:15 -070066
halcanary2a243382015-09-09 08:16:41 -070067DEF_SIMPLE_GM(imagefilters_xfermodes, canvas, 480, 480) {
reed49124372015-04-20 09:10:31 -070068 canvas->translate(10, 10);
69
reed7e4186a2015-04-20 07:27:15 -070070 // just need an imagefilter to trigger the code-path (which creates a tmp layer)
robertphillipsae8c9332016-04-05 15:09:00 -070071 sk_sp<SkImageFilter> imf(SkImageFilter::MakeMatrixFilter(SkMatrix::I(),
72 kNone_SkFilterQuality,
73 nullptr));
reed7e4186a2015-04-20 07:27:15 -070074
reed374772b2016-10-05 17:33:02 -070075 const SkBlendMode modes[] = {
76 SkBlendMode::kSrcATop, SkBlendMode::kDstIn
reed7e4186a2015-04-20 07:27:15 -070077 };
xidachen467ddc02015-12-10 12:08:44 -080078
reed7e4186a2015-04-20 07:27:15 -070079 for (size_t i = 0; i < SK_ARRAY_COUNT(modes); ++i) {
80 canvas->save();
halcanary2a243382015-09-09 08:16:41 -070081 do_draw(canvas, modes[i], nullptr);
reed49124372015-04-20 09:10:31 -070082 canvas->translate(240, 0);
halcanary2a243382015-09-09 08:16:41 -070083 do_draw(canvas, modes[i], imf);
reed7e4186a2015-04-20 07:27:15 -070084 canvas->restore();
xidachen467ddc02015-12-10 12:08:44 -080085
reed49124372015-04-20 09:10:31 -070086 canvas->translate(0, 240);
reed7e4186a2015-04-20 07:27:15 -070087 }
halcanary2a243382015-09-09 08:16:41 -070088}
reedf65fb652015-12-07 09:28:34 -080089
reed9ce9d672016-03-17 10:51:11 -070090static sk_sp<SkImage> make_image(SkCanvas* canvas) {
Brian Osman5f500922016-12-29 11:50:48 -050091 const SkImageInfo info = SkImageInfo::MakeS32(100, 100, kPremul_SkAlphaType);
Mike Kleinea3f0142019-03-20 11:12:10 -050092 auto surface(ToolUtils::makeSurface(canvas, info));
reedf65fb652015-12-07 09:28:34 -080093 surface->getCanvas()->drawRect(SkRect::MakeXYWH(25, 25, 50, 50), SkPaint());
reed9ce9d672016-03-17 10:51:11 -070094 return surface->makeImageSnapshot();
reedf65fb652015-12-07 09:28:34 -080095}
96
97// Compare blurs when we're tightly clipped (fast) and not as tightly (slower)
98//
99// Expect the two to draw the same (modulo the extra border of pixels when the clip is larger)
100//
101DEF_SIMPLE_GM(fast_slow_blurimagefilter, canvas, 620, 260) {
reed9ce9d672016-03-17 10:51:11 -0700102 sk_sp<SkImage> image(make_image(canvas));
reedf65fb652015-12-07 09:28:34 -0800103 const SkRect r = SkRect::MakeIWH(image->width(), image->height());
104
105 canvas->translate(10, 10);
106 for (SkScalar sigma = 8; sigma <= 128; sigma *= 2) {
107 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -0700108 paint.setImageFilter(SkBlurImageFilter::Make(sigma, sigma, nullptr));
reedf65fb652015-12-07 09:28:34 -0800109
110 canvas->save();
111 // we outset the clip by 1, to fall out of the fast-case in drawImage
112 // i.e. the clip is larger than the image
113 for (SkScalar outset = 0; outset <= 1; ++outset) {
114 canvas->save();
115 canvas->clipRect(r.makeOutset(outset, outset));
116 canvas->drawImage(image, 0, 0, &paint);
117 canvas->restore();
118 canvas->translate(0, r.height() + 20);
119 }
120 canvas->restore();
121 canvas->translate(r.width() + 20, 0);
122 }
123}
reedbfd5f172016-01-07 11:28:08 -0800124
125///////////////////////////////////////////////////////////////////////////////////////////////////
reedbfd5f172016-01-07 11:28:08 -0800126
robertphillipsef6a47b2016-04-08 08:01:20 -0700127static void draw_set(SkCanvas* canvas, sk_sp<SkImageFilter> filters[], int count) {
reedbfd5f172016-01-07 11:28:08 -0800128 const SkRect r = SkRect::MakeXYWH(30, 30, 200, 200);
129 const SkScalar offset = 250;
130 SkScalar dx = 0, dy = 0;
131
132 for (int i = 0; i < count; ++i) {
133 canvas->save();
134 SkRRect rr = SkRRect::MakeRectXY(r.makeOffset(dx, dy), 20, 20);
reed66998382016-09-21 11:15:07 -0700135 canvas->clipRRect(rr, true);
Florin Malita53f77bd2017-04-28 13:48:37 -0400136 canvas->saveLayer({ &rr.getBounds(), nullptr, filters[i].get(), nullptr, nullptr, 0 });
reedbfd5f172016-01-07 11:28:08 -0800137 canvas->drawColor(0x40FFFFFF);
138 canvas->restore();
139 canvas->restore();
140
141 if (0 == dx) {
142 dx = offset;
143 } else {
144 dx = 0;
145 dy = offset;
146 }
147 }
148}
149
150DEF_SIMPLE_GM(savelayer_with_backdrop, canvas, 830, 550) {
151 SkColorMatrix cm;
152 cm.setSaturation(10);
Mike Reed50d79af2019-04-21 22:17:03 -0400153 sk_sp<SkColorFilter> cf(SkColorFilters::Matrix(cm));
reedbfd5f172016-01-07 11:28:08 -0800154 const SkScalar kernel[] = { 4, 0, 4, 0, -15, 0, 4, 0, 4 };
robertphillipsef6a47b2016-04-08 08:01:20 -0700155 sk_sp<SkImageFilter> filters[] = {
156 SkBlurImageFilter::Make(10, 10, nullptr),
157 SkDilateImageFilter::Make(8, 8, nullptr),
158 SkMatrixConvolutionImageFilter::Make(
159 { 3, 3 }, kernel, 1, 0, { 0, 0 },
reedbfd5f172016-01-07 11:28:08 -0800160 SkMatrixConvolutionImageFilter::kClampToBlack_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -0700161 true, nullptr),
162 SkColorFilterImageFilter::Make(std::move(cf), nullptr),
reedbfd5f172016-01-07 11:28:08 -0800163 };
164
165 const struct {
166 SkScalar fSx, fSy, fTx, fTy;
167 } xforms[] = {
168 { 1, 1, 0, 0 },
169 { 0.5f, 0.5f, 530, 0 },
170 { 0.25f, 0.25f, 530, 275 },
171 { 0.125f, 0.125f, 530, 420 },
172 };
173
174 SkPaint paint;
175 paint.setFilterQuality(kMedium_SkFilterQuality);
Hal Canaryc465d132017-12-08 10:21:31 -0500176 sk_sp<SkImage> image(GetResourceAsImage("images/mandrill_512.png"));
reedbfd5f172016-01-07 11:28:08 -0800177
178 canvas->translate(20, 20);
179 for (const auto& xform : xforms) {
180 canvas->save();
181 canvas->translate(xform.fTx, xform.fTy);
182 canvas->scale(xform.fSx, xform.fSy);
183 canvas->drawImage(image, 0, 0, &paint);
184 draw_set(canvas, filters, SK_ARRAY_COUNT(filters));
185 canvas->restore();
186 }
reedbfd5f172016-01-07 11:28:08 -0800187}