aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkRegion.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/SkRegion.cpp')
-rw-r--r--src/core/SkRegion.cpp226
1 files changed, 6 insertions, 220 deletions
diff --git a/src/core/SkRegion.cpp b/src/core/SkRegion.cpp
index 376f79c255..ce4252394c 100644
--- a/src/core/SkRegion.cpp
+++ b/src/core/SkRegion.cpp
@@ -555,230 +555,16 @@ void SkRegion::translate(int dx, int dy, SkRegion* dst) const
///////////////////////////////////////////////////////////////////////////////
-#include "SkChunkAlloc.h"
-#include "SkTDArray.h"
-#include "SkTSearch.h"
-#include "SkTemplates.h"
-
-template <typename T> int SkTCmp2Int(const T& a, const T& b) {
- return (a < b) ? -1 : ((b < a) ? 1 : 0);
-}
-
-struct VEdge {
- int32_t fX;
- int fDir; // 1, -1
-};
-
-static VEdge* append_rect(VEdge* edge, const SkIRect& r) {
- edge[0].fX = r.fLeft;
- edge[0].fDir = -1;
- edge[1].fX = r.fRight;
- edge[1].fDir = 1;
- return edge + 2;
-}
-
-class Accumulator {
-public:
- Accumulator(SkRegion::RunType top, int numRects);
- ~Accumulator() {}
-
- void append(int32_t bottom, const VEdge edge[], int count);
-
- int count() const { return fTotalCount; }
- void copyTo(SkRegion::RunType dst[]);
-
-private:
- struct Row {
- SkRegion::RunType* fPtr;
- SkRegion::RunType fBottom;
- int fCount; // just [L R] count
- };
- SkChunkAlloc fAlloc;
- SkTDArray<Row> fRows;
- SkRegion::RunType fTop;
- int fTotalCount;
-};
-
-Accumulator::Accumulator(SkRegion::RunType top, int numRects)
- : fAlloc((1 + numRects * 2 + 1) * sizeof(int32_t)) {
- fTop = top;
- fTotalCount = 2; // Top + final sentinel
-}
-
-static int union_edges(SkRegion::RunType dst[], const VEdge edge[], int count) {
- if (0 == count) {
- return 0;
- }
-
- SkRegion::RunType* startDst = dst;
- const VEdge* stop = edge + count;
-
- SkRegion::RunType currR;
- int dir = edge->fDir;
-
- *dst++ = edge->fX; // initial L
- while (++edge < stop) {
- int prevDir = dir;
- dir += edge->fDir;
- if (0 == dir) { // we finished an interval
- currR = edge->fX;
- } else if (0 == prevDir && edge->fX > currR) {
- *dst++ = currR;
- *dst++ = edge->fX;
- }
- }
- SkASSERT(0 == dir);
- *dst++ = currR;
- SkDEBUGCODE(int resultCount = dst - startDst;)
- SkASSERT(resultCount <= count && (resultCount & 1) == 0);
- return dst - startDst;
-}
-
-void Accumulator::append(int32_t bottom, const VEdge edge[], int count) {
- SkASSERT((count & 1) == 0);
-
- size_t size = count * sizeof(SkRegion::RunType);
- int32_t* row = (SkRegion::RunType*)fAlloc.allocThrow(size);
- int rowCount = union_edges(row, edge, count);
-
- Row* r = fRows.count() ? &fRows[fRows.count() - 1] : NULL;
- if (r && (r->fCount == rowCount) &&
- !memcmp(r->fPtr, row,
- rowCount * sizeof(SkRegion::RunType))) {
- r->fBottom = bottom; // update bottom
- fAlloc.unalloc(row);
- } else {
- Row* r = fRows.append();
- r->fPtr = row;
- r->fBottom = bottom;
- r->fCount = rowCount;
- fTotalCount += 1 + rowCount + 1;
- }
-}
-
-void Accumulator::copyTo(SkRegion::RunType dst[]) {
- SkDEBUGCODE(SkRegion::RunType* startDst = dst;)
-
- *dst++ = fTop;
-
- const Row* curr = fRows.begin();
- const Row* stop = fRows.end();
- while (curr < stop) {
- *dst++ = curr->fBottom;
- memcpy(dst, curr->fPtr, curr->fCount * sizeof(SkRegion::RunType));
- dst += curr->fCount;
- *dst++ = SkRegion::kRunTypeSentinel;
- curr += 1;
- }
- *dst++ = SkRegion::kRunTypeSentinel;
- SkASSERT(dst - startDst == fTotalCount);
-}
-
-/////////////
-
-struct RNode {
- RNode* fNext;
- const SkIRect* fRect;
-};
-
-static int compare_rnode_top(const void* e0, const void* e1) {
- const RNode* r0 = static_cast<const RNode*>(e0);
- const RNode* r1 = static_cast<const RNode*>(e1);
- return SkTCmp2Int<int32_t>(r0->fRect->fTop, r1->fRect->fTop);
-}
-
-static int compare_vedge(const void* e0, const void* e1) {
- const VEdge* v0 = static_cast<const VEdge*>(e0);
- const VEdge* v1 = static_cast<const VEdge*>(e1);
- return SkTCmp2Int<int32_t>(v0->fX, v1->fX);
-}
-
bool SkRegion::setRects(const SkIRect rects[], int count) {
if (0 == count) {
- return this->setEmpty();
- }
- if (1 == count) {
- return this->setRect(rects[0]);
- }
-
- int i;
- SkIRect sentinelRect = SkIRect::MakeLTRB(kRunTypeSentinel, kRunTypeSentinel,
- kRunTypeSentinel, kRunTypeSentinel);
-
- SkAutoTArray<RNode> nodeStorage(count + 1);
- RNode* nodes = nodeStorage.get();
- for (i = 0; i < count; i++) {
- if (!rects[i].isEmpty()) {
- nodes->fRect = &rects[i];
- nodes += 1;
- }
- }
- // recompute count, since we may have skipped empty rects
- count = nodes - nodeStorage.get();
- nodes = nodeStorage.get();
- // we are now done with the original rects[] parameter
- SkDEBUGCODE(rects = NULL;)
-
- SkQSort(nodes, count, sizeof(nodes[0]), compare_rnode_top);
- for (i = 0; i < count; i++) {
- nodes[i].fNext = &nodes[i + 1];
- }
- nodes[count].fNext = NULL;
- nodes[count].fRect = &sentinelRect;
-
- SkAutoTArray<VEdge> edgeStorage(count * 2);
-
- VEdge* edges = edgeStorage.get();
- RNode* nodeHead = nodeStorage.get();
-
- int32_t currY = nodeHead->fRect->fTop;
- Accumulator accum(currY, count);
-
- while (nodeHead->fNext) {
- RNode* node = nodeHead;
-
- int32_t nextY = kRunTypeSentinel;
- const SkIRect* r = node->fRect;
- for (;;) {
- if (r->fTop > currY) {
- nextY = SkMin32(nextY, r->fTop);
- break;
- }
- edges = append_rect(edges, *r);
- nextY = SkMin32(nextY, r->fBottom);
- node = node->fNext;
- r = node->fRect;
- }
- int edgeCount = edges - edgeStorage.get();
- edges = edgeStorage.get();
- SkASSERT(edgeCount <= count * 2);
-
- SkQSort(edges, edgeCount, sizeof(edges[0]), compare_vedge);
- accum.append(nextY, edges, edgeCount);
-
- RNode* prev = NULL;
- node = nodeHead;
- while (node->fRect->fTop <= currY) {
- RNode* next = node->fNext;
- if (node->fRect->fBottom <= nextY) {
- // drop this rect from our linklist
- SkASSERT(node->fRect->fBottom == nextY);
- if (prev) {
- prev->fNext = next;
- } else {
- nodeHead = next;
- }
- } else {
- prev = node;
- }
- node = next;
+ this->setEmpty();
+ } else {
+ this->setRect(rects[0]);
+ for (int i = 1; i < count; i++) {
+ this->op(rects[i], kUnion_Op);
}
- currY = nextY;
}
-
- SkAutoTArray<RunType> runs(accum.count());
- accum.copyTo(runs.get());
- return this->setRuns(runs.get(), accum.count());
+ return !this->isEmpty();
}
///////////////////////////////////////////////////////////////////////////////