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