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