Flutter Engine
The Flutter Engine
SkClipStack.h
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#ifndef SkClipStack_DEFINED
9#define SkClipStack_DEFINED
10
13#include "include/core/SkPath.h"
15#include "include/core/SkRect.h"
21#include "src/base/SkTLazy.h"
22
23#include <cstddef>
24#include <cstdint>
25#include <utility>
26
27// Because a single save/restore state can have multiple clips, this class
28// stores the stack depth (fSaveCount) and clips (fDeque) separately.
29// Each clip in fDeque stores the stack state to which it belongs
30// (i.e., the fSaveCount in force when it was added). Restores are thus
31// implemented by removing clips from fDeque that have an fSaveCount larger
32// then the freshly decremented count.
34public:
36 // The bounding box contains all the pixels that can be written to
38 // The bounding box contains all the pixels that cannot be written to.
39 // The real bound extends out to infinity and all the pixels outside
40 // of the bound can be written to. Note that some of the pixels inside
41 // the bound may also be writeable but all pixels that cannot be
42 // written to are guaranteed to be inside.
44 };
45
46 /**
47 * An element of the clip stack. It represents a shape combined with the prevoius clip using a
48 * set operator. Each element can be antialiased or not.
49 */
50 class Element {
51 public:
52 /** This indicates the shape type of the clip element in device space. */
53 enum class DeviceSpaceType {
54 //!< This element makes the clip empty (regardless of previous elements).
55 kEmpty,
56 //!< This element combines a device space rect with the current clip.
57 kRect,
58 //!< This element combines a device space round-rect with the current clip.
59 kRRect,
60 //!< This element combines a device space path with the current clip.
61 kPath,
62 //!< This element does not have geometry, but applies a shader to the clip
63 kShader,
64
65 kLastType = kShader
66 };
67 static const int kTypeCnt = (int)DeviceSpaceType::kLastType + 1;
68
70 this->initCommon(0, SkClipOp::kIntersect, false);
71 this->setEmpty();
72 }
73
74 Element(const Element&);
75
76 Element(const SkRect& rect, const SkMatrix& m, SkClipOp op, bool doAA) {
77 this->initRect(0, rect, m, op, doAA);
78 }
79
80 Element(const SkRRect& rrect, const SkMatrix& m, SkClipOp op, bool doAA) {
81 this->initRRect(0, rrect, m, op, doAA);
82 }
83
84 Element(const SkPath& path, const SkMatrix& m, SkClipOp op, bool doAA) {
85 this->initPath(0, path, m, op, doAA);
86 }
87
89 this->initShader(0, std::move(shader));
90 }
91
92 Element(const SkRect& rect, bool doAA) {
93 this->initReplaceRect(0, rect, doAA);
94 }
95
97
98 bool operator== (const Element& element) const;
99 bool operator!= (const Element& element) const { return !(*this == element); }
100
101 //!< Call to get the type of the clip element.
102 DeviceSpaceType getDeviceSpaceType() const { return fDeviceSpaceType; }
103
104 //!< Call to get the save count associated with this clip element.
105 int getSaveCount() const { return fSaveCount; }
106
107 //!< Call if getDeviceSpaceType() is kPath to get the path.
108 const SkPath& getDeviceSpacePath() const {
109 SkASSERT(DeviceSpaceType::kPath == fDeviceSpaceType);
110 return *fDeviceSpacePath;
111 }
112
113 //!< Call if getDeviceSpaceType() is kRRect to get the round-rect.
115 SkASSERT(DeviceSpaceType::kRRect == fDeviceSpaceType);
116 return fDeviceSpaceRRect;
117 }
118
119 //!< Call if getDeviceSpaceType() is kRect to get the rect.
120 const SkRect& getDeviceSpaceRect() const {
121 SkASSERT(DeviceSpaceType::kRect == fDeviceSpaceType &&
122 (fDeviceSpaceRRect.isRect() || fDeviceSpaceRRect.isEmpty()));
123 return fDeviceSpaceRRect.getBounds();
124 }
125
126 //!<Call if getDeviceSpaceType() is kShader to get a reference to the clip shader.
128 return fShader;
129 }
130 const SkShader* getShader() const {
131 return fShader.get();
132 }
133
134 //!< Call if getDeviceSpaceType() is not kEmpty to get the set operation used to combine
135 //!< this element.
136 SkClipOp getOp() const { return fOp; }
137 // Augments getOps()'s behavior by requiring a clip reset before the op is applied.
138 bool isReplaceOp() const { return fIsReplace; }
139
140 //!< Call to get the element as a path, regardless of its type.
141 void asDeviceSpacePath(SkPath* path) const;
142
143 //!< Call if getType() is not kPath to get the element as a round rect.
145 SkASSERT(DeviceSpaceType::kPath != fDeviceSpaceType);
146 return fDeviceSpaceRRect;
147 }
148
149 /** If getType() is not kEmpty this indicates whether the clip shape should be anti-aliased
150 when it is rasterized. */
151 bool isAA() const { return fDoAA; }
152
153 //!< Inverts the fill of the clip shape. Note that a kEmpty element remains kEmpty.
154 void invertShapeFillType();
155
156 /** The GenID can be used by clip stack clients to cache representations of the clip. The
157 ID corresponds to the set of clip elements up to and including this element within the
158 stack not to the element itself. That is the same clip path in different stacks will
159 have a different ID since the elements produce different clip result in the context of
160 their stacks. */
161 uint32_t getGenID() const { SkASSERT(kInvalidGenID != fGenID); return fGenID; }
162
163 /**
164 * Gets the bounds of the clip element, either the rect or path bounds. (Whether the shape
165 * is inverse filled is not considered.)
166 */
167 const SkRect& getBounds() const;
168
169 /**
170 * Conservatively checks whether the clip shape contains the rect/rrect. (Whether the shape
171 * is inverse filled is not considered.)
172 */
173 bool contains(const SkRect& rect) const;
174 bool contains(const SkRRect& rrect) const;
175
176 /**
177 * Is the clip shape inverse filled.
178 */
179 bool isInverseFilled() const {
180 return DeviceSpaceType::kPath == fDeviceSpaceType &&
181 fDeviceSpacePath->isInverseFillType();
182 }
183
184#ifdef SK_DEBUG
185 /**
186 * Dumps the element to SkDebugf. This is intended for Skia development debugging
187 * Don't rely on the existence of this function or the formatting of its output.
188 */
189 void dump() const;
190#endif
191
192 private:
193 friend class SkClipStack;
194
195 SkTLazy<SkPath> fDeviceSpacePath;
196 SkRRect fDeviceSpaceRRect;
197 sk_sp<SkShader> fShader;
198 int fSaveCount; // save count of stack when this element was added.
199 SkClipOp fOp;
200 DeviceSpaceType fDeviceSpaceType;
201 bool fDoAA;
202 bool fIsReplace;
203
204 /* fFiniteBoundType and fFiniteBound are used to incrementally update the clip stack's
205 bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound represents the
206 conservative bounding box of the pixels that aren't clipped (i.e., any pixels that can be
207 drawn to are inside the bound). When fFiniteBoundType is kInsideOut_BoundsType (which
208 occurs when a clip is inverse filled), fFiniteBound represents the conservative bounding
209 box of the pixels that _are_ clipped (i.e., any pixels that cannot be drawn to are inside
210 the bound). When fFiniteBoundType is kInsideOut_BoundsType the actual bound is the
211 infinite plane. This behavior of fFiniteBoundType and fFiniteBound is required so that we
212 can capture the cancelling out of the extensions to infinity when two inverse filled
213 clips are Booleaned together. */
214 SkClipStack::BoundsType fFiniteBoundType;
215 SkRect fFiniteBound;
216
217 // When element is applied to the previous elements in the stack is the result known to be
218 // equivalent to a single rect intersection? IIOW, is the clip effectively a rectangle.
219 bool fIsIntersectionOfRects;
220
221 uint32_t fGenID;
222 Element(int saveCount) {
223 this->initCommon(saveCount, SkClipOp::kIntersect, false);
224 this->setEmpty();
225 }
226
227 Element(int saveCount, const SkRRect& rrect, const SkMatrix& m, SkClipOp op, bool doAA) {
228 this->initRRect(saveCount, rrect, m, op, doAA);
229 }
230
231 Element(int saveCount, const SkRect& rect, const SkMatrix& m, SkClipOp op, bool doAA) {
232 this->initRect(saveCount, rect, m, op, doAA);
233 }
234
235 Element(int saveCount, const SkPath& path, const SkMatrix& m, SkClipOp op, bool doAA) {
236 this->initPath(saveCount, path, m, op, doAA);
237 }
238
239 Element(int saveCount, sk_sp<SkShader> shader) {
240 this->initShader(saveCount, std::move(shader));
241 }
242
243 Element(int saveCount, const SkRect& rect, bool doAA) {
244 this->initReplaceRect(saveCount, rect, doAA);
245 }
246
247 void initCommon(int saveCount, SkClipOp op, bool doAA);
248 void initRect(int saveCount, const SkRect&, const SkMatrix&, SkClipOp, bool doAA);
249 void initRRect(int saveCount, const SkRRect&, const SkMatrix&, SkClipOp, bool doAA);
250 void initPath(int saveCount, const SkPath&, const SkMatrix&, SkClipOp, bool doAA);
251 void initAsPath(int saveCount, const SkPath&, const SkMatrix&, SkClipOp, bool doAA);
252 void initShader(int saveCount, sk_sp<SkShader>);
253 void initReplaceRect(int saveCount, const SkRect&, bool doAA);
254
255 void setEmpty();
256
257 // All Element methods below are only used within SkClipStack.cpp
258 inline void checkEmpty() const;
259 inline bool canBeIntersectedInPlace(int saveCount, SkClipOp op) const;
260 /* This method checks to see if two rect clips can be safely merged into one. The issue here
261 is that to be strictly correct all the edges of the resulting rect must have the same
262 anti-aliasing. */
263 bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const;
264 /** Determines possible finite bounds for the Element given the previous element of the
265 stack */
266 void updateBoundAndGenID(const Element* prior);
267 // The different combination of fill & inverse fill when combining bounding boxes
268 enum FillCombo {
269 kPrev_Cur_FillCombo,
270 kPrev_InvCur_FillCombo,
271 kInvPrev_Cur_FillCombo,
272 kInvPrev_InvCur_FillCombo
273 };
274 // per-set operation functions used by updateBoundAndGenID().
275 inline void combineBoundsDiff(FillCombo combination, const SkRect& prevFinite);
276 inline void combineBoundsIntersection(int combination, const SkRect& prevFinite);
277 };
278
279 SkClipStack();
280 SkClipStack(void* storage, size_t size);
281 SkClipStack(const SkClipStack& b);
282 ~SkClipStack();
283
285 bool operator==(const SkClipStack& b) const;
286 bool operator!=(const SkClipStack& b) const { return !(*this == b); }
287
288 void reset();
289
290 int getSaveCount() const { return fSaveCount; }
291 void save();
292 void restore();
293
295 public:
296 AutoRestore(SkClipStack* cs, bool doSave)
297 : fCS(cs), fSaveCount(cs->getSaveCount())
298 {
299 if (doSave) {
300 fCS->save();
301 }
302 }
304 SkASSERT(fCS->getSaveCount() >= fSaveCount); // no underflow
305 while (fCS->getSaveCount() > fSaveCount) {
306 fCS->restore();
307 }
308 }
309
310 private:
311 SkClipStack* fCS;
312 const int fSaveCount;
313 };
314
315 /**
316 * getBounds places the current finite bound in its first parameter. In its
317 * second, it indicates which kind of bound is being returned. If
318 * 'canvFiniteBound' is a normal bounding box then it encloses all writeable
319 * pixels. If 'canvFiniteBound' is an inside out bounding box then it
320 * encloses all the un-writeable pixels and the true/normal bound is the
321 * infinite plane. isIntersectionOfRects is an optional parameter
322 * that is true if 'canvFiniteBound' resulted from an intersection of rects.
323 */
324 void getBounds(SkRect* canvFiniteBound,
325 BoundsType* boundType,
326 bool* isIntersectionOfRects = nullptr) const;
327
328 SkRect bounds(const SkIRect& deviceBounds) const;
329 bool isEmpty(const SkIRect& deviceBounds) const;
330
331 /**
332 * Returns true if the input (r)rect in device space is entirely contained
333 * by the clip. A return value of false does not guarantee that the (r)rect
334 * is not contained by the clip.
335 */
336 bool quickContains(const SkRect& devRect) const {
337 return this->isWideOpen() || this->internalQuickContains(devRect);
338 }
339
340 bool quickContains(const SkRRect& devRRect) const {
341 return this->isWideOpen() || this->internalQuickContains(devRRect);
342 }
343
344 void clipDevRect(const SkIRect& ir, SkClipOp op) {
345 SkRect r;
346 r.set(ir);
347 this->clipRect(r, SkMatrix::I(), op, false);
348 }
349 void clipRect(const SkRect&, const SkMatrix& matrix, SkClipOp, bool doAA);
350 void clipRRect(const SkRRect&, const SkMatrix& matrix, SkClipOp, bool doAA);
351 void clipPath(const SkPath&, const SkMatrix& matrix, SkClipOp, bool doAA);
353 // An optimized version of clipDevRect(emptyRect, kIntersect, ...)
354 void clipEmpty();
355
356 void replaceClip(const SkRect& devRect, bool doAA);
357
358 /**
359 * isWideOpen returns true if the clip state corresponds to the infinite
360 * plane (i.e., draws are not limited at all)
361 */
362 bool isWideOpen() const { return this->getTopmostGenID() == kWideOpenGenID; }
363
364 /**
365 * This method quickly and conservatively determines whether the entire stack is equivalent to
366 * intersection with a rrect given a bounds, where the rrect must not contain the entire bounds.
367 *
368 * @param bounds A bounds on what will be drawn through the clip. The clip only need be
369 * equivalent to a intersection with a rrect for draws within the bounds. The
370 * returned rrect must intersect the bounds but need not be contained by the
371 * bounds.
372 * @param rrect If return is true rrect will contain the rrect equivalent to the stack.
373 * @param aa If return is true aa will indicate whether the equivalent rrect clip is
374 * antialiased.
375 * @return true if the stack is equivalent to a single rrect intersect clip, false otherwise.
376 */
377 bool isRRect(const SkRect& bounds, SkRRect* rrect, bool* aa) const;
378
379 /**
380 * The generation ID has three reserved values to indicate special
381 * (potentially ignorable) cases
382 */
383 static const uint32_t kInvalidGenID = 0; //!< Invalid id that is never returned by
384 //!< SkClipStack. Useful when caching clips
385 //!< based on GenID.
386 static const uint32_t kEmptyGenID = 1; // no pixels writeable
387 static const uint32_t kWideOpenGenID = 2; // all pixels writeable
388
389 uint32_t getTopmostGenID() const;
390
391#ifdef SK_DEBUG
392 /**
393 * Dumps the contents of the clip stack to SkDebugf. This is intended for Skia development
394 * debugging. Don't rely on the existence of this function or the formatting of its output.
395 */
396 void dump() const;
397#endif
398
399public:
400 class Iter {
401 public:
405 };
406
407 /**
408 * Creates an uninitialized iterator. Must be reset()
409 */
410 Iter();
411
412 Iter(const SkClipStack& stack, IterStart startLoc);
413
414 /**
415 * Return the clip element for this iterator. If next()/prev() returns NULL, then the
416 * iterator is done.
417 */
418 const Element* next();
419 const Element* prev();
420
421 /**
422 * Moves the iterator to the topmost element with the specified RegionOp and returns that
423 * element. If no clip element with that op is found, the first element is returned.
424 */
425 const Element* skipToTopmost(SkClipOp op);
426
427 /**
428 * Restarts the iterator on a clip stack.
429 */
430 void reset(const SkClipStack& stack, IterStart startLoc);
431
432 private:
433 const SkClipStack* fStack;
434 SkDeque::Iter fIter;
435 };
436
437 /**
438 * The B2TIter iterates from the bottom of the stack to the top.
439 * It inherits privately from Iter to prevent access to reverse iteration.
440 */
441 class B2TIter : private Iter {
442 public:
444
445 /**
446 * Wrap Iter's 2 parameter ctor to force initialization to the
447 * beginning of the deque/bottom of the stack
448 */
449 B2TIter(const SkClipStack& stack)
450 : INHERITED(stack, kBottom_IterStart) {
451 }
452
453 using Iter::next;
454
455 /**
456 * Wrap Iter::reset to force initialization to the
457 * beginning of the deque/bottom of the stack
458 */
459 void reset(const SkClipStack& stack) {
461 }
462
463 private:
464
465 using INHERITED = Iter;
466 };
467
468 /**
469 * GetConservativeBounds returns a conservative bound of the current clip.
470 * Since this could be the infinite plane (if inverse fills were involved) the
471 * maxWidth and maxHeight parameters can be used to limit the returned bound
472 * to the expected drawing area. Similarly, the offsetX and offsetY parameters
473 * allow the caller to offset the returned bound to account for translated
474 * drawing areas (i.e., those resulting from a saveLayer). For finite bounds,
475 * the translation (+offsetX, +offsetY) is applied before the clamp to the
476 * maximum rectangle: [0,maxWidth) x [0,maxHeight).
477 * isIntersectionOfRects is an optional parameter that is true when
478 * 'devBounds' is the result of an intersection of rects. In this case
479 * 'devBounds' is the exact answer/clip.
480 */
482 int offsetY,
483 int maxWidth,
484 int maxHeight,
485 SkRect* devBounds,
486 bool* isIntersectionOfRects = nullptr) const;
487
488private:
489 friend class Iter;
490
491 SkDeque fDeque;
492 int fSaveCount;
493
494 bool internalQuickContains(const SkRect& devRect) const;
495 bool internalQuickContains(const SkRRect& devRRect) const;
496
497 /**
498 * Helper for clipDevPath, etc.
499 */
500 void pushElement(const Element& element);
501
502 /**
503 * Restore the stack back to the specified save count.
504 */
505 void restoreTo(int saveCount);
506
507 /**
508 * Return the next unique generation ID.
509 */
510 static uint32_t GetNextGenID();
511};
512
513#endif
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkClipOp
Definition: SkClipOp.h:13
@ kRRect
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv)
Definition: SkYUVMath.cpp:629
AutoRestore(SkClipStack *cs, bool doSave)
Definition: SkClipStack.h:296
B2TIter(const SkClipStack &stack)
Definition: SkClipStack.h:449
void reset(const SkClipStack &stack)
Definition: SkClipStack.h:459
bool operator!=(const Element &element) const
Call to get the type of the clip element.
Definition: SkClipStack.h:99
sk_sp< SkShader > refShader() const
Definition: SkClipStack.h:127
Element(sk_sp< SkShader > shader)
Definition: SkClipStack.h:88
Element(const SkRect &rect, bool doAA)
Definition: SkClipStack.h:92
Element(const SkRect &rect, const SkMatrix &m, SkClipOp op, bool doAA)
Definition: SkClipStack.h:76
const SkShader * getShader() const
Definition: SkClipStack.h:130
@ kPath
This element does not have geometry, but applies a shader to the clip.
@ kRect
This element combines a device space round-rect with the current clip.
@ kRRect
This element combines a device space path with the current clip.
SkClipOp getOp() const
Definition: SkClipStack.h:136
uint32_t getGenID() const
Definition: SkClipStack.h:161
const SkRect & getDeviceSpaceRect() const
Call if getDeviceSpaceType() is kShader to get a reference to the clip shader.
Definition: SkClipStack.h:120
bool isAA() const
Inverts the fill of the clip shape. Note that a kEmpty element remains kEmpty.
Definition: SkClipStack.h:151
static const int kTypeCnt
Definition: SkClipStack.h:67
int getSaveCount() const
Call if getDeviceSpaceType() is kPath to get the path.
Definition: SkClipStack.h:105
const SkRRect & getDeviceSpaceRRect() const
Call if getDeviceSpaceType() is kRect to get the rect.
Definition: SkClipStack.h:114
bool isInverseFilled() const
Definition: SkClipStack.h:179
DeviceSpaceType getDeviceSpaceType() const
Call to get the save count associated with this clip element.
Definition: SkClipStack.h:102
Element(const SkRRect &rrect, const SkMatrix &m, SkClipOp op, bool doAA)
Definition: SkClipStack.h:80
const SkPath & getDeviceSpacePath() const
Call if getDeviceSpaceType() is kRRect to get the round-rect.
Definition: SkClipStack.h:108
bool operator==(const Element &element) const
Definition: SkClipStack.cpp:58
const SkRRect & asDeviceSpaceRRect() const
Definition: SkClipStack.h:144
const SkRect & getBounds() const
Definition: SkClipStack.cpp:84
bool contains(const SkRect &rect) const
Element(const SkPath &path, const SkMatrix &m, SkClipOp op, bool doAA)
Definition: SkClipStack.h:84
bool isReplaceOp() const
Call to get the element as a path, regardless of its type.
Definition: SkClipStack.h:138
void asDeviceSpacePath(SkPath *path) const
Call if getType() is not kPath to get the element as a round rect.
void reset(const SkClipStack &stack, IterStart startLoc)
const Element * skipToTopmost(SkClipOp op)
const Element * next()
const Element * prev()
@ kNormal_BoundsType
Definition: SkClipStack.h:37
@ kInsideOut_BoundsType
Definition: SkClipStack.h:43
void clipRect(const SkRect &, const SkMatrix &matrix, SkClipOp, bool doAA)
void clipShader(sk_sp< SkShader >)
bool isRRect(const SkRect &bounds, SkRRect *rrect, bool *aa) const
bool quickContains(const SkRRect &devRRect) const
Definition: SkClipStack.h:340
static const uint32_t kEmptyGenID
Definition: SkClipStack.h:386
void clipRRect(const SkRRect &, const SkMatrix &matrix, SkClipOp, bool doAA)
bool quickContains(const SkRect &devRect) const
Definition: SkClipStack.h:336
void getBounds(SkRect *canvFiniteBound, BoundsType *boundType, bool *isIntersectionOfRects=nullptr) const
bool isEmpty(const SkIRect &deviceBounds) const
void clipDevRect(const SkIRect &ir, SkClipOp op)
Definition: SkClipStack.h:344
void getConservativeBounds(int offsetX, int offsetY, int maxWidth, int maxHeight, SkRect *devBounds, bool *isIntersectionOfRects=nullptr) const
void clipEmpty()
bool operator==(const SkClipStack &b) const
SkClipStack & operator=(const SkClipStack &b)
uint32_t getTopmostGenID() const
int getSaveCount() const
Definition: SkClipStack.h:290
static const uint32_t kInvalidGenID
Definition: SkClipStack.h:383
static const uint32_t kWideOpenGenID
Definition: SkClipStack.h:387
void restore()
bool operator!=(const SkClipStack &b) const
Definition: SkClipStack.h:286
bool isWideOpen() const
Definition: SkClipStack.h:362
void clipPath(const SkPath &, const SkMatrix &matrix, SkClipOp, bool doAA)
SkRect bounds(const SkIRect &deviceBounds) const
void replaceClip(const SkRect &devRect, bool doAA)
@ kBack_IterStart
Definition: SkDeque.h:66
@ kFront_IterStart
Definition: SkDeque.h:65
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
Definition: SkPath.h:59
bool isInverseFillType() const
Definition: SkPath.h:244
bool isRect() const
Definition: SkRRect.h:84
bool isEmpty() const
Definition: SkRRect.h:83
const SkRect & getBounds() const
Definition: SkRRect.h:279
T * get() const
Definition: SkRefCnt.h:303
static bool b
Definition: dart.idl:42
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
SkRRect rrect
Definition: SkRecords.h:232
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
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
SkScalar offsetX
SkScalar offsetY
Definition: SkRect.h:32
void set(const SkIRect &src)
Definition: SkRect.h:849