LCOV - code coverage report
Current view: directory - gfx/skia/src/core - SkRegion.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 703 0 0.0 %
Date: 2012-06-02 Functions: 58 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 "SkTemplates.h"
      12                 : #include "SkThread.h"
      13                 : 
      14                 : SkDEBUGCODE(int32_t gRgnAllocCounter;)
      15                 : 
      16                 : /////////////////////////////////////////////////////////////////////////////////////////////////
      17                 : 
      18                 : /*  Pass in a scanline, beginning with the Left value of the pair (i.e. not the Y beginning)
      19                 : */
      20               0 : static SkRegion::RunType* skip_scanline(const SkRegion::RunType runs[])
      21                 : {
      22               0 :     while (runs[0] != SkRegion::kRunTypeSentinel)
      23                 :     {
      24               0 :         SkASSERT(runs[0] < runs[1]);    // valid span
      25               0 :         runs += 2;
      26                 :     }
      27               0 :     return (SkRegion::RunType*)(runs + 1);  // return past the X-sentinel
      28                 : }
      29                 : 
      30                 : // returns true if runs are just a rect
      31               0 : bool SkRegion::ComputeRunBounds(const SkRegion::RunType runs[], int count, SkIRect* bounds)
      32                 : {
      33               0 :     assert_sentinel(runs[0], false);    // top
      34                 : 
      35               0 :     if (count == kRectRegionRuns)
      36                 :     {
      37               0 :         assert_sentinel(runs[1], false);    // bottom
      38               0 :         assert_sentinel(runs[2], false);    // left
      39               0 :         assert_sentinel(runs[3], false);    // right
      40               0 :         assert_sentinel(runs[4], true);
      41               0 :         assert_sentinel(runs[5], true);
      42                 : 
      43               0 :         SkASSERT(runs[0] < runs[1]);    // valid height
      44               0 :         SkASSERT(runs[2] < runs[3]);    // valid width
      45                 : 
      46               0 :         bounds->set(runs[2], runs[0], runs[3], runs[1]);
      47               0 :         return true;
      48                 :     }
      49                 : 
      50               0 :     int left = SK_MaxS32;
      51               0 :     int rite = SK_MinS32;
      52                 :     int bot;
      53                 : 
      54               0 :     bounds->fTop = *runs++;
      55               0 :     do {
      56               0 :         bot = *runs++;
      57               0 :         if (*runs < SkRegion::kRunTypeSentinel)
      58                 :         {
      59               0 :             if (left > *runs)
      60               0 :                 left = *runs;
      61               0 :             runs = skip_scanline(runs);
      62               0 :             if (rite < runs[-2])
      63               0 :                 rite = runs[-2];
      64                 :         }
      65                 :         else
      66               0 :             runs += 1;  // skip X-sentinel
      67               0 :     } while (runs[0] < SkRegion::kRunTypeSentinel);
      68               0 :     bounds->fLeft = left;
      69               0 :     bounds->fRight = rite;
      70               0 :     bounds->fBottom = bot;
      71               0 :     return false;
      72                 : }
      73                 : 
      74                 : //////////////////////////////////////////////////////////////////////////
      75                 : 
      76               0 : SkRegion::SkRegion() {
      77               0 :     fBounds.set(0, 0, 0, 0);
      78               0 :     fRunHead = SkRegion_gEmptyRunHeadPtr;
      79               0 : }
      80                 : 
      81               0 : SkRegion::SkRegion(const SkRegion& src) {
      82               0 :     fRunHead = SkRegion_gEmptyRunHeadPtr;   // just need a value that won't trigger sk_free(fRunHead)
      83               0 :     this->setRegion(src);
      84               0 : }
      85                 : 
      86               0 : SkRegion::SkRegion(const SkIRect& rect) {
      87               0 :     fRunHead = SkRegion_gEmptyRunHeadPtr;   // just need a value that won't trigger sk_free(fRunHead)
      88               0 :     this->setRect(rect);
      89               0 : }
      90                 : 
      91               0 : SkRegion::~SkRegion() {
      92               0 :     this->freeRuns();
      93               0 : }
      94                 : 
      95               0 : void SkRegion::freeRuns() {
      96               0 :     if (fRunHead->isComplex()) {
      97               0 :         SkASSERT(fRunHead->fRefCnt >= 1);
      98               0 :         if (sk_atomic_dec(&fRunHead->fRefCnt) == 1) {
      99                 :             //SkASSERT(gRgnAllocCounter > 0);
     100                 :             //SkDEBUGCODE(sk_atomic_dec(&gRgnAllocCounter));
     101                 :             //SkDEBUGF(("************** gRgnAllocCounter::free %d\n", gRgnAllocCounter));
     102               0 :             sk_free(fRunHead);
     103                 :         }
     104                 :     }
     105               0 : }
     106                 : 
     107               0 : void SkRegion::allocateRuns(int count) {
     108               0 :     fRunHead = RunHead::Alloc(count);
     109               0 : }
     110                 : 
     111               0 : SkRegion& SkRegion::operator=(const SkRegion& src) {
     112               0 :     (void)this->setRegion(src);
     113               0 :     return *this;
     114                 : }
     115                 : 
     116               0 : void SkRegion::swap(SkRegion& other) {
     117               0 :     SkTSwap<SkIRect>(fBounds, other.fBounds);
     118               0 :     SkTSwap<RunHead*>(fRunHead, other.fRunHead);
     119               0 : }
     120                 : 
     121               0 : bool SkRegion::setEmpty() {
     122               0 :     this->freeRuns();
     123               0 :     fBounds.set(0, 0, 0, 0);
     124               0 :     fRunHead = SkRegion_gEmptyRunHeadPtr;
     125               0 :     return false;
     126                 : }
     127                 : 
     128               0 : bool SkRegion::setRect(int32_t left, int32_t top,
     129                 :                        int32_t right, int32_t bottom) {
     130               0 :     if (left >= right || top >= bottom) {
     131               0 :         return this->setEmpty();
     132                 :     }
     133               0 :     this->freeRuns();
     134               0 :     fBounds.set(left, top, right, bottom);
     135               0 :     fRunHead = SkRegion_gRectRunHeadPtr;
     136               0 :     return true;
     137                 : }
     138                 : 
     139               0 : bool SkRegion::setRect(const SkIRect& r) {
     140               0 :     return this->setRect(r.fLeft, r.fTop, r.fRight, r.fBottom);
     141                 : }
     142                 : 
     143               0 : bool SkRegion::setRegion(const SkRegion& src) {
     144               0 :     if (this != &src) {
     145               0 :         this->freeRuns();
     146                 : 
     147               0 :         fBounds = src.fBounds;
     148               0 :         fRunHead = src.fRunHead;
     149               0 :         if (fRunHead->isComplex()) {
     150               0 :             sk_atomic_inc(&fRunHead->fRefCnt);
     151                 :         }
     152                 :     }
     153               0 :     return fRunHead != SkRegion_gEmptyRunHeadPtr;
     154                 : }
     155                 : 
     156               0 : bool SkRegion::op(const SkIRect& rect, const SkRegion& rgn, Op op) {
     157               0 :     SkRegion tmp(rect);
     158                 : 
     159               0 :     return this->op(tmp, rgn, op);
     160                 : }
     161                 : 
     162               0 : bool SkRegion::op(const SkRegion& rgn, const SkIRect& rect, Op op) {
     163               0 :     SkRegion tmp(rect);
     164                 : 
     165               0 :     return this->op(rgn, tmp, op);
     166                 : }
     167                 : 
     168                 : ///////////////////////////////////////////////////////////////////////////////
     169                 : 
     170                 : #ifdef SK_BUILD_FOR_ANDROID
     171                 : char* SkRegion::toString()
     172                 : {
     173                 :     Iterator iter(*this);
     174                 :     int count = 0;
     175                 :     while (!iter.done()) {
     176                 :         count++;
     177                 :         iter.next();
     178                 :     }
     179                 :     // 4 ints, up to 10 digits each plus sign, 3 commas, '(', ')', SkRegion() and '\0'
     180                 :     const int max = (count*((11*4)+5))+11+1;
     181                 :     char* result = (char*)malloc(max);
     182                 :     if (result == NULL) {
     183                 :         return NULL;
     184                 :     }
     185                 :     count = sprintf(result, "SkRegion(");
     186                 :     iter.reset(*this);
     187                 :     while (!iter.done()) {
     188                 :         const SkIRect& r = iter.rect();
     189                 :         count += sprintf(result+count, "(%d,%d,%d,%d)", r.fLeft, r.fTop, r.fRight, r.fBottom);
     190                 :         iter.next();
     191                 :     }
     192                 :     count += sprintf(result+count, ")");
     193                 :     return result;
     194                 : }
     195                 : #endif
     196                 : 
     197                 : //////////////////////////////////////////////////////////////////////////////////////
     198                 : 
     199               0 : int SkRegion::count_runtype_values(int* itop, int* ibot) const
     200                 : {
     201               0 :     if (this == NULL)
     202                 :     {
     203               0 :         *itop = SK_MinS32;
     204               0 :         *ibot = SK_MaxS32;
     205               0 :         return 0;
     206                 :     }
     207                 : 
     208                 :     int maxT;
     209                 : 
     210               0 :     if (this->isRect())
     211               0 :         maxT = 2;
     212                 :     else
     213                 :     {
     214               0 :         SkASSERT(this->isComplex());
     215                 :         // skip the top
     216               0 :         const RunType*  runs = fRunHead->readonly_runs() + 1;
     217               0 :         maxT = 0;
     218                 : 
     219               0 :         do {
     220               0 :             const RunType* next = skip_scanline(runs + 1);
     221               0 :             SkASSERT(next > runs);
     222               0 :             int         T = (int)(next - runs - 1);
     223               0 :             if (maxT < T)
     224               0 :                 maxT = T;
     225               0 :             runs = next;
     226               0 :         } while (runs[0] < SkRegion::kRunTypeSentinel);
     227                 :     }
     228               0 :     *itop = fBounds.fTop;
     229               0 :     *ibot = fBounds.fBottom;
     230               0 :     return maxT;
     231                 : }
     232                 : 
     233               0 : bool SkRegion::setRuns(RunType runs[], int count)
     234                 : {
     235               0 :     SkDEBUGCODE(this->validate();)
     236               0 :     SkASSERT(count > 0);
     237                 : 
     238               0 :     if (count <= 2)
     239                 :     {
     240                 :     //  SkDEBUGF(("setRuns: empty\n"));
     241               0 :         assert_sentinel(runs[count-1], true);
     242               0 :         return this->setEmpty();
     243                 :     }
     244                 : 
     245                 :     // trim off any empty spans from the top and bottom
     246                 :     // weird I should need this, perhaps op() could be smarter...
     247               0 :     if (count > kRectRegionRuns)
     248                 :     {
     249               0 :         RunType* stop = runs + count;
     250               0 :         assert_sentinel(runs[0], false);    // top
     251               0 :         assert_sentinel(runs[1], false);    // bottom
     252               0 :         if (runs[2] == SkRegion::kRunTypeSentinel)    // should be first left...
     253                 :         {
     254               0 :             runs += 2;  // skip empty initial span
     255               0 :             runs[0] = runs[-1]; // set new top to prev bottom
     256               0 :             assert_sentinel(runs[1], false);    // bot: a sentinal would mean two in a row
     257               0 :             assert_sentinel(runs[2], false);    // left
     258               0 :             assert_sentinel(runs[3], false);    // right
     259                 :         }
     260                 : 
     261                 :         // now check for a trailing empty span
     262               0 :         assert_sentinel(stop[-1], true);
     263               0 :         assert_sentinel(stop[-2], true);
     264               0 :         assert_sentinel(stop[-3], false);   // should be last right
     265               0 :         if (stop[-4] == SkRegion::kRunTypeSentinel)   // eek, stop[-3] was a bottom with no x-runs
     266                 :         {
     267               0 :             stop[-3] = SkRegion::kRunTypeSentinel;    // kill empty last span
     268               0 :             stop -= 2;
     269               0 :             assert_sentinel(stop[-1], true);
     270               0 :             assert_sentinel(stop[-2], true);
     271               0 :             assert_sentinel(stop[-3], false);
     272               0 :             assert_sentinel(stop[-4], false);
     273               0 :             assert_sentinel(stop[-5], false);
     274                 :         }
     275               0 :         count = (int)(stop - runs);
     276                 :     }
     277                 : 
     278               0 :     SkASSERT(count >= kRectRegionRuns);
     279                 : 
     280               0 :     if (ComputeRunBounds(runs, count, &fBounds))
     281                 :     {
     282                 :     //  SkDEBUGF(("setRuns: rect[%d %d %d %d]\n", fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom));
     283               0 :         return this->setRect(fBounds);
     284                 :     }
     285                 : 
     286                 :     //  if we get here, we need to become a complex region
     287                 : 
     288               0 :     if (!fRunHead->isComplex() || fRunHead->fRunCount != count)
     289                 :     {
     290                 : #ifdef SK_DEBUGx
     291                 :         SkDebugf("setRuns: rgn [");
     292                 :         {
     293                 :             const RunType* r = runs;
     294                 : 
     295                 :             SkDebugf(" top: %d\n", *r++);
     296                 :             while (*r < SkRegion::kRunTypeSentinel)
     297                 :             {
     298                 :                 SkDebugf(" bottom: %d", *r++);
     299                 :                 while (*r < SkRegion::kRunTypeSentinel)
     300                 :                 {
     301                 :                     SkDebugf(" [%d %d]", r[0], r[1]);
     302                 :                     r += 2;
     303                 :                 }
     304                 :                 SkDebugf("\n");
     305                 :             }
     306                 :         }
     307                 : #endif
     308               0 :         this->freeRuns();
     309               0 :         this->allocateRuns(count);
     310                 :     }
     311                 :     
     312                 :     // must call this before we can write directly into runs()
     313                 :     // in case we are sharing the buffer with another region (copy on write)
     314               0 :     fRunHead = fRunHead->ensureWritable();
     315               0 :     memcpy(fRunHead->writable_runs(), runs, count * sizeof(RunType));
     316                 : 
     317               0 :     SkDEBUGCODE(this->validate();)
     318                 : 
     319               0 :     return true;
     320                 : }
     321                 : 
     322               0 : void SkRegion::BuildRectRuns(const SkIRect& bounds,
     323                 :                              RunType runs[kRectRegionRuns])
     324                 : {
     325               0 :     runs[0] = bounds.fTop;
     326               0 :     runs[1] = bounds.fBottom;
     327               0 :     runs[2] = bounds.fLeft;
     328               0 :     runs[3] = bounds.fRight;
     329               0 :     runs[4] = kRunTypeSentinel;
     330               0 :     runs[5] = kRunTypeSentinel;
     331               0 : }
     332                 : 
     333               0 : static SkRegion::RunType* find_scanline(const SkRegion::RunType runs[], int y)
     334                 : {
     335               0 :     SkASSERT(y >= runs[0]); // if this fails, we didn't do a quick check on the boudns
     336                 : 
     337               0 :     runs += 1;  // skip top-Y
     338               0 :     for (;;)
     339                 :     {
     340               0 :         if (runs[0] == SkRegion::kRunTypeSentinel)
     341                 :             break;
     342               0 :         if (y < runs[0])
     343               0 :             return (SkRegion::RunType*)&runs[1];
     344               0 :         runs = skip_scanline(runs + 1); // skip the Y value before calling
     345                 :     }
     346               0 :     return NULL;
     347                 : }
     348                 : 
     349               0 : bool SkRegion::contains(int32_t x, int32_t y) const
     350                 : {
     351               0 :     if (!fBounds.contains(x, y))
     352               0 :         return false;
     353                 : 
     354               0 :     if (this->isRect())
     355               0 :         return true;
     356                 : 
     357               0 :     SkASSERT(this->isComplex());
     358               0 :     const RunType* runs = find_scanline(fRunHead->readonly_runs(), y);
     359                 : 
     360               0 :     if (runs)
     361               0 :     {   for (;;)
     362               0 :         {   if (x < runs[0])
     363                 :                 break;
     364               0 :             if (x < runs[1])
     365               0 :                 return true;
     366               0 :             runs += 2;
     367                 :         }
     368                 :     }
     369               0 :     return false;
     370                 : }
     371                 : 
     372               0 : bool SkRegion::contains(const SkIRect& r) const
     373                 : {
     374               0 :     SkRegion tmp(r);
     375                 :     
     376               0 :     return this->contains(tmp);
     377                 : }
     378                 : 
     379               0 : bool SkRegion::contains(const SkRegion& rgn) const
     380                 : {
     381               0 :     if (this->isEmpty() || rgn.isEmpty() || !fBounds.contains(rgn.fBounds))
     382               0 :         return false;
     383                 : 
     384               0 :     if (this->isRect())
     385               0 :         return true;
     386                 : 
     387               0 :     SkRegion    tmp;
     388                 :     
     389               0 :     tmp.op(*this, rgn, kUnion_Op);
     390               0 :     return tmp == *this;
     391                 : }
     392                 : 
     393               0 : const SkRegion::RunType* SkRegion::getRuns(RunType tmpStorage[], int* count) const
     394                 : {
     395               0 :     SkASSERT(tmpStorage && count);
     396               0 :     const RunType* runs = tmpStorage;
     397                 : 
     398               0 :     if (this->isEmpty())
     399                 :     {
     400               0 :         tmpStorage[0] = kRunTypeSentinel;
     401               0 :         *count = 1;
     402                 :     }
     403               0 :     else if (this->isRect())
     404                 :     {
     405               0 :         BuildRectRuns(fBounds, tmpStorage);
     406               0 :         *count = kRectRegionRuns;
     407                 :     }
     408                 :     else
     409                 :     {
     410               0 :         *count = fRunHead->fRunCount;
     411               0 :         runs = fRunHead->readonly_runs();
     412                 :     }
     413               0 :     return runs;
     414                 : }
     415                 : 
     416                 : /////////////////////////////////////////////////////////////////////////////////////
     417                 : 
     418               0 : bool SkRegion::intersects(const SkIRect& r) const {
     419               0 :     if (this->isEmpty() || r.isEmpty()) {
     420               0 :         return false;
     421                 :     }
     422                 :     
     423               0 :     if (!SkIRect::Intersects(fBounds, r)) {
     424               0 :         return false;
     425                 :     }
     426                 : 
     427               0 :     if (this->isRect()) {
     428               0 :         return true;
     429                 :     }
     430                 :     
     431                 :     // we are complex
     432               0 :     SkRegion tmp;
     433               0 :     return tmp.op(*this, r, kIntersect_Op);
     434                 : }
     435                 : 
     436               0 : bool SkRegion::intersects(const SkRegion& rgn) const {
     437               0 :     if (this->isEmpty() || rgn.isEmpty()) {
     438               0 :         return false;
     439                 :     }
     440                 :     
     441               0 :     if (!SkIRect::Intersects(fBounds, rgn.fBounds)) {
     442               0 :         return false;
     443                 :     }
     444                 :     
     445               0 :     if (this->isRect() && rgn.isRect()) {
     446               0 :         return true;
     447                 :     }
     448                 :     
     449                 :     // one or both of us is complex
     450                 :     // TODO: write a faster version that aborts as soon as we write the first
     451                 :     //       non-empty span, to avoid build the entire result
     452               0 :     SkRegion tmp;
     453               0 :     return tmp.op(*this, rgn, kIntersect_Op);
     454                 : }
     455                 : 
     456                 : /////////////////////////////////////////////////////////////////////////////////////
     457                 : 
     458               0 : bool operator==(const SkRegion& a, const SkRegion& b) {
     459               0 :     SkDEBUGCODE(a.validate();)
     460               0 :     SkDEBUGCODE(b.validate();)
     461                 : 
     462               0 :     if (&a == &b) {
     463               0 :         return true;
     464                 :     }
     465               0 :     if (a.fBounds != b.fBounds) {
     466               0 :         return false;
     467                 :     }
     468                 :     
     469               0 :     const SkRegion::RunHead* ah = a.fRunHead;
     470               0 :     const SkRegion::RunHead* bh = b.fRunHead;
     471                 : 
     472                 :     // this catches empties and rects being equal
     473               0 :     if (ah == bh) {
     474               0 :         return true;
     475                 :     }
     476                 :     // now we insist that both are complex (but different ptrs)
     477               0 :     if (!ah->isComplex() || !bh->isComplex()) {
     478               0 :         return false;
     479                 :     }
     480                 :     return  ah->fRunCount == bh->fRunCount &&
     481               0 :             !memcmp(ah->readonly_runs(), bh->readonly_runs(),
     482               0 :                     ah->fRunCount * sizeof(SkRegion::RunType));
     483                 : }
     484                 : 
     485               0 : void SkRegion::translate(int dx, int dy, SkRegion* dst) const {
     486               0 :     SkDEBUGCODE(this->validate();)
     487                 : 
     488               0 :     if (NULL == dst) {
     489               0 :         return;
     490                 :     }
     491               0 :     if (this->isEmpty()) {
     492               0 :         dst->setEmpty();
     493               0 :     } else if (this->isRect()) {
     494                 :         dst->setRect(fBounds.fLeft + dx, fBounds.fTop + dy,
     495               0 :                      fBounds.fRight + dx, fBounds.fBottom + dy);
     496                 :     } else {
     497               0 :         if (this == dst) {
     498               0 :             dst->fRunHead = dst->fRunHead->ensureWritable();
     499                 :         } else {
     500               0 :             SkRegion    tmp;
     501               0 :             tmp.allocateRuns(fRunHead->fRunCount);
     502               0 :             tmp.fBounds = fBounds;
     503               0 :             dst->swap(tmp);
     504                 :         }
     505                 : 
     506               0 :         dst->fBounds.offset(dx, dy);
     507                 :         
     508               0 :         const RunType*  sruns = fRunHead->readonly_runs();
     509               0 :         RunType*        druns = dst->fRunHead->writable_runs();
     510                 : 
     511               0 :         *druns++ = (SkRegion::RunType)(*sruns++ + dy);    // top
     512               0 :         for (;;) {
     513               0 :             int bottom = *sruns++;
     514               0 :             if (bottom == kRunTypeSentinel) {
     515                 :                 break;
     516                 :             }
     517               0 :             *druns++ = (SkRegion::RunType)(bottom + dy);  // bottom;
     518               0 :             for (;;) {
     519               0 :                 int x = *sruns++;
     520               0 :                 if (x == kRunTypeSentinel) {
     521                 :                     break;
     522                 :                 }
     523               0 :                 *druns++ = (SkRegion::RunType)(x + dx);
     524               0 :                 *druns++ = (SkRegion::RunType)(*sruns++ + dx);
     525                 :             }
     526               0 :             *druns++ = kRunTypeSentinel;    // x sentinel
     527                 :         }
     528               0 :         *druns++ = kRunTypeSentinel;    // y sentinel
     529                 : 
     530               0 :         SkASSERT(sruns - fRunHead->readonly_runs() == fRunHead->fRunCount);
     531               0 :         SkASSERT(druns - dst->fRunHead->readonly_runs() == dst->fRunHead->fRunCount);
     532                 :     }
     533                 : 
     534               0 :     SkDEBUGCODE(this->validate();)
     535                 : }
     536                 : 
     537                 : ///////////////////////////////////////////////////////////////////////////////
     538                 : 
     539               0 : bool SkRegion::setRects(const SkIRect rects[], int count) {
     540               0 :     if (0 == count) {
     541               0 :         this->setEmpty();
     542                 :     } else {
     543               0 :         this->setRect(rects[0]);
     544               0 :         for (int i = 1; i < count; i++) {
     545               0 :             this->op(rects[i], kUnion_Op);
     546                 :         }
     547                 :     }
     548               0 :     return !this->isEmpty();
     549                 : }
     550                 : 
     551                 : ///////////////////////////////////////////////////////////////////////////////
     552                 : 
     553                 : #if defined _WIN32 && _MSC_VER >= 1300  // disable warning : local variable used without having been initialized
     554                 : #pragma warning ( push )
     555                 : #pragma warning ( disable : 4701 )
     556                 : #endif
     557                 : 
     558                 : #ifdef SK_DEBUG
     559               0 : static void assert_valid_pair(int left, int rite)
     560                 : {
     561               0 :     SkASSERT(left == SkRegion::kRunTypeSentinel || left < rite);
     562               0 : }
     563                 : #else
     564                 :     #define assert_valid_pair(left, rite)
     565                 : #endif
     566                 : 
     567                 : struct spanRec {
     568                 :     const SkRegion::RunType*    fA_runs;
     569                 :     const SkRegion::RunType*    fB_runs;
     570                 :     int                         fA_left, fA_rite, fB_left, fB_rite;
     571                 :     int                         fLeft, fRite, fInside;
     572                 :     
     573               0 :     void init(const SkRegion::RunType a_runs[], const SkRegion::RunType b_runs[])
     574                 :     {        
     575               0 :         fA_left = *a_runs++;
     576               0 :         fA_rite = *a_runs++;
     577               0 :         fB_left = *b_runs++;
     578               0 :         fB_rite = *b_runs++;
     579                 : 
     580               0 :         fA_runs = a_runs;
     581               0 :         fB_runs = b_runs;
     582               0 :     }
     583                 :     
     584               0 :     bool done() const
     585                 :     {
     586                 :         SkASSERT(fA_left <= SkRegion::kRunTypeSentinel);
     587                 :         SkASSERT(fB_left <= SkRegion::kRunTypeSentinel);
     588               0 :         return fA_left == SkRegion::kRunTypeSentinel && fB_left == SkRegion::kRunTypeSentinel;
     589                 :     }
     590                 : 
     591               0 :     void next()
     592                 :     {
     593               0 :         assert_valid_pair(fA_left, fA_rite);
     594               0 :         assert_valid_pair(fB_left, fB_rite);
     595                 : 
     596               0 :         int     inside, left, rite SK_INIT_TO_AVOID_WARNING;
     597               0 :         bool    a_flush = false;
     598               0 :         bool    b_flush = false;
     599                 :         
     600               0 :         int a_left = fA_left;
     601               0 :         int a_rite = fA_rite;
     602               0 :         int b_left = fB_left;
     603               0 :         int b_rite = fB_rite;
     604                 : 
     605               0 :         if (a_left < b_left)
     606                 :         {
     607               0 :             inside = 1;
     608               0 :             left = a_left;
     609               0 :             if (a_rite <= b_left)   // [...] <...>
     610                 :             {
     611               0 :                 rite = a_rite;
     612               0 :                 a_flush = true;
     613                 :             }
     614                 :             else // [...<..]...> or [...<...>...]
     615               0 :                 rite = a_left = b_left;
     616                 :         }
     617               0 :         else if (b_left < a_left)
     618                 :         {
     619               0 :             inside = 2;
     620               0 :             left = b_left;
     621               0 :             if (b_rite <= a_left)   // [...] <...>
     622                 :             {
     623               0 :                 rite = b_rite;
     624               0 :                 b_flush = true;
     625                 :             }
     626                 :             else // [...<..]...> or [...<...>...]
     627               0 :                 rite = b_left = a_left;
     628                 :         }
     629                 :         else    // a_left == b_left
     630                 :         {
     631               0 :             inside = 3;
     632               0 :             left = a_left;  // or b_left
     633               0 :             if (a_rite <= b_rite)
     634                 :             {
     635               0 :                 rite = b_left = a_rite;
     636               0 :                 a_flush = true;
     637                 :             }
     638               0 :             if (b_rite <= a_rite)
     639                 :             {
     640               0 :                 rite = a_left = b_rite;
     641               0 :                 b_flush = true;
     642                 :             }
     643                 :         }
     644                 : 
     645               0 :         if (a_flush)
     646                 :         {
     647               0 :             a_left = *fA_runs++;
     648               0 :             a_rite = *fA_runs++;
     649                 :         }
     650               0 :         if (b_flush)
     651                 :         {
     652               0 :             b_left = *fB_runs++;
     653               0 :             b_rite = *fB_runs++;
     654                 :         }
     655                 : 
     656               0 :         SkASSERT(left <= rite);
     657                 :         
     658                 :         // now update our state
     659               0 :         fA_left = a_left;
     660               0 :         fA_rite = a_rite;
     661               0 :         fB_left = b_left;
     662               0 :         fB_rite = b_rite;
     663                 :         
     664               0 :         fLeft = left;
     665               0 :         fRite = rite;
     666               0 :         fInside = inside;
     667               0 :     }
     668                 : };
     669                 : 
     670               0 : static SkRegion::RunType* operate_on_span(const SkRegion::RunType a_runs[],
     671                 :                                           const SkRegion::RunType b_runs[],
     672                 :                                           SkRegion::RunType dst[],
     673                 :                                           int min, int max)
     674                 : {
     675                 :     spanRec rec;
     676               0 :     bool    firstInterval = true;
     677                 :     
     678               0 :     rec.init(a_runs, b_runs);
     679                 : 
     680               0 :     while (!rec.done())
     681                 :     {
     682               0 :         rec.next();
     683                 :         
     684               0 :         int left = rec.fLeft;
     685               0 :         int rite = rec.fRite;
     686                 :         
     687                 :         // add left,rite to our dst buffer (checking for coincidence
     688               0 :         if ((unsigned)(rec.fInside - min) <= (unsigned)(max - min) &&
     689                 :             left < rite)    // skip if equal
     690                 :         {
     691               0 :             if (firstInterval || dst[-1] < left)
     692                 :             {
     693               0 :                 *dst++ = (SkRegion::RunType)(left);
     694               0 :                 *dst++ = (SkRegion::RunType)(rite);
     695               0 :                 firstInterval = false;
     696                 :             }
     697                 :             else    // update the right edge
     698               0 :                 dst[-1] = (SkRegion::RunType)(rite);
     699                 :         }
     700                 :     }
     701                 : 
     702               0 :     *dst++ = SkRegion::kRunTypeSentinel;
     703               0 :     return dst;
     704                 : }
     705                 : 
     706                 : #if defined _WIN32 && _MSC_VER >= 1300
     707                 : #pragma warning ( pop )
     708                 : #endif
     709                 : 
     710                 : static const struct {
     711                 :     uint8_t fMin;
     712                 :     uint8_t fMax;
     713                 : } gOpMinMax[] = {
     714                 :     { 1, 1 },   // Difference
     715                 :     { 3, 3 },   // Intersection
     716                 :     { 1, 3 },   // Union
     717                 :     { 1, 2 }    // XOR
     718                 : };
     719                 : 
     720                 : class RgnOper {
     721                 : public:
     722               0 :     RgnOper(int top, SkRegion::RunType dst[], SkRegion::Op op)
     723                 :     {
     724                 :         // need to ensure that the op enum lines up with our minmax array
     725                 :         SkASSERT(SkRegion::kDifference_Op == 0);
     726                 :         SkASSERT(SkRegion::kIntersect_Op == 1);
     727                 :         SkASSERT(SkRegion::kUnion_Op == 2);
     728                 :         SkASSERT(SkRegion::kXOR_Op == 3);
     729               0 :         SkASSERT((unsigned)op <= 3);
     730                 : 
     731               0 :         fStartDst = dst;
     732               0 :         fPrevDst = dst + 1;
     733               0 :         fPrevLen = 0;       // will never match a length from operate_on_span
     734               0 :         fTop = (SkRegion::RunType)(top);    // just a first guess, we might update this
     735                 : 
     736               0 :         fMin = gOpMinMax[op].fMin;
     737               0 :         fMax = gOpMinMax[op].fMax;
     738               0 :     }
     739                 : 
     740               0 :     void addSpan(int bottom, const SkRegion::RunType a_runs[], const SkRegion::RunType b_runs[])
     741                 :     {
     742               0 :         SkRegion::RunType*  start = fPrevDst + fPrevLen + 1;    // skip X values and slot for the next Y
     743               0 :         SkRegion::RunType*  stop = operate_on_span(a_runs, b_runs, start, fMin, fMax);
     744               0 :         size_t              len = stop - start;
     745                 : 
     746               0 :         if (fPrevLen == len && !memcmp(fPrevDst, start, len * sizeof(SkRegion::RunType)))   // update Y value
     747               0 :             fPrevDst[-1] = (SkRegion::RunType)(bottom);
     748                 :         else    // accept the new span
     749                 :         {
     750               0 :             if (len == 1 && fPrevLen == 0) {
     751               0 :                 fTop = (SkRegion::RunType)(bottom); // just update our bottom
     752                 :             } else {
     753               0 :                 start[-1] = (SkRegion::RunType)(bottom);
     754               0 :                 fPrevDst = start;
     755               0 :                 fPrevLen = len;
     756                 :             }
     757                 :         }
     758               0 :     }
     759                 :     
     760               0 :     int flush()
     761                 :     {
     762               0 :         fStartDst[0] = fTop;
     763               0 :         fPrevDst[fPrevLen] = SkRegion::kRunTypeSentinel;
     764               0 :         return (int)(fPrevDst - fStartDst + fPrevLen + 1);
     765                 :     }
     766                 : 
     767                 :     uint8_t fMin, fMax;
     768                 : 
     769                 : private:
     770                 :     SkRegion::RunType*  fStartDst;
     771                 :     SkRegion::RunType*  fPrevDst;
     772                 :     size_t              fPrevLen;
     773                 :     SkRegion::RunType   fTop;
     774                 : };
     775                 : 
     776               0 : static int operate(const SkRegion::RunType a_runs[],
     777                 :                    const SkRegion::RunType b_runs[],
     778                 :                    SkRegion::RunType dst[],
     779                 :                    SkRegion::Op op) {
     780                 :     const SkRegion::RunType gSentinel[] = {
     781                 :         SkRegion::kRunTypeSentinel,
     782                 :         // just need a 2nd value, since spanRec.init() reads 2 values, even
     783                 :         // though if the first value is the sentinel, it ignores the 2nd value.
     784                 :         // w/o the 2nd value here, we might read uninitialized memory.
     785                 :         0,
     786               0 :     };
     787                 : 
     788               0 :     int a_top = *a_runs++;
     789               0 :     int a_bot = *a_runs++;
     790               0 :     int b_top = *b_runs++;
     791               0 :     int b_bot = *b_runs++;
     792                 : 
     793               0 :     assert_sentinel(a_top, false);
     794               0 :     assert_sentinel(a_bot, false);
     795               0 :     assert_sentinel(b_top, false);
     796               0 :     assert_sentinel(b_bot, false);
     797                 : 
     798               0 :     RgnOper oper(SkMin32(a_top, b_top), dst, op);
     799                 :     
     800               0 :     bool firstInterval = true;
     801               0 :     int prevBot = SkRegion::kRunTypeSentinel; // so we fail the first test
     802                 :     
     803               0 :     while (a_bot < SkRegion::kRunTypeSentinel ||
     804                 :            b_bot < SkRegion::kRunTypeSentinel) {
     805               0 :         int                         top, bot SK_INIT_TO_AVOID_WARNING;
     806               0 :         const SkRegion::RunType*    run0 = gSentinel;
     807               0 :         const SkRegion::RunType*    run1 = gSentinel;
     808               0 :         bool                        a_flush = false;
     809               0 :         bool                        b_flush = false;
     810                 : 
     811               0 :         if (a_top < b_top) {
     812               0 :             top = a_top;
     813               0 :             run0 = a_runs;
     814               0 :             if (a_bot <= b_top) {   // [...] <...>
     815               0 :                 bot = a_bot;
     816               0 :                 a_flush = true;
     817                 :             } else {  // [...<..]...> or [...<...>...]
     818               0 :                 bot = a_top = b_top;
     819                 :             }
     820               0 :         } else if (b_top < a_top) {
     821               0 :             top = b_top;
     822               0 :             run1 = b_runs;
     823               0 :             if (b_bot <= a_top) {   // [...] <...>
     824               0 :                 bot = b_bot;
     825               0 :                 b_flush = true;
     826                 :             } else {    // [...<..]...> or [...<...>...]
     827               0 :                 bot = b_top = a_top;
     828                 :             }
     829                 :         } else {    // a_top == b_top
     830               0 :             top = a_top;    // or b_top
     831               0 :             run0 = a_runs;
     832               0 :             run1 = b_runs;
     833               0 :             if (a_bot <= b_bot) {
     834               0 :                 bot = b_top = a_bot;
     835               0 :                 a_flush = true;
     836                 :             }
     837               0 :             if (b_bot <= a_bot) {
     838               0 :                 bot = a_top = b_bot;
     839               0 :                 b_flush = true;
     840                 :             }
     841                 :         }
     842                 :         
     843               0 :         if (top > prevBot) {
     844               0 :             oper.addSpan(top, gSentinel, gSentinel);
     845                 :         }
     846               0 :         oper.addSpan(bot, run0, run1);
     847               0 :         firstInterval = false;
     848                 : 
     849               0 :         if (a_flush) {
     850               0 :             a_runs = skip_scanline(a_runs);
     851               0 :             a_top = a_bot;
     852               0 :             a_bot = *a_runs++;
     853               0 :             if (a_bot == SkRegion::kRunTypeSentinel) {
     854               0 :                 a_top = a_bot;
     855                 :             }
     856                 :         }
     857               0 :         if (b_flush) {
     858               0 :             b_runs = skip_scanline(b_runs);
     859               0 :             b_top = b_bot;
     860               0 :             b_bot = *b_runs++;
     861               0 :             if (b_bot == SkRegion::kRunTypeSentinel) {
     862               0 :                 b_top = b_bot;
     863                 :             }
     864                 :         }
     865                 :         
     866               0 :         prevBot = bot;
     867                 :     }
     868               0 :     return oper.flush();
     869                 : }
     870                 : 
     871                 : ///////////////////////////////////////////////////////////////////////////////
     872                 : 
     873                 : /*  Given count RunTypes in a complex region, return the worst case number of
     874                 :     logical intervals that represents (i.e. number of rects that would be
     875                 :     returned from the iterator).
     876                 :  
     877                 :     We could just return count/2, since there must be at least 2 values per
     878                 :     interval, but we can first trim off the const overhead of the initial TOP
     879                 :     value, plus the final BOTTOM + 2 sentinels.
     880                 :  */
     881               0 : static int count_to_intervals(int count) {
     882               0 :     SkASSERT(count >= 6);   // a single rect is 6 values
     883               0 :     return (count - 4) >> 1;
     884                 : }
     885                 : 
     886                 : /*  Given a number of intervals, what is the worst case representation of that
     887                 :     many intervals?
     888                 :  
     889                 :     Worst case (from a storage perspective), is a vertical stack of single
     890                 :     intervals:  TOP + N * (BOTTOM LEFT RIGHT SENTINEL) + SENTINEL
     891                 :  */
     892               0 : static int intervals_to_count(int intervals) {
     893               0 :     return 1 + intervals * 4 + 1;
     894                 : }
     895                 : 
     896                 : /*  Given the counts of RunTypes in two regions, return the worst-case number
     897                 :     of RunTypes need to store the result after a region-op.
     898                 :  */
     899               0 : static int compute_worst_case_count(int a_count, int b_count) {
     900               0 :     int a_intervals = count_to_intervals(a_count);
     901               0 :     int b_intervals = count_to_intervals(b_count);
     902                 :     // Our heuristic worst case is ai * (bi + 1) + bi * (ai + 1)
     903               0 :     int intervals = 2 * a_intervals * b_intervals + a_intervals + b_intervals;
     904                 :     // convert back to number of RunType values
     905               0 :     return intervals_to_count(intervals);
     906                 : }
     907                 : 
     908               0 : bool SkRegion::op(const SkRegion& rgnaOrig, const SkRegion& rgnbOrig, Op op)
     909                 : {
     910               0 :     SkDEBUGCODE(this->validate();)
     911                 : 
     912               0 :     SkASSERT((unsigned)op < kOpCount);
     913                 :     
     914               0 :     if (kReplace_Op == op)
     915               0 :         return this->set(rgnbOrig);
     916                 :     
     917                 :     // swith to using pointers, so we can swap them as needed
     918               0 :     const SkRegion* rgna = &rgnaOrig;
     919               0 :     const SkRegion* rgnb = &rgnbOrig;
     920                 :     // after this point, do not refer to rgnaOrig or rgnbOrig!!!
     921                 : 
     922                 :     // collaps difference and reverse-difference into just difference
     923               0 :     if (kReverseDifference_Op == op)
     924                 :     {
     925               0 :         SkTSwap<const SkRegion*>(rgna, rgnb);
     926               0 :         op = kDifference_Op;
     927                 :     }
     928                 : 
     929                 :     SkIRect bounds;
     930               0 :     bool    a_empty = rgna->isEmpty();
     931               0 :     bool    b_empty = rgnb->isEmpty();
     932               0 :     bool    a_rect = rgna->isRect();
     933               0 :     bool    b_rect = rgnb->isRect();
     934                 : 
     935               0 :     switch (op) {
     936                 :     case kDifference_Op:
     937               0 :         if (a_empty)
     938               0 :             return this->setEmpty();
     939               0 :         if (b_empty || !SkIRect::Intersects(rgna->fBounds, rgnb->fBounds))
     940               0 :             return this->setRegion(*rgna);
     941               0 :         break;
     942                 : 
     943                 :     case kIntersect_Op:
     944               0 :         if ((a_empty | b_empty)
     945               0 :                 || !bounds.intersect(rgna->fBounds, rgnb->fBounds))
     946               0 :             return this->setEmpty();
     947               0 :         if (a_rect & b_rect)
     948               0 :             return this->setRect(bounds);
     949               0 :         break;
     950                 : 
     951                 :     case kUnion_Op:
     952               0 :         if (a_empty)
     953               0 :             return this->setRegion(*rgnb);
     954               0 :         if (b_empty)
     955               0 :             return this->setRegion(*rgna);
     956               0 :         if (a_rect && rgna->fBounds.contains(rgnb->fBounds))
     957               0 :             return this->setRegion(*rgna);
     958               0 :         if (b_rect && rgnb->fBounds.contains(rgna->fBounds))
     959               0 :             return this->setRegion(*rgnb);
     960               0 :         break;
     961                 : 
     962                 :     case kXOR_Op:
     963               0 :         if (a_empty)
     964               0 :             return this->setRegion(*rgnb);
     965               0 :         if (b_empty)
     966               0 :             return this->setRegion(*rgna);
     967               0 :         break;
     968                 :     default:
     969               0 :         SkDEBUGFAIL("unknown region op");
     970               0 :         return !this->isEmpty();
     971                 :     }
     972                 : 
     973                 :     RunType tmpA[kRectRegionRuns];
     974                 :     RunType tmpB[kRectRegionRuns];
     975                 : 
     976                 :     int a_count, b_count;
     977               0 :     const RunType* a_runs = rgna->getRuns(tmpA, &a_count);
     978               0 :     const RunType* b_runs = rgnb->getRuns(tmpB, &b_count);
     979                 : 
     980               0 :     int dstCount = compute_worst_case_count(a_count, b_count);
     981               0 :     SkAutoSTMalloc<32, RunType> array(dstCount);
     982                 : 
     983               0 :     int count = operate(a_runs, b_runs, array.get(), op);
     984               0 :     SkASSERT(count <= dstCount);
     985               0 :     return this->setRuns(array.get(), count);
     986                 : }
     987                 : 
     988                 : //////////////////////////////////////////////////////////////////////////////////////////////////////////
     989                 : 
     990                 : #include "SkBuffer.h"
     991                 : 
     992               0 : uint32_t SkRegion::flatten(void* storage) const {
     993               0 :     if (NULL == storage) {
     994               0 :         uint32_t size = sizeof(int32_t); // -1 (empty), 0 (rect), runCount
     995               0 :         if (!this->isEmpty()) {
     996               0 :             size += sizeof(fBounds);
     997               0 :             if (this->isComplex()) {
     998               0 :                 size += fRunHead->fRunCount * sizeof(RunType);
     999                 :             }
    1000                 :         }
    1001               0 :         return size;
    1002                 :     }
    1003                 : 
    1004               0 :     SkWBuffer   buffer(storage);
    1005                 : 
    1006               0 :     if (this->isEmpty()) {
    1007               0 :         buffer.write32(-1);
    1008                 :     } else {
    1009               0 :         bool isRect = this->isRect();
    1010                 : 
    1011               0 :         buffer.write32(isRect ? 0 : fRunHead->fRunCount);
    1012               0 :         buffer.write(&fBounds, sizeof(fBounds));
    1013                 : 
    1014               0 :         if (!isRect) {
    1015               0 :             buffer.write(fRunHead->readonly_runs(),
    1016               0 :                          fRunHead->fRunCount * sizeof(RunType));
    1017                 :         }
    1018                 :     }
    1019               0 :     return buffer.pos();
    1020                 : }
    1021                 : 
    1022               0 : uint32_t SkRegion::unflatten(const void* storage) {
    1023               0 :     SkRBuffer   buffer(storage);
    1024               0 :     SkRegion    tmp;
    1025                 :     int32_t     count;
    1026                 :     
    1027               0 :     count = buffer.readS32();
    1028               0 :     if (count >= 0) {
    1029               0 :         buffer.read(&tmp.fBounds, sizeof(tmp.fBounds));
    1030               0 :         if (count == 0) {
    1031               0 :             tmp.fRunHead = SkRegion_gRectRunHeadPtr;
    1032                 :         } else {
    1033               0 :             tmp.allocateRuns(count);
    1034               0 :             buffer.read(tmp.fRunHead->writable_runs(), count * sizeof(RunType));
    1035                 :         }
    1036                 :     }
    1037               0 :     this->swap(tmp);
    1038               0 :     return buffer.pos();
    1039                 : }
    1040                 : 
    1041                 : ///////////////////////////////////////////////////////////////////////////////
    1042                 : 
    1043               0 : const SkRegion& SkRegion::GetEmptyRegion() {
    1044               0 :     static SkRegion gEmpty;
    1045               0 :     return gEmpty;
    1046                 : }
    1047                 : 
    1048                 : ///////////////////////////////////////////////////////////////////////////////
    1049                 : 
    1050                 : #ifdef SK_DEBUG
    1051                 : 
    1052               0 : static const SkRegion::RunType* validate_line(const SkRegion::RunType run[], const SkIRect& bounds)
    1053                 : {
    1054                 :     // *run is the bottom of the current span
    1055               0 :     SkASSERT(*run > bounds.fTop);
    1056               0 :     SkASSERT(*run <= bounds.fBottom);
    1057               0 :     run += 1;
    1058                 : 
    1059                 :     // check for empty span
    1060               0 :     if (*run != SkRegion::kRunTypeSentinel)
    1061                 :     {
    1062               0 :         int prevRite = bounds.fLeft - 1;
    1063               0 :         do {
    1064               0 :             int left = *run++;
    1065               0 :             int rite = *run++;
    1066               0 :             SkASSERT(left < rite);
    1067               0 :             SkASSERT(left > prevRite);
    1068               0 :             SkASSERT(rite <= bounds.fRight);
    1069               0 :             prevRite = rite;
    1070                 :         } while (*run < SkRegion::kRunTypeSentinel);
    1071                 :     }
    1072               0 :     return run + 1; // skip sentinel
    1073                 : }
    1074                 : 
    1075               0 : void SkRegion::validate() const
    1076                 : {
    1077               0 :     if (this->isEmpty())
    1078                 :     {
    1079                 :         // check for explicit empty (the zero rect), so we can compare rects to know when
    1080                 :         // two regions are equal (i.e. emptyRectA == emptyRectB)
    1081                 :         // this is stricter than just asserting fBounds.isEmpty()
    1082               0 :         SkASSERT(fBounds.fLeft == 0 && fBounds.fTop == 0 && fBounds.fRight == 0 && fBounds.fBottom == 0);
    1083                 :     }
    1084                 :     else
    1085                 :     {
    1086               0 :         SkASSERT(!fBounds.isEmpty());
    1087               0 :         if (!this->isRect())
    1088                 :         {
    1089               0 :             SkASSERT(fRunHead->fRefCnt >= 1);
    1090               0 :             SkASSERT(fRunHead->fRunCount >= kRectRegionRuns);
    1091                 : 
    1092               0 :             const RunType* run = fRunHead->readonly_runs();
    1093               0 :             const RunType* stop = run + fRunHead->fRunCount;
    1094                 : 
    1095                 :             // check that our bounds match our runs
    1096                 :             {
    1097                 :                 SkIRect bounds;
    1098               0 :                 bool isARect = ComputeRunBounds(run, stop - run, &bounds);
    1099               0 :                 SkASSERT(!isARect);
    1100               0 :                 SkASSERT(bounds == fBounds);
    1101                 :             }
    1102                 : 
    1103               0 :             SkASSERT(*run == fBounds.fTop);
    1104               0 :             run++;
    1105               0 :             do {
    1106               0 :                 run = validate_line(run, fBounds);
    1107                 :             } while (*run < kRunTypeSentinel);
    1108               0 :             SkASSERT(run + 1 == stop);
    1109                 :         }
    1110                 :     }
    1111               0 : }
    1112                 : 
    1113               0 : void SkRegion::dump() const
    1114                 : {
    1115               0 :     if (this->isEmpty())
    1116               0 :         SkDebugf("  rgn: empty\n");
    1117                 :     else
    1118                 :     {
    1119               0 :         SkDebugf("  rgn: [%d %d %d %d]", fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
    1120               0 :         if (this->isComplex())
    1121                 :         {
    1122               0 :             const RunType* runs = fRunHead->readonly_runs();
    1123               0 :             for (int i = 0; i < fRunHead->fRunCount; i++)
    1124               0 :                 SkDebugf(" %d", runs[i]);
    1125                 :         }
    1126               0 :         SkDebugf("\n");
    1127                 :     }
    1128               0 : }
    1129                 : 
    1130                 : #endif
    1131                 : 
    1132                 : /////////////////////////////////////////////////////////////////////////////////////
    1133                 : 
    1134               0 : SkRegion::Iterator::Iterator(const SkRegion& rgn) {
    1135               0 :     this->reset(rgn);
    1136               0 : }
    1137                 : 
    1138               0 : bool SkRegion::Iterator::rewind() {
    1139               0 :     if (fRgn) {
    1140               0 :         this->reset(*fRgn);
    1141               0 :         return true;
    1142                 :     }
    1143               0 :     return false;
    1144                 : }
    1145                 : 
    1146               0 : void SkRegion::Iterator::reset(const SkRegion& rgn) {
    1147               0 :     fRgn = &rgn;
    1148               0 :     if (rgn.isEmpty()) {
    1149               0 :         fDone = true;
    1150                 :     } else {
    1151               0 :         fDone = false;
    1152               0 :         if (rgn.isRect()) {
    1153               0 :             fRect = rgn.fBounds;
    1154               0 :             fRuns = NULL;
    1155                 :         } else {
    1156               0 :             fRuns = rgn.fRunHead->readonly_runs();
    1157               0 :             fRect.set(fRuns[2], fRuns[0], fRuns[3], fRuns[1]);
    1158               0 :             fRuns += 4;
    1159                 :         }
    1160                 :     }
    1161               0 : }
    1162                 : 
    1163               0 : void SkRegion::Iterator::next() {
    1164               0 :     if (fDone) {
    1165               0 :         return;
    1166                 :     }
    1167                 : 
    1168               0 :     if (fRuns == NULL) {   // rect case
    1169               0 :         fDone = true;
    1170               0 :         return;
    1171                 :     }
    1172                 : 
    1173               0 :     const RunType* runs = fRuns;
    1174                 : 
    1175               0 :     if (runs[0] < kRunTypeSentinel) { // valid X value
    1176               0 :         fRect.fLeft = runs[0];
    1177               0 :         fRect.fRight = runs[1];
    1178               0 :         runs += 2;
    1179                 :     } else {    // we're at the end of a line
    1180               0 :         runs += 1;
    1181               0 :         if (runs[0] < kRunTypeSentinel) { // valid Y value
    1182               0 :             if (runs[1] == kRunTypeSentinel) {    // empty line
    1183               0 :                 fRect.fTop = runs[0];
    1184               0 :                 runs += 2;
    1185                 :             } else {
    1186               0 :                 fRect.fTop = fRect.fBottom;
    1187                 :             }
    1188                 :     
    1189               0 :             fRect.fBottom = runs[0];
    1190               0 :             assert_sentinel(runs[1], false);
    1191               0 :             fRect.fLeft = runs[1];
    1192               0 :             fRect.fRight = runs[2];
    1193               0 :             runs += 3;
    1194                 :         } else {    // end of rgn
    1195               0 :             fDone = true;
    1196                 :         }
    1197                 :     }
    1198               0 :     fRuns = runs;
    1199                 : }
    1200                 : 
    1201               0 : SkRegion::Cliperator::Cliperator(const SkRegion& rgn, const SkIRect& clip)
    1202               0 :         : fIter(rgn), fClip(clip), fDone(true) {
    1203               0 :     const SkIRect& r = fIter.rect();
    1204                 : 
    1205               0 :     while (!fIter.done()) {
    1206               0 :         if (r.fTop >= clip.fBottom) {
    1207               0 :             break;
    1208                 :         }
    1209               0 :         if (fRect.intersect(clip, r)) {
    1210               0 :             fDone = false;
    1211               0 :             break;
    1212                 :         }
    1213               0 :         fIter.next();
    1214                 :     }
    1215               0 : }
    1216                 : 
    1217               0 : void SkRegion::Cliperator::next() {
    1218               0 :     if (fDone) {
    1219               0 :         return;
    1220                 :     }
    1221                 : 
    1222               0 :     const SkIRect& r = fIter.rect();
    1223                 : 
    1224               0 :     fDone = true;
    1225               0 :     fIter.next();
    1226               0 :     while (!fIter.done()) {
    1227               0 :         if (r.fTop >= fClip.fBottom) {
    1228               0 :             break;
    1229                 :         }
    1230               0 :         if (fRect.intersect(fClip, r)) {
    1231               0 :             fDone = false;
    1232               0 :             break;
    1233                 :         }
    1234               0 :         fIter.next();
    1235                 :     }
    1236                 : }
    1237                 : 
    1238                 : ///////////////////////////////////////////////////////////////////////////////
    1239                 : 
    1240               0 : static SkRegion::RunType* find_y(const SkRegion::RunType runs[], int y) {
    1241               0 :     int top = *runs++;
    1242               0 :     if (top <= y) {
    1243               0 :         for (;;) {
    1244               0 :             int bot = *runs++;
    1245               0 :             if (bot > y) {
    1246               0 :                 if (bot == SkRegion::kRunTypeSentinel ||
    1247                 :                     *runs == SkRegion::kRunTypeSentinel) {
    1248                 :                     break;
    1249                 :                                 }
    1250               0 :                 return (SkRegion::RunType*)runs;
    1251                 :             }
    1252               0 :             runs = skip_scanline(runs);
    1253                 :         }
    1254                 :     }
    1255               0 :     return NULL;
    1256                 : }
    1257                 : 
    1258               0 : SkRegion::Spanerator::Spanerator(const SkRegion& rgn, int y, int left,
    1259                 :                                  int right) {
    1260               0 :     SkDEBUGCODE(rgn.validate();)
    1261                 : 
    1262               0 :     const SkIRect& r = rgn.getBounds();
    1263                 : 
    1264               0 :     fDone = true;
    1265               0 :     if (!rgn.isEmpty() && y >= r.fTop && y < r.fBottom &&
    1266                 :             right > r.fLeft && left < r.fRight) {
    1267               0 :         if (rgn.isRect()) {
    1268               0 :             if (left < r.fLeft) {
    1269               0 :                 left = r.fLeft;
    1270                 :             }
    1271               0 :             if (right > r.fRight) {
    1272               0 :                 right = r.fRight;
    1273                 :             }
    1274               0 :             fLeft = left;
    1275               0 :             fRight = right;
    1276               0 :             fRuns = NULL;    // means we're a rect, not a rgn
    1277               0 :             fDone = false;
    1278                 :         } else {
    1279                 :             const SkRegion::RunType* runs = find_y(
    1280               0 :                                               rgn.fRunHead->readonly_runs(), y);
    1281               0 :             if (runs) {
    1282               0 :                 for (;;) {
    1283                 :                     // runs[0..1] is to the right of the span, so we're done
    1284               0 :                     if (runs[0] >= right) {
    1285               0 :                         break;
    1286                 :                     }
    1287                 :                     // runs[0..1] is to the left of the span, so continue
    1288               0 :                     if (runs[1] <= left) {
    1289               0 :                         runs += 2;
    1290               0 :                         continue;
    1291                 :                     }
    1292                 :                     // runs[0..1] intersects the span
    1293               0 :                     fRuns = runs;
    1294               0 :                     fLeft = left;
    1295               0 :                     fRight = right;
    1296               0 :                     fDone = false;
    1297               0 :                     break;
    1298                 :                 }
    1299                 :             }
    1300                 :         }
    1301                 :     }
    1302               0 : }
    1303                 : 
    1304               0 : bool SkRegion::Spanerator::next(int* left, int* right) {
    1305               0 :     if (fDone) {
    1306               0 :         return false;
    1307                 :     }
    1308                 : 
    1309               0 :     if (fRuns == NULL) {   // we're a rect
    1310               0 :         fDone = true;   // ok, now we're done
    1311               0 :         if (left) {
    1312               0 :             *left = fLeft;
    1313                 :         }
    1314               0 :         if (right) {
    1315               0 :             *right = fRight;
    1316                 :         }
    1317               0 :         return true;    // this interval is legal
    1318                 :     }
    1319                 : 
    1320               0 :     const SkRegion::RunType* runs = fRuns;
    1321                 : 
    1322               0 :     if (runs[0] >= fRight) {
    1323               0 :         fDone = true;
    1324               0 :         return false;
    1325                 :     }
    1326                 : 
    1327               0 :     SkASSERT(runs[1] > fLeft);
    1328                 : 
    1329               0 :     if (left) {
    1330               0 :         *left = SkMax32(fLeft, runs[0]);
    1331                 :     }
    1332               0 :     if (right) {
    1333               0 :         *right = SkMin32(fRight, runs[1]);
    1334                 :     }
    1335               0 :     fRuns = runs + 2;
    1336               0 :     return true;
    1337                 : }
    1338                 : 
    1339                 : ///////////////////////////////////////////////////////////////////////////////
    1340                 : 
    1341                 : #ifdef SK_DEBUG
    1342                 : 
    1343               0 : bool SkRegion::debugSetRuns(const RunType runs[], int count) {
    1344                 :     // we need to make a copy, since the real method may modify the array, and
    1345                 :     // so it cannot be const.
    1346                 :     
    1347               0 :     SkAutoTArray<RunType> storage(count);
    1348               0 :     memcpy(storage.get(), runs, count * sizeof(RunType));
    1349               0 :     return this->setRuns(storage.get(), count);
    1350                 : }
    1351                 : 
    1352                 : #endif

Generated by: LCOV version 1.7