1 :
2 : /*
3 : * Copyright 2006 The Android Open Source Project
4 : *
5 : * Use of this source code is governed by a BSD-style license that can be
6 : * found in the LICENSE file.
7 : */
8 :
9 :
10 : #include "SkRegionPriv.h"
11 : #include "SkBlitter.h"
12 : #include "SkScan.h"
13 : #include "SkTDArray.h"
14 : #include "SkPath.h"
15 :
16 0 : class SkRgnBuilder : public SkBlitter {
17 : public:
18 : virtual ~SkRgnBuilder();
19 :
20 : // returns true if it could allocate the working storage needed
21 : bool init(int maxHeight, int maxTransitions);
22 :
23 0 : void done() {
24 0 : if (fCurrScanline != NULL) {
25 0 : fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
26 0 : if (!this->collapsWithPrev()) { // flush the last line
27 0 : fCurrScanline = fCurrScanline->nextScanline();
28 : }
29 : }
30 0 : }
31 :
32 : int computeRunCount() const;
33 : void copyToRect(SkIRect*) const;
34 : void copyToRgn(SkRegion::RunType runs[]) const;
35 :
36 : virtual void blitH(int x, int y, int width);
37 :
38 : #ifdef SK_DEBUG
39 : void dump() const {
40 : SkDebugf("SkRgnBuilder: Top = %d\n", fTop);
41 : const Scanline* line = (Scanline*)fStorage;
42 : while (line < fCurrScanline) {
43 : SkDebugf("SkRgnBuilder::Scanline: LastY=%d, fXCount=%d", line->fLastY, line->fXCount);
44 : for (int i = 0; i < line->fXCount; i++) {
45 : SkDebugf(" %d", line->firstX()[i]);
46 : }
47 : SkDebugf("\n");
48 :
49 : line = line->nextScanline();
50 : }
51 : }
52 : #endif
53 : private:
54 : struct Scanline {
55 : SkRegion::RunType fLastY;
56 : SkRegion::RunType fXCount;
57 :
58 0 : SkRegion::RunType* firstX() const { return (SkRegion::RunType*)(this + 1); }
59 0 : Scanline* nextScanline() const {
60 0 : return (Scanline*)((SkRegion::RunType*)(this + 1) + fXCount);
61 : }
62 : };
63 : SkRegion::RunType* fStorage;
64 : Scanline* fCurrScanline;
65 : Scanline* fPrevScanline;
66 : // points at next avialable x[] in fCurrScanline
67 : SkRegion::RunType* fCurrXPtr;
68 : SkRegion::RunType fTop; // first Y value
69 :
70 : int fStorageCount;
71 :
72 0 : bool collapsWithPrev() {
73 0 : if (fPrevScanline != NULL &&
74 : fPrevScanline->fLastY + 1 == fCurrScanline->fLastY &&
75 : fPrevScanline->fXCount == fCurrScanline->fXCount &&
76 0 : !memcmp(fPrevScanline->firstX(),
77 0 : fCurrScanline->firstX(),
78 0 : fCurrScanline->fXCount * sizeof(SkRegion::RunType)))
79 : {
80 : // update the height of fPrevScanline
81 0 : fPrevScanline->fLastY = fCurrScanline->fLastY;
82 0 : return true;
83 : }
84 0 : return false;
85 : }
86 : };
87 :
88 0 : SkRgnBuilder::~SkRgnBuilder() {
89 0 : sk_free(fStorage);
90 0 : }
91 :
92 0 : bool SkRgnBuilder::init(int maxHeight, int maxTransitions) {
93 0 : if ((maxHeight | maxTransitions) < 0) {
94 0 : return false;
95 : }
96 :
97 : Sk64 count, size;
98 :
99 : // compute the count with +1 and +3 slop for the working buffer
100 0 : count.setMul(maxHeight + 1, 3 + maxTransitions);
101 0 : if (!count.is32() || count.isNeg()) {
102 0 : return false;
103 : }
104 0 : fStorageCount = count.get32();
105 :
106 0 : size.setMul(fStorageCount, sizeof(SkRegion::RunType));
107 0 : if (!size.is32() || size.isNeg()) {
108 0 : return false;
109 : }
110 :
111 0 : fStorage = (SkRegion::RunType*)sk_malloc_flags(size.get32(), 0);
112 0 : if (NULL == fStorage) {
113 0 : return false;
114 : }
115 :
116 0 : fCurrScanline = NULL; // signal empty collection
117 0 : fPrevScanline = NULL; // signal first scanline
118 0 : return true;
119 : }
120 :
121 0 : void SkRgnBuilder::blitH(int x, int y, int width) {
122 0 : if (fCurrScanline == NULL) { // first time
123 0 : fTop = (SkRegion::RunType)(y);
124 0 : fCurrScanline = (Scanline*)fStorage;
125 0 : fCurrScanline->fLastY = (SkRegion::RunType)(y);
126 0 : fCurrXPtr = fCurrScanline->firstX();
127 : } else {
128 0 : SkASSERT(y >= fCurrScanline->fLastY);
129 :
130 0 : if (y > fCurrScanline->fLastY) {
131 : // if we get here, we're done with fCurrScanline
132 0 : fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
133 :
134 0 : int prevLastY = fCurrScanline->fLastY;
135 0 : if (!this->collapsWithPrev()) {
136 0 : fPrevScanline = fCurrScanline;
137 0 : fCurrScanline = fCurrScanline->nextScanline();
138 :
139 : }
140 0 : if (y - 1 > prevLastY) { // insert empty run
141 0 : fCurrScanline->fLastY = (SkRegion::RunType)(y - 1);
142 0 : fCurrScanline->fXCount = 0;
143 0 : fCurrScanline = fCurrScanline->nextScanline();
144 : }
145 : // setup for the new curr line
146 0 : fCurrScanline->fLastY = (SkRegion::RunType)(y);
147 0 : fCurrXPtr = fCurrScanline->firstX();
148 : }
149 : }
150 : // check if we should extend the current run, or add a new one
151 0 : if (fCurrXPtr > fCurrScanline->firstX() && fCurrXPtr[-1] == x) {
152 0 : fCurrXPtr[-1] = (SkRegion::RunType)(x + width);
153 : } else {
154 0 : fCurrXPtr[0] = (SkRegion::RunType)(x);
155 0 : fCurrXPtr[1] = (SkRegion::RunType)(x + width);
156 0 : fCurrXPtr += 2;
157 : }
158 0 : SkASSERT(fCurrXPtr - fStorage < fStorageCount);
159 0 : }
160 :
161 0 : int SkRgnBuilder::computeRunCount() const {
162 0 : if (fCurrScanline == NULL) {
163 0 : return 0;
164 : }
165 :
166 0 : const SkRegion::RunType* line = fStorage;
167 0 : const SkRegion::RunType* stop = (const SkRegion::RunType*)fCurrScanline;
168 :
169 0 : return 2 + (int)(stop - line);
170 : }
171 :
172 0 : void SkRgnBuilder::copyToRect(SkIRect* r) const {
173 0 : SkASSERT(fCurrScanline != NULL);
174 0 : SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage == 4);
175 :
176 0 : const Scanline* line = (const Scanline*)fStorage;
177 0 : SkASSERT(line->fXCount == 2);
178 :
179 0 : r->set(line->firstX()[0], fTop, line->firstX()[1], line->fLastY + 1);
180 0 : }
181 :
182 0 : void SkRgnBuilder::copyToRgn(SkRegion::RunType runs[]) const {
183 0 : SkASSERT(fCurrScanline != NULL);
184 0 : SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage > 4);
185 :
186 0 : const Scanline* line = (const Scanline*)fStorage;
187 0 : const Scanline* stop = fCurrScanline;
188 :
189 0 : *runs++ = fTop;
190 0 : do {
191 0 : *runs++ = (SkRegion::RunType)(line->fLastY + 1);
192 0 : int count = line->fXCount;
193 0 : if (count) {
194 0 : memcpy(runs, line->firstX(), count * sizeof(SkRegion::RunType));
195 0 : runs += count;
196 : }
197 0 : *runs++ = SkRegion::kRunTypeSentinel;
198 0 : line = line->nextScanline();
199 : } while (line < stop);
200 0 : SkASSERT(line == stop);
201 0 : *runs = SkRegion::kRunTypeSentinel;
202 0 : }
203 :
204 0 : static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) {
205 : static const uint8_t gPathVerbToInitialLastIndex[] = {
206 : 0, // kMove_Verb
207 : 1, // kLine_Verb
208 : 2, // kQuad_Verb
209 : 3, // kCubic_Verb
210 : 0, // kClose_Verb
211 : 0 // kDone_Verb
212 : };
213 :
214 : static const uint8_t gPathVerbToMaxEdges[] = {
215 : 0, // kMove_Verb
216 : 1, // kLine_Verb
217 : 2, // kQuad_VerbB
218 : 3, // kCubic_Verb
219 : 0, // kClose_Verb
220 : 0 // kDone_Verb
221 : };
222 :
223 0 : SkPath::Iter iter(path, true);
224 : SkPoint pts[4];
225 : SkPath::Verb verb;
226 :
227 0 : int maxEdges = 0;
228 0 : SkScalar top = SkIntToScalar(SK_MaxS16);
229 0 : SkScalar bot = SkIntToScalar(SK_MinS16);
230 :
231 0 : while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
232 0 : maxEdges += gPathVerbToMaxEdges[verb];
233 :
234 0 : int lastIndex = gPathVerbToInitialLastIndex[verb];
235 0 : if (lastIndex > 0) {
236 0 : for (int i = 1; i <= lastIndex; i++) {
237 0 : if (top > pts[i].fY) {
238 0 : top = pts[i].fY;
239 0 : } else if (bot < pts[i].fY) {
240 0 : bot = pts[i].fY;
241 : }
242 : }
243 0 : } else if (SkPath::kMove_Verb == verb) {
244 0 : if (top > pts[0].fY) {
245 0 : top = pts[0].fY;
246 0 : } else if (bot < pts[0].fY) {
247 0 : bot = pts[0].fY;
248 : }
249 : }
250 : }
251 0 : SkASSERT(top <= bot);
252 :
253 0 : *itop = SkScalarRound(top);
254 0 : *ibot = SkScalarRound(bot);
255 0 : return maxEdges;
256 : }
257 :
258 0 : bool SkRegion::setPath(const SkPath& path, const SkRegion& clip) {
259 0 : SkDEBUGCODE(this->validate();)
260 :
261 0 : if (clip.isEmpty()) {
262 0 : return this->setEmpty();
263 : }
264 :
265 0 : if (path.isEmpty()) {
266 0 : if (path.isInverseFillType()) {
267 0 : return this->set(clip);
268 : } else {
269 0 : return this->setEmpty();
270 : }
271 : }
272 :
273 : // compute worst-case rgn-size for the path
274 : int pathTop, pathBot;
275 0 : int pathTransitions = count_path_runtype_values(path, &pathTop, &pathBot);
276 : int clipTop, clipBot;
277 : int clipTransitions;
278 :
279 0 : clipTransitions = clip.count_runtype_values(&clipTop, &clipBot);
280 :
281 0 : int top = SkMax32(pathTop, clipTop);
282 0 : int bot = SkMin32(pathBot, clipBot);
283 :
284 0 : if (top >= bot)
285 0 : return this->setEmpty();
286 :
287 0 : SkRgnBuilder builder;
288 :
289 0 : if (!builder.init(bot - top, SkMax32(pathTransitions, clipTransitions))) {
290 : // can't allocate working space, so return false
291 0 : return this->setEmpty();
292 : }
293 :
294 0 : SkScan::FillPath(path, clip, &builder);
295 0 : builder.done();
296 :
297 0 : int count = builder.computeRunCount();
298 0 : if (count == 0) {
299 0 : return this->setEmpty();
300 0 : } else if (count == kRectRegionRuns) {
301 0 : builder.copyToRect(&fBounds);
302 0 : this->setRect(fBounds);
303 : } else {
304 0 : SkRegion tmp;
305 :
306 0 : tmp.fRunHead = RunHead::Alloc(count);
307 0 : builder.copyToRgn(tmp.fRunHead->writable_runs());
308 0 : ComputeRunBounds(tmp.fRunHead->readonly_runs(), count, &tmp.fBounds);
309 0 : this->swap(tmp);
310 : }
311 0 : SkDEBUGCODE(this->validate();)
312 0 : return true;
313 : }
314 :
315 : /////////////////////////////////////////////////////////////////////////////////////////////////
316 : /////////////////////////////////////////////////////////////////////////////////////////////////
317 :
318 : struct Edge {
319 : enum {
320 : kY0Link = 0x01,
321 : kY1Link = 0x02,
322 :
323 : kCompleteLink = (kY0Link | kY1Link)
324 : };
325 :
326 : SkRegion::RunType fX;
327 : SkRegion::RunType fY0, fY1;
328 : uint8_t fFlags;
329 : Edge* fNext;
330 :
331 0 : void set(int x, int y0, int y1) {
332 0 : SkASSERT(y0 != y1);
333 :
334 0 : fX = (SkRegion::RunType)(x);
335 0 : fY0 = (SkRegion::RunType)(y0);
336 0 : fY1 = (SkRegion::RunType)(y1);
337 0 : fFlags = 0;
338 0 : SkDEBUGCODE(fNext = NULL;)
339 0 : }
340 :
341 0 : int top() const {
342 0 : return SkFastMin32(fY0, fY1);
343 : }
344 : };
345 :
346 0 : static void find_link(Edge* base, Edge* stop) {
347 0 : SkASSERT(base < stop);
348 :
349 0 : if (base->fFlags == Edge::kCompleteLink) {
350 0 : SkASSERT(base->fNext);
351 0 : return;
352 : }
353 :
354 0 : SkASSERT(base + 1 < stop);
355 :
356 0 : int y0 = base->fY0;
357 0 : int y1 = base->fY1;
358 :
359 0 : Edge* e = base;
360 0 : if ((base->fFlags & Edge::kY0Link) == 0) {
361 0 : for (;;) {
362 0 : e += 1;
363 0 : if ((e->fFlags & Edge::kY1Link) == 0 && y0 == e->fY1) {
364 0 : SkASSERT(NULL == e->fNext);
365 0 : e->fNext = base;
366 0 : e->fFlags = SkToU8(e->fFlags | Edge::kY1Link);
367 : break;
368 : }
369 : }
370 : }
371 :
372 0 : e = base;
373 0 : if ((base->fFlags & Edge::kY1Link) == 0) {
374 0 : for (;;) {
375 0 : e += 1;
376 0 : if ((e->fFlags & Edge::kY0Link) == 0 && y1 == e->fY0) {
377 0 : SkASSERT(NULL == base->fNext);
378 0 : base->fNext = e;
379 0 : e->fFlags = SkToU8(e->fFlags | Edge::kY0Link);
380 : break;
381 : }
382 : }
383 : }
384 :
385 0 : base->fFlags = Edge::kCompleteLink;
386 : }
387 :
388 0 : static int extract_path(Edge* edge, Edge* stop, SkPath* path) {
389 0 : while (0 == edge->fFlags) {
390 0 : edge++; // skip over "used" edges
391 : }
392 :
393 0 : SkASSERT(edge < stop);
394 :
395 0 : Edge* base = edge;
396 0 : Edge* prev = edge;
397 0 : edge = edge->fNext;
398 0 : SkASSERT(edge != base);
399 :
400 0 : int count = 1;
401 0 : path->moveTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY0));
402 0 : prev->fFlags = 0;
403 0 : do {
404 0 : if (prev->fX != edge->fX || prev->fY1 != edge->fY0) { // skip collinear
405 0 : path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1)); // V
406 0 : path->lineTo(SkIntToScalar(edge->fX), SkIntToScalar(edge->fY0)); // H
407 : }
408 0 : prev = edge;
409 0 : edge = edge->fNext;
410 0 : count += 1;
411 0 : prev->fFlags = 0;
412 : } while (edge != base);
413 0 : path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1)); // V
414 0 : path->close();
415 0 : return count;
416 : }
417 :
418 : #include "SkTSearch.h"
419 :
420 0 : static int EdgeProc(const Edge* a, const Edge* b) {
421 0 : return (a->fX == b->fX) ? a->top() - b->top() : a->fX - b->fX;
422 : }
423 :
424 0 : bool SkRegion::getBoundaryPath(SkPath* path) const {
425 : // path could safely be NULL if we're empty, but the caller shouldn't
426 : // *know* that
427 0 : SkASSERT(path);
428 :
429 0 : if (this->isEmpty()) {
430 0 : return false;
431 : }
432 :
433 0 : const SkIRect& bounds = this->getBounds();
434 :
435 0 : if (this->isRect()) {
436 : SkRect r;
437 0 : r.set(bounds); // this converts the ints to scalars
438 0 : path->addRect(r);
439 0 : return true;
440 : }
441 :
442 0 : SkRegion::Iterator iter(*this);
443 0 : SkTDArray<Edge> edges;
444 :
445 0 : for (const SkIRect& r = iter.rect(); !iter.done(); iter.next()) {
446 0 : Edge* edge = edges.append(2);
447 0 : edge[0].set(r.fLeft, r.fBottom, r.fTop);
448 0 : edge[1].set(r.fRight, r.fTop, r.fBottom);
449 : }
450 0 : SkQSort(edges.begin(), edges.count(), sizeof(Edge),
451 0 : (SkQSortCompareProc)EdgeProc);
452 :
453 0 : int count = edges.count();
454 0 : Edge* start = edges.begin();
455 0 : Edge* stop = start + count;
456 : Edge* e;
457 :
458 0 : for (e = start; e != stop; e++) {
459 0 : find_link(e, stop);
460 : }
461 :
462 : #ifdef SK_DEBUG
463 0 : for (e = start; e != stop; e++) {
464 0 : SkASSERT(e->fNext != NULL);
465 0 : SkASSERT(e->fFlags == Edge::kCompleteLink);
466 : }
467 : #endif
468 :
469 0 : path->incReserve(count << 1);
470 0 : do {
471 0 : SkASSERT(count > 1);
472 0 : count -= extract_path(start, stop, path);
473 : } while (count > 0);
474 :
475 0 : return true;
476 : }
477 :
|