LCOV - code coverage report
Current view: directory - gfx/skia/src/core - SkRegion_path.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 237 0 0.0 %
Date: 2012-06-02 Functions: 20 0 0.0 %

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

Generated by: LCOV version 1.7