Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
image.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2011 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"
9
15#include "include/core/SkData.h"
16#include "include/core/SkFont.h"
23#include "include/core/SkRect.h"
27#include "include/core/SkSize.h"
42#include "tools/GpuToolUtils.h"
43#include "tools/ToolUtils.h"
45
46#if defined(SK_GRAPHITE)
48#endif
49
50#include <functional>
51#include <utility>
52
53#if defined(SK_GRAPHITE)
55#endif
56
63
64static void draw_contents(SkSurface* surface, SkColor fillC) {
66 SkIntToScalar(surface->height()));
67 SkCanvas* canvas = surface->getCanvas();
68
69 SkScalar stroke = size.fWidth / 10;
70 SkScalar radius = (size.fWidth - stroke) / 2;
71
73
74 paint.setAntiAlias(true);
75 paint.setColor(fillC);
76 canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);
77
79 paint.setStrokeWidth(stroke);
80 paint.setColor(SK_ColorBLACK);
81 canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);
82}
83
84static void test_surface(SkCanvas* canvas, SkSurface* surf, bool usePaint) {
86 sk_sp<SkImage> imgR = surf->makeImageSnapshot();
87
88 if (true) {
89 sk_sp<SkImage> imgR2 = surf->makeImageSnapshot();
90 SkASSERT(imgR == imgR2);
91 }
92
93 imgR = ToolUtils::MakeTextureImage(canvas, std::move(imgR));
96
97 // since we've drawn after we snapped imgR, imgG will be a different obj unless the
98 // gpu context has been abandoned (in which case they will both be null)
99 SkASSERT(imgR != imgG || (!imgR && !imgG));
100
102
103 SkSamplingOptions sampling;
105
106 canvas->drawImage(imgR, 0, 0, sampling, usePaint ? &paint : nullptr);
107 canvas->drawImage(imgG, 0, 80, sampling, usePaint ? &paint : nullptr);
108 surf->draw(canvas, 0, 160, SkSamplingOptions(), usePaint ? &paint : nullptr);
109
110 SkRect src1, src2, src3;
111 src1.setIWH(surf->width(), surf->height());
112 src2.setLTRB(SkIntToScalar(-surf->width() / 2), SkIntToScalar(-surf->height() / 2),
113 SkIntToScalar(surf->width()), SkIntToScalar(surf->height()));
114 src3.setIWH(surf->width() / 2, surf->height() / 2);
115
116 SkRect dst1, dst2, dst3, dst4;
117 dst1.setLTRB(0, 240, 65, 305);
118 dst2.setLTRB(0, 320, 65, 385);
119 dst3.setLTRB(0, 400, 65, 465);
120 dst4.setLTRB(0, 480, 65, 545);
121
122 canvas->drawImageRect(imgR, src1, dst1, sampling, usePaint ? &paint : nullptr,
124 canvas->drawImageRect(imgG, src2, dst2, sampling, usePaint ? &paint : nullptr,
126 canvas->drawImageRect(imgR, src3, dst3, sampling, usePaint ? &paint : nullptr,
128 canvas->drawImageRect(imgG, dst4, sampling, usePaint ? &paint : nullptr);
129}
130
131class ImageGM : public skiagm::GM {
132 void* fBuffer;
133 size_t fBufferSize;
134 SkSize fSize;
135 enum {
136 W = 64,
137 H = 64,
138 RB = W * 4 + 8,
139 };
140public:
142 fBufferSize = RB * H;
143 fBuffer = sk_malloc_throw(fBufferSize);
144 fSize.set(SkIntToScalar(W), SkIntToScalar(H));
145 }
146
147 ~ImageGM() override {
148 sk_free(fBuffer);
149 }
150
151protected:
152 SkString getName() const override { return SkString("image-surface"); }
153
154 SkISize getISize() override { return SkISize::Make(960, 1200); }
155
156 void onDraw(SkCanvas* canvas) override {
157 canvas->scale(2, 2);
158
160
161 canvas->drawString("Original Img", 10, 60, font, SkPaint());
162 canvas->drawString("Modified Img", 10, 140, font, SkPaint());
163 canvas->drawString("Cur Surface", 10, 220, font, SkPaint());
164 canvas->drawString("Full Crop", 10, 300, font, SkPaint());
165 canvas->drawString("Over-crop", 10, 380, font, SkPaint());
166 canvas->drawString("Upper-left", 10, 460, font, SkPaint());
167 canvas->drawString("No Crop", 10, 540, font, SkPaint());
168
169 canvas->drawString("Pre-Alloc Img", 80, 10, font, SkPaint());
170 canvas->drawString("New Alloc Img", 160, 10, font, SkPaint());
171 canvas->drawString( "GPU", 265, 10, font, SkPaint());
172
173 canvas->translate(80, 20);
174
175 // since we draw into this directly, we need to start fresh
176 sk_bzero(fBuffer, fBufferSize);
177
179 sk_sp<SkSurface> surf0(SkSurfaces::WrapPixels(info, fBuffer, RB));
181 sk_sp<SkSurface> surf2(
183
184 test_surface(canvas, surf0.get(), true);
185 canvas->translate(80, 0);
186 test_surface(canvas, surf1.get(), true);
187 if (surf2) {
188 canvas->translate(80, 0);
189 test_surface(canvas, surf2.get(), true);
190 }
191 }
192
193private:
194 using INHERITED = skiagm::GM;
195};
196DEF_GM( return new ImageGM; )
197
198///////////////////////////////////////////////////////////////////////////////////////////////////
199
200static void draw_pixmap(SkCanvas* canvas, const SkPixmap& pmap) {
202 bitmap.installPixels(pmap);
203 canvas->drawImage(bitmap.asImage(), 0, 0);
204}
205
206static void show_scaled_pixels(SkCanvas* canvas, SkImage* image) {
207 SkAutoCanvasRestore acr(canvas, true);
208
209 canvas->drawImage(image, 0, 0);
210 canvas->translate(110, 10);
211
213 SkAutoPixmapStorage storage;
214 storage.alloc(info);
215
216 const SkImage::CachingHint chints[] = {
218 };
219
220 for (auto ch : chints) {
221 canvas->save();
222 for (auto s : gSamplings) {
223 if (image->scalePixels(storage, s, ch)) {
224 draw_pixmap(canvas, storage);
225 }
226 canvas->translate(70, 0);
227 }
228 canvas->restore();
229 canvas->translate(0, 45);
230 }
231}
232
233static void draw_contents(SkCanvas* canvas) {
236 paint.setStrokeWidth(20);
237 canvas->drawCircle(50, 50, 35, paint);
238}
239
242 void (*draw)(SkCanvas*)) {
244 draw(surface->getCanvas());
245 return surface->makeImageSnapshot();
246}
247
250 void (*draw)(SkCanvas*)) {
251 SkPictureRecorder recorder;
252 draw(recorder.beginRecording(SkRect::MakeIWH(info.width(), info.height())));
254 info.dimensions(),
255 nullptr,
256 nullptr,
259}
260
267
270 void (*draw)(SkCanvas*)) {
271 if (!ctx) {
272 return nullptr;
273 }
274
276 if (!surface) {
277 return nullptr;
278 }
279
280 draw(surface->getCanvas());
281 return surface->makeImageSnapshot();
282}
283
286 void (*)(SkCanvas*));
287
288class ScalePixelsGM : public skiagm::GM {
289public:
291
292protected:
293 SkString getName() const override { return SkString("scale-pixels"); }
294
295 SkISize getISize() override { return SkISize::Make(960, 1200); }
296
297 void onDraw(SkCanvas* canvas) override {
299
300 const ImageMakerProc procs[] = {
302 };
303 for (auto& proc : procs) {
305 if (image) {
306 show_scaled_pixels(canvas, image.get());
307 }
308 canvas->translate(0, 120);
309 }
310 }
311
312private:
313 using INHERITED = skiagm::GM;
314};
315DEF_GM( return new ScalePixelsGM; )
316
317///////////////////////////////////////////////////////////////////////////////////////////////////
318
319DEF_SIMPLE_GM_CAN_FAIL(new_texture_image, canvas, errorMsg, 280, 115) {
320
322 bool isGPU = SkToBool(dContext);
323
324#if defined(SK_GRAPHITE)
325 skgpu::graphite::Recorder* recorder = canvas->recorder();
326 isGPU = isGPU || SkToBool(recorder);
327#endif
328
329 if (!isGPU) {
332 }
333
334 auto render_image = [](SkCanvas* canvas) {
335 canvas->clear(SK_ColorBLUE);
337 paint.setColor(SK_ColorRED);
338 canvas->drawRect(SkRect::MakeXYWH(10.f,10.f,10.f,10.f), paint);
339 paint.setColor(SK_ColorGREEN);
340 canvas->drawRect(SkRect::MakeXYWH(30.f,10.f,10.f,10.f), paint);
341 paint.setColor(SK_ColorYELLOW);
342 canvas->drawRect(SkRect::MakeXYWH(10.f,30.f,10.f,10.f), paint);
343 paint.setColor(SK_ColorCYAN);
344 canvas->drawRect(SkRect::MakeXYWH(30.f,30.f,10.f,10.f), paint);
345 };
346
347 static constexpr int kSize = 50;
351 SkBitmap bmp;
352 bmp.allocPixels(ii);
353 SkCanvas bmpCanvas(bmp);
354 render_image(&bmpCanvas);
355
356 std::function<sk_sp<SkImage>()> imageFactories[] = {
357 // Create sw raster image.
358 [&] { return bmp.asImage(); },
359 // Create encoded image.
360 [&] {
362 SkASSERT_RELEASE(SkPngEncoder::Encode(&stream, bmp.pixmap(), {}));
363 return SkImages::DeferredFromEncodedData(stream.detachAsData());
364 },
365 // Create YUV encoded image.
366 [&] {
368 SkASSERT_RELEASE(SkJpegEncoder::Encode(&stream, bmp.pixmap(), {}));
369 return SkImages::DeferredFromEncodedData(stream.detachAsData());
370 },
371 // Create a picture image.
372 [&] {
373 SkPictureRecorder recorder;
374 SkCanvas* canvas =
376 render_image(canvas);
380 nullptr,
381 nullptr,
383 srgbColorSpace);
384 },
385 // Create a texture image
386 [&]() -> sk_sp<SkImage> {
388 if (dContext) {
390 } else {
391#if defined(SK_GRAPHITE)
392 surface = SkSurfaces::RenderTarget(recorder, ii);
393#endif
394 }
395
396 if (!surface) {
397 return nullptr;
398 }
399 render_image(surface->getCanvas());
400 return surface->makeImageSnapshot();
401 }};
402
403 constexpr SkScalar kPad = 5.f;
404 canvas->translate(kPad, kPad);
405 for (const auto& factory : imageFactories) {
406 sk_sp<SkImage> image(factory());
407 if (image) {
408 for (auto mm : { false, true }) {
409 sk_sp<SkImage> texImage;
410 if (dContext) {
411 texImage = SkImages::TextureFromImage(dContext,
412 image,
413 mm ? skgpu::Mipmapped::kYes
414 : skgpu::Mipmapped::kNo);
415 } else {
416#if defined(SK_GRAPHITE)
417 texImage = SkImages::TextureFromImage(recorder, image, {mm});
418#endif
419 }
420 if (texImage) {
421 canvas->drawImage(texImage, 0, mm ? kSize + kPad : 0);
422 }
423 }
424 }
425 canvas->translate(kSize + kPad, 0);
426 }
427
429}
430
431static void draw_pixmap(SkCanvas* canvas, const SkPixmap& pm, SkScalar x, SkScalar y) {
433}
434
435static void slam_ff(const SkPixmap& pm) {
436 for (int y = 0; y < pm.height(); ++y) {
437 for (int x = 0; x < pm.width(); ++x) {
438 *pm.writable_addr32(x, y) = *pm.addr32(x, y) | SkPackARGB32(0xFF, 0, 0, 0);
439 }
440 }
441}
442
443DEF_SIMPLE_GM(scalepixels_unpremul, canvas, 1080, 280) {
446 pm.alloc(info);
447 for (int y = 0; y < 16; ++y) {
448 for (int x = 0; x < 16; ++x) {
449 *pm.writable_addr32(x, y) = SkPackARGB32NoCheck(0, (y << 4) | y, (x << 4) | x, 0xFF);
450 }
451 }
454
455 for (auto s : gSamplings) {
456 pm.scalePixels(pm2, s);
457 slam_ff(pm2);
458 draw_pixmap(canvas, pm2, 10, 10);
459 canvas->translate(pm2.width() + 10.0f, 0);
460 }
461}
462
463///////////////////////////////////////////////////////////////////////////////////////////////////
464
466 sk_sp<SkPicture> picture;
467 {
468 SkPictureRecorder recorder;
469 SkCanvas* canvas = recorder.beginRecording(SkRect::MakeIWH(200, 200));
470 canvas->drawCircle(100, 100, 100, SkPaint());
471 picture = recorder.finishRecordingAsPicture();
472 }
473
474 return SkImages::DeferredFromPicture(std::move(picture),
475 {200, 200},
476 /* matrix= */ nullptr,
477 /* paint= */ nullptr,
480}
481
483 if (!img) {
484 return nullptr;
485 }
486
487 SkSerialProcs sProcs;
488 sProcs.fImageProc = [](SkImage* img, void*) -> sk_sp<SkData> {
489 return SkPngEncoder::Encode(as_IB(img)->directContext(), img, SkPngEncoder::Options{});
490 };
491 SkBinaryWriteBuffer writer(sProcs);
492
493 writer.writeImage(img);
494 size_t length = writer.bytesWritten();
496 writer.writeToMemory(data->writable_data());
497
498 SkReadBuffer reader(data->data(), length);
499 return reader.readImage();
500}
501
502DEF_SIMPLE_GM_CAN_FAIL(image_subset, canvas, errorMsg, 440, 220) {
503 auto img = make_lazy_image();
504 if (!img) {
505 *errorMsg = "Failed to make lazy image.";
507 }
508
510#if defined(SK_GRAPHITE)
511 auto recorder = canvas->recorder();
512#endif
513
514 canvas->drawImage(img, 10, 10);
515
516 sk_sp<SkImage> subset;
517
518#if defined(SK_GRAPHITE)
519 if (recorder) {
520 subset = img->makeSubset(recorder, {100, 100, 200, 200}, {});
521 } else
522#endif
523 {
524 subset = img->makeSubset(dContext, {100, 100, 200, 200});
525 }
526
527 canvas->drawImage(subset, 220, 10);
528 subset = serial_deserial(subset.get());
529 canvas->drawImage(subset, 220+110, 10);
531}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
static GrDirectContext * GrAsDirectContext(GrContext_Base *base)
kUnpremul_SkAlphaType
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkASSERT_RELEASE(cond)
Definition SkAssert.h:100
#define SkASSERT(cond)
Definition SkAssert.h:116
static SkPMColor SkPackARGB32(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
static SkPMColor SkPackARGB32NoCheck(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition SkColorType.h:24
constexpr SkColor SK_ColorYELLOW
Definition SkColor.h:139
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorCYAN
Definition SkColor.h:143
constexpr SkColor SK_ColorBLUE
Definition SkColor.h:135
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition SkColor.h:131
static SkImage_Base * as_IB(SkImage *image)
static void sk_bzero(void *buffer, size_t size)
Definition SkMalloc.h:105
SK_API void sk_free(void *)
static void * sk_malloc_throw(size_t size)
Definition SkMalloc.h:67
#define SkIntToScalar(x)
Definition SkScalar.h:57
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
Definition aaclip.cpp:27
constexpr int kPad
void onDraw(SkCanvas *canvas) override
Definition image.cpp:156
~ImageGM() override
Definition image.cpp:147
ImageGM()
Definition image.cpp:141
SkString getName() const override
Definition image.cpp:152
SkISize getISize() override
Definition image.cpp:154
SkISize getISize() override
Definition image.cpp:295
void onDraw(SkCanvas *canvas) override
Definition image.cpp:297
SkString getName() const override
Definition image.cpp:293
void alloc(const SkImageInfo &)
size_t bytesWritten() const
void writeImage(const SkImage *) override
void writeToMemory(void *dst) const
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition SkBitmap.cpp:258
sk_sp< SkImage > asImage() const
Definition SkBitmap.cpp:645
const SkPixmap & pixmap() const
Definition SkBitmap.h:133
void drawRect(const SkRect &rect, const SkPaint &paint)
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
virtual GrRecordingContext * recordingContext() const
virtual skgpu::graphite::Recorder * recorder() const
@ kStrict_SrcRectConstraint
sample only inside bounds; slower
Definition SkCanvas.h:1542
void clear(SkColor color)
Definition SkCanvas.h:1199
void drawImageRect(const SkImage *, const SkRect &src, const SkRect &dst, const SkSamplingOptions &, const SkPaint *, SrcRectConstraint)
int save()
Definition SkCanvas.cpp:451
void scale(SkScalar sx, SkScalar sy)
void drawString(const char str[], SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint)
Definition SkCanvas.h:1803
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition SkCanvas.h:1528
void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint &paint)
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition SkData.cpp:116
CachingHint
Definition SkImage.h:463
@ kDisallow_CachingHint
disallows internally caching decoded and copied pixels
Definition SkImage.h:465
@ kAllow_CachingHint
allows internally caching decoded and copied pixels
Definition SkImage.h:464
bool scalePixels(const SkPixmap &dst, const SkSamplingOptions &, CachingHint cachingHint=kAllow_CachingHint) const
Definition SkImage.cpp:127
@ kStroke_Style
set to stroke geometry
Definition SkPaint.h:194
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
bool scalePixels(const SkPixmap &dst, const SkSamplingOptions &) const
const uint32_t * addr32() const
Definition SkPixmap.h:352
int width() const
Definition SkPixmap.h:160
uint32_t * writable_addr32(int x, int y) const
Definition SkPixmap.h:537
int height() const
Definition SkPixmap.h:166
sk_sp< SkImage > readImage()
int width() const
Definition SkSurface.h:178
void draw(SkCanvas *canvas, SkScalar x, SkScalar y, const SkSamplingOptions &sampling, const SkPaint *paint)
sk_sp< SkImage > makeImageSnapshot()
Definition SkSurface.cpp:90
int height() const
Definition SkSurface.h:184
T * get() const
Definition SkRefCnt.h:303
static constexpr char kErrorMsg_DrawSkippedGpuOnly[]
Definition gm.h:127
static constexpr int kSize
const Paint & paint
VkSurfaceKHR surface
Definition main.cc:49
sk_sp< SkImage > image
Definition examples.cpp:29
float SkScalar
Definition extension.cpp:12
struct MyStruct s
#define DEF_GM(CODE)
Definition gm.h:40
#define DEF_SIMPLE_GM_CAN_FAIL(NAME, CANVAS, ERR_MSG, W, H)
Definition gm.h:62
#define DEF_SIMPLE_GM(NAME, CANVAS, W, H)
Definition gm.h:50
size_t length
double y
double x
SK_API sk_sp< SkImage > DeferredFromPicture(sk_sp< SkPicture > picture, const SkISize &dimensions, const SkMatrix *matrix, const SkPaint *paint, BitDepth bitDepth, sk_sp< SkColorSpace > colorSpace, SkSurfaceProps props)
SK_API sk_sp< SkImage > DeferredFromEncodedData(sk_sp< SkData > encoded, std::optional< SkAlphaType > alphaType=std::nullopt)
SK_API sk_sp< SkImage > TextureFromImage(GrDirectContext *, const SkImage *, skgpu::Mipmapped=skgpu::Mipmapped::kNo, skgpu::Budgeted=skgpu::Budgeted::kYes)
SK_API sk_sp< SkImage > RasterFromPixmapCopy(const SkPixmap &pixmap)
@ kU8
uses 8-bit unsigned int per color component
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
SK_API sk_sp< SkSurface > WrapPixels(const SkImageInfo &imageInfo, void *pixels, size_t rowBytes, const SkSurfaceProps *surfaceProps=nullptr)
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
sk_sp< SkTypeface > DefaultPortableTypeface()
sk_sp< SkImage > MakeTextureImage(SkCanvas *canvas, sk_sp< SkImage > orig)
Definition SkMD5.cpp:130
static constexpr SkCubicResampler Mitchell()
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
static SkImageInfo MakeN32Premul(int width, int height)
static SkImageInfo MakeN32(int width, int height, SkAlphaType at)
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
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
void setIWH(int32_t width, int32_t height)
Definition SkRect.h:950
void setLTRB(float left, float top, float right, float bottom)
Definition SkRect.h:865
SkSerialImageProc fImageProc
static constexpr SkSize Make(SkScalar w, SkScalar h)
Definition SkSize.h:56
static void draw_pixmap(SkCanvas *canvas, const SkPixmap &pmap)
Definition image.cpp:200
sk_sp< SkImage >(* ImageMakerProc)(const SkImageInfo &, GrRecordingContext *, void(*)(SkCanvas *))
Definition image.cpp:284
static sk_sp< SkImage > make_gpu(const SkImageInfo &info, GrRecordingContext *ctx, void(*draw)(SkCanvas *))
Definition image.cpp:268
static void draw_contents(SkSurface *surface, SkColor fillC)
Definition image.cpp:64
static void show_scaled_pixels(SkCanvas *canvas, SkImage *image)
Definition image.cpp:206
static sk_sp< SkImage > make_codec(const SkImageInfo &info, GrRecordingContext *, void(*draw)(SkCanvas *))
Definition image.cpp:261
const SkSamplingOptions gSamplings[]
Definition image.cpp:57
static void test_surface(SkCanvas *canvas, SkSurface *surf, bool usePaint)
Definition image.cpp:84
static sk_sp< SkImage > serial_deserial(SkImage *img)
Definition image.cpp:482
static void slam_ff(const SkPixmap &pm)
Definition image.cpp:435
static sk_sp< SkImage > make_lazy_image()
Definition image.cpp:465
static sk_sp< SkImage > make_raster(const SkImageInfo &info, GrRecordingContext *, void(*draw)(SkCanvas *))
Definition image.cpp:240
static sk_sp< SkPicture > make_picture()
Definition picture.cpp:22