Home | History | Annotate | Download | only in core
      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
    291