1/*
2 * Copyright 2014 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 "SkCanvas.h"
11#include "SkColorFilter.h"
12#include "SkColorPriv.h"
13#include "SkShader.h"
14
15#include "SkBlurImageFilter.h"
16#include "SkColorMatrixFilter.h"
17#include "SkDisplacementMapEffect.h"
18#include "SkDropShadowImageFilter.h"
19#include "SkGradientShader.h"
20#include "SkImageSource.h"
21#include "SkMorphologyImageFilter.h"
22#include "SkColorFilterImageFilter.h"
23#include "SkLightingImageFilter.h"
24#include "SkMergeImageFilter.h"
25#include "SkOffsetImageFilter.h"
26#include "SkPoint3.h"
27#include "SkSurface.h"
28
29namespace {
30
31void make_checkerboard(SkBitmap* bitmap);
32sk_sp<SkImage> make_gradient_circle(int width, int height);
33void draw(SkCanvas* canvas, const SkBitmap& bitmap, const SkRect& rect,
34                 sk_sp<SkImageFilter> filter);
35
36};
37
38///////////////////////////////////////////////////////////////////////////////
39
40DEF_SIMPLE_GM(imagefilterscropexpand, canvas, 730, 650) {
41    SkImageFilter::CropRect cropRect(
42        SkRect::Make(SkIRect::MakeXYWH(10, 10, 44, 44)),
43        SkImageFilter::CropRect::kHasAll_CropEdge);
44
45    sk_sp<SkImage> gradientCircle(make_gradient_circle(64, 64));
46    SkBitmap checkerboard;
47    make_checkerboard(&checkerboard);
48
49    sk_sp<SkImageFilter> gradientCircleSource(SkImageSource::Make(std::move(gradientCircle)));
50    sk_sp<SkImageFilter> noopCropped(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
51    // This color matrix saturates the green component but only partly increases the opacity.
52    // For the opaque checkerboard, the opacity boost doesn't matter but it does impact the
53    // area outside the checkerboard.
54    SkScalar matrix[20] = { 1, 0, 0, 0, 0,
55                            0, 1, 0, 0, 255,
56                            0, 0, 1, 0, 0,
57                            0, 0, 0, 1, 32 };
58    sk_sp<SkColorFilter> cfAlphaTrans(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
59
60    SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64));
61    SkScalar MARGIN = SkIntToScalar(12);
62
63    SkPoint3 pointLocation = SkPoint3::Make(0, 0, SkIntToScalar(10));
64    SkScalar kd = SkIntToScalar(2);
65    SkScalar surfaceScale = SkIntToScalar(1);
66    SkIRect bounds;
67    r.roundOut(&bounds);
68
69    SkPaint paint;
70    canvas->translate(MARGIN, MARGIN);
71    for (int outset = -15; outset <= 20; outset += 5) {
72        canvas->save();
73        SkRect rect = cropRect.rect();
74        rect.outset(SkIntToScalar(outset),
75                    SkIntToScalar(outset));
76        SkImageFilter::CropRect bigRect(rect, SkImageFilter::CropRect::kHasAll_CropEdge);
77
78        draw(canvas, checkerboard, rect, SkColorFilterImageFilter::Make(cfAlphaTrans,
79                                                                        noopCropped,
80                                                                        &bigRect));
81
82        draw(canvas, checkerboard, rect, SkBlurImageFilter::Make(0.3f, 0.3f,
83                                                                 noopCropped,
84                                                                 &bigRect));
85
86        draw(canvas, checkerboard, rect, SkBlurImageFilter::Make(8.0f, 8.0f,
87                                                                 noopCropped,
88                                                                 &bigRect));
89
90        draw(canvas, checkerboard, rect, SkDilateImageFilter::Make(2, 2,
91                                                                   noopCropped,
92                                                                   &bigRect));
93
94        draw(canvas, checkerboard, rect, SkErodeImageFilter::Make(2, 2,
95                                                                  noopCropped,
96                                                                  &bigRect));
97
98        draw(canvas, checkerboard, rect,
99             SkDropShadowImageFilter::Make(
100                                SkIntToScalar(10),
101                                SkIntToScalar(10),
102                                SkIntToScalar(3),
103                                SkIntToScalar(3),
104                                SK_ColorBLUE,
105                                SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
106                                noopCropped,
107                                &bigRect));
108
109        draw(canvas, checkerboard, rect,
110             SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
111                                           SkDisplacementMapEffect::kR_ChannelSelectorType,
112                                           SkIntToScalar(12),
113                                           gradientCircleSource,
114                                           noopCropped,
115                                           &bigRect));
116
117        draw(canvas, checkerboard, rect,
118             SkOffsetImageFilter::Make(SkIntToScalar(-8), SkIntToScalar(16),
119                                       noopCropped,
120                                       &bigRect));
121
122        draw(canvas, checkerboard, rect,
123             SkLightingImageFilter::MakePointLitDiffuse(pointLocation,
124                                                        SK_ColorWHITE,
125                                                        surfaceScale,
126                                                        kd,
127                                                        noopCropped,
128                                                        &bigRect));
129
130        canvas->restore();
131        canvas->translate(0, SkIntToScalar(80));
132    }
133}
134
135namespace {
136    void make_checkerboard(SkBitmap* bitmap) {
137        bitmap->allocN32Pixels(64, 64);
138        SkCanvas canvas(*bitmap);
139        canvas.clear(0xFFFF0000);
140        SkPaint darkPaint;
141        darkPaint.setColor(sk_tool_utils::color_to_565(0xFF404040));
142        SkPaint lightPaint;
143        lightPaint.setColor(sk_tool_utils::color_to_565(0xFFA0A0A0));
144        for (int y = 8; y < 48; y += 16) {
145            for (int x = 8; x < 48; x += 16) {
146                canvas.save();
147                canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
148                canvas.drawRect(SkRect::MakeXYWH(0, 0, 8, 8), darkPaint);
149                canvas.drawRect(SkRect::MakeXYWH(8, 0, 8, 8), lightPaint);
150                canvas.drawRect(SkRect::MakeXYWH(0, 8, 8, 8), lightPaint);
151                canvas.drawRect(SkRect::MakeXYWH(8, 8, 8, 8), darkPaint);
152                canvas.restore();
153            }
154        }
155    }
156
157    sk_sp<SkImage> make_gradient_circle(int width, int height) {
158        SkScalar x = SkIntToScalar(width / 2);
159        SkScalar y = SkIntToScalar(height / 2);
160        SkScalar radius = SkMinScalar(x, y) * 0.8f;
161        auto surface(SkSurface::MakeRasterN32Premul(width, height));
162        SkCanvas* canvas = surface->getCanvas();
163        canvas->clear(0x00000000);
164        SkColor colors[2];
165        colors[0] = SK_ColorWHITE;
166        colors[1] = SK_ColorBLACK;
167        SkPaint paint;
168        paint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr,
169                                                     2, SkShader::kClamp_TileMode));
170        canvas->drawCircle(x, y, radius, paint);
171
172        return surface->makeImageSnapshot();
173    }
174
175    void draw(SkCanvas* canvas, const SkBitmap& bitmap, const SkRect& rect,
176                     sk_sp<SkImageFilter> filter) {
177        SkPaint paint;
178        paint.setImageFilter(std::move(filter));
179        canvas->saveLayer(&rect, &paint);
180        canvas->drawBitmap(bitmap, 0, 0);
181        canvas->restore();
182
183        SkPaint strokePaint;
184        strokePaint.setColor(0xFFFF0000);
185        strokePaint.setStyle(SkPaint::kStroke_Style);
186        canvas->drawRect(rect, strokePaint);
187
188        canvas->translate(SkIntToScalar(80), 0);
189    }
190};
191