blob: 6108bde8d4e6bad2d7731f5b5c9538574c56dc81 [file] [log] [blame]
Mike Reed113fd342017-01-14 13:45:02 -05001/*
2 * Copyright 2017 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/SkColorSpace.h"
13#include "include/core/SkFont.h"
14#include "include/core/SkImage.h"
15#include "include/core/SkImageFilter.h"
16#include "include/core/SkImageInfo.h"
17#include "include/core/SkMaskFilter.h"
18#include "include/core/SkMatrix.h"
19#include "include/core/SkPaint.h"
20#include "include/core/SkPicture.h"
21#include "include/core/SkPictureRecorder.h"
22#include "include/core/SkPoint.h"
23#include "include/core/SkRect.h"
24#include "include/core/SkRefCnt.h"
25#include "include/core/SkScalar.h"
26#include "include/core/SkShader.h"
27#include "include/core/SkSize.h"
28#include "include/core/SkString.h"
29#include "include/core/SkSurface.h"
30#include "include/core/SkTextBlob.h"
31#include "include/core/SkTileMode.h"
32#include "include/core/SkTypeface.h"
33#include "include/core/SkTypes.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040034#include "include/effects/SkGradientShader.h"
Michael Ludwig898bbfa2019-08-02 15:21:23 -040035#include "include/effects/SkImageFilters.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050036#include "include/effects/SkShaderMaskFilter.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040037#include "include/utils/SkRandom.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050038#include "src/core/SkCanvasPriv.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040039#include "tools/Resources.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050040#include "tools/ToolUtils.h"
Yuqian Lid196cbe2017-02-23 10:28:33 -050041
Ben Wagner7fde8e12019-05-01 17:28:53 -040042#include <string.h>
43#include <initializer_list>
44
Robert Phillips42f30942017-01-17 10:48:52 -050045// This GM tests out the deprecated Android-specific unclipped saveLayer "feature".
46// In particular, it attempts to compare the performance of unclipped saveLayers with alternatives.
47
48static void save_layer_unclipped(SkCanvas* canvas,
49 SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
Mike Reed18a8df62019-09-03 15:44:47 -040050 SkPaint paint;
51 paint.setAlphaf(0.25f);
Mike Reed113fd342017-01-14 13:45:02 -050052 SkRect rect = SkRect::MakeLTRB(l, t, r, b);
Mike Reedb42a3272020-05-30 16:02:14 -040053 canvas->saveLayer({ &rect, &paint, nullptr,
Cary Clark7eddfb82018-03-13 14:41:10 -040054 (SkCanvas::SaveLayerFlags) SkCanvasPriv::kDontClipToLayer_SaveLayerFlag });
Mike Reed113fd342017-01-14 13:45:02 -050055}
56
57static void do_draw(SkCanvas* canvas) {
58 SkPaint paint;
Mike Reed18a8df62019-09-03 15:44:47 -040059 paint.setColor(0xFFFF0000);
Mike Reed113fd342017-01-14 13:45:02 -050060
Mike Reed113fd342017-01-14 13:45:02 -050061 for (int i = 0; i < 20; ++i) {
Mike Reed113fd342017-01-14 13:45:02 -050062 canvas->drawRect({ 15, 15, 290, 40 }, paint);
63 canvas->translate(0, 30);
64 }
65}
66
Robert Phillips42f30942017-01-17 10:48:52 -050067class UnclippedSaveLayerGM : public skiagm::GM {
68public:
Mike Reed18a8df62019-09-03 15:44:47 -040069 UnclippedSaveLayerGM() { this->setBGColor(SK_ColorWHITE); }
Mike Reed113fd342017-01-14 13:45:02 -050070
Robert Phillips42f30942017-01-17 10:48:52 -050071protected:
72 bool runAsBench() const override { return true; }
73
74 SkString onShortName() override {
Mike Reed18a8df62019-09-03 15:44:47 -040075 return SkString("savelayer_unclipped");
Mike Reed113fd342017-01-14 13:45:02 -050076 }
Robert Phillips42f30942017-01-17 10:48:52 -050077
78 SkISize onISize() override { return SkISize::Make(320, 640); }
79
80 void onDraw(SkCanvas* canvas) override {
81 const SkScalar L = 10;
82 const SkScalar T = 10;
83 const SkScalar R = 310;
84 const SkScalar B = 630;
85
86 canvas->clipRect({ L, T, R, B });
87
Mike Reed18a8df62019-09-03 15:44:47 -040088 SkAutoCanvasRestore acr(canvas, true);
89 save_layer_unclipped(canvas, L, T, R, T + 100);
90 save_layer_unclipped(canvas, L, B - 100, R, B);
Robert Phillips42f30942017-01-17 10:48:52 -050091
Mike Reed18a8df62019-09-03 15:44:47 -040092 do_draw(canvas);
Robert Phillips42f30942017-01-17 10:48:52 -050093 }
94
95private:
Robert Phillips42f30942017-01-17 10:48:52 -050096 typedef skiagm::GM INHERITED;
97};
Mike Reed18a8df62019-09-03 15:44:47 -040098DEF_GM(return new UnclippedSaveLayerGM;)
Robert Phillips42f30942017-01-17 10:48:52 -050099
Yuqian Lid196cbe2017-02-23 10:28:33 -0500100DEF_SIMPLE_GM(picture_savelayer, canvas, 320, 640) {
101 SkPaint paint1, paint2, paint3;
Mike Reed9407e242019-02-15 16:13:57 -0500102 paint1.setAlphaf(0.5f);
103 paint2.setAlphaf(0.25f);
Yuqian Lid196cbe2017-02-23 10:28:33 -0500104 paint3.setColor(0xFFFF0000);
105 SkRect rect1{40, 5, 80, 70}, rect2{5, 40, 70, 80}, rect3{10, 10, 70, 70};
106 // In the future, we might also test the clipped case by allowing i = 0
107 for(int i = 1; i < 2; ++i) {
108 canvas->translate(100 * i, 0);
Cary Clark7eddfb82018-03-13 14:41:10 -0400109 auto flag = i ?
110 (SkCanvas::SaveLayerFlags) SkCanvasPriv::kDontClipToLayer_SaveLayerFlag : 0;
Mike Reedb42a3272020-05-30 16:02:14 -0400111 canvas->saveLayer(SkCanvas::SaveLayerRec(&rect1, &paint1, nullptr, flag));
112 canvas->saveLayer(SkCanvas::SaveLayerRec(&rect2, &paint2, nullptr, flag));
Yuqian Lid196cbe2017-02-23 10:28:33 -0500113 canvas->drawRect(rect3, paint3);
114 canvas->restore();
115 canvas->restore();
116 }
117};
118
Mike Reedc61abee2017-02-28 17:45:27 -0500119// Test kInitWithPrevious_SaveLayerFlag by drawing an image, save a layer with the flag, which
120// should seed the layer with the image (from below). Then we punch a hole in the layer and
121// restore with kPlus mode, which should show the mandrill super-bright on the outside, but
122// normal where we punched the hole.
123DEF_SIMPLE_GM(savelayer_initfromprev, canvas, 256, 256) {
Hal Canaryc465d132017-12-08 10:21:31 -0500124 canvas->drawImage(GetResourceAsImage("images/mandrill_256.png"), 0, 0, nullptr);
Mike Reedc61abee2017-02-28 17:45:27 -0500125
126 SkCanvas::SaveLayerRec rec;
127 SkPaint paint;
128 paint.setBlendMode(SkBlendMode::kPlus);
129 rec.fSaveLayerFlags = SkCanvas::kInitWithPrevious_SaveLayerFlag;
130 rec.fPaint = &paint;
131 canvas->saveLayer(rec);
132 paint.setBlendMode(SkBlendMode::kClear);
133 canvas->drawCircle(128, 128, 96, paint);
134 canvas->restore();
135};
Robert Phillips42f30942017-01-17 10:48:52 -0500136
Mike Reedb42a3272020-05-30 16:02:14 -0400137#ifdef SK_SUPPORT_LEGACY_LAYERCLIPMASK
Florin Malita53f77bd2017-04-28 13:48:37 -0400138static void draw_mask(SkCanvas* canvas, int size) {
139 const SkScalar cx = size * SK_ScalarHalf,
140 cy = cx;
141 const SkColor colors[] = { 0x00000000, 0xffff0000, 0x00000000, 0xffff0000, 0x00000000,
142 0xffff0000, 0x00000000, 0xffff0000, 0x00000000 };
143
144 SkPaint paint;
145 paint.setAntiAlias(true);
146 paint.setShader(SkGradientShader::MakeSweep(cx, cy, colors, nullptr, SK_ARRAY_COUNT(colors)));
147 canvas->drawPaint(paint);
148
149 paint.setShader(SkGradientShader::MakeRadial({cx, cy}, size / 4, colors, nullptr, 2,
Mike Reedfae8fce2019-04-03 10:27:45 -0400150 SkTileMode::kClamp));
Florin Malita53f77bd2017-04-28 13:48:37 -0400151 canvas->drawCircle(cx, cy, size / 4, paint);
152}
153
154DEF_SIMPLE_GM(savelayer_clipmask, canvas, 1200, 1200) {
155 static constexpr int kSize = 100;
156 static constexpr SkRect kLayerBounds = { kSize * 0.25f, kSize * 0.25f,
157 kSize * 0.75f, kSize * 0.75f };
158 static constexpr struct {
159 const SkRect* bounds;
160 const SkScalar matrix[9];
161 } kConfigs[] = {
162 { nullptr, { 1 , 0 , 0, 0 , 1 , 0, 0, 0, 1 } },
163 { nullptr, { 2 , 0 , 0, 0 , 2 , 0, 0, 0, 1 } },
164 { nullptr, { 2 , 0 , -50, 0 , 2 , -50, 0, 0, 1 } },
165 { nullptr, { 0.707f, -0.707f, 50, 0.707f, 0.707f, -20, 0, 0, 1 } },
166 { nullptr, { 0.5f , 0 , 25, 0 , 0.5f , 25, 0, 0, 1 } },
167
168 { &kLayerBounds, { 1 , 0 , 0, 0 , 1 , 0, 0, 0, 1 } },
169 { &kLayerBounds, { 2 , 0 , 0, 0 , 2 , 0, 0, 0, 1 } },
170 { &kLayerBounds, { 2 , 0 , -50, 0 , 2 , -50, 0, 0, 1 } },
171 { &kLayerBounds, { 0.707f, -0.707f, 50, 0.707f, 0.707f, -20, 0, 0, 1 } },
172 { &kLayerBounds, { 0.5f , 0 , 25, 0 , 0.5f , 25, 0, 0, 1 } },
173 };
174
175 using MaskMakerFunc = sk_sp<SkImage> (*)(int size);
176 static const MaskMakerFunc kMaskMakers[] = {
177 [](int size) -> sk_sp<SkImage> {
178 auto surf = SkSurface::MakeRaster(SkImageInfo::MakeA8(size, size));
179 draw_mask(surf->getCanvas(), size);
180 return surf->makeImageSnapshot();
181 },
182
183 [](int size) -> sk_sp<SkImage> {
184 auto surf = SkSurface::MakeRasterN32Premul(size, size);
185 draw_mask(surf->getCanvas(), size);
186 return surf->makeImageSnapshot();
187 },
188
189 [](int size) -> sk_sp<SkImage> {
190 SkPictureRecorder recorder;
191 draw_mask(recorder.beginRecording(size, size), size);
192 return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
193 SkISize::Make(size, size),
194 nullptr, nullptr,
195 SkImage::BitDepth::kU8,
196 SkColorSpace::MakeSRGB());
197 }
198 };
199
200 using PaintMakerFunc = SkPaint (*)();
201 static const PaintMakerFunc kPaintMakers[] = {
202 []() -> SkPaint { return SkPaint(); },
203 []() -> SkPaint {
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400204 SkPaint p; p.setImageFilter(SkImageFilters::Blur(2, 2, nullptr)); return p;
Florin Malita53f77bd2017-04-28 13:48:37 -0400205 },
206 []() -> SkPaint { SkPaint p; p.setBlendMode(SkBlendMode::kSrcOut); return p; },
207 };
208
209 canvas->drawColor(0xffcccccc);
210
211 SkMatrix clipMatrix;
212 SkCanvas::SaveLayerRec rec;
213 rec.fClipMatrix = &clipMatrix;
214
215 for (const auto& paintMaker : kPaintMakers) {
216 auto layerPaint = paintMaker();
217 rec.fPaint = &layerPaint;
218
219 for (const auto& maskMaker : kMaskMakers) {
Mike Kleinb34ab042017-05-01 21:34:14 +0000220 sk_sp<SkImage> mask = maskMaker(kSize);
221 rec.fClipMask = mask.get();
Florin Malita53f77bd2017-04-28 13:48:37 -0400222
223 canvas->save();
224 for (const auto cfg : kConfigs) {
225 rec.fBounds = cfg.bounds;
226 clipMatrix.set9(cfg.matrix);
227 canvas->saveLayer(rec);
228
229 SkPaint paint;
230 paint.setColor(0xff0000ff);
231 canvas->drawRect(SkRect::MakeWH(50, 50), paint);
232 paint.setColor(0xffff0000);
233 canvas->drawRect(SkRect::MakeXYWH(50, 0, 50, 50), paint);
234 paint.setColor(0xff00ff00);
235 canvas->drawRect(SkRect::MakeXYWH(50, 50, 50, 50), paint);
236 paint.setColor(0xffffff00);
237 canvas->drawRect(SkRect::MakeXYWH(0, 50, 50, 50), paint);
238
239 canvas->restore();
240 canvas->translate(120, 0);
241 }
242 canvas->restore();
243 canvas->translate(0, 120);
244 }
245 }
246}
Mike Reedb42a3272020-05-30 16:02:14 -0400247#endif
Mike Reed910ca0f2018-04-25 13:04:05 -0400248
249DEF_SIMPLE_GM(savelayer_coverage, canvas, 500, 500) {
250 canvas->saveLayer(nullptr, nullptr);
251
252 SkRect r = { 0, 0, 200, 200 };
253 SkPaint layerPaint;
254 layerPaint.setBlendMode(SkBlendMode::kModulate);
255
256 auto image = GetResourceAsImage("images/mandrill_128.png");
257
258 auto proc = [layerPaint](SkCanvas* canvas, SkCanvas::SaveLayerRec& rec) {
259 SkPaint paint;
260 paint.setColor(SK_ColorRED);
261
262 canvas->saveLayer(rec);
263 canvas->drawCircle(100, 100, 50, paint);
264 paint.setColor(0x8800FF00);
265 canvas->drawRect({10, 90, 190, 110}, paint);
266 canvas->restore();
267 };
268
269 const int yflags[] = { 0, SkCanvas::kInitWithPrevious_SaveLayerFlag };
270 for (int y = 0; y <= 1; ++y) {
271 const int xflags[] = { 0, SkCanvas::kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag };
272 for (int x = 0; x <= 1; ++x) {
273 canvas->save();
274 canvas->translate(x * 200.f, y * 200.f);
275
276 SkCanvas::SaveLayerRec rec(&r, &layerPaint, yflags[y] | xflags[x]);
277 canvas->drawImageRect(image, r, nullptr);
278 proc(canvas, rec);
279
280 canvas->restore();
281 }
282 }
283
284 canvas->restore();
285}
286
Mike Reedb42a3272020-05-30 16:02:14 -0400287#ifdef SK_SUPPORT_LEGACY_LAYERCLIPMASK
Michael Ludwigbeb7cd22019-04-08 11:11:42 -0400288DEF_SIMPLE_GM(savelayer_clipmask_maskfilter, canvas, 500, 500) {
289 // Offscreen surface for making the clip mask and mask filter images
290 auto surf = SkSurface::MakeRaster(SkImageInfo::MakeA8(100, 100));
291 SkPaint maskPaint;
292 maskPaint.setColor(SK_ColorWHITE);
293 maskPaint.setAntiAlias(true);
294
295 // Draw a centered circle for the mask filter
296 surf->getCanvas()->clear(SK_ColorTRANSPARENT);
297 surf->getCanvas()->drawCircle(50.f, 50.f, 50.f, maskPaint);
298 auto maskFilterImage = surf->makeImageSnapshot();
299 sk_sp<SkMaskFilter> maskFilter = SkShaderMaskFilter::Make(maskFilterImage->makeShader());
300
301 // Cut out a cross for the clip mask
302 surf->getCanvas()->clear(SK_ColorTRANSPARENT);
303 surf->getCanvas()->drawRect(SkRect::MakeLTRB(0.f, 0.f, 40.f, 40.f), maskPaint);
304 surf->getCanvas()->drawRect(SkRect::MakeLTRB(60.f, 0.f, 100.f, 40.f), maskPaint);
305 surf->getCanvas()->drawRect(SkRect::MakeLTRB(0.f, 60.f, 40.f, 100.f), maskPaint);
306 surf->getCanvas()->drawRect(SkRect::MakeLTRB(60.f, 60.f, 100.f, 100.f), maskPaint);
307 auto clipMaskImage = surf->makeImageSnapshot();
308 SkMatrix clipMatrix = SkMatrix::I();
309 SkRect clipBounds = SkRect::MakeWH(100, 100);
310
311 // On the main canvas, save a 100x100 layer three times, applying clip mask, mask filter, or
Michael Ludwigeced98b2020-03-03 10:39:41 -0500312 // both, translating across the GM for each configuration. Since the mask filter is provided
313 // on the layer restore paint, it must be ignored by the restore since coverage is not well
314 // defined.
Michael Ludwigbeb7cd22019-04-08 11:11:42 -0400315 canvas->clear(SK_ColorGRAY);
316
317 canvas->translate(25.f, 0.f);
318
319 // Clip mask only
320 SkCanvas::SaveLayerRec rec;
321 rec.fBounds = &clipBounds;
322 rec.fClipMask = clipMaskImage.get();
323 rec.fClipMatrix = &clipMatrix;
324 canvas->saveLayer(rec);
325 canvas->clear(SK_ColorWHITE);
326 canvas->restore();
327
328 canvas->translate(125.f, 0.f);
329
Michael Ludwigeced98b2020-03-03 10:39:41 -0500330 // Mask filter only (should be ignored, producing a white square)
Michael Ludwigbeb7cd22019-04-08 11:11:42 -0400331 maskPaint.setMaskFilter(maskFilter);
332 rec.fClipMask = nullptr;
333 rec.fPaint = &maskPaint;
334 canvas->saveLayer(rec);
335 canvas->clear(SK_ColorWHITE);
336 canvas->restore();
337
338 canvas->translate(125.f, 0.f);
339
Michael Ludwigeced98b2020-03-03 10:39:41 -0500340 // Both (mask filter is ignored, but clip mask should not, so should look like first draw)
Michael Ludwigbeb7cd22019-04-08 11:11:42 -0400341 rec.fClipMask = clipMaskImage.get();
342 canvas->saveLayer(rec);
343 canvas->clear(SK_ColorWHITE);
344 canvas->restore();
345}
Mike Reedb42a3272020-05-30 16:02:14 -0400346#endif
Michael Ludwigbeb7cd22019-04-08 11:11:42 -0400347
Mike Reedd5674082019-04-19 15:00:47 -0400348static void draw_cell(SkCanvas* canvas, sk_sp<SkTextBlob> blob, SkColor c, SkScalar w, SkScalar h,
349 bool useDrawBehind) {
Mike Reed148b7fd2018-12-18 17:38:18 -0500350 SkRect r = SkRect::MakeWH(w, h);
351 SkPaint p;
352 p.setColor(c);
353 p.setBlendMode(SkBlendMode::kSrc);
354 canvas->drawRect(r, p);
355 p.setBlendMode(SkBlendMode::kSrcOver);
356
357 const SkScalar margin = 80;
358 r.fLeft = w - margin;
359
360 // save the behind image
361 SkDEBUGCODE(int sc0 =) canvas->getSaveCount();
362 SkDEBUGCODE(int sc1 =) SkCanvasPriv::SaveBehind(canvas, &r);
363 SkDEBUGCODE(int sc2 =) canvas->getSaveCount();
364 SkASSERT(sc0 == sc1);
365 SkASSERT(sc0 + 1 == sc2);
366
367 // draw the foreground (including over the 'behind' section)
368 p.setColor(SK_ColorBLACK);
369 canvas->drawTextBlob(blob, 10, 30, p);
370
371 // draw the treatment
372 const SkPoint pts[] = { {r.fLeft,0}, {r.fRight, 0} };
373 const SkColor colors[] = { 0x88000000, 0x0 };
Mike Reedfae8fce2019-04-03 10:27:45 -0400374 auto sh = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
Mike Reed148b7fd2018-12-18 17:38:18 -0500375 p.setShader(sh);
376 p.setBlendMode(SkBlendMode::kDstIn);
Mike Reedd5674082019-04-19 15:00:47 -0400377
378 if (useDrawBehind) {
379 SkCanvasPriv::DrawBehind(canvas, p);
380 } else {
381 canvas->drawRect(r, p);
382 }
Mike Reed148b7fd2018-12-18 17:38:18 -0500383
384 // this should restore the behind image
385 canvas->restore();
386 SkDEBUGCODE(int sc3 =) canvas->getSaveCount();
387 SkASSERT(sc3 == sc0);
388
389 // just outline where we expect the treatment to appear
390 p.reset();
391 p.setStyle(SkPaint::kStroke_Style);
Mike Reed9407e242019-02-15 16:13:57 -0500392 p.setAlphaf(0.25f);
Mike Reed148b7fd2018-12-18 17:38:18 -0500393}
394
Mike Reedd5674082019-04-19 15:00:47 -0400395static void draw_list(SkCanvas* canvas, sk_sp<SkTextBlob> blob, bool useDrawBehind) {
Mike Reed148b7fd2018-12-18 17:38:18 -0500396 SkAutoCanvasRestore acr(canvas, true);
397
398 SkRandom rand;
399 SkScalar w = 400;
400 SkScalar h = 40;
401 for (int i = 0; i < 8; ++i) {
402 SkColor c = rand.nextU(); // ensure we're opaque
403 c = (c & 0xFFFFFF) | 0x80000000;
Mike Reedd5674082019-04-19 15:00:47 -0400404 draw_cell(canvas, blob, c, w, h, useDrawBehind);
Mike Reed148b7fd2018-12-18 17:38:18 -0500405 canvas->translate(0, h);
406 }
407}
408
Mike Reedd5674082019-04-19 15:00:47 -0400409DEF_SIMPLE_GM(save_behind, canvas, 830, 670) {
Mike Reed148b7fd2018-12-18 17:38:18 -0500410 SkFont font;
Mike Reed2ce36402019-04-21 18:15:23 -0400411 font.setTypeface(ToolUtils::create_portable_typeface());
Mike Reed148b7fd2018-12-18 17:38:18 -0500412 font.setSize(30);
Mike Reed2ce36402019-04-21 18:15:23 -0400413
Mike Reed148b7fd2018-12-18 17:38:18 -0500414 const char text[] = "This is a very long line of text";
415 auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
416
Mike Reedd5674082019-04-19 15:00:47 -0400417 for (bool useDrawBehind : {false, true}) {
418 canvas->save();
419
420 draw_list(canvas, blob, useDrawBehind);
421 canvas->translate(0, 350);
422 canvas->saveLayer({0, 0, 400, 320}, nullptr);
423 draw_list(canvas, blob, useDrawBehind);
424 canvas->restore();
425
426 canvas->restore();
427 canvas->translate(430, 0);
428 }
Mike Reed148b7fd2018-12-18 17:38:18 -0500429}
Mike Reed1f3548c2019-07-12 12:53:11 -0400430
431#include "include/effects/SkGradientShader.h"
432
433DEF_SIMPLE_GM(savelayer_f16, canvas, 900, 300) {
434 int n = 15;
435 SkRect r{0, 0, 300, 300};
436 SkPaint paint;
437
438 const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
439 paint.setShader(SkGradientShader::MakeSweep(r.centerX(), r.centerY(),
440 colors, nullptr, SK_ARRAY_COUNT(colors)));
441
442 canvas->drawOval(r, paint);
443
444 paint.setAlphaf(1.0f/n);
445 paint.setBlendMode(SkBlendMode::kPlus);
446
447 for (auto flags : {0, (int)SkCanvas::kF16ColorType}) {
448 canvas->translate(r.width(), 0);
449
450 SkCanvas::SaveLayerRec rec;
451 rec.fSaveLayerFlags = flags;
452 canvas->saveLayer(rec);
453 for (int i = 0; i < n; ++i) {
454 canvas->drawOval(r, paint);
455 }
456 canvas->restore();
457 }
458}