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
8 #include "SkRegionPriv.h"
9 #include "SkBlitter.h"
10 #include "SkScan.h"
11 #include "SkTSort.h"
12 #include "SkTDArray.h"
13 #include "SkPath.h"
14
15 // The rgnbuilder caller *seems* to pass short counts, possible often seens early failure, so
16 // we may not want to promote this to a "std" routine just yet.
sk_memeq32(const int32_t * SK_RESTRICT a,const int32_t * SK_RESTRICT b,int count)17 static bool sk_memeq32(const int32_t* SK_RESTRICT a, const int32_t* SK_RESTRICT b, int count) {
18 for (int i = 0; i < count; ++i) {
19 if (a[i] != b[i]) {
20 return false;
21 }
22 }
23 return true;
24 }
25
26 class SkRgnBuilder : public SkBlitter {
27 public:
28 SkRgnBuilder();
29 ~SkRgnBuilder() override;
30
31 // returns true if it could allocate the working storage needed
32 bool init(int maxHeight, int maxTransitions, bool pathIsInverse);
33
done()34 void done() {
35 if (fCurrScanline != nullptr) {
36 fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
37 if (!this->collapsWithPrev()) { // flush the last line
38 fCurrScanline = fCurrScanline->nextScanline();
39 }
40 }
41 }
42
43 int computeRunCount() const;
44 void copyToRect(SkIRect*) const;
45 void copyToRgn(SkRegion::RunType runs[]) const;
46
47 void blitH(int x, int y, int width) override;
blitAntiH(int x,int y,const SkAlpha antialias[],const int16_t runs[])48 void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override {
49 SkDEBUGFAIL("blitAntiH not implemented");
50 }
51
52 #ifdef SK_DEBUG
dump() const53 void dump() const {
54 SkDebugf("SkRgnBuilder: Top = %d\n", fTop);
55 const Scanline* line = (Scanline*)fStorage;
56 while (line < fCurrScanline) {
57 SkDebugf("SkRgnBuilder::Scanline: LastY=%d, fXCount=%d", line->fLastY, line->fXCount);
58 for (int i = 0; i < line->fXCount; i++) {
59 SkDebugf(" %d", line->firstX()[i]);
60 }
61 SkDebugf("\n");
62
63 line = line->nextScanline();
64 }
65 }
66 #endif
67 private:
68 /*
69 * Scanline mimics a row in the region, nearly. A row in a region is:
70 * [Bottom IntervalCount [L R]... Sentinel]
71 * while a Scanline is
72 * [LastY XCount [L R]... uninitialized]
73 * The two are the same length (which is good), but we have to transmute
74 * the scanline a little when we convert it to a region-row.
75 *
76 * Potentially we could recode this to exactly match the row format, in
77 * which case copyToRgn() could be a single memcpy. Not sure that is worth
78 * the effort.
79 */
80 struct Scanline {
81 SkRegion::RunType fLastY;
82 SkRegion::RunType fXCount;
83
firstXSkRgnBuilder::Scanline84 SkRegion::RunType* firstX() const { return (SkRegion::RunType*)(this + 1); }
nextScanlineSkRgnBuilder::Scanline85 Scanline* nextScanline() const {
86 // add final +1 for the x-sentinel
87 return (Scanline*)((SkRegion::RunType*)(this + 1) + fXCount + 1);
88 }
89 };
90 SkRegion::RunType* fStorage;
91 Scanline* fCurrScanline;
92 Scanline* fPrevScanline;
93 // points at next avialable x[] in fCurrScanline
94 SkRegion::RunType* fCurrXPtr;
95 SkRegion::RunType fTop; // first Y value
96
97 int fStorageCount;
98
collapsWithPrev()99 bool collapsWithPrev() {
100 if (fPrevScanline != nullptr &&
101 fPrevScanline->fLastY + 1 == fCurrScanline->fLastY &&
102 fPrevScanline->fXCount == fCurrScanline->fXCount &&
103 sk_memeq32(fPrevScanline->firstX(), fCurrScanline->firstX(), fCurrScanline->fXCount))
104 {
105 // update the height of fPrevScanline
106 fPrevScanline->fLastY = fCurrScanline->fLastY;
107 return true;
108 }
109 return false;
110 }
111 };
112
SkRgnBuilder()113 SkRgnBuilder::SkRgnBuilder()
114 : fStorage(nullptr) {
115 }
116
~SkRgnBuilder()117 SkRgnBuilder::~SkRgnBuilder() {
118 sk_free(fStorage);
119 }
120
init(int maxHeight,int maxTransitions,bool pathIsInverse)121 bool SkRgnBuilder::init(int maxHeight, int maxTransitions, bool pathIsInverse) {
122 if ((maxHeight | maxTransitions) < 0) {
123 return false;
124 }
125
126 if (pathIsInverse) {
127 // allow for additional X transitions to "invert" each scanline
128 // [ L' ... normal transitions ... R' ]
129 //
130 maxTransitions += 2;
131 }
132
133 // compute the count with +1 and +3 slop for the working buffer
134 int64_t count = sk_64_mul(maxHeight + 1, 3 + maxTransitions);
135
136 if (pathIsInverse) {
137 // allow for two "empty" rows for the top and bottom
138 // [ Y, 1, L, R, S] == 5 (*2 for top and bottom)
139 count += 10;
140 }
141
142 if (count < 0 || !sk_64_isS32(count)) {
143 return false;
144 }
145 fStorageCount = sk_64_asS32(count);
146
147 int64_t size = sk_64_mul(fStorageCount, sizeof(SkRegion::RunType));
148 if (size < 0 || !sk_64_isS32(size)) {
149 return false;
150 }
151
152 fStorage = (SkRegion::RunType*)sk_malloc_flags(sk_64_asS32(size), 0);
153 if (nullptr == fStorage) {
154 return false;
155 }
156
157 fCurrScanline = nullptr; // signal empty collection
158 fPrevScanline = nullptr; // signal first scanline
159 return true;
160 }
161
blitH(int x,int y,int width)162 void SkRgnBuilder::blitH(int x, int y, int width) {
163 if (fCurrScanline == nullptr) { // first time
164 fTop = (SkRegion::RunType)(y);
165 fCurrScanline = (Scanline*)fStorage;
166 fCurrScanline->fLastY = (SkRegion::RunType)(y);
167 fCurrXPtr = fCurrScanline->firstX();
168 } else {
169 SkASSERT(y >= fCurrScanline->fLastY);
170
171 if (y > fCurrScanline->fLastY) {
172 // if we get here, we're done with fCurrScanline
173 fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
174
175 int prevLastY = fCurrScanline->fLastY;
176 if (!this->collapsWithPrev()) {
177 fPrevScanline = fCurrScanline;
178 fCurrScanline = fCurrScanline->nextScanline();
179
180 }
181 if (y - 1 > prevLastY) { // insert empty run
182 fCurrScanline->fLastY = (SkRegion::RunType)(y - 1);
183 fCurrScanline->fXCount = 0;
184 fCurrScanline = fCurrScanline->nextScanline();
185 }
186 // setup for the new curr line
187 fCurrScanline->fLastY = (SkRegion::RunType)(y);
188 fCurrXPtr = fCurrScanline->firstX();
189 }
190 }
191 // check if we should extend the current run, or add a new one
192 if (fCurrXPtr > fCurrScanline->firstX() && fCurrXPtr[-1] == x) {
193 fCurrXPtr[-1] = (SkRegion::RunType)(x + width);
194 } else {
195 fCurrXPtr[0] = (SkRegion::RunType)(x);
196 fCurrXPtr[1] = (SkRegion::RunType)(x + width);
197 fCurrXPtr += 2;
198 }
199 SkASSERT(fCurrXPtr - fStorage < fStorageCount);
200 }
201
computeRunCount() const202 int SkRgnBuilder::computeRunCount() const {
203 if (fCurrScanline == nullptr) {
204 return 0;
205 }
206
207 const SkRegion::RunType* line = fStorage;
208 const SkRegion::RunType* stop = (const SkRegion::RunType*)fCurrScanline;
209
210 return 2 + (int)(stop - line);
211 }
212
copyToRect(SkIRect * r) const213 void SkRgnBuilder::copyToRect(SkIRect* r) const {
214 SkASSERT(fCurrScanline != nullptr);
215 // A rect's scanline is [bottom intervals left right sentinel] == 5
216 SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage == 5);
217
218 const Scanline* line = (const Scanline*)fStorage;
219 SkASSERT(line->fXCount == 2);
220
221 r->set(line->firstX()[0], fTop, line->firstX()[1], line->fLastY + 1);
222 }
223
copyToRgn(SkRegion::RunType runs[]) const224 void SkRgnBuilder::copyToRgn(SkRegion::RunType runs[]) const {
225 SkASSERT(fCurrScanline != nullptr);
226 SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage > 4);
227
228 const Scanline* line = (const Scanline*)fStorage;
229 const Scanline* stop = fCurrScanline;
230
231 *runs++ = fTop;
232 do {
233 *runs++ = (SkRegion::RunType)(line->fLastY + 1);
234 int count = line->fXCount;
235 *runs++ = count >> 1; // intervalCount
236 if (count) {
237 memcpy(runs, line->firstX(), count * sizeof(SkRegion::RunType));
238 runs += count;
239 }
240 *runs++ = SkRegion::kRunTypeSentinel;
241 line = line->nextScanline();
242 } while (line < stop);
243 SkASSERT(line == stop);
244 *runs = SkRegion::kRunTypeSentinel;
245 }
246
verb_to_initial_last_index(unsigned verb)247 static unsigned verb_to_initial_last_index(unsigned verb) {
248 static const uint8_t gPathVerbToInitialLastIndex[] = {
249 0, // kMove_Verb
250 1, // kLine_Verb
251 2, // kQuad_Verb
252 2, // kConic_Verb
253 3, // kCubic_Verb
254 0, // kClose_Verb
255 0 // kDone_Verb
256 };
257 SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToInitialLastIndex));
258 return gPathVerbToInitialLastIndex[verb];
259 }
260
verb_to_max_edges(unsigned verb)261 static unsigned verb_to_max_edges(unsigned verb) {
262 static const uint8_t gPathVerbToMaxEdges[] = {
263 0, // kMove_Verb
264 1, // kLine_Verb
265 2, // kQuad_VerbB
266 2, // kConic_VerbB
267 3, // kCubic_Verb
268 0, // kClose_Verb
269 0 // kDone_Verb
270 };
271 SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToMaxEdges));
272 return gPathVerbToMaxEdges[verb];
273 }
274
275 // If returns 0, ignore itop and ibot
count_path_runtype_values(const SkPath & path,int * itop,int * ibot)276 static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) {
277 SkPath::Iter iter(path, true);
278 SkPoint pts[4];
279 SkPath::Verb verb;
280
281 int maxEdges = 0;
282 SkScalar top = SkIntToScalar(SK_MaxS16);
283 SkScalar bot = SkIntToScalar(SK_MinS16);
284
285 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
286 maxEdges += verb_to_max_edges(verb);
287
288 int lastIndex = verb_to_initial_last_index(verb);
289 if (lastIndex > 0) {
290 for (int i = 1; i <= lastIndex; i++) {
291 if (top > pts[i].fY) {
292 top = pts[i].fY;
293 } else if (bot < pts[i].fY) {
294 bot = pts[i].fY;
295 }
296 }
297 } else if (SkPath::kMove_Verb == verb) {
298 if (top > pts[0].fY) {
299 top = pts[0].fY;
300 } else if (bot < pts[0].fY) {
301 bot = pts[0].fY;
302 }
303 }
304 }
305 if (0 == maxEdges) {
306 return 0; // we have only moves+closes
307 }
308
309 SkASSERT(top <= bot);
310 *itop = SkScalarRoundToInt(top);
311 *ibot = SkScalarRoundToInt(bot);
312 return maxEdges;
313 }
314
check_inverse_on_empty_return(SkRegion * dst,const SkPath & path,const SkRegion & clip)315 static bool check_inverse_on_empty_return(SkRegion* dst, const SkPath& path, const SkRegion& clip) {
316 if (path.isInverseFillType()) {
317 return dst->set(clip);
318 } else {
319 return dst->setEmpty();
320 }
321 }
322
setPath(const SkPath & path,const SkRegion & clip)323 bool SkRegion::setPath(const SkPath& path, const SkRegion& clip) {
324 SkDEBUGCODE(this->validate();)
325
326 if (clip.isEmpty()) {
327 return this->setEmpty();
328 }
329
330 if (path.isEmpty()) {
331 return check_inverse_on_empty_return(this, path, clip);
332 }
333
334 // compute worst-case rgn-size for the path
335 int pathTop, pathBot;
336 int pathTransitions = count_path_runtype_values(path, &pathTop, &pathBot);
337 if (0 == pathTransitions) {
338 return check_inverse_on_empty_return(this, path, clip);
339 }
340
341 int clipTop, clipBot;
342 int clipTransitions = clip.count_runtype_values(&clipTop, &clipBot);
343
344 int top = SkMax32(pathTop, clipTop);
345 int bot = SkMin32(pathBot, clipBot);
346 if (top >= bot) {
347 return check_inverse_on_empty_return(this, path, clip);
348 }
349
350 SkRgnBuilder builder;
351
352 if (!builder.init(bot - top,
353 SkMax32(pathTransitions, clipTransitions),
354 path.isInverseFillType())) {
355 // can't allocate working space, so return false
356 return this->setEmpty();
357 }
358
359 SkScan::FillPath(path, clip, &builder);
360 builder.done();
361
362 int count = builder.computeRunCount();
363 if (count == 0) {
364 return this->setEmpty();
365 } else if (count == kRectRegionRuns) {
366 builder.copyToRect(&fBounds);
367 this->setRect(fBounds);
368 } else {
369 SkRegion tmp;
370
371 tmp.fRunHead = RunHead::Alloc(count);
372 builder.copyToRgn(tmp.fRunHead->writable_runs());
373 tmp.fRunHead->computeRunBounds(&tmp.fBounds);
374 this->swap(tmp);
375 }
376 SkDEBUGCODE(this->validate();)
377 return true;
378 }
379
380 /////////////////////////////////////////////////////////////////////////////////////////////////
381 /////////////////////////////////////////////////////////////////////////////////////////////////
382
383 struct Edge {
384 enum {
385 kY0Link = 0x01,
386 kY1Link = 0x02,
387
388 kCompleteLink = (kY0Link | kY1Link)
389 };
390
391 SkRegion::RunType fX;
392 SkRegion::RunType fY0, fY1;
393 uint8_t fFlags;
394 Edge* fNext;
395
setEdge396 void set(int x, int y0, int y1) {
397 SkASSERT(y0 != y1);
398
399 fX = (SkRegion::RunType)(x);
400 fY0 = (SkRegion::RunType)(y0);
401 fY1 = (SkRegion::RunType)(y1);
402 fFlags = 0;
403 SkDEBUGCODE(fNext = nullptr;)
404 }
405
topEdge406 int top() const {
407 return SkFastMin32(fY0, fY1);
408 }
409 };
410
find_link(Edge * base,Edge * stop)411 static void find_link(Edge* base, Edge* stop) {
412 SkASSERT(base < stop);
413
414 if (base->fFlags == Edge::kCompleteLink) {
415 SkASSERT(base->fNext);
416 return;
417 }
418
419 SkASSERT(base + 1 < stop);
420
421 int y0 = base->fY0;
422 int y1 = base->fY1;
423
424 Edge* e = base;
425 if ((base->fFlags & Edge::kY0Link) == 0) {
426 for (;;) {
427 e += 1;
428 if ((e->fFlags & Edge::kY1Link) == 0 && y0 == e->fY1) {
429 SkASSERT(nullptr == e->fNext);
430 e->fNext = base;
431 e->fFlags = SkToU8(e->fFlags | Edge::kY1Link);
432 break;
433 }
434 }
435 }
436
437 e = base;
438 if ((base->fFlags & Edge::kY1Link) == 0) {
439 for (;;) {
440 e += 1;
441 if ((e->fFlags & Edge::kY0Link) == 0 && y1 == e->fY0) {
442 SkASSERT(nullptr == base->fNext);
443 base->fNext = e;
444 e->fFlags = SkToU8(e->fFlags | Edge::kY0Link);
445 break;
446 }
447 }
448 }
449
450 base->fFlags = Edge::kCompleteLink;
451 }
452
extract_path(Edge * edge,Edge * stop,SkPath * path)453 static int extract_path(Edge* edge, Edge* stop, SkPath* path) {
454 while (0 == edge->fFlags) {
455 edge++; // skip over "used" edges
456 }
457
458 SkASSERT(edge < stop);
459
460 Edge* base = edge;
461 Edge* prev = edge;
462 edge = edge->fNext;
463 SkASSERT(edge != base);
464
465 int count = 1;
466 path->moveTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY0));
467 prev->fFlags = 0;
468 do {
469 if (prev->fX != edge->fX || prev->fY1 != edge->fY0) { // skip collinear
470 path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1)); // V
471 path->lineTo(SkIntToScalar(edge->fX), SkIntToScalar(edge->fY0)); // H
472 }
473 prev = edge;
474 edge = edge->fNext;
475 count += 1;
476 prev->fFlags = 0;
477 } while (edge != base);
478 path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1)); // V
479 path->close();
480 return count;
481 }
482
483 struct EdgeLT {
operator ()EdgeLT484 bool operator()(const Edge& a, const Edge& b) const {
485 return (a.fX == b.fX) ? a.top() < b.top() : a.fX < b.fX;
486 }
487 };
488
getBoundaryPath(SkPath * path) const489 bool SkRegion::getBoundaryPath(SkPath* path) const {
490 // path could safely be nullptr if we're empty, but the caller shouldn't
491 // *know* that
492 SkASSERT(path);
493
494 if (this->isEmpty()) {
495 return false;
496 }
497
498 const SkIRect& bounds = this->getBounds();
499
500 if (this->isRect()) {
501 SkRect r;
502 r.set(bounds); // this converts the ints to scalars
503 path->addRect(r);
504 return true;
505 }
506
507 SkRegion::Iterator iter(*this);
508 SkTDArray<Edge> edges;
509
510 for (const SkIRect& r = iter.rect(); !iter.done(); iter.next()) {
511 Edge* edge = edges.append(2);
512 edge[0].set(r.fLeft, r.fBottom, r.fTop);
513 edge[1].set(r.fRight, r.fTop, r.fBottom);
514 }
515
516 int count = edges.count();
517 Edge* start = edges.begin();
518 Edge* stop = start + count;
519 SkTQSort<Edge>(start, stop - 1, EdgeLT());
520
521 Edge* e;
522 for (e = start; e != stop; e++) {
523 find_link(e, stop);
524 }
525
526 #ifdef SK_DEBUG
527 for (e = start; e != stop; e++) {
528 SkASSERT(e->fNext != nullptr);
529 SkASSERT(e->fFlags == Edge::kCompleteLink);
530 }
531 #endif
532
533 path->incReserve(count << 1);
534 do {
535 SkASSERT(count > 1);
536 count -= extract_path(start, stop, path);
537 } while (count > 0);
538
539 return true;
540 }
541