Flutter Engine
The Flutter Engine
imagefilterstransformed.cpp
Go to the documentation of this file.
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/gm.h"
13#include "include/core/SkFont.h"
18#include "include/core/SkRect.h"
22#include "include/core/SkSize.h"
29#include "tools/DecodeUtils.h"
30#include "tools/Resources.h"
31#include "tools/ToolUtils.h"
34
35#include <utility>
36
37namespace skiagm {
38
39// This GM draws image filters with a CTM containing shearing / rotation.
40// It checks that the scale portion of the CTM is correctly extracted
41// and applied to the image inputs separately from the non-scale portion.
42
46 SkScalar radius = std::min(x, y) * 0.8f;
47
49 SkCanvas* canvas = surface->getCanvas();
50
51 canvas->clear(0x00000000);
52 SkColor colors[2];
56 paint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
58 canvas->drawCircle(x, y, radius, paint);
59
60 return surface->makeImageSnapshot();
61}
62
64public:
67 }
68
69protected:
70 SkString getName() const override { return SkString("imagefilterstransformed"); }
71
72 SkISize getISize() override { return SkISize::Make(420, 240); }
73
74 void onOnceBeforeDraw() override {
75 fCheckerboard =
76 ToolUtils::create_checkerboard_image(64, 64, 0xFFA0A0A0, 0xFF404040, 8);
77 fGradientCircle = make_gradient_circle(64, 64);
78 }
79
80 void onDraw(SkCanvas* canvas) override {
81 sk_sp<SkImageFilter> gradient(SkImageFilters::Image(fGradientCircle,
85 sk_sp<SkImageFilter> filters[] = {
86 SkImageFilters::Blur(12, 0, nullptr),
87 SkImageFilters::DropShadow(0, 15, 8, 0, SK_ColorGREEN, nullptr),
89 std::move(gradient), checkerboard),
92 };
93
94 const SkScalar margin = SkIntToScalar(20);
95 const SkScalar size = SkIntToScalar(60);
96
97 for (size_t j = 0; j < 3; j++) {
98 canvas->save();
99 canvas->translate(margin, 0);
100 for (size_t i = 0; i < std::size(filters); ++i) {
102 paint.setColor(SK_ColorWHITE);
103 paint.setImageFilter(filters[i]);
104 paint.setAntiAlias(true);
105 canvas->save();
107 canvas->scale(SkDoubleToScalar(0.8), SkDoubleToScalar(0.8));
108 if (j == 1) {
109 canvas->rotate(SkIntToScalar(45));
110 } else if (j == 2) {
111 canvas->skew(SkDoubleToScalar(0.5), SkDoubleToScalar(0.2));
112 }
115 size, size * SkDoubleToScalar(0.6)), paint);
116 canvas->restore();
117 canvas->translate(size + margin, 0);
118 }
119 canvas->restore();
120 canvas->translate(0, size + margin);
121 }
122 }
123
124private:
125 sk_sp<SkImage> fCheckerboard;
126 sk_sp<SkImage> fGradientCircle;
127 using INHERITED = GM;
128};
129DEF_GM( return new ImageFiltersTransformedGM; )
130} // namespace skiagm
131
132//////////////////////////////////////////////////////////////////////////////
133
134DEF_SIMPLE_GM(rotate_imagefilter, canvas, 500, 500) {
136
137 const SkRect r = SkRect::MakeXYWH(50, 50, 100, 100);
138
139 sk_sp<SkImageFilter> filters[] = {
140 nullptr,
141 SkImageFilters::Blur(6, 0, nullptr),
143 };
144
145 for (auto& filter : filters) {
146 paint.setAntiAlias(false);
147 paint.setImageFilter(filter);
148
149 canvas->save();
150
151 canvas->drawRect(r, paint);
152
153 canvas->translate(150, 0);
154 canvas->save();
155 canvas->rotate(30, 100, 100);
156 canvas->drawRect(r, paint);
157 canvas->restore();
158
159 paint.setAntiAlias(true);
160 canvas->translate(150, 0);
161 canvas->save();
162 canvas->rotate(30, 100, 100);
163 canvas->drawRect(r, paint);
164 canvas->restore();
165
166 canvas->restore();
167 canvas->translate(0, 150);
168 }
169}
170
172public:
173
174 // Start at 132 degrees, since that resulted in a skipped draw before the fix to
175 // SkLocalMatrixImageFilter's computeFastBounds() function.
176 ImageFilterMatrixWLocalMatrix() : fDegrees(132.f) {}
177
178protected:
179 SkString getName() const override { return SkString("imagefilter_matrix_localmatrix"); }
180
181 SkISize getISize() override { return SkISize::Make(512, 512); }
182
183 bool onAnimate(double nanos) override {
184 // Animate the rotation angle to ensure the local matrix bounds modifications work
185 // for a variety of transformations.
186 fDegrees = TimeUtils::Scaled(1e-9f * nanos, 360.f);
187 return true;
188 }
189
190 void onOnceBeforeDraw() override {
191 fImage = ToolUtils::GetResourceAsImage("images/mandrill_256.png");
192 }
193
194 void onDraw(SkCanvas* canvas) override {
195 SkMatrix localMatrix;
196 localMatrix.preTranslate(128, 128);
197 localMatrix.preScale(2.0f, 2.0f);
198
199 // This matrix applies a rotate around the center of the image (prior to the simulated
200 // hi-dpi 2x device scale).
201 SkMatrix filterMatrix;
202 filterMatrix.setRotate(fDegrees, 64, 64);
203
204 sk_sp<SkImageFilter> filter =
207 ->makeWithLocalMatrix(localMatrix);
208
209 SkPaint p;
210 p.setImageFilter(filter);
211 canvas->drawImage(fImage.get(), 128, 128, SkSamplingOptions(), &p);
212 }
213
214private:
215 SkScalar fDegrees;
216 sk_sp<SkImage> fImage;
217};
218
220
222public:
223
224 // Start at 70 degrees since that highlighted the issue in skbug.com/10888
225 ImageFilterComposedTransform() : fDegrees(70.f) {}
226
227protected:
228 SkString getName() const override { return SkString("imagefilter_composed_transform"); }
229
230 SkISize getISize() override { return SkISize::Make(512, 512); }
231
232 bool onAnimate(double nanos) override {
233 // Animate the rotation angle to test a variety of transformations
234 fDegrees = TimeUtils::Scaled(1e-9f * nanos, 360.f);
235 return true;
236 }
237
238 void onOnceBeforeDraw() override {
239 fImage = ToolUtils::GetResourceAsImage("images/mandrill_256.png");
240 }
241
242 void onDraw(SkCanvas* canvas) override {
244 // All four quadrants should render the same
245 this->drawFilter(canvas, 0.f, 0.f, this->makeDirectFilter(matrix));
246 this->drawFilter(canvas, 256.f, 0.f, this->makeEarlyComposeFilter(matrix));
247 this->drawFilter(canvas, 0.f, 256.f, this->makeLateComposeFilter(matrix));
248 this->drawFilter(canvas, 256.f, 256.f, this->makeFullComposeFilter(matrix));
249 }
250
251private:
252 SkScalar fDegrees;
253 sk_sp<SkImage> fImage;
254
255 void drawFilter(SkCanvas* canvas, SkScalar tx, SkScalar ty, sk_sp<SkImageFilter> filter) const {
256 SkPaint p;
257 p.setImageFilter(std::move(filter));
258
259 canvas->save();
260 canvas->translate(tx, ty);
261 canvas->clipRect(SkRect::MakeWH(256, 256));
262 canvas->scale(0.5f, 0.5f);
263 canvas->translate(128, 128);
264 canvas->drawImage(fImage, 0, 0, SkSamplingOptions(SkFilterMode::kLinear), &p);
265 canvas->restore();
266 }
267
268 // offset(matrix(offset))
269 sk_sp<SkImageFilter> makeDirectFilter(const SkMatrix& matrix) const {
270 SkPoint v = {fImage->width() / 2.f, fImage->height() / 2.f};
271 sk_sp<SkImageFilter> filter = SkImageFilters::Offset(-v.fX, -v.fY, nullptr);
273 std::move(filter));
274 filter = SkImageFilters::Offset(v.fX, v.fY, std::move(filter));
275 return filter;
276 }
277
278 // offset(compose(matrix, offset))
279 sk_sp<SkImageFilter> makeEarlyComposeFilter(const SkMatrix& matrix) const {
280 SkPoint v = {fImage->width() / 2.f, fImage->height() / 2.f};
284 filter = SkImageFilters::Compose(std::move(filter), std::move(offset));
285 filter = SkImageFilters::Offset(v.fX, v.fY, std::move(filter));
286 return filter;
287 }
288
289 // compose(offset, matrix(offset))
290 sk_sp<SkImageFilter> makeLateComposeFilter(const SkMatrix& matrix) const {
291 SkPoint v = {fImage->width() / 2.f, fImage->height() / 2.f};
292 sk_sp<SkImageFilter> filter = SkImageFilters::Offset(-v.fX, -v.fY, nullptr);
294 std::move(filter));
296 filter = SkImageFilters::Compose(std::move(offset), std::move(filter));
297 return filter;
298 }
299
300 // compose(offset, compose(matrix, offset))
301 sk_sp<SkImageFilter> makeFullComposeFilter(const SkMatrix& matrix) const {
302 SkPoint v = {fImage->width() / 2.f, fImage->height() / 2.f};
306 filter = SkImageFilters::Compose(std::move(filter), std::move(offset));
307 offset = SkImageFilters::Offset(v.fX, v.fY, nullptr);
308 filter = SkImageFilters::Compose(std::move(offset), std::move(filter));
309 return filter;
310 }
311};
312
314
315// Tests SkImageFilters::Image under tricky matrices (mirrors and perspective)
316DEF_SIMPLE_GM(imagefilter_transformed_image, canvas, 256, 256) {
317 sk_sp<SkImage> image = ToolUtils::GetResourceAsImage("images/color_wheel.png");
319
320 const SkRect imageRect = SkRect::MakeIWH(image->width(), image->height());
321
322 SkM44 m1 = SkM44::Translate(0.9f * image->width(), 0.1f * image->height()) *
323 SkM44::Scale(-.8f, .8f);
324
325 SkM44 m2 = SkM44::RectToRect({-1.f, -1.f, 1.f, 1.f}, imageRect) *
326 SkM44::Perspective(0.01f, 100.f, SK_ScalarPI / 3.f) *
327 SkM44::Translate(0.f, 0.f, -2.f) *
328 SkM44::Rotate({0.f, 1.f, 0.f}, SK_ScalarPI / 6.f) *
329 SkM44::RectToRect(imageRect, {-1.f, -1.f, 1.f, 1.f});
330
332 canvas->drawString("Columns should match", 5.f, 15.f, font, SkPaint());
333 canvas->translate(0.f, 10.f);
334
336 for (auto m : {m1, m2}) {
337 canvas->save();
338 for (bool canvasTransform : {false, true}) {
339 canvas->save();
340 canvas->clipRect(imageRect);
341
342 sk_sp<SkImageFilter> finalFilter;
343 if (canvasTransform) {
344 canvas->concat(m);
345 finalFilter = imageFilter;
346 } else {
347 finalFilter = SkImageFilters::MatrixTransform(m.asM33(), sampling, imageFilter);
348 }
349
351 paint.setImageFilter(std::move(finalFilter));
352 canvas->drawPaint(paint);
353
354 canvas->restore();
355 canvas->translate(image->width(), 0.f);
356 }
357 canvas->restore();
358
359 canvas->translate(0.f, image->height());
360 }
361}
@ kSrcOver
r = s + (1-sa)*d
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
#define SK_ScalarHalf
Definition: SkScalar.h:19
#define SkDoubleToScalar(x)
Definition: SkScalar.h:64
#define SkIntToScalar(x)
Definition: SkScalar.h:57
#define SK_ScalarPI
Definition: SkScalar.h:21
bool onAnimate(double nanos) override
void onDraw(SkCanvas *canvas) override
void onDraw(SkCanvas *canvas) override
bool onAnimate(double nanos) override
void drawOval(const SkRect &oval, const SkPaint &paint)
Definition: SkCanvas.cpp:1698
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
Definition: SkCanvas.cpp:1361
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
void drawPaint(const SkPaint &paint)
Definition: SkCanvas.cpp:1668
void clear(SkColor color)
Definition: SkCanvas.h:1199
void rotate(SkScalar degrees)
Definition: SkCanvas.cpp:1300
int save()
Definition: SkCanvas.cpp:447
void scale(SkScalar sx, SkScalar sy)
Definition: SkCanvas.cpp:1289
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
void drawString(const char str[], SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint)
Definition: SkCanvas.h:1803
void skew(SkScalar sx, SkScalar sy)
Definition: SkCanvas.cpp:1312
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition: SkCanvas.h:1528
void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint &paint)
Definition: SkCanvas.cpp:2707
Definition: SkFont.h:35
static sk_sp< SkShader > MakeRadial(const SkPoint &center, SkScalar radius, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
sk_sp< SkImageFilter > makeWithLocalMatrix(const SkMatrix &matrix) const
static sk_sp< SkImageFilter > DropShadow(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, SkColor color, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Erode(SkScalar radiusX, SkScalar radiusY, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Blur(SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > DisplacementMap(SkColorChannel xChannelSelector, SkColorChannel yChannelSelector, SkScalar scale, sk_sp< SkImageFilter > displacement, sk_sp< SkImageFilter > color, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Compose(sk_sp< SkImageFilter > outer, sk_sp< SkImageFilter > inner)
static sk_sp< SkImageFilter > Image(sk_sp< SkImage > image, const SkRect &srcRect, const SkRect &dstRect, const SkSamplingOptions &sampling)
static sk_sp< SkImageFilter > MatrixTransform(const SkMatrix &matrix, const SkSamplingOptions &sampling, sk_sp< SkImageFilter > input)
static sk_sp< SkImageFilter > Blend(SkBlendMode mode, sk_sp< SkImageFilter > background, sk_sp< SkImageFilter > foreground=nullptr, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Offset(SkScalar dx, SkScalar dy, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Dilate(SkScalar radiusX, SkScalar radiusY, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
int width() const
Definition: SkImage.h:285
int height() const
Definition: SkImage.h:291
Definition: SkM44.h:150
static SkM44 Rotate(SkV3 axis, SkScalar radians)
Definition: SkM44.h:239
static SkM44 RectToRect(const SkRect &src, const SkRect &dst)
Definition: SkM44.cpp:304
static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z=0)
Definition: SkM44.h:225
static SkM44 Perspective(float near, float far, float angle)
Definition: SkM44.cpp:343
static SkM44 Scale(SkScalar x, SkScalar y, SkScalar z=1)
Definition: SkM44.h:232
static SkMatrix RotateDeg(SkScalar deg)
Definition: SkMatrix.h:104
SkMatrix & setRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:452
SkMatrix & preTranslate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.cpp:263
SkMatrix & preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:315
T * get() const
Definition: SkRefCnt.h:303
Definition: gm.h:110
GM(SkColor backgroundColor=SK_ColorWHITE)
Definition: gm.cpp:81
void setBGColor(SkColor)
Definition: gm.cpp:159
void onDraw(SkCanvas *canvas) override
const Paint & paint
Definition: color_source.cc:38
VkSurfaceKHR surface
Definition: main.cc:49
float SkScalar
Definition: extension.cpp:12
#define DEF_GM(CODE)
Definition: gm.h:40
static float min(float r, float g, float b)
Definition: hsl.cpp:48
DEF_SIMPLE_GM(rotate_imagefilter, canvas, 500, 500)
double y
double x
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
sk_sp< const SkImage > image
Definition: SkRecords.h:269
PODArray< SkColor > colors
Definition: SkRecords.h:276
SkSamplingOptions sampling
Definition: SkRecords.h:337
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
static float Scaled(float time, float speed, float period=0)
Definition: TimeUtils.h:27
SkFont DefaultPortableFont()
sk_sp< SkImage > GetResourceAsImage(const char *resource)
Definition: DecodeUtils.h:25
sk_sp< SkImage > create_checkerboard_image(int w, int h, SkColor c1, SkColor c2, int checkSize)
Definition: ToolUtils.cpp:168
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
font
Font Metadata and Metrics.
DEF_GM(return F(C(clipbox), 0.0f, 0.0f, {})) DEF_GM(return F(C(clipbox)
SkSamplingOptions(SkFilterMode::kLinear))
static sk_sp< SkImage > make_gradient_circle(int width, int height)
int32_t height
int32_t width
SeparatedVector2 offset
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
static SkImageInfo MakeN32Premul(int width, int height)
float fX
x-axis value
Definition: SkPoint_impl.h:164
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
float fY
y-axis value
Definition: SkPoint_impl.h:165
static SkRect MakeIWH(int w, int h)
Definition: SkRect.h:623
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
static void checkerboard(SkCanvas *canvas, SkColor c1, SkColor c2, int size)