Flutter Engine
The Flutter Engine
savelayer.cpp
Go to the documentation of this file.
1/*
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
8#include "gm/gm.h"
13#include "include/core/SkFont.h"
24#include "include/core/SkRect.h"
28#include "include/core/SkSize.h"
39#include "src/base/SkRandom.h"
41#include "tools/DecodeUtils.h"
42#include "tools/Resources.h"
43#include "tools/ToolUtils.h"
45
46#include <string.h>
47#include <initializer_list>
48
49// Test kInitWithPrevious_SaveLayerFlag by drawing an image, save a layer with the flag, which
50// should seed the layer with the image (from below). Then we punch a hole in the layer and
51// restore with kPlus mode, which should show the mandrill super-bright on the outside, but
52// normal where we punched the hole.
53DEF_SIMPLE_GM(savelayer_initfromprev, canvas, 256, 256) {
54 canvas->drawImage(ToolUtils::GetResourceAsImage("images/mandrill_256.png"), 0, 0);
55
58 paint.setBlendMode(SkBlendMode::kPlus);
60 rec.fPaint = &paint;
61 canvas->saveLayer(rec);
62 paint.setBlendMode(SkBlendMode::kClear);
63 canvas->drawCircle(128, 128, 96, paint);
64 canvas->restore();
65};
66
68 bool useDrawBehind) {
70 SkPaint p;
71 p.setColor(c);
72 p.setBlendMode(SkBlendMode::kSrc);
73 canvas->drawRect(r, p);
74 p.setBlendMode(SkBlendMode::kSrcOver);
75
76 const SkScalar margin = 80;
77 r.fLeft = w - margin;
78
79 // save the behind image
80 SkDEBUGCODE(int sc0 =) canvas->getSaveCount();
81 SkDEBUGCODE(int sc1 =) SkCanvasPriv::SaveBehind(canvas, &r);
82 SkDEBUGCODE(int sc2 =) canvas->getSaveCount();
83 SkASSERT(sc0 == sc1);
84 SkASSERT(sc0 + 1 == sc2);
85
86 // draw the foreground (including over the 'behind' section)
87 p.setColor(SK_ColorBLACK);
88 canvas->drawTextBlob(blob, 10, 30, p);
89
90 // draw the treatment
91 const SkPoint pts[] = { {r.fLeft,0}, {r.fRight, 0} };
92 const SkColor colors[] = { 0x88000000, 0x0 };
94 p.setShader(sh);
95 p.setBlendMode(SkBlendMode::kDstIn);
96
97 if (useDrawBehind) {
99 } else {
100 canvas->drawRect(r, p);
101 }
102
103 // this should restore the behind image
104 canvas->restore();
105 SkDEBUGCODE(int sc3 =) canvas->getSaveCount();
106 SkASSERT(sc3 == sc0);
107
108 // just outline where we expect the treatment to appear
109 p.reset();
110 p.setStyle(SkPaint::kStroke_Style);
111 p.setAlphaf(0.25f);
112}
113
114static void draw_list(SkCanvas* canvas, sk_sp<SkTextBlob> blob, bool useDrawBehind) {
115 SkAutoCanvasRestore acr(canvas, true);
116
117 SkRandom rand;
118 SkScalar w = 400;
119 SkScalar h = 40;
120 for (int i = 0; i < 8; ++i) {
121 SkColor c = rand.nextU(); // ensure we're opaque
122 c = (c & 0xFFFFFF) | 0x80000000;
123 draw_cell(canvas, blob, c, w, h, useDrawBehind);
124 canvas->translate(0, h);
125 }
126}
127
128DEF_SIMPLE_GM(save_behind, canvas, 830, 670) {
130 font.setSize(30);
131
132 const char text[] = "This is a very long line of text";
133 auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
134
135 for (bool useDrawBehind : {false, true}) {
136 canvas->save();
137
138 draw_list(canvas, blob, useDrawBehind);
139 canvas->translate(0, 350);
140 canvas->saveLayer({0, 0, 400, 320}, nullptr);
141 draw_list(canvas, blob, useDrawBehind);
142 canvas->restore();
143
144 canvas->restore();
145 canvas->translate(430, 0);
146 }
147}
148
150
151DEF_SIMPLE_GM(savelayer_f16, canvas, 900, 300) {
152 int n = 15;
153 SkRect r{0, 0, 300, 300};
155
157 paint.setShader(SkGradientShader::MakeSweep(r.centerX(), r.centerY(),
158 colors, nullptr, std::size(colors)));
159
160 canvas->drawOval(r, paint);
161
162 paint.setAlphaf(1.0f/n);
163 paint.setBlendMode(SkBlendMode::kPlus);
164
165 for (auto flags : {0, (int)SkCanvas::kF16ColorType}) {
166 canvas->translate(r.width(), 0);
167
170 canvas->saveLayer(rec);
171 for (int i = 0; i < n; ++i) {
172 canvas->drawOval(r, paint);
173 }
174 canvas->restore();
175 }
176}
177
178static void draw_atlas(SkCanvas* canvas, SkImage* image) {
179 SkRSXform xforms[] = {{1, 0, 0, 0}, {1, 0, 50, 50}};
180 SkRect tex[] = {{0, 0, 100, 100}, {0, 0, 100, 100}};
181 SkColor colors[] = {0xffffffff, 0xffffffff};
183
184 canvas->drawAtlas(image,
185 xforms,
186 tex,
187 colors,
188 2,
191 nullptr,
192 &paint);
193}
194
195static void draw_vertices(SkCanvas* canvas, SkImage* image) {
196 SkPoint pts[] = {{0, 0}, {0, 100}, {100, 100}, {100, 0}, {100, 100}, {0, 100}};
197 sk_sp<SkVertices> verts =
199
202
203 canvas->drawVertices(verts, SkBlendMode::kSrc, paint);
204}
205
206static void draw_points(SkCanvas* canvas, SkImage* image) {
207 SkPoint pts[] = {{50, 50}, {75, 75}};
210 paint.setStrokeWidth(100);
211 paint.setStrokeCap(SkPaint::kSquare_Cap);
212
214}
215
216static void draw_image_set(SkCanvas* canvas, SkImage* image) {
217 SkRect r = SkRect::MakeWH(100, 100);
218 SkCanvas::ImageSetEntry entries[] = {
222 };
223
226 entries, 2, nullptr, nullptr, SkFilterMode::kNearest, &paint);
227}
228
229/*
230 Picture optimization looks for single drawing operations inside a saveLayer with alpha. It tries
231 to push the alpha into the drawing operation itself. That's only valid if the draw logically
232 touches each pixel once. A handful of draws do not behave like that. They instead act like
233 repeated, independent draws. This GM tests this with several operations.
234 */
235DEF_SIMPLE_GM(skbug_14554, canvas, 310, 630) {
236 sk_sp<SkImage> image = ToolUtils::GetResourceAsImage("images/mandrill_128.png");
238
239 using DrawProc = void(*)(SkCanvas*, SkImage*);
240
242 canvas->save();
243 for (bool injectExtraOp : {false, true}) {
244 auto c = rec.beginRecording(SkRect::MakeWH(150, 150));
245 c->saveLayerAlphaf(nullptr, 0.6f);
246 proc(c, image.get());
247 // For the second draw of each test-case, we inject an extra (useless) operation, which
248 // inhibits the optimization and produces the correct result.
249 if (injectExtraOp) {
250 c->translate(1, 0);
251 }
252 c->restore();
253
254 auto pic = rec.finishRecordingAsPicture();
255
256 canvas->drawPicture(pic);
257 canvas->translate(160, 0);
258 }
259 canvas->restore();
260 canvas->translate(0, 160);
261 }
262}
const char *(* DrawProc)(const BezierRec *, int)
Definition: BezierBench.cpp:21
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kPlus
r = min(s + d, 1)
@ kDstIn
r = d * sa
@ kSrcOver
r = s + (1-sa)*d
@ kSrcIn
r = s * da
@ kClear
r = 0
uint32_t SkColor
Definition: SkColor.h:37
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
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
static void DrawBehind(SkCanvas *canvas, const SkPaint &paint)
Definition: SkCanvasPriv.h:56
static int SaveBehind(SkCanvas *canvas, const SkRect *subset)
Definition: SkCanvasPriv.h:53
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint &paint)
Definition: SkCanvas.cpp:1710
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
int getSaveCount() const
Definition: SkCanvas.cpp:431
void experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt, const SkPoint dstClips[], const SkMatrix preViewMatrices[], const SkSamplingOptions &, const SkPaint *paint=nullptr, SrcRectConstraint constraint=kStrict_SrcRectConstraint)
Definition: SkCanvas.cpp:1853
@ kF16ColorType
Definition: SkCanvas.h:674
@ kInitWithPrevious_SaveLayerFlag
initializes with previous contents
Definition: SkCanvas.h:672
void drawAtlas(const SkImage *atlas, const SkRSXform xform[], const SkRect tex[], const SkColor colors[], int count, SkBlendMode mode, const SkSamplingOptions &sampling, const SkRect *cullRect, const SkPaint *paint)
Definition: SkCanvas.cpp:1810
void drawVertices(const SkVertices *vertices, SkBlendMode mode, const SkPaint &paint)
Definition: SkCanvas.cpp:1720
@ kPoints_PointMode
draw each point separately
Definition: SkCanvas.h:1241
void drawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
Definition: SkCanvas.cpp:2484
@ kNone_QuadAAFlags
Definition: SkCanvas.h:1664
int saveLayerAlphaf(const SkRect *bounds, float alpha)
Definition: SkCanvas.cpp:1077
Definition: SkFont.h:35
static sk_sp< SkShader > MakeSweep(SkScalar cx, SkScalar cy, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, SkScalar startAngle, SkScalar endAngle, uint32_t flags, const SkMatrix *localMatrix)
static sk_sp< SkShader > MakeLinear(const SkPoint pts[2], const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition: SkImage.cpp:179
@ kSquare_Cap
adds square
Definition: SkPaint.h:336
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
uint32_t nextU()
Definition: SkRandom.h:42
static sk_sp< SkTextBlob > MakeFromText(const void *text, size_t byteLength, const SkFont &font, SkTextEncoding encoding=SkTextEncoding::kUTF8)
Definition: SkTextBlob.cpp:788
static sk_sp< SkVertices > MakeCopy(VertexMode mode, int vertexCount, const SkPoint positions[], const SkPoint texs[], const SkColor colors[], int indexCount, const uint16_t indices[])
Definition: SkVertices.cpp:200
@ kTriangles_VertexMode
Definition: SkVertices.h:31
T * get() const
Definition: SkRefCnt.h:303
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
FlutterSemanticsFlag flags
std::u16string text
sk_sp< const SkImage > image
Definition: SkRecords.h:269
PODArray< SkRSXform > xforms
Definition: SkRecords.h:332
PODArray< SkColor > colors
Definition: SkRecords.h:276
SkFont DefaultPortableFont()
sk_sp< SkImage > GetResourceAsImage(const char *resource)
Definition: DecodeUtils.h:25
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.
sh
Definition: run_sh.py:10
SkScalar w
SkScalar h
static void draw_list(SkCanvas *canvas, sk_sp< SkTextBlob > blob, bool useDrawBehind)
Definition: savelayer.cpp:114
static void draw_points(SkCanvas *canvas, SkImage *image)
Definition: savelayer.cpp:206
static void draw_image_set(SkCanvas *canvas, SkImage *image)
Definition: savelayer.cpp:216
static void draw_vertices(SkCanvas *canvas, SkImage *image)
Definition: savelayer.cpp:195
static void draw_atlas(SkCanvas *canvas, SkImage *image)
Definition: savelayer.cpp:178
DEF_SIMPLE_GM(savelayer_initfromprev, canvas, 256, 256)
Definition: savelayer.cpp:53
static void draw_cell(SkCanvas *canvas, sk_sp< SkTextBlob > blob, SkColor c, SkScalar w, SkScalar h, bool useDrawBehind)
Definition: savelayer.cpp:67
const SkPaint * fPaint
Definition: SkCanvas.h:743
SaveLayerFlags fSaveLayerFlags
Definition: SkCanvas.h:763
constexpr SkRect makeOffset(float dx, float dy) const
Definition: SkRect.h:965
SkScalar fLeft
smaller x-axis bounds
Definition: extension.cpp:14
SkScalar fRight
larger x-axis bounds
Definition: extension.cpp:16
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609