blob: 319884b0261bf88f831585fd86735ed8caa26cdc [file] [log] [blame]
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +00001/*
2 * Copyright 2012 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
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +000010#include "SkArithmeticMode.h"
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +000011#include "SkBlurImageFilter.h"
senorblanco@chromium.org44888c62012-08-20 19:23:24 +000012#include "SkColorFilter.h"
13#include "SkColorFilterImageFilter.h"
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +000014#include "SkColorMatrixFilter.h"
fmalita5598b632015-09-15 11:26:13 -070015#include "SkImage.h"
16#include "SkImageSource.h"
senorblancoeae84c22016-01-26 08:41:02 -080017#include "SkMatrixConvolutionImageFilter.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000018#include "SkReadBuffer.h"
robertphillips4ba94e22016-04-04 12:07:47 -070019#include "SkSpecialImage.h"
20#include "SkSpecialSurface.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000021#include "SkWriteBuffer.h"
senorblanco@chromium.org4a9a6122012-12-04 14:18:50 +000022#include "SkMergeImageFilter.h"
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +000023#include "SkMorphologyImageFilter.h"
commit-bot@chromium.org6c4e71a2013-11-20 21:32:10 +000024#include "SkTestImageFilters.h"
senorblanco@chromium.org350b4d52013-08-01 14:59:05 +000025#include "SkXfermodeImageFilter.h"
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +000026
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +000027// More closely models how Blink's OffsetFilter works as of 10/23/13. SkOffsetImageFilter doesn't
28// perform a draw and this one does.
29class SimpleOffsetFilter : public SkImageFilter {
30public:
reed7daaaa42014-08-21 10:53:34 -070031 class Registrar {
32 public:
33 Registrar() {
34 SkFlattenable::Register("SimpleOffsetFilter",
mtklein3b375452016-04-04 14:57:19 -070035 SimpleOffsetFilter::CreateProc,
36 SimpleOffsetFilter::GetFlattenableType());
reed7daaaa42014-08-21 10:53:34 -070037 }
38 };
robertphillips43c2ad42016-04-04 05:05:11 -070039 static sk_sp<SkImageFilter> Make(SkScalar dx, SkScalar dy, sk_sp<SkImageFilter> input) {
40 return sk_sp<SkImageFilter>(new SimpleOffsetFilter(dx, dy, std::move(input)));
commit-bot@chromium.org20774272014-03-18 10:28:27 +000041 }
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +000042
robertphillips43c2ad42016-04-04 05:05:11 -070043 SK_TO_STRING_OVERRIDE()
44 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SimpleOffsetFilter);
45
46protected:
robertphillips4ba94e22016-04-04 12:07:47 -070047 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
48 SkIPoint* offset) const override {
49 SkIPoint inputOffset = SkIPoint::Make(0, 0);
50 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
51 if (!input) {
52 return nullptr;
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +000053 }
54
55 SkIRect bounds;
robertphillips4ba94e22016-04-04 12:07:47 -070056 input = this->applyCropRect(ctx, input.get(), &inputOffset, &bounds);
57 if (!input) {
58 return nullptr;
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +000059 }
60
robertphillips4ba94e22016-04-04 12:07:47 -070061 SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height());
62
63 sk_sp<SkSpecialSurface> surf(source->makeSurface(info));
64 if (!surf) {
65 return nullptr;
66 }
67
68 SkCanvas* canvas = surf->getCanvas();
69 SkASSERT(canvas);
70
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +000071 SkPaint paint;
72 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
robertphillips4ba94e22016-04-04 12:07:47 -070073
74 input->draw(canvas, fDX - bounds.left(), fDY - bounds.top(), &paint);
75
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +000076 offset->fX += bounds.left();
77 offset->fY += bounds.top();
robertphillips4ba94e22016-04-04 12:07:47 -070078 return surf->makeImageSnapshot();
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +000079 }
80
mtklein36352bf2015-03-25 18:17:31 -070081 void flatten(SkWriteBuffer& buffer) const override {
reed9fa60da2014-08-21 07:59:51 -070082 this->INHERITED::flatten(buffer);
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +000083 buffer.writeScalar(fDX);
84 buffer.writeScalar(fDY);
85 }
86
87private:
robertphillips43c2ad42016-04-04 05:05:11 -070088 SimpleOffsetFilter(SkScalar dx, SkScalar dy, sk_sp<SkImageFilter> input)
89 : SkImageFilter(&input, 1, nullptr)
90 , fDX(dx)
91 , fDY(dy) {
92 }
commit-bot@chromium.org20774272014-03-18 10:28:27 +000093
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +000094 SkScalar fDX, fDY;
reed9fa60da2014-08-21 07:59:51 -070095
96 typedef SkImageFilter INHERITED;
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +000097};
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +000098
reed7daaaa42014-08-21 10:53:34 -070099static SimpleOffsetFilter::Registrar gReg;
100
reed60c9b582016-04-03 09:11:13 -0700101sk_sp<SkFlattenable> SimpleOffsetFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -0700102 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
103 SkScalar dx = buffer.readScalar();
104 SkScalar dy = buffer.readScalar();
robertphillips43c2ad42016-04-04 05:05:11 -0700105 return Make(dx, dy, common.getInput(0));
reed9fa60da2014-08-21 07:59:51 -0700106}
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +0000107
robertphillipsf3f5bad2014-12-19 13:49:15 -0800108#ifndef SK_IGNORE_TO_STRING
109void SimpleOffsetFilter::toString(SkString* str) const {
110 str->appendf("SimpleOffsetFilter: (");
111 str->append(")");
112}
113#endif
114
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +0000115class ImageFiltersGraphGM : public skiagm::GM {
116public:
commit-bot@chromium.org60c8d242014-05-27 16:28:43 +0000117 ImageFiltersGraphGM() {}
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +0000118
119protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000120
robertphillips943a4622015-09-03 13:32:33 -0700121 SkString onShortName() override {
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +0000122 return SkString("imagefiltersgraph");
123 }
124
senorblancoeae84c22016-01-26 08:41:02 -0800125 SkISize onISize() override { return SkISize::Make(600, 150); }
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +0000126
robertphillips943a4622015-09-03 13:32:33 -0700127 void onOnceBeforeDraw() override {
reed9ce9d672016-03-17 10:51:11 -0700128 fImage = SkImage::MakeFromBitmap(
129 sk_tool_utils::create_string_bitmap(100, 100, SK_ColorWHITE, 20, 70, 96, "e"));
commit-bot@chromium.org60c8d242014-05-27 16:28:43 +0000130 }
131
robertphillips943a4622015-09-03 13:32:33 -0700132 void onDraw(SkCanvas* canvas) override {
mtklein871ad7a2015-03-27 12:33:46 -0700133 canvas->clear(SK_ColorBLACK);
senorblanco@chromium.org985fa792012-10-24 15:14:26 +0000134 {
robertphillips549c8992016-04-01 09:28:51 -0700135 sk_sp<SkImageFilter> bitmapSource(SkImageSource::Make(fImage));
robertphillips2238c9d2016-03-30 13:34:16 -0700136 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
137 SkXfermode::kSrcIn_Mode));
robertphillips6e7025a2016-04-04 04:31:25 -0700138 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(4.0f, 4.0f, std::move(bitmapSource)));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700139 sk_sp<SkImageFilter> erode(SkErodeImageFilter::Make(4, 4, blur));
robertphillips5605b562016-04-05 11:50:42 -0700140 sk_sp<SkImageFilter> color(SkColorFilterImageFilter::Make(std::move(cf),
141 std::move(erode)));
robertphillips2238c9d2016-03-30 13:34:16 -0700142 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(blur, color));
rmistry@google.comae933ce2012-08-23 18:19:56 +0000143
senorblanco@chromium.org985fa792012-10-24 15:14:26 +0000144 SkPaint paint;
robertphillips2238c9d2016-03-30 13:34:16 -0700145 paint.setImageFilter(std::move(merge));
senorblanco@chromium.org985fa792012-10-24 15:14:26 +0000146 canvas->drawPaint(paint);
senorblanco@chromium.org34a849d2013-10-24 15:59:31 +0000147 canvas->translate(SkIntToScalar(100), 0);
senorblanco@chromium.org985fa792012-10-24 15:14:26 +0000148 }
149 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700150 sk_sp<SkImageFilter> morph(SkDilateImageFilter::Make(5, 5, nullptr));
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +0000151
senorblanco@chromium.org985fa792012-10-24 15:14:26 +0000152 SkScalar matrix[20] = { SK_Scalar1, 0, 0, 0, 0,
153 0, SK_Scalar1, 0, 0, 0,
154 0, 0, SK_Scalar1, 0, 0,
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000155 0, 0, 0, 0.5f, 0 };
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +0000156
robertphillips43c2ad42016-04-04 05:05:11 -0700157 sk_sp<SkColorFilter> matrixFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
robertphillips5605b562016-04-05 11:50:42 -0700158 sk_sp<SkImageFilter> colorMorph(SkColorFilterImageFilter::Make(std::move(matrixFilter),
159 std::move(morph)));
senorblanco@chromium.org985fa792012-10-24 15:14:26 +0000160 SkPaint paint;
reedcfb6bdf2016-03-29 11:32:50 -0700161 paint.setImageFilter(SkXfermodeImageFilter::Make(
robertphillips43c2ad42016-04-04 05:05:11 -0700162 SkXfermode::Make(SkXfermode::kSrcOver_Mode),
robertphillipsb591c772016-04-04 08:06:17 -0700163 colorMorph.get()));
reedcfb6bdf2016-03-29 11:32:50 -0700164
reed9ce9d672016-03-17 10:51:11 -0700165 DrawClippedImage(canvas, fImage.get(), paint);
senorblanco@chromium.org34a849d2013-10-24 15:59:31 +0000166 canvas->translate(SkIntToScalar(100), 0);
senorblanco@chromium.org985fa792012-10-24 15:14:26 +0000167 }
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +0000168 {
169 SkScalar matrix[20] = { SK_Scalar1, 0, 0, 0, 0,
170 0, SK_Scalar1, 0, 0, 0,
171 0, 0, SK_Scalar1, 0, 0,
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000172 0, 0, 0, 0.5f, 0 };
robertphillips43c2ad42016-04-04 05:05:11 -0700173 sk_sp<SkColorFilter> matrixCF(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
robertphillips5605b562016-04-05 11:50:42 -0700174 sk_sp<SkImageFilter> matrixFilter(SkColorFilterImageFilter::Make(std::move(matrixCF),
175 nullptr));
robertphillips43c2ad42016-04-04 05:05:11 -0700176 sk_sp<SkImageFilter> offsetFilter(SimpleOffsetFilter::Make(10.0f, 10.f, matrixFilter));
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +0000177
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +0000178 SkPaint paint;
reedcfb6bdf2016-03-29 11:32:50 -0700179 paint.setImageFilter(
180 SkXfermodeImageFilter::Make(SkArithmeticMode::Make(0, SK_Scalar1, SK_Scalar1, 0),
robertphillipsb591c772016-04-04 08:06:17 -0700181 matrixFilter.get(), offsetFilter.get(), nullptr));
reedcfb6bdf2016-03-29 11:32:50 -0700182
reed9ce9d672016-03-17 10:51:11 -0700183 DrawClippedImage(canvas, fImage.get(), paint);
senorblanco@chromium.org34a849d2013-10-24 15:59:31 +0000184 canvas->translate(SkIntToScalar(100), 0);
185 }
186 {
robertphillips6e7025a2016-04-04 04:31:25 -0700187 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(SkIntToScalar(10),
188 SkIntToScalar(10),
189 nullptr));
senorblanco@chromium.org34a849d2013-10-24 15:59:31 +0000190
senorblanco@chromium.org34a849d2013-10-24 15:59:31 +0000191 SkImageFilter::CropRect cropRect(SkRect::MakeWH(SkIntToScalar(95), SkIntToScalar(100)));
senorblanco@chromium.org34a849d2013-10-24 15:59:31 +0000192 SkPaint paint;
reedcfb6bdf2016-03-29 11:32:50 -0700193 paint.setImageFilter(
robertphillipsb591c772016-04-04 08:06:17 -0700194 SkXfermodeImageFilter::Make(SkXfermode::Make(SkXfermode::kSrcIn_Mode), blur.get(),
reedcfb6bdf2016-03-29 11:32:50 -0700195 nullptr, &cropRect));
reed9ce9d672016-03-17 10:51:11 -0700196 DrawClippedImage(canvas, fImage.get(), paint);
senorblanco@chromium.org34a849d2013-10-24 15:59:31 +0000197 canvas->translate(SkIntToScalar(100), 0);
commit-bot@chromium.orgbbfe4542013-10-24 01:46:11 +0000198 }
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000199 {
senorblancoeae84c22016-01-26 08:41:02 -0800200 // Dilate -> matrix convolution.
201 // This tests that a filter using asFragmentProcessor (matrix
202 // convolution) correctly handles a non-zero source offset
203 // (supplied by the dilate).
robertphillipsfc11b0a2016-04-05 09:09:36 -0700204 sk_sp<SkImageFilter> dilate(SkDilateImageFilter::Make(5, 5, nullptr));
senorblancoeae84c22016-01-26 08:41:02 -0800205
senorblancoeae84c22016-01-26 08:41:02 -0800206 SkScalar kernel[9] = {
207 SkIntToScalar(-1), SkIntToScalar( -1 ), SkIntToScalar(-1),
208 SkIntToScalar(-1), SkIntToScalar( 7 ), SkIntToScalar(-1),
209 SkIntToScalar(-1), SkIntToScalar( -1 ), SkIntToScalar(-1),
210 };
211 SkISize kernelSize = SkISize::Make(3, 3);
212 SkScalar gain = 1.0f, bias = SkIntToScalar(0);
213 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
214 auto tileMode = SkMatrixConvolutionImageFilter::kClamp_TileMode;
215 bool convolveAlpha = false;
robertphillipsfc11b0a2016-04-05 09:09:36 -0700216 sk_sp<SkImageFilter> convolve(
senorblancoeae84c22016-01-26 08:41:02 -0800217 SkMatrixConvolutionImageFilter::Create(kernelSize,
218 kernel,
219 gain,
220 bias,
221 kernelOffset,
222 tileMode,
223 convolveAlpha,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700224 dilate.get()));
senorblancoeae84c22016-01-26 08:41:02 -0800225
226 SkPaint paint;
robertphillipsfc11b0a2016-04-05 09:09:36 -0700227 paint.setImageFilter(std::move(convolve));
reed9ce9d672016-03-17 10:51:11 -0700228 DrawClippedImage(canvas, fImage.get(), paint);
senorblancoeae84c22016-01-26 08:41:02 -0800229 canvas->translate(SkIntToScalar(100), 0);
230 }
231 {
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000232 // Test that crop offsets are absolute, not relative to the parent's crop rect.
robertphillips5605b562016-04-05 11:50:42 -0700233 sk_sp<SkColorFilter> cf1(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
234 SkXfermode::kSrcIn_Mode));
235 sk_sp<SkColorFilter> cf2(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
236 SkXfermode::kSrcIn_Mode));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000237 SkImageFilter::CropRect outerRect(SkRect::MakeXYWH(SkIntToScalar(10), SkIntToScalar(10),
238 SkIntToScalar(80), SkIntToScalar(80)));
239 SkImageFilter::CropRect innerRect(SkRect::MakeXYWH(SkIntToScalar(20), SkIntToScalar(20),
240 SkIntToScalar(60), SkIntToScalar(60)));
robertphillips5605b562016-04-05 11:50:42 -0700241 sk_sp<SkImageFilter> color1(SkColorFilterImageFilter::Make(std::move(cf1),
242 nullptr,
243 &outerRect));
244 sk_sp<SkImageFilter> color2(SkColorFilterImageFilter::Make(std::move(cf2),
245 std::move(color1),
246 &innerRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000247
248 SkPaint paint;
robertphillipsfc11b0a2016-04-05 09:09:36 -0700249 paint.setImageFilter(std::move(color2));
mtklein871ad7a2015-03-27 12:33:46 -0700250 paint.setColor(SK_ColorRED);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000251 canvas->drawRect(SkRect::MakeXYWH(0, 0, 100, 100), paint);
252 canvas->translate(SkIntToScalar(100), 0);
253 }
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +0000254 }
255
256private:
fmalita5598b632015-09-15 11:26:13 -0700257 static void DrawClippedImage(SkCanvas* canvas, const SkImage* image, const SkPaint& paint) {
258 canvas->save();
259 canvas->clipRect(SkRect::MakeIWH(image->width(), image->height()));
260 canvas->drawImage(image, 0, 0, &paint);
261 canvas->restore();
262 }
263
reed9ce9d672016-03-17 10:51:11 -0700264 sk_sp<SkImage> fImage;
fmalita5598b632015-09-15 11:26:13 -0700265
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +0000266 typedef GM INHERITED;
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +0000267};
268
269///////////////////////////////////////////////////////////////////////////////
270
robertphillips943a4622015-09-03 13:32:33 -0700271DEF_GM(return new ImageFiltersGraphGM;)