Flutter Engine
The Flutter Engine
SkRegion_path.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
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
10#include "include/core/SkPath.h"
11#include "include/core/SkRect.h"
22#include "src/base/SkSafeMath.h"
23#include "src/base/SkTSort.h"
24#include "src/core/SkBlitter.h"
26#include "src/core/SkScan.h"
27
28#include <algorithm>
29#include <cstdint>
30#include <cstring>
31#include <iterator>
32
33// The rgnbuilder caller *seems* to pass short counts, possible often seens early failure, so
34// we may not want to promote this to a "std" routine just yet.
35static bool sk_memeq32(const int32_t* SK_RESTRICT a, const int32_t* SK_RESTRICT b, int count) {
36 for (int i = 0; i < count; ++i) {
37 if (a[i] != b[i]) {
38 return false;
39 }
40 }
41 return true;
42}
43
44class SkRgnBuilder : public SkBlitter {
45public:
47 ~SkRgnBuilder() override;
48
49 // returns true if it could allocate the working storage needed
50 bool init(int maxHeight, int maxTransitions, bool pathIsInverse);
51
52 void done() {
53 if (fCurrScanline != nullptr) {
54 fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
55 if (!this->collapsWithPrev()) { // flush the last line
56 fCurrScanline = fCurrScanline->nextScanline();
57 }
58 }
59 }
60
61 int computeRunCount() const;
62 void copyToRect(SkIRect*) const;
63 void copyToRgn(SkRegion::RunType runs[]) const;
64
65 void blitH(int x, int y, int width) override;
66 void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override {
67 SkDEBUGFAIL("blitAntiH not implemented");
68 }
69
70#ifdef SK_DEBUG
71 void dump() const {
72 SkDebugf("SkRgnBuilder: Top = %d\n", fTop);
73 Scanline* line = (Scanline*)fStorage;
74 while (line < fCurrScanline) {
75 SkDebugf("SkRgnBuilder::Scanline: LastY=%d, fXCount=%d", line->fLastY, line->fXCount);
76 for (int i = 0; i < line->fXCount; i++) {
77 SkDebugf(" %d", line->firstX()[i]);
78 }
79 SkDebugf("\n");
80
81 line = line->nextScanline();
82 }
83 }
84#endif
85private:
86 /*
87 * Scanline mimics a row in the region, nearly. A row in a region is:
88 * [Bottom IntervalCount [L R]... Sentinel]
89 * while a Scanline is
90 * [LastY XCount [L R]... uninitialized]
91 * The two are the same length (which is good), but we have to transmute
92 * the scanline a little when we convert it to a region-row.
93 *
94 * Potentially we could recode this to exactly match the row format, in
95 * which case copyToRgn() could be a single memcpy. Not sure that is worth
96 * the effort.
97 */
98 struct Scanline {
99 SkRegion::RunType fLastY;
100 SkRegion::RunType fXCount;
101
102 SkRegion::RunType* firstX() { return (SkRegion::RunType*)(this + 1); }
103 Scanline* nextScanline() {
104 // add final +1 for the x-sentinel
105 return (Scanline*)((SkRegion::RunType*)(this + 1) + fXCount + 1);
106 }
107 };
108 SkRegion::RunType* fStorage;
109 Scanline* fCurrScanline;
110 Scanline* fPrevScanline;
111 // points at next avialable x[] in fCurrScanline
112 SkRegion::RunType* fCurrXPtr;
113 SkRegion::RunType fTop; // first Y value
114
115 int fStorageCount;
116
117 bool collapsWithPrev() {
118 if (fPrevScanline != nullptr &&
119 fPrevScanline->fLastY + 1 == fCurrScanline->fLastY &&
120 fPrevScanline->fXCount == fCurrScanline->fXCount &&
121 sk_memeq32(fPrevScanline->firstX(), fCurrScanline->firstX(), fCurrScanline->fXCount))
122 {
123 // update the height of fPrevScanline
124 fPrevScanline->fLastY = fCurrScanline->fLastY;
125 return true;
126 }
127 return false;
128 }
129};
130
132 : fStorage(nullptr) {
133}
134
136 sk_free(fStorage);
137}
138
139bool SkRgnBuilder::init(int maxHeight, int maxTransitions, bool pathIsInverse) {
140 if ((maxHeight | maxTransitions) < 0) {
141 return false;
142 }
143
144 SkSafeMath safe;
145
146 if (pathIsInverse) {
147 // allow for additional X transitions to "invert" each scanline
148 // [ L' ... normal transitions ... R' ]
149 //
150 maxTransitions = safe.addInt(maxTransitions, 2);
151 }
152
153 // compute the count with +1 and +3 slop for the working buffer
154 size_t count = safe.mul(safe.addInt(maxHeight, 1), safe.addInt(3, maxTransitions));
155
156 if (pathIsInverse) {
157 // allow for two "empty" rows for the top and bottom
158 // [ Y, 1, L, R, S] == 5 (*2 for top and bottom)
159 count = safe.add(count, 10);
160 }
161
162 if (!safe || !SkTFitsIn<int32_t>(count)) {
163 return false;
164 }
165 fStorageCount = SkToS32(count);
166
167 fStorage = (SkRegion::RunType*)sk_malloc_canfail(fStorageCount, sizeof(SkRegion::RunType));
168 if (nullptr == fStorage) {
169 return false;
170 }
171
172 fCurrScanline = nullptr; // signal empty collection
173 fPrevScanline = nullptr; // signal first scanline
174 return true;
175}
176
177void SkRgnBuilder::blitH(int x, int y, int width) {
178 if (fCurrScanline == nullptr) { // first time
179 fTop = (SkRegion::RunType)(y);
180 fCurrScanline = (Scanline*)fStorage;
181 fCurrScanline->fLastY = (SkRegion::RunType)(y);
182 fCurrXPtr = fCurrScanline->firstX();
183 } else {
184 SkASSERT(y >= fCurrScanline->fLastY);
185
186 if (y > fCurrScanline->fLastY) {
187 // if we get here, we're done with fCurrScanline
188 fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
189
190 int prevLastY = fCurrScanline->fLastY;
191 if (!this->collapsWithPrev()) {
192 fPrevScanline = fCurrScanline;
193 fCurrScanline = fCurrScanline->nextScanline();
194
195 }
196 if (y - 1 > prevLastY) { // insert empty run
197 fCurrScanline->fLastY = (SkRegion::RunType)(y - 1);
198 fCurrScanline->fXCount = 0;
199 fCurrScanline = fCurrScanline->nextScanline();
200 }
201 // setup for the new curr line
202 fCurrScanline->fLastY = (SkRegion::RunType)(y);
203 fCurrXPtr = fCurrScanline->firstX();
204 }
205 }
206 // check if we should extend the current run, or add a new one
207 if (fCurrXPtr > fCurrScanline->firstX() && fCurrXPtr[-1] == x) {
208 fCurrXPtr[-1] = (SkRegion::RunType)(x + width);
209 } else {
210 fCurrXPtr[0] = (SkRegion::RunType)(x);
211 fCurrXPtr[1] = (SkRegion::RunType)(x + width);
212 fCurrXPtr += 2;
213 }
214 SkASSERT(fCurrXPtr - fStorage < fStorageCount);
215}
216
218 if (fCurrScanline == nullptr) {
219 return 0;
220 }
221
222 const SkRegion::RunType* line = fStorage;
223 const SkRegion::RunType* stop = (const SkRegion::RunType*)fCurrScanline;
224
225 return 2 + (int)(stop - line);
226}
227
229 SkASSERT(fCurrScanline != nullptr);
230 // A rect's scanline is [bottom intervals left right sentinel] == 5
231 SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage == 5);
232
233 Scanline* line = (Scanline*)fStorage;
234 SkASSERT(line->fXCount == 2);
235
236 r->setLTRB(line->firstX()[0], fTop, line->firstX()[1], line->fLastY + 1);
237}
238
239void SkRgnBuilder::copyToRgn(SkRegion::RunType runs[]) const {
240 SkASSERT(fCurrScanline != nullptr);
241 SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage > 4);
242
243 Scanline* line = (Scanline*)fStorage;
244 const Scanline* stop = fCurrScanline;
245
246 *runs++ = fTop;
247 do {
248 *runs++ = (SkRegion::RunType)(line->fLastY + 1);
249 int count = line->fXCount;
250 *runs++ = count >> 1; // intervalCount
251 if (count) {
252 memcpy(runs, line->firstX(), count * sizeof(SkRegion::RunType));
253 runs += count;
254 }
256 line = line->nextScanline();
257 } while (line < stop);
258 SkASSERT(line == stop);
260}
261
262static unsigned verb_to_initial_last_index(unsigned verb) {
263 static const uint8_t gPathVerbToInitialLastIndex[] = {
264 0, // kMove_Verb
265 1, // kLine_Verb
266 2, // kQuad_Verb
267 2, // kConic_Verb
268 3, // kCubic_Verb
269 0, // kClose_Verb
270 0 // kDone_Verb
271 };
272 SkASSERT((unsigned)verb < std::size(gPathVerbToInitialLastIndex));
273 return gPathVerbToInitialLastIndex[verb];
274}
275
276static unsigned verb_to_max_edges(unsigned verb) {
277 static const uint8_t gPathVerbToMaxEdges[] = {
278 0, // kMove_Verb
279 1, // kLine_Verb
280 2, // kQuad_VerbB
281 2, // kConic_VerbB
282 3, // kCubic_Verb
283 0, // kClose_Verb
284 0 // kDone_Verb
285 };
286 SkASSERT((unsigned)verb < std::size(gPathVerbToMaxEdges));
287 return gPathVerbToMaxEdges[verb];
288}
289
290// If returns 0, ignore itop and ibot
291static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) {
292 SkPath::Iter iter(path, true);
293 SkPoint pts[4];
294 SkPath::Verb verb;
295
296 int maxEdges = 0;
299
300 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
301 maxEdges += verb_to_max_edges(verb);
302
303 int lastIndex = verb_to_initial_last_index(verb);
304 if (lastIndex > 0) {
305 for (int i = 1; i <= lastIndex; i++) {
306 if (top > pts[i].fY) {
307 top = pts[i].fY;
308 } else if (bot < pts[i].fY) {
309 bot = pts[i].fY;
310 }
311 }
312 } else if (SkPath::kMove_Verb == verb) {
313 if (top > pts[0].fY) {
314 top = pts[0].fY;
315 } else if (bot < pts[0].fY) {
316 bot = pts[0].fY;
317 }
318 }
319 }
320 if (0 == maxEdges) {
321 return 0; // we have only moves+closes
322 }
323
324 SkASSERT(top <= bot);
325 *itop = SkScalarRoundToInt(top);
326 *ibot = SkScalarRoundToInt(bot);
327 return maxEdges;
328}
329
331 if (path.isInverseFillType()) {
332 return dst->set(clip);
333 } else {
334 return dst->setEmpty();
335 }
336}
337
339 SkDEBUGCODE(SkRegionPriv::Validate(*this));
340
341 if (clip.isEmpty() || !path.isFinite() || path.isEmpty()) {
342 // This treats non-finite paths as empty as well, so this returns empty or 'clip' if
343 // it's inverse-filled. If clip is also empty, path's fill type doesn't really matter
344 // and this region ends up empty.
346 }
347
348 // Our builder is very fragile, and can't be called with spans/rects out of Y->X order.
349 // To ensure this, we only "fill" clipped to a rect (the clip's bounds), and if the
350 // clip is more complex than that, we just post-intersect the result with the clip.
351 const SkIRect clipBounds = clip.getBounds();
352 if (clip.isComplex()) {
353 if (!this->setPath(path, SkRegion(clipBounds))) {
354 return false;
355 }
356 return this->op(clip, kIntersect_Op);
357 }
358
359 // SkScan::FillPath has limits on the coordinate range of the clipping SkRegion. If it's too
360 // big, tile the clip bounds and union the pieces back together.
361 if (SkScan::PathRequiresTiling(clipBounds)) {
362 static constexpr int kTileSize = 32767 >> 1; // Limit so coords can fit into SkFixed (16.16)
363 const SkIRect pathBounds = path.getBounds().roundOut();
364
365 this->setEmpty();
366
367 // Note: With large integers some intermediate calculations can overflow, but the
368 // end results will still be in integer range. Using int64_t for the intermediate
369 // values will handle this situation.
370 for (int64_t top = clipBounds.fTop; top < clipBounds.fBottom; top += kTileSize) {
371 int64_t bot = std::min(top + kTileSize, (int64_t)clipBounds.fBottom);
372 for (int64_t left = clipBounds.fLeft; left < clipBounds.fRight; left += kTileSize) {
373 int64_t right = std::min(left + kTileSize, (int64_t)clipBounds.fRight);
374
375 SkIRect tileClipBounds = {(int)left, (int)top, (int)right, (int)bot};
376 if (!SkIRect::Intersects(pathBounds, tileClipBounds)) {
377 continue;
378 }
379
380 // Shift coordinates so the top left is (0,0) during scan conversion and then
381 // translate the SkRegion afterwards.
382 tileClipBounds.offset(-left, -top);
383 SkASSERT(!SkScan::PathRequiresTiling(tileClipBounds));
384 SkRegion tile;
385 tile.setPath(path.makeTransform(SkMatrix::Translate(-left, -top)),
386 SkRegion(tileClipBounds));
387 tile.translate(left, top);
388 this->op(tile, kUnion_Op);
389 }
390 }
391 // During tiling we only applied the bounds of the tile, now that we have a full SkRegion,
392 // apply the original clip.
393 return this->op(clip, kIntersect_Op);
394 }
395
396 // compute worst-case rgn-size for the path
397 int pathTop, pathBot;
398 int pathTransitions = count_path_runtype_values(path, &pathTop, &pathBot);
399 if (0 == pathTransitions) {
401 }
402
403 int clipTop, clipBot;
404 int clipTransitions = clip.count_runtype_values(&clipTop, &clipBot);
405
406 int top = std::max(pathTop, clipTop);
407 int bot = std::min(pathBot, clipBot);
408 if (top >= bot) {
410 }
411
413
414 if (!builder.init(bot - top,
415 std::max(pathTransitions, clipTransitions),
416 path.isInverseFillType())) {
417 // can't allocate working space, so return false
418 return this->setEmpty();
419 }
420
422 builder.done();
423
424 int count = builder.computeRunCount();
425 if (count == 0) {
426 return this->setEmpty();
427 } else if (count == kRectRegionRuns) {
428 builder.copyToRect(&fBounds);
429 this->setRect(fBounds);
430 } else {
431 SkRegion tmp;
432
433 tmp.fRunHead = RunHead::Alloc(count);
434 builder.copyToRgn(tmp.fRunHead->writable_runs());
435 tmp.fRunHead->computeRunBounds(&tmp.fBounds);
436 this->swap(tmp);
437 }
438 SkDEBUGCODE(SkRegionPriv::Validate(*this));
439 return true;
440}
441
442/////////////////////////////////////////////////////////////////////////////////////////////////
443/////////////////////////////////////////////////////////////////////////////////////////////////
444
445struct Edge {
446 enum {
447 kY0Link = 0x01,
448 kY1Link = 0x02,
449
451 };
452
455 uint8_t fFlags;
457
458 void set(int x, int y0, int y1) {
459 SkASSERT(y0 != y1);
460
464 fFlags = 0;
465 SkDEBUGCODE(fNext = nullptr;)
466 }
467
468 int top() const {
469 return std::min(fY0, fY1);
470 }
471};
472
473static void find_link(Edge* base, Edge* stop) {
474 SkASSERT(base < stop);
475
476 if (base->fFlags == Edge::kCompleteLink) {
477 SkASSERT(base->fNext);
478 return;
479 }
480
481 SkASSERT(base + 1 < stop);
482
483 int y0 = base->fY0;
484 int y1 = base->fY1;
485
486 Edge* e = base;
487 if ((base->fFlags & Edge::kY0Link) == 0) {
488 for (;;) {
489 e += 1;
490 if ((e->fFlags & Edge::kY1Link) == 0 && y0 == e->fY1) {
491 SkASSERT(nullptr == e->fNext);
492 e->fNext = base;
493 e->fFlags = SkToU8(e->fFlags | Edge::kY1Link);
494 break;
495 }
496 }
497 }
498
499 e = base;
500 if ((base->fFlags & Edge::kY1Link) == 0) {
501 for (;;) {
502 e += 1;
503 if ((e->fFlags & Edge::kY0Link) == 0 && y1 == e->fY0) {
504 SkASSERT(nullptr == base->fNext);
505 base->fNext = e;
506 e->fFlags = SkToU8(e->fFlags | Edge::kY0Link);
507 break;
508 }
509 }
510 }
511
512 base->fFlags = Edge::kCompleteLink;
513}
514
515static int extract_path(Edge* edge, Edge* stop, SkPath* path) {
516 while (0 == edge->fFlags) {
517 edge++; // skip over "used" edges
518 }
519
520 SkASSERT(edge < stop);
521
522 Edge* base = edge;
523 Edge* prev = edge;
524 edge = edge->fNext;
525 SkASSERT(edge != base);
526
527 int count = 1;
528 path->moveTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY0));
529 prev->fFlags = 0;
530 do {
531 if (prev->fX != edge->fX || prev->fY1 != edge->fY0) { // skip collinear
532 path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1)); // V
533 path->lineTo(SkIntToScalar(edge->fX), SkIntToScalar(edge->fY0)); // H
534 }
535 prev = edge;
536 edge = edge->fNext;
537 count += 1;
538 prev->fFlags = 0;
539 } while (edge != base);
540 path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1)); // V
541 path->close();
542 return count;
543}
544
545struct EdgeLT {
546 bool operator()(const Edge& a, const Edge& b) const {
547 return (a.fX == b.fX) ? a.top() < b.top() : a.fX < b.fX;
548 }
549};
550
552 // path could safely be nullptr if we're empty, but the caller shouldn't
553 // *know* that
554 SkASSERT(path);
555
556 if (this->isEmpty()) {
557 return false;
558 }
559
560 const SkIRect& bounds = this->getBounds();
561
562 if (this->isRect()) {
563 SkRect r;
564 r.set(bounds); // this converts the ints to scalars
565 path->addRect(r);
566 return true;
567 }
568
569 SkRegion::Iterator iter(*this);
570 SkTDArray<Edge> edges;
571
572 for (const SkIRect& r = iter.rect(); !iter.done(); iter.next()) {
573 Edge* edge = edges.append(2);
574 edge[0].set(r.fLeft, r.fBottom, r.fTop);
575 edge[1].set(r.fRight, r.fTop, r.fBottom);
576 }
577
578 int count = edges.size();
579 Edge* start = edges.begin();
580 Edge* stop = start + count;
581 SkTQSort<Edge>(start, stop, EdgeLT());
582
583 Edge* e;
584 for (e = start; e != stop; e++) {
585 find_link(e, stop);
586 }
587
588#ifdef SK_DEBUG
589 for (e = start; e != stop; e++) {
590 SkASSERT(e->fNext != nullptr);
591 SkASSERT(e->fFlags == Edge::kCompleteLink);
592 }
593#endif
594
595 path->incReserve(count << 1);
596 do {
597 SkASSERT(count > 1);
598 count -= extract_path(start, stop, path);
599 } while (count > 0);
600
601 return true;
602}
int count
Definition: FontMgrTest.cpp:50
const SkRect fBounds
static float prev(float f)
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SkASSERT(cond)
Definition: SkAssert.h:116
uint8_t SkAlpha
Definition: SkColor.h:26
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SK_RESTRICT
Definition: SkFeatures.h:42
SK_API void sk_free(void *)
static void * sk_malloc_canfail(size_t size)
Definition: SkMalloc.h:93
static constexpr int16_t SK_MaxS16
Definition: SkMath.h:18
static constexpr int16_t SK_MinS16
Definition: SkMath.h:19
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
static constexpr int SkRegion_kRunTypeSentinel
Definition: SkRegionPriv.h:35
static unsigned verb_to_initial_last_index(unsigned verb)
static unsigned verb_to_max_edges(unsigned verb)
static void find_link(Edge *base, Edge *stop)
static bool sk_memeq32(const int32_t *SK_RESTRICT a, const int32_t *SK_RESTRICT b, int count)
static int count_path_runtype_values(const SkPath &path, int *itop, int *ibot)
static bool check_inverse_on_empty_return(SkRegion *dst, const SkPath &path, const SkRegion &clip)
static int extract_path(Edge *edge, Edge *stop, SkPath *path)
#define SkScalarRoundToInt(x)
Definition: SkScalar.h:37
#define SkIntToScalar(x)
Definition: SkScalar.h:57
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
constexpr int32_t SkToS32(S x)
Definition: SkTo.h:25
constexpr uint8_t SkToU8(S x)
Definition: SkTo.h:22
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv)
Definition: SkYUVMath.cpp:629
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
Verb next(SkPoint pts[4])
Definition: SkPath.cpp:1901
Definition: SkPath.h:59
bool isEmpty() const
Definition: SkPath.cpp:416
const SkRect & getBounds() const
Definition: SkPath.cpp:430
@ kMove_Verb
Definition: SkPath.h:1466
@ kDone_Verb
Definition: SkPath.h:1472
SkRegion::RunType RunType
Definition: SkRegionPriv.h:22
const SkIRect & rect() const
Definition: SkRegion.h:501
bool done() const
Definition: SkRegion.h:488
void translate(int dx, int dy)
Definition: SkRegion.h:349
bool getBoundaryPath(SkPath *path) const
bool setEmpty()
Definition: SkRegion.cpp:185
@ kUnion_Op
target unioned with operand
Definition: SkRegion.h:369
@ kIntersect_Op
target intersected with operand
Definition: SkRegion.h:368
bool isRect() const
Definition: SkRegion.h:152
const SkIRect & getBounds() const
Definition: SkRegion.h:165
bool op(const SkIRect &rect, Op op)
Definition: SkRegion.h:384
bool setRect(const SkIRect &rect)
Definition: SkRegion.cpp:192
bool isEmpty() const
Definition: SkRegion.h:146
bool setPath(const SkPath &path, const SkRegion &clip)
void swap(SkRegion &other)
Definition: SkRegion.cpp:170
~SkRgnBuilder() override
int computeRunCount() const
void copyToRgn(SkRegion::RunType runs[]) const
bool init(int maxHeight, int maxTransitions, bool pathIsInverse)
void blitH(int x, int y, int width) override
Blit a horizontal run of one or more pixels.
void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override
void copyToRect(SkIRect *) const
int addInt(int a, int b)
Definition: SkSafeMath.h:43
size_t add(size_t x, size_t y)
Definition: SkSafeMath.h:33
size_t mul(size_t x, size_t y)
Definition: SkSafeMath.h:29
static bool PathRequiresTiling(const SkIRect &bounds)
static void FillPath(const SkPath &, const SkIRect &, SkBlitter *)
int size() const
Definition: SkTDArray.h:138
T * begin()
Definition: SkTDArray.h:150
T * append()
Definition: SkTDArray.h:191
float SkScalar
Definition: extension.cpp:12
static bool b
struct MyStruct a[10]
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
double y
double x
Optional< SkRect > bounds
Definition: SkRecords.h:189
void Validate(const Table &table)
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
dst
Definition: cp.py:12
int32_t width
bool operator()(const Edge &a, const Edge &b) const
uint8_t fFlags
int top() const
SkRegionPriv::RunType fX
void set(int x, int y0, int y1)
SkRegionPriv::RunType fY0
SkRegionPriv::RunType fY1
@ kCompleteLink
Edge * fNext
Definition: SkRect.h:32
static bool Intersects(const SkIRect &a, const SkIRect &b)
Definition: SkRect.h:535
int32_t fBottom
larger y-axis bounds
Definition: SkRect.h:36
int32_t fTop
smaller y-axis bounds
Definition: SkRect.h:34
void offset(int32_t dx, int32_t dy)
Definition: SkRect.h:367
int32_t fLeft
smaller x-axis bounds
Definition: SkRect.h:33
void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom)
Definition: SkRect.h:253
int32_t fRight
larger x-axis bounds
Definition: SkRect.h:35
float fY
y-axis value
Definition: SkPoint_impl.h:165
void set(const SkIRect &src)
Definition: SkRect.h:849
SkRegion::RunType * writable_runs()
Definition: SkRegionPriv.h:116
static RunHead * Alloc(int count)
Definition: SkRegionPriv.h:85
void computeRunBounds(SkIRect *bounds)
Definition: SkRegionPriv.h:195