| OLD | NEW |
| (Empty) |
| 1 | |
| 2 /* | |
| 3 * Copyright 2011 Google Inc. | |
| 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 #include "SkRegion.h" | |
| 9 #include "SkChunkAlloc.h" | |
| 10 #include "SkTDArray.h" | |
| 11 #include "SkTemplates.h" | |
| 12 | |
| 13 #if 0 | |
| 14 | |
| 15 struct VEdge { | |
| 16 VEdge* fPrev; | |
| 17 VEdge* fNext; | |
| 18 | |
| 19 SkRegion::RunType fX; | |
| 20 SkRegion::RunType fTop; | |
| 21 SkRegion::RunType fBottom; | |
| 22 int fWinding; | |
| 23 | |
| 24 void removeFromList() { | |
| 25 fPrev->fNext = fNext; | |
| 26 fNext->fPrev = fPrev; | |
| 27 } | |
| 28 | |
| 29 void backwardsInsert() { | |
| 30 while (fPrev->fX > fX) { | |
| 31 VEdge* prev = fPrev; | |
| 32 VEdge* next = this; | |
| 33 | |
| 34 // remove prev from the list | |
| 35 prev->fPrev->fNext = next; | |
| 36 next->fPrev = prev->fPrev; | |
| 37 | |
| 38 // insert prev after next | |
| 39 prev->fNext = next->fNext; | |
| 40 next->fNext->fPrev = prev; | |
| 41 next->fNext = prev; | |
| 42 prev->fPrev = next; | |
| 43 } | |
| 44 } | |
| 45 | |
| 46 static void SetFromRect(VEdge edges[], const SkIRect& r) { | |
| 47 edges[0].fX = r.fLeft; | |
| 48 edges[0].fTop = r.fTop; | |
| 49 edges[0].fBottom = r.fBottom; | |
| 50 edges[0].fWinding = -1; | |
| 51 | |
| 52 edges[1].fX = r.fRight; | |
| 53 edges[1].fTop = r.fTop; | |
| 54 edges[1].fBottom = r.fBottom; | |
| 55 edges[1].fWinding = 1; | |
| 56 } | |
| 57 }; | |
| 58 | |
| 59 class Accumulator { | |
| 60 public: | |
| 61 Accumulator(SkRegion::RunType top, int numRects); | |
| 62 ~Accumulator() {} | |
| 63 | |
| 64 SkRegion::RunType append(SkRegion::RunType top, const VEdge* edge); | |
| 65 | |
| 66 int count() const { return fTotalCount; } | |
| 67 void copyTo(SkRegion::RunType dst[]); | |
| 68 | |
| 69 private: | |
| 70 struct Row { | |
| 71 SkRegion::RunType* fPtr; | |
| 72 SkRegion::RunType fBottom; | |
| 73 int fCount; // just [L R] count | |
| 74 }; | |
| 75 SkChunkAlloc fAlloc; | |
| 76 SkTDArray<Row> fRows; | |
| 77 SkRegion::RunType fTop; | |
| 78 int fTotalCount; | |
| 79 int fRectCount; | |
| 80 }; | |
| 81 | |
| 82 Accumulator::Accumulator(SkRegion::RunType top, int numRects) | |
| 83 : fAlloc((1 + numRects * 2 + 1) * sizeof(int32_t)) { | |
| 84 fRectCount = numRects; | |
| 85 fTop = top; | |
| 86 fTotalCount = 2; // Top + final sentinel | |
| 87 } | |
| 88 | |
| 89 //#define TRACE_ROW(code) code | |
| 90 #define TRACE_ROW(code) | |
| 91 | |
| 92 SkRegion::RunType Accumulator::append(SkRegion::RunType currY, const VEdge* edge
) { | |
| 93 // worst-case size | |
| 94 size_t size = fRectCount * 2 * sizeof(SkRegion::RunType); | |
| 95 SkRegion::RunType* row = (SkRegion::RunType*)fAlloc.allocThrow(size); | |
| 96 SkRegion::RunType* rowHead = row; | |
| 97 | |
| 98 SkRegion::RunType nextY = SkRegion::kRunTypeSentinel; | |
| 99 int winding = edge->fWinding; | |
| 100 | |
| 101 // record the L R values for this row | |
| 102 | |
| 103 if (edge->fTop > currY) { | |
| 104 nextY = SkMin32(nextY, edge->fTop); | |
| 105 TRACE_ROW(SkDebugf("Y %d\n", currY);) | |
| 106 } else { | |
| 107 SkRegion::RunType currR; | |
| 108 *row++ = edge->fX; | |
| 109 TRACE_ROW(SkDebugf("Y %d [%d", currY, edge->fX);) | |
| 110 edge = edge->fNext; | |
| 111 for (;;) { | |
| 112 if (edge->fTop > currY) { | |
| 113 nextY = SkMin32(nextY, edge->fTop); | |
| 114 break; | |
| 115 } | |
| 116 | |
| 117 int prevWinding = winding; | |
| 118 winding += edge->fWinding; | |
| 119 if (0 == winding) { // we finished an interval | |
| 120 currR = edge->fX; | |
| 121 } else if (0 == prevWinding && edge->fX > currR) { | |
| 122 *row++ = currR; | |
| 123 *row++ = edge->fX; | |
| 124 TRACE_ROW(SkDebugf(" %d] [%d", currR, edge->fX);) | |
| 125 } | |
| 126 | |
| 127 nextY = SkMin32(nextY, edge->fBottom); | |
| 128 edge = edge->fNext; | |
| 129 } | |
| 130 SkASSERT(0 == winding); | |
| 131 *row++ = currR; | |
| 132 TRACE_ROW(SkDebugf(" %d]\n", currR);) | |
| 133 } | |
| 134 int rowCount = row - rowHead; | |
| 135 | |
| 136 // now see if we have already seen this row, or if its unique | |
| 137 | |
| 138 Row* r = fRows.count() ? &fRows[fRows.count() - 1] : NULL; | |
| 139 if (r && (r->fCount == rowCount) && | |
| 140 !memcmp(r->fPtr, rowHead, | |
| 141 rowCount * sizeof(SkRegion::RunType))) { | |
| 142 r->fBottom = nextY; // update bottom | |
| 143 fAlloc.unalloc(rowHead); | |
| 144 } else { | |
| 145 Row* r = fRows.append(); | |
| 146 r->fPtr = rowHead; | |
| 147 r->fBottom = nextY; | |
| 148 r->fCount = rowCount; | |
| 149 fTotalCount += 1 + rowCount + 1; | |
| 150 } | |
| 151 | |
| 152 return nextY; | |
| 153 } | |
| 154 | |
| 155 void Accumulator::copyTo(SkRegion::RunType dst[]) { | |
| 156 SkDEBUGCODE(SkRegion::RunType* startDst = dst;) | |
| 157 | |
| 158 *dst++ = fTop; | |
| 159 | |
| 160 const Row* curr = fRows.begin(); | |
| 161 const Row* stop = fRows.end(); | |
| 162 while (curr < stop) { | |
| 163 *dst++ = curr->fBottom; | |
| 164 memcpy(dst, curr->fPtr, curr->fCount * sizeof(SkRegion::RunType)); | |
| 165 dst += curr->fCount; | |
| 166 *dst++ = SkRegion::kRunTypeSentinel; | |
| 167 curr += 1; | |
| 168 } | |
| 169 *dst++ = SkRegion::kRunTypeSentinel; | |
| 170 SkASSERT(dst - startDst == fTotalCount); | |
| 171 } | |
| 172 | |
| 173 /////////////////////////////////////////////////////////////////////////////// | |
| 174 | |
| 175 template <typename T> int SkTCmp2Int(const T& a, const T& b) { | |
| 176 return (a < b) ? -1 : ((b < a) ? 1 : 0); | |
| 177 } | |
| 178 | |
| 179 static inline int SkCmp32(int32_t a, int32_t b) { | |
| 180 return (a < b) ? -1 : ((b < a) ? 1 : 0); | |
| 181 } | |
| 182 | |
| 183 static int compare_edgeptr(const void* p0, const void* p1) { | |
| 184 const VEdge* e0 = *static_cast<VEdge*const*>(p0); | |
| 185 const VEdge* e1 = *static_cast<VEdge*const*>(p1); | |
| 186 | |
| 187 SkRegion::RunType v0 = e0->fTop; | |
| 188 SkRegion::RunType v1 = e1->fTop; | |
| 189 | |
| 190 if (v0 == v1) { | |
| 191 v0 = e0->fX; | |
| 192 v1 = e1->fX; | |
| 193 } | |
| 194 return SkCmp32(v0, v1); | |
| 195 } | |
| 196 | |
| 197 // fillout edge[] from rects[], sorted. Return the head, and set the tail | |
| 198 // | |
| 199 static VEdge* sort_edges(VEdge** edgePtr, VEdge edge[], const SkIRect rects[], | |
| 200 int rectCount, VEdge** edgeTail) { | |
| 201 int i; | |
| 202 VEdge** ptr = edgePtr; | |
| 203 for (int i = 0; i < rectCount; i++) { | |
| 204 if (!rects[i].isEmpty()) { | |
| 205 VEdge::SetFromRect(edge, rects[i]); | |
| 206 *ptr++ = edge++; | |
| 207 *ptr++ = edge++; | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 int edgeCount = ptr - edgePtr; | |
| 212 if (0 == edgeCount) { | |
| 213 // all the rects[] were empty | |
| 214 return NULL; | |
| 215 } | |
| 216 | |
| 217 qsort(edgePtr, edgeCount, sizeof(*edgePtr), compare_edgeptr); | |
| 218 for (i = 1; i < edgeCount; i++) { | |
| 219 edgePtr[i - 1]->fNext = edgePtr[i]; | |
| 220 edgePtr[i]->fPrev = edgePtr[i - 1]; | |
| 221 } | |
| 222 *edgeTail = edgePtr[edgeCount - 1]; | |
| 223 return edgePtr[0]; | |
| 224 } | |
| 225 | |
| 226 bool SkRegion::setRects(const SkIRect rects[], int rectCount) { | |
| 227 if (0 == rectCount) { | |
| 228 return this->setEmpty(); | |
| 229 } | |
| 230 if (1 == rectCount) { | |
| 231 return this->setRect(rects[0]); | |
| 232 } | |
| 233 | |
| 234 int edgeCount = rectCount * 2; | |
| 235 SkAutoMalloc memory((sizeof(VEdge) + sizeof(VEdge*)) * edgeCount); | |
| 236 VEdge** edgePtr = (VEdge**)memory.get(); | |
| 237 VEdge* tail, *head = (VEdge*)(edgePtr + edgeCount); | |
| 238 head = sort_edges(edgePtr, head, rects, rectCount, &tail); | |
| 239 // check if we have no edges | |
| 240 if (NULL == head) { | |
| 241 return this->setEmpty(); | |
| 242 } | |
| 243 | |
| 244 // at this stage, we don't really care about edgeCount, or if rectCount is | |
| 245 // larger that it should be (since sort_edges might have skipped some | |
| 246 // empty rects[]). rectCount now is just used for worst-case allocations | |
| 247 | |
| 248 VEdge headEdge, tailEdge; | |
| 249 headEdge.fPrev = NULL; | |
| 250 headEdge.fNext = head; | |
| 251 headEdge.fTop = SK_MinS32; | |
| 252 headEdge.fX = SK_MinS32; | |
| 253 head->fPrev = &headEdge; | |
| 254 | |
| 255 tailEdge.fPrev = tail; | |
| 256 tailEdge.fNext = NULL; | |
| 257 tailEdge.fTop = SK_MaxS32; | |
| 258 tail->fNext = &tailEdge; | |
| 259 | |
| 260 int32_t currY = head->fTop; | |
| 261 Accumulator accum(currY, rectCount); | |
| 262 | |
| 263 while (head->fNext) { | |
| 264 VEdge* edge = head; | |
| 265 // accumulate the current | |
| 266 SkRegion::RunType nextY = accum.append(currY, edge); | |
| 267 // remove the old | |
| 268 while (edge->fTop <= currY) { | |
| 269 VEdge* next = edge->fNext; | |
| 270 if (edge->fBottom <= nextY) { | |
| 271 edge->removeFromList(); | |
| 272 } | |
| 273 edge = next; | |
| 274 } | |
| 275 // insert (sorted) the new | |
| 276 while (edge->fTop == nextY) { | |
| 277 VEdge* next = edge->fNext; | |
| 278 edge->backwardsInsert(); | |
| 279 edge = next; | |
| 280 } | |
| 281 currY = nextY; | |
| 282 head = headEdge.fNext; | |
| 283 } | |
| 284 | |
| 285 SkAutoTArray<RunType> runs(accum.count()); | |
| 286 accum.copyTo(runs.get()); | |
| 287 return this->setRuns(runs.get(), accum.count()); | |
| 288 } | |
| 289 | |
| 290 #endif | |
| OLD | NEW |