LCOV - app.info - gfx/skia/src/core/SkRegion_path.cpp

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