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