LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkAAClip.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 926 1314 70.5 %
Date: 2017-07-14 16:53:18 Functions: 88 116 75.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2011 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "SkAAClip.h"
       9             : #include "SkAtomics.h"
      10             : #include "SkBlitter.h"
      11             : #include "SkColorPriv.h"
      12             : #include "SkPath.h"
      13             : #include "SkScan.h"
      14             : #include "SkUtils.h"
      15             : 
      16             : class AutoAAClipValidate {
      17             : public:
      18         815 :     AutoAAClipValidate(const SkAAClip& clip) : fClip(clip) {
      19         815 :         fClip.validate();
      20         815 :     }
      21        1630 :     ~AutoAAClipValidate() {
      22         815 :         fClip.validate();
      23         815 :     }
      24             : private:
      25             :     const SkAAClip& fClip;
      26             : };
      27             : 
      28             : #ifdef SK_DEBUG
      29             :     #define AUTO_AACLIP_VALIDATE(clip)  AutoAAClipValidate acv(clip)
      30             : #else
      31             :     #define AUTO_AACLIP_VALIDATE(clip)
      32             : #endif
      33             : 
      34             : ///////////////////////////////////////////////////////////////////////////////
      35             : 
      36             : #define kMaxInt32   0x7FFFFFFF
      37             : 
      38             : #ifdef SK_DEBUG
      39        5288 : static inline bool x_in_rect(int x, const SkIRect& rect) {
      40        5288 :     return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
      41             : }
      42             : #endif
      43             : 
      44        5435 : static inline bool y_in_rect(int y, const SkIRect& rect) {
      45        5435 :     return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
      46             : }
      47             : 
      48             : /*
      49             :  *  Data runs are packed [count, alpha]
      50             :  */
      51             : 
      52             : struct SkAAClip::YOffset {
      53             :     int32_t  fY;
      54             :     uint32_t fOffset;
      55             : };
      56             : 
      57             : struct SkAAClip::RunHead {
      58             :     int32_t fRefCnt;
      59             :     int32_t fRowCount;
      60             :     size_t  fDataSize;
      61             : 
      62       44087 :     YOffset* yoffsets() {
      63       44087 :         return (YOffset*)((char*)this + sizeof(RunHead));
      64             :     }
      65       21962 :     const YOffset* yoffsets() const {
      66       21962 :         return (const YOffset*)((const char*)this + sizeof(RunHead));
      67             :     }
      68        6292 :     uint8_t* data() {
      69        6292 :         return (uint8_t*)(this->yoffsets() + fRowCount);
      70             :     }
      71       18312 :     const uint8_t* data() const {
      72       18312 :         return (const uint8_t*)(this->yoffsets() + fRowCount);
      73             :     }
      74             : 
      75         305 :     static RunHead* Alloc(int rowCount, size_t dataSize) {
      76         305 :         size_t size = sizeof(RunHead) + rowCount * sizeof(YOffset) + dataSize;
      77         305 :         RunHead* head = (RunHead*)sk_malloc_throw(size);
      78         305 :         head->fRefCnt = 1;
      79         305 :         head->fRowCount = rowCount;
      80         305 :         head->fDataSize = dataSize;
      81         305 :         return head;
      82             :     }
      83             : 
      84          30 :     static int ComputeRowSizeForWidth(int width) {
      85             :         // 2 bytes per segment, where each segment can store up to 255 for count
      86          30 :         int segments = 0;
      87         330 :         while (width > 0) {
      88         150 :             segments += 1;
      89         150 :             int n = SkMin32(width, 255);
      90         150 :             width -= n;
      91             :         }
      92          30 :         return segments * 2;    // each segment is row[0] + row[1] (n + alpha)
      93             :     }
      94             : 
      95          30 :     static RunHead* AllocRect(const SkIRect& bounds) {
      96          30 :         SkASSERT(!bounds.isEmpty());
      97          30 :         int width = bounds.width();
      98          30 :         size_t rowSize = ComputeRowSizeForWidth(width);
      99          30 :         RunHead* head = RunHead::Alloc(1, rowSize);
     100          30 :         YOffset* yoff = head->yoffsets();
     101          30 :         yoff->fY = bounds.height() - 1;
     102          30 :         yoff->fOffset = 0;
     103          30 :         uint8_t* row = head->data();
     104         330 :         while (width > 0) {
     105         150 :             int n = SkMin32(width, 255);
     106         150 :             row[0] = n;
     107         150 :             row[1] = 0xFF;
     108         150 :             width -= n;
     109         150 :             row += 2;
     110             :         }
     111          30 :         return head;
     112             :     }
     113             : };
     114             : 
     115             : class SkAAClip::Iter {
     116             : public:
     117             :     Iter(const SkAAClip&);
     118             : 
     119        1129 :     bool done() const { return fDone; }
     120        1140 :     int top() const { return fTop; }
     121        1140 :     int bottom() const { return fBottom; }
     122        1600 :     const uint8_t* data() const { return fData; }
     123             :     void next();
     124             : 
     125             : private:
     126             :     const YOffset* fCurrYOff;
     127             :     const YOffset* fStopYOff;
     128             :     const uint8_t* fData;
     129             : 
     130             :     int fTop, fBottom;
     131             :     bool fDone;
     132             : };
     133             : 
     134         246 : SkAAClip::Iter::Iter(const SkAAClip& clip) {
     135         246 :     if (clip.isEmpty()) {
     136           0 :         fDone = true;
     137           0 :         fTop = fBottom = clip.fBounds.fBottom;
     138           0 :         fData = nullptr;
     139           0 :         fCurrYOff = nullptr;
     140           0 :         fStopYOff = nullptr;
     141           0 :         return;
     142             :     }
     143             : 
     144         246 :     const RunHead* head = clip.fRunHead;
     145         246 :     fCurrYOff = head->yoffsets();
     146         246 :     fStopYOff = fCurrYOff + head->fRowCount;
     147         246 :     fData     = head->data() + fCurrYOff->fOffset;
     148             : 
     149             :     // setup first value
     150         246 :     fTop = clip.fBounds.fTop;
     151         246 :     fBottom = clip.fBounds.fTop + fCurrYOff->fY + 1;
     152         246 :     fDone = false;
     153             : }
     154             : 
     155         894 : void SkAAClip::Iter::next() {
     156         894 :     if (!fDone) {
     157         894 :         const YOffset* prev = fCurrYOff;
     158         894 :         const YOffset* curr = prev + 1;
     159         894 :         SkASSERT(curr <= fStopYOff);
     160             : 
     161         894 :         fTop = fBottom;
     162         894 :         if (curr >= fStopYOff) {
     163         213 :             fDone = true;
     164         213 :             fBottom = kMaxInt32;
     165         213 :             fData = nullptr;
     166             :         } else {
     167         681 :             fBottom += curr->fY - prev->fY;
     168         681 :             fData += curr->fOffset - prev->fOffset;
     169         681 :             fCurrYOff = curr;
     170             :         }
     171             :     }
     172         894 : }
     173             : 
     174             : #ifdef SK_DEBUG
     175             : // assert we're exactly width-wide, and then return the number of bytes used
     176       19870 : static size_t compute_row_length(const uint8_t row[], int width) {
     177       19870 :     const uint8_t* origRow = row;
     178      313000 :     while (width > 0) {
     179      146565 :         int n = row[0];
     180      146565 :         SkASSERT(n > 0);
     181      146565 :         SkASSERT(n <= width);
     182      146565 :         row += 2;
     183      146565 :         width -= n;
     184             :     }
     185       19870 :     SkASSERT(0 == width);
     186       19870 :     return row - origRow;
     187             : }
     188             : 
     189        6990 : void SkAAClip::validate() const {
     190        6990 :     if (nullptr == fRunHead) {
     191        4175 :         SkASSERT(fBounds.isEmpty());
     192        4175 :         return;
     193             :     }
     194        2815 :     SkASSERT(!fBounds.isEmpty());
     195             : 
     196        2815 :     const RunHead* head = fRunHead;
     197        2815 :     SkASSERT(head->fRefCnt > 0);
     198        2815 :     SkASSERT(head->fRowCount > 0);
     199             : 
     200        2815 :     const YOffset* yoff = head->yoffsets();
     201        2815 :     const YOffset* ystop = yoff + head->fRowCount;
     202        2815 :     const int lastY = fBounds.height() - 1;
     203             : 
     204             :     // Y and offset must be monotonic
     205        2815 :     int prevY = -1;
     206        2815 :     int32_t prevOffset = -1;
     207       38897 :     while (yoff < ystop) {
     208       18041 :         SkASSERT(prevY < yoff->fY);
     209       18041 :         SkASSERT(yoff->fY <= lastY);
     210       18041 :         prevY = yoff->fY;
     211       18041 :         SkASSERT(prevOffset < (int32_t)yoff->fOffset);
     212       18041 :         prevOffset = yoff->fOffset;
     213       18041 :         const uint8_t* row = head->data() + yoff->fOffset;
     214       18041 :         size_t rowLength = compute_row_length(row, fBounds.width());
     215       18041 :         SkASSERT(yoff->fOffset + rowLength <= head->fDataSize);
     216       18041 :         yoff += 1;
     217             :     }
     218             :     // check the last entry;
     219        2815 :     --yoff;
     220        2815 :     SkASSERT(yoff->fY == lastY);
     221             : }
     222             : 
     223           0 : static void dump_one_row(const uint8_t* SK_RESTRICT row,
     224             :                          int width, int leading_num) {
     225           0 :     if (leading_num) {
     226           0 :         SkDebugf( "%03d ", leading_num );
     227             :     }
     228           0 :     while (width > 0) {
     229           0 :         int n = row[0];
     230           0 :         int val = row[1];
     231           0 :         char out = '.';
     232           0 :         if (val == 0xff) {
     233           0 :             out = '*';
     234           0 :         } else if (val > 0) {
     235           0 :             out = '+';
     236             :         }
     237           0 :         for (int i = 0 ; i < n ; i++) {
     238           0 :             SkDebugf( "%c", out );
     239             :         }
     240           0 :         row += 2;
     241           0 :         width -= n;
     242             :     }
     243           0 :     SkDebugf( "\n" );
     244           0 : }
     245             : 
     246           0 : void SkAAClip::debug(bool compress_y) const {
     247           0 :     Iter iter(*this);
     248           0 :     const int width = fBounds.width();
     249             : 
     250           0 :     int y = fBounds.fTop;
     251           0 :     while (!iter.done()) {
     252           0 :         if (compress_y) {
     253           0 :             dump_one_row(iter.data(), width, iter.bottom() - iter.top() + 1);
     254             :         } else {
     255           0 :             do {
     256           0 :                 dump_one_row(iter.data(), width, 0);
     257           0 :             } while (++y < iter.bottom());
     258             :         }
     259           0 :         iter.next();
     260             :     }
     261           0 : }
     262             : #endif
     263             : 
     264             : ///////////////////////////////////////////////////////////////////////////////
     265             : 
     266             : // Count the number of zeros on the left and right edges of the passed in
     267             : // RLE row. If 'row' is all zeros return 'width' in both variables.
     268         871 : static void count_left_right_zeros(const uint8_t* row, int width,
     269             :                                    int* leftZ, int* riteZ) {
     270         871 :     int zeros = 0;
     271         385 :     do {
     272        1256 :         if (row[1]) {
     273         868 :             break;
     274             :         }
     275         388 :         int n = row[0];
     276         388 :         SkASSERT(n > 0);
     277         388 :         SkASSERT(n <= width);
     278         388 :         zeros += n;
     279         388 :         row += 2;
     280         388 :         width -= n;
     281         388 :     } while (width > 0);
     282         871 :     *leftZ = zeros;
     283             : 
     284         871 :     if (0 == width) {
     285             :         // this line is completely empty return 'width' in both variables
     286           3 :         *riteZ = *leftZ;
     287           3 :         return;
     288             :     }
     289             : 
     290         868 :     zeros = 0;
     291       10320 :     while (width > 0) {
     292        4726 :         int n = row[0];
     293        4726 :         SkASSERT(n > 0);
     294        4726 :         if (0 == row[1]) {
     295        1315 :             zeros += n;
     296             :         } else {
     297        3411 :             zeros = 0;
     298             :         }
     299        4726 :         row += 2;
     300        4726 :         width -= n;
     301             :     }
     302         868 :     *riteZ = zeros;
     303             : }
     304             : 
     305             : #ifdef SK_DEBUG
     306           0 : static void test_count_left_right_zeros() {
     307             :     static bool gOnce;
     308           0 :     if (gOnce) {
     309           0 :         return;
     310             :     }
     311           0 :     gOnce = true;
     312             : 
     313           0 :     const uint8_t data0[] = {  0, 0,     10, 0xFF };
     314           0 :     const uint8_t data1[] = {  0, 0,     5, 0xFF, 2, 0, 3, 0xFF };
     315           0 :     const uint8_t data2[] = {  7, 0,     5, 0, 2, 0, 3, 0xFF };
     316           0 :     const uint8_t data3[] = {  0, 5,     5, 0xFF, 2, 0, 3, 0 };
     317           0 :     const uint8_t data4[] = {  2, 3,     2, 0, 5, 0xFF, 3, 0 };
     318           0 :     const uint8_t data5[] = { 10, 10,    10, 0 };
     319           0 :     const uint8_t data6[] = {  2, 2,     2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
     320             : 
     321             :     const uint8_t* array[] = {
     322             :         data0, data1, data2, data3, data4, data5, data6
     323           0 :     };
     324             : 
     325           0 :     for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
     326           0 :         const uint8_t* data = array[i];
     327           0 :         const int expectedL = *data++;
     328           0 :         const int expectedR = *data++;
     329           0 :         int L = 12345, R = 12345;
     330           0 :         count_left_right_zeros(data, 10, &L, &R);
     331           0 :         SkASSERT(expectedL == L);
     332           0 :         SkASSERT(expectedR == R);
     333             :     }
     334             : }
     335             : #endif
     336             : 
     337             : // modify row in place, trimming off (zeros) from the left and right sides.
     338             : // return the number of bytes that were completely eliminated from the left
     339          94 : static int trim_row_left_right(uint8_t* row, int width, int leftZ, int riteZ) {
     340          94 :     int trim = 0;
     341         130 :     while (leftZ > 0) {
     342          79 :         SkASSERT(0 == row[1]);
     343          79 :         int n = row[0];
     344          79 :         SkASSERT(n > 0);
     345          79 :         SkASSERT(n <= width);
     346          79 :         width -= n;
     347          79 :         row += 2;
     348          79 :         if (n > leftZ) {
     349          61 :             row[-2] = n - leftZ;
     350          61 :             break;
     351             :         }
     352          18 :         trim += 2;
     353          18 :         leftZ -= n;
     354          18 :         SkASSERT(leftZ >= 0);
     355             :     }
     356             : 
     357          94 :     if (riteZ) {
     358             :         // walk row to the end, and then we'll back up to trim riteZ
     359         805 :         while (width > 0) {
     360         390 :             int n = row[0];
     361         390 :             SkASSERT(n <= width);
     362         390 :             width -= n;
     363         390 :             row += 2;
     364             :         }
     365             :         // now skip whole runs of zeros
     366         254 :         do {
     367         279 :             row -= 2;
     368         279 :             SkASSERT(0 == row[1]);
     369         279 :             int n = row[0];
     370         279 :             SkASSERT(n > 0);
     371         279 :             if (n > riteZ) {
     372           4 :                 row[0] = n - riteZ;
     373           4 :                 break;
     374             :             }
     375         275 :             riteZ -= n;
     376         275 :             SkASSERT(riteZ >= 0);
     377         275 :         } while (riteZ > 0);
     378             :     }
     379             : 
     380          94 :     return trim;
     381             : }
     382             : 
     383             : #ifdef SK_DEBUG
     384             : // assert that this row is exactly this width
     385          99 : static void assert_row_width(const uint8_t* row, int width) {
     386         176 :     while (width > 0) {
     387          77 :         int n = row[0];
     388          77 :         SkASSERT(n > 0);
     389          77 :         SkASSERT(n <= width);
     390          77 :         width -= n;
     391          77 :         row += 2;
     392             :     }
     393          22 :     SkASSERT(0 == width);
     394          22 : }
     395             : 
     396         275 : static void test_trim_row_left_right() {
     397             :     static bool gOnce;
     398         275 :     if (gOnce) {
     399         274 :         return;
     400             :     }
     401           1 :     gOnce = true;
     402             : 
     403           1 :     uint8_t data0[] = {  0, 0, 0,   10,    10, 0xFF };
     404           1 :     uint8_t data1[] = {  2, 0, 0,   10,    5, 0, 2, 0, 3, 0xFF };
     405           1 :     uint8_t data2[] = {  5, 0, 2,   10,    5, 0, 2, 0, 3, 0xFF };
     406           1 :     uint8_t data3[] = {  6, 0, 2,   10,    5, 0, 2, 0, 3, 0xFF };
     407           1 :     uint8_t data4[] = {  0, 0, 0,   10,    2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
     408           1 :     uint8_t data5[] = {  1, 0, 0,   10,    2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
     409           1 :     uint8_t data6[] = {  0, 1, 0,   10,    2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
     410           1 :     uint8_t data7[] = {  1, 1, 0,   10,    2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
     411           1 :     uint8_t data8[] = {  2, 2, 2,   10,    2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
     412           1 :     uint8_t data9[] = {  5, 2, 4,   10,    2, 0, 2, 0, 2, 0, 2, 0xFF, 2, 0 };
     413           1 :     uint8_t data10[] ={  74, 0, 4, 150,    9, 0, 65, 0, 76, 0xFF };
     414             : 
     415             :     uint8_t* array[] = {
     416             :         data0, data1, data2, data3, data4,
     417             :         data5, data6, data7, data8, data9,
     418             :         data10
     419           1 :     };
     420             : 
     421          12 :     for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
     422          11 :         uint8_t* data = array[i];
     423          11 :         const int trimL = *data++;
     424          11 :         const int trimR = *data++;
     425          11 :         const int expectedSkip = *data++;
     426          11 :         const int origWidth = *data++;
     427          11 :         assert_row_width(data, origWidth);
     428          11 :         int skip = trim_row_left_right(data, origWidth, trimL, trimR);
     429          11 :         SkASSERT(expectedSkip == skip);
     430          11 :         int expectedWidth = origWidth - trimL - trimR;
     431          11 :         assert_row_width(data + skip, expectedWidth);
     432             :     }
     433             : }
     434             : #endif
     435             : 
     436         275 : bool SkAAClip::trimLeftRight() {
     437         275 :     SkDEBUGCODE(test_trim_row_left_right();)
     438             : 
     439         275 :     if (this->isEmpty()) {
     440           0 :         return false;
     441             :     }
     442             : 
     443         550 :     AUTO_AACLIP_VALIDATE(*this);
     444             : 
     445         275 :     const int width = fBounds.width();
     446         275 :     RunHead* head = fRunHead;
     447         275 :     YOffset* yoff = head->yoffsets();
     448         275 :     YOffset* stop = yoff + head->fRowCount;
     449         275 :     uint8_t* base = head->data();
     450             : 
     451             :     // After this loop, 'leftZeros' & 'rightZeros' will contain the minimum
     452             :     // number of zeros on the left and right of the clip. This information
     453             :     // can be used to shrink the bounding box.
     454         275 :     int leftZeros = width;
     455         275 :     int riteZeros = width;
     456        1491 :     while (yoff < stop) {
     457             :         int L, R;
     458         871 :         count_left_right_zeros(base + yoff->fOffset, width, &L, &R);
     459         871 :         SkASSERT(L + R < width || (L == width && R == width));
     460         871 :         if (L < leftZeros) {
     461         471 :             leftZeros = L;
     462             :         }
     463         871 :         if (R < riteZeros) {
     464         546 :             riteZeros = R;
     465             :         }
     466         871 :         if (0 == (leftZeros | riteZeros)) {
     467             :             // no trimming to do
     468         263 :             return true;
     469             :         }
     470         608 :         yoff += 1;
     471             :     }
     472             : 
     473          12 :     SkASSERT(leftZeros || riteZeros);
     474          12 :     if (width == leftZeros) {
     475           0 :         SkASSERT(width == riteZeros);
     476           0 :         return this->setEmpty();
     477             :     }
     478             : 
     479          12 :     this->validate();
     480             : 
     481          12 :     fBounds.fLeft += leftZeros;
     482          12 :     fBounds.fRight -= riteZeros;
     483          12 :     SkASSERT(!fBounds.isEmpty());
     484             : 
     485             :     // For now we don't realloc the storage (for time), we just shrink in place
     486             :     // This means we don't have to do any memmoves either, since we can just
     487             :     // play tricks with the yoff->fOffset for each row
     488          12 :     yoff = head->yoffsets();
     489         178 :     while (yoff < stop) {
     490          83 :         uint8_t* row = base + yoff->fOffset;
     491          83 :         SkDEBUGCODE((void)compute_row_length(row, width);)
     492          83 :         yoff->fOffset += trim_row_left_right(row, width, leftZeros, riteZeros);
     493          83 :         SkDEBUGCODE((void)compute_row_length(base + yoff->fOffset, width - leftZeros - riteZeros);)
     494          83 :         yoff += 1;
     495             :     }
     496          12 :     return true;
     497             : }
     498             : 
     499         557 : static bool row_is_all_zeros(const uint8_t* row, int width) {
     500         557 :     SkASSERT(width > 0);
     501         101 :     do {
     502         658 :         if (row[1]) {
     503         550 :             return false;
     504             :         }
     505         108 :         int n = row[0];
     506         108 :         SkASSERT(n <= width);
     507         108 :         width -= n;
     508         108 :         row += 2;
     509         108 :     } while (width > 0);
     510           7 :     SkASSERT(0 == width);
     511           7 :     return true;
     512             : }
     513             : 
     514         275 : bool SkAAClip::trimTopBottom() {
     515         275 :     if (this->isEmpty()) {
     516           0 :         return false;
     517             :     }
     518             : 
     519         275 :     this->validate();
     520             : 
     521         275 :     const int width = fBounds.width();
     522         275 :     RunHead* head = fRunHead;
     523         275 :     YOffset* yoff = head->yoffsets();
     524         275 :     YOffset* stop = yoff + head->fRowCount;
     525         275 :     const uint8_t* base = head->data();
     526             : 
     527             :     //  Look to trim away empty rows from the top.
     528             :     //
     529         275 :     int skip = 0;
     530         279 :     while (yoff < stop) {
     531         277 :         const uint8_t* data = base + yoff->fOffset;
     532         277 :         if (!row_is_all_zeros(data, width)) {
     533         275 :             break;
     534             :         }
     535           2 :         skip += 1;
     536           2 :         yoff += 1;
     537             :     }
     538         275 :     SkASSERT(skip <= head->fRowCount);
     539         275 :     if (skip == head->fRowCount) {
     540           0 :         return this->setEmpty();
     541             :     }
     542         275 :     if (skip > 0) {
     543             :         // adjust fRowCount and fBounds.fTop, and slide all the data up
     544             :         // as we remove [skip] number of YOffset entries
     545           2 :         yoff = head->yoffsets();
     546           2 :         int dy = yoff[skip - 1].fY + 1;
     547           5 :         for (int i = skip; i < head->fRowCount; ++i) {
     548           3 :             SkASSERT(yoff[i].fY >= dy);
     549           3 :             yoff[i].fY -= dy;
     550             :         }
     551           2 :         YOffset* dst = head->yoffsets();
     552           2 :         size_t size = head->fRowCount * sizeof(YOffset) + head->fDataSize;
     553           2 :         memmove(dst, dst + skip, size - skip * sizeof(YOffset));
     554             : 
     555           2 :         fBounds.fTop += dy;
     556           2 :         SkASSERT(!fBounds.isEmpty());
     557           2 :         head->fRowCount -= skip;
     558           2 :         SkASSERT(head->fRowCount > 0);
     559             : 
     560           2 :         this->validate();
     561             :         // need to reset this after the memmove
     562           2 :         base = head->data();
     563             :     }
     564             : 
     565             :     //  Look to trim away empty rows from the bottom.
     566             :     //  We know that we have at least one non-zero row, so we can just walk
     567             :     //  backwards without checking for running past the start.
     568             :     //
     569         275 :     stop = yoff = head->yoffsets() + head->fRowCount;
     570         280 :     do {
     571         280 :         yoff -= 1;
     572         280 :     } while (row_is_all_zeros(base + yoff->fOffset, width));
     573         275 :     skip = SkToInt(stop - yoff - 1);
     574         275 :     SkASSERT(skip >= 0 && skip < head->fRowCount);
     575         275 :     if (skip > 0) {
     576             :         // removing from the bottom is easier than from the top, as we don't
     577             :         // have to adjust any of the Y values, we just have to trim the array
     578           5 :         memmove(stop - skip, stop, head->fDataSize);
     579             : 
     580           5 :         fBounds.fBottom = fBounds.fTop + yoff->fY + 1;
     581           5 :         SkASSERT(!fBounds.isEmpty());
     582           5 :         head->fRowCount -= skip;
     583           5 :         SkASSERT(head->fRowCount > 0);
     584             :     }
     585         275 :     this->validate();
     586             : 
     587         275 :     return true;
     588             : }
     589             : 
     590             : // can't validate before we're done, since trimming is part of the process of
     591             : // making us valid after the Builder. Since we build from top to bottom, its
     592             : // possible our fBounds.fBottom is bigger than our last scanline of data, so
     593             : // we trim fBounds.fBottom back up.
     594             : //
     595             : // TODO: check for duplicates in X and Y to further compress our data
     596             : //
     597         275 : bool SkAAClip::trimBounds() {
     598         275 :     if (this->isEmpty()) {
     599           0 :         return false;
     600             :     }
     601             : 
     602         275 :     const RunHead* head = fRunHead;
     603         275 :     const YOffset* yoff = head->yoffsets();
     604             : 
     605         275 :     SkASSERT(head->fRowCount > 0);
     606         275 :     const YOffset& lastY = yoff[head->fRowCount - 1];
     607         275 :     SkASSERT(lastY.fY + 1 <= fBounds.height());
     608         275 :     fBounds.fBottom = fBounds.fTop + lastY.fY + 1;
     609         275 :     SkASSERT(lastY.fY + 1 == fBounds.height());
     610         275 :     SkASSERT(!fBounds.isEmpty());
     611             : 
     612         275 :     return this->trimTopBottom() && this->trimLeftRight();
     613             : }
     614             : 
     615             : ///////////////////////////////////////////////////////////////////////////////
     616             : 
     617        1594 : void SkAAClip::freeRuns() {
     618        1594 :     if (fRunHead) {
     619         427 :         SkASSERT(fRunHead->fRefCnt >= 1);
     620         427 :         if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) {
     621         305 :             sk_free(fRunHead);
     622             :         }
     623             :     }
     624        1594 : }
     625             : 
     626        1114 : SkAAClip::SkAAClip() {
     627        1114 :     fBounds.setEmpty();
     628        1114 :     fRunHead = nullptr;
     629        1114 : }
     630             : 
     631           0 : SkAAClip::SkAAClip(const SkAAClip& src) {
     632           0 :     SkDEBUGCODE(fBounds.setEmpty();)    // need this for validate
     633           0 :     fRunHead = nullptr;
     634           0 :     *this = src;
     635           0 : }
     636             : 
     637        2124 : SkAAClip::~SkAAClip() {
     638        1062 :     this->freeRuns();
     639        1062 : }
     640             : 
     641         122 : SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
     642         244 :     AUTO_AACLIP_VALIDATE(*this);
     643         122 :     src.validate();
     644             : 
     645         122 :     if (this != &src) {
     646         122 :         this->freeRuns();
     647         122 :         fBounds = src.fBounds;
     648         122 :         fRunHead = src.fRunHead;
     649         122 :         if (fRunHead) {
     650         122 :             sk_atomic_inc(&fRunHead->fRefCnt);
     651             :         }
     652             :     }
     653         244 :     return *this;
     654             : }
     655             : 
     656           0 : bool operator==(const SkAAClip& a, const SkAAClip& b) {
     657           0 :     a.validate();
     658           0 :     b.validate();
     659             : 
     660           0 :     if (&a == &b) {
     661           0 :         return true;
     662             :     }
     663           0 :     if (a.fBounds != b.fBounds) {
     664           0 :         return false;
     665             :     }
     666             : 
     667           0 :     const SkAAClip::RunHead* ah = a.fRunHead;
     668           0 :     const SkAAClip::RunHead* bh = b.fRunHead;
     669             : 
     670             :     // this catches empties and rects being equal
     671           0 :     if (ah == bh) {
     672           0 :         return true;
     673             :     }
     674             : 
     675             :     // now we insist that both are complex (but different ptrs)
     676           0 :     if (!a.fRunHead || !b.fRunHead) {
     677           0 :         return false;
     678             :     }
     679             : 
     680           0 :     return  ah->fRowCount == bh->fRowCount &&
     681           0 :             ah->fDataSize == bh->fDataSize &&
     682           0 :             !memcmp(ah->data(), bh->data(), ah->fDataSize);
     683             : }
     684             : 
     685           0 : void SkAAClip::swap(SkAAClip& other) {
     686           0 :     AUTO_AACLIP_VALIDATE(*this);
     687           0 :     other.validate();
     688             : 
     689           0 :     SkTSwap(fBounds, other.fBounds);
     690           0 :     SkTSwap(fRunHead, other.fRunHead);
     691           0 : }
     692             : 
     693           0 : bool SkAAClip::set(const SkAAClip& src) {
     694           0 :     *this = src;
     695           0 :     return !this->isEmpty();
     696             : }
     697             : 
     698         105 : bool SkAAClip::setEmpty() {
     699         105 :     this->freeRuns();
     700         105 :     fBounds.setEmpty();
     701         105 :     fRunHead = nullptr;
     702         105 :     return false;
     703             : }
     704             : 
     705          30 : bool SkAAClip::setRect(const SkIRect& bounds) {
     706          30 :     if (bounds.isEmpty()) {
     707           0 :         return this->setEmpty();
     708             :     }
     709             : 
     710          60 :     AUTO_AACLIP_VALIDATE(*this);
     711             : 
     712             : #if 0
     713             :     SkRect r;
     714             :     r.set(bounds);
     715             :     SkPath path;
     716             :     path.addRect(r);
     717             :     return this->setPath(path);
     718             : #else
     719          30 :     this->freeRuns();
     720          30 :     fBounds = bounds;
     721          30 :     fRunHead = RunHead::AllocRect(bounds);
     722          30 :     SkASSERT(!this->isEmpty());
     723          30 :     return true;
     724             : #endif
     725             : }
     726             : 
     727        1386 : bool SkAAClip::isRect() const {
     728        1386 :     if (this->isEmpty()) {
     729          20 :         return false;
     730             :     }
     731             : 
     732        1366 :     const RunHead* head = fRunHead;
     733        1366 :     if (head->fRowCount != 1) {
     734        1052 :         return false;
     735             :     }
     736         314 :     const YOffset* yoff = head->yoffsets();
     737         314 :     if (yoff->fY != fBounds.fBottom - 1) {
     738         289 :         return false;
     739             :     }
     740             : 
     741          25 :     const uint8_t* row = head->data() + yoff->fOffset;
     742          25 :     int width = fBounds.width();
     743         140 :     do {
     744         165 :         if (row[1] != 0xFF) {
     745           0 :             return false;
     746             :         }
     747         165 :         int n = row[0];
     748         165 :         SkASSERT(n <= width);
     749         165 :         width -= n;
     750         165 :         row += 2;
     751         165 :     } while (width > 0);
     752          25 :     return true;
     753             : }
     754             : 
     755         113 : bool SkAAClip::setRect(const SkRect& r, bool doAA) {
     756         113 :     if (r.isEmpty()) {
     757           0 :         return this->setEmpty();
     758             :     }
     759             : 
     760         226 :     AUTO_AACLIP_VALIDATE(*this);
     761             : 
     762             :     // TODO: special case this
     763             : 
     764         226 :     SkPath path;
     765         113 :     path.addRect(r);
     766         113 :     return this->setPath(path, nullptr, doAA);
     767             : }
     768             : 
     769           0 : static void append_run(SkTDArray<uint8_t>& array, uint8_t value, int count) {
     770           0 :     SkASSERT(count >= 0);
     771           0 :     while (count > 0) {
     772           0 :         int n = count;
     773           0 :         if (n > 255) {
     774           0 :             n = 255;
     775             :         }
     776           0 :         uint8_t* data = array.append(2);
     777           0 :         data[0] = n;
     778           0 :         data[1] = value;
     779           0 :         count -= n;
     780             :     }
     781           0 : }
     782             : 
     783          40 : bool SkAAClip::setRegion(const SkRegion& rgn) {
     784          40 :     if (rgn.isEmpty()) {
     785          10 :         return this->setEmpty();
     786             :     }
     787          30 :     if (rgn.isRect()) {
     788          30 :         return this->setRect(rgn.getBounds());
     789             :     }
     790             : 
     791             : #if 0
     792             :     SkAAClip clip;
     793             :     SkRegion::Iterator iter(rgn);
     794             :     for (; !iter.done(); iter.next()) {
     795             :         clip.op(iter.rect(), SkRegion::kUnion_Op);
     796             :     }
     797             :     this->swap(clip);
     798             :     return !this->isEmpty();
     799             : #else
     800           0 :     const SkIRect& bounds = rgn.getBounds();
     801           0 :     const int offsetX = bounds.fLeft;
     802           0 :     const int offsetY = bounds.fTop;
     803             : 
     804           0 :     SkTDArray<YOffset> yArray;
     805           0 :     SkTDArray<uint8_t> xArray;
     806             : 
     807           0 :     yArray.setReserve(SkMin32(bounds.height(), 1024));
     808           0 :     xArray.setReserve(SkMin32(bounds.width() * 128, 64 * 1024));
     809             : 
     810           0 :     SkRegion::Iterator iter(rgn);
     811           0 :     int prevRight = 0;
     812           0 :     int prevBot = 0;
     813           0 :     YOffset* currY = nullptr;
     814             : 
     815           0 :     for (; !iter.done(); iter.next()) {
     816           0 :         const SkIRect& r = iter.rect();
     817           0 :         SkASSERT(bounds.contains(r));
     818             : 
     819           0 :         int bot = r.fBottom - offsetY;
     820           0 :         SkASSERT(bot >= prevBot);
     821           0 :         if (bot > prevBot) {
     822           0 :             if (currY) {
     823             :                 // flush current row
     824           0 :                 append_run(xArray, 0, bounds.width() - prevRight);
     825             :             }
     826             :             // did we introduce an empty-gap from the prev row?
     827           0 :             int top = r.fTop - offsetY;
     828           0 :             if (top > prevBot) {
     829           0 :                 currY = yArray.append();
     830           0 :                 currY->fY = top - 1;
     831           0 :                 currY->fOffset = xArray.count();
     832           0 :                 append_run(xArray, 0, bounds.width());
     833             :             }
     834             :             // create a new record for this Y value
     835           0 :             currY = yArray.append();
     836           0 :             currY->fY = bot - 1;
     837           0 :             currY->fOffset = xArray.count();
     838           0 :             prevRight = 0;
     839           0 :             prevBot = bot;
     840             :         }
     841             : 
     842           0 :         int x = r.fLeft - offsetX;
     843           0 :         append_run(xArray, 0, x - prevRight);
     844             : 
     845           0 :         int w = r.fRight - r.fLeft;
     846           0 :         append_run(xArray, 0xFF, w);
     847           0 :         prevRight = x + w;
     848           0 :         SkASSERT(prevRight <= bounds.width());
     849             :     }
     850             :     // flush last row
     851           0 :     append_run(xArray, 0, bounds.width() - prevRight);
     852             : 
     853             :     // now pack everything into a RunHead
     854           0 :     RunHead* head = RunHead::Alloc(yArray.count(), xArray.bytes());
     855           0 :     memcpy(head->yoffsets(), yArray.begin(), yArray.bytes());
     856           0 :     memcpy(head->data(), xArray.begin(), xArray.bytes());
     857             : 
     858           0 :     this->setEmpty();
     859           0 :     fBounds = bounds;
     860           0 :     fRunHead = head;
     861           0 :     this->validate();
     862           0 :     return true;
     863             : #endif
     864             : }
     865             : 
     866             : ///////////////////////////////////////////////////////////////////////////////
     867             : 
     868        5435 : const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
     869        5435 :     SkASSERT(fRunHead);
     870             : 
     871        5435 :     if (!y_in_rect(y, fBounds)) {
     872           0 :         return nullptr;
     873             :     }
     874        5435 :     y -= fBounds.y();  // our yoffs values are relative to the top
     875             : 
     876        5435 :     const YOffset* yoff = fRunHead->yoffsets();
     877       67863 :     while (yoff->fY < y) {
     878       31214 :         yoff += 1;
     879       31214 :         SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
     880             :     }
     881             : 
     882        5435 :     if (lastYForRow) {
     883         297 :         *lastYForRow = fBounds.y() + yoff->fY;
     884             :     }
     885        5435 :     return fRunHead->data() + yoff->fOffset;
     886             : }
     887             : 
     888        5288 : const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
     889        5288 :     SkASSERT(x_in_rect(x, fBounds));
     890        5288 :     x -= fBounds.x();
     891             : 
     892             :     // first skip up to X
     893             :     for (;;) {
     894       16455 :         int n = data[0];
     895       16455 :         if (x < n) {
     896        5288 :             if (initialCount) {
     897        5288 :                 *initialCount = n - x;
     898             :             }
     899        5288 :             break;
     900             :         }
     901       11167 :         data += 2;
     902       11167 :         x -= n;
     903       11167 :     }
     904        5288 :     return data;
     905             : }
     906             : 
     907         298 : bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
     908         298 :     if (this->isEmpty()) {
     909           0 :         return false;
     910             :     }
     911         298 :     if (!fBounds.contains(left, top, right, bottom)) {
     912           9 :         return false;
     913             :     }
     914             : #if 0
     915             :     if (this->isRect()) {
     916             :         return true;
     917             :     }
     918             : #endif
     919             : 
     920         289 :     int lastY SK_INIT_TO_AVOID_WARNING;
     921         289 :     const uint8_t* row = this->findRow(top, &lastY);
     922         289 :     if (lastY < bottom) {
     923         147 :         return false;
     924             :     }
     925             :     // now just need to check in X
     926             :     int count;
     927         142 :     row = this->findX(row, left, &count);
     928             : #if 0
     929             :     return count >= (right - left) && 0xFF == row[1];
     930             : #else
     931         142 :     int rectWidth = right - left;
     932         186 :     while (0xFF == row[1]) {
     933         146 :         if (count >= rectWidth) {
     934         124 :             return true;
     935             :         }
     936          22 :         rectWidth -= count;
     937          22 :         row += 2;
     938          22 :         count = row[0];
     939             :     }
     940          18 :     return false;
     941             : #endif
     942             : }
     943             : 
     944             : ///////////////////////////////////////////////////////////////////////////////
     945             : 
     946             : class SkAAClip::Builder {
     947             :     SkIRect fBounds;
     948             :     struct Row {
     949             :         int fY;
     950             :         int fWidth;
     951             :         SkTDArray<uint8_t>* fData;
     952             :     };
     953             :     SkTDArray<Row>  fRows;
     954             :     Row* fCurrRow;
     955             :     int fPrevY;
     956             :     int fWidth;
     957             :     int fMinY;
     958             : 
     959             : public:
     960         275 :     Builder(const SkIRect& bounds) : fBounds(bounds) {
     961         275 :         fPrevY = -1;
     962         275 :         fWidth = bounds.width();
     963         275 :         fCurrRow = nullptr;
     964         275 :         fMinY = bounds.fTop;
     965         275 :     }
     966             : 
     967         550 :     ~Builder() {
     968         275 :         Row* row = fRows.begin();
     969         275 :         Row* stop = fRows.end();
     970        3601 :         while (row < stop) {
     971        1663 :             delete row->fData;
     972        1663 :             row += 1;
     973             :         }
     974         275 :     }
     975             : 
     976         427 :     const SkIRect& getBounds() const { return fBounds; }
     977             : 
     978       12839 :     void addRun(int x, int y, U8CPU alpha, int count) {
     979       12839 :         SkASSERT(count > 0);
     980       12839 :         SkASSERT(fBounds.contains(x, y));
     981       12839 :         SkASSERT(fBounds.contains(x + count - 1, y));
     982             : 
     983       12839 :         x -= fBounds.left();
     984       12839 :         y -= fBounds.top();
     985             : 
     986       12839 :         Row* row = fCurrRow;
     987       12839 :         if (y != fPrevY) {
     988        2746 :             SkASSERT(y > fPrevY);
     989        2746 :             fPrevY = y;
     990        2746 :             row = this->flushRow(true);
     991        2746 :             row->fY = y;
     992        2746 :             row->fWidth = 0;
     993        2746 :             SkASSERT(row->fData);
     994        2746 :             SkASSERT(0 == row->fData->count());
     995        2746 :             fCurrRow = row;
     996             :         }
     997             : 
     998       12839 :         SkASSERT(row->fWidth <= x);
     999       12839 :         SkASSERT(row->fWidth < fBounds.width());
    1000             : 
    1001       12839 :         SkTDArray<uint8_t>& data = *row->fData;
    1002             : 
    1003       12839 :         int gap = x - row->fWidth;
    1004       12839 :         if (gap) {
    1005         176 :             AppendRun(data, 0, gap);
    1006         176 :             row->fWidth += gap;
    1007         176 :             SkASSERT(row->fWidth < fBounds.width());
    1008             :         }
    1009             : 
    1010       12839 :         AppendRun(data, alpha, count);
    1011       12839 :         row->fWidth += count;
    1012       12839 :         SkASSERT(row->fWidth <= fBounds.width());
    1013       12839 :     }
    1014             : 
    1015           0 :     void addColumn(int x, int y, U8CPU alpha, int height) {
    1016           0 :         SkASSERT(fBounds.contains(x, y + height - 1));
    1017             : 
    1018           0 :         this->addRun(x, y, alpha, 1);
    1019           0 :         this->flushRowH(fCurrRow);
    1020           0 :         y -= fBounds.fTop;
    1021           0 :         SkASSERT(y == fCurrRow->fY);
    1022           0 :         fCurrRow->fY = y + height - 1;
    1023           0 :     }
    1024             : 
    1025           3 :     void addRectRun(int x, int y, int width, int height) {
    1026           3 :         SkASSERT(fBounds.contains(x + width - 1, y + height - 1));
    1027           3 :         this->addRun(x, y, 0xFF, width);
    1028             : 
    1029             :         // we assum the rect must be all we'll see for these scanlines
    1030             :         // so we ensure our row goes all the way to our right
    1031           3 :         this->flushRowH(fCurrRow);
    1032             : 
    1033           3 :         y -= fBounds.fTop;
    1034           3 :         SkASSERT(y == fCurrRow->fY);
    1035           3 :         fCurrRow->fY = y + height - 1;
    1036           3 :     }
    1037             : 
    1038         119 :     void addAntiRectRun(int x, int y, int width, int height,
    1039             :                         SkAlpha leftAlpha, SkAlpha rightAlpha) {
    1040             :         // According to SkBlitter.cpp, no matter whether leftAlpha is 0 or positive,
    1041             :         // we should always consider [x, x+1] as the left-most column and [x+1, x+1+width]
    1042             :         // as the rect with full alpha.
    1043         119 :         SkASSERT(fBounds.contains(x + width + (rightAlpha > 0 ? 1 : 0),
    1044             :                  y + height - 1));
    1045         119 :         SkASSERT(width >= 0);
    1046             : 
    1047             :         // Conceptually we're always adding 3 runs, but we should
    1048             :         // merge or omit them if possible.
    1049         119 :         if (leftAlpha == 0xFF) {
    1050           0 :             width++;
    1051         119 :         } else if (leftAlpha > 0) {
    1052           0 :           this->addRun(x++, y, leftAlpha, 1);
    1053             :         } else {
    1054             :           // leftAlpha is 0, ignore the left column
    1055         119 :           x++;
    1056             :         }
    1057         119 :         if (rightAlpha == 0xFF) {
    1058           0 :             width++;
    1059             :         }
    1060         119 :         if (width > 0) {
    1061         119 :             this->addRun(x, y, 0xFF, width);
    1062             :         }
    1063         119 :         if (rightAlpha > 0 && rightAlpha < 255) {
    1064           0 :             this->addRun(x + width, y, rightAlpha, 1);
    1065             :         }
    1066             : 
    1067             :         // we assume the rect must be all we'll see for these scanlines
    1068             :         // so we ensure our row goes all the way to our right
    1069         119 :         this->flushRowH(fCurrRow);
    1070             : 
    1071         119 :         y -= fBounds.fTop;
    1072         119 :         SkASSERT(y == fCurrRow->fY);
    1073         119 :         fCurrRow->fY = y + height - 1;
    1074         119 :     }
    1075             : 
    1076         275 :     bool finish(SkAAClip* target) {
    1077         275 :         this->flushRow(false);
    1078             : 
    1079         275 :         const Row* row = fRows.begin();
    1080         275 :         const Row* stop = fRows.end();
    1081             : 
    1082         275 :         size_t dataSize = 0;
    1083        3601 :         while (row < stop) {
    1084        1663 :             dataSize += row->fData->count();
    1085        1663 :             row += 1;
    1086             :         }
    1087             : 
    1088         275 :         if (0 == dataSize) {
    1089           0 :             return target->setEmpty();
    1090             :         }
    1091             : 
    1092         275 :         SkASSERT(fMinY >= fBounds.fTop);
    1093         275 :         SkASSERT(fMinY < fBounds.fBottom);
    1094         275 :         int adjustY = fMinY - fBounds.fTop;
    1095         275 :         fBounds.fTop = fMinY;
    1096             : 
    1097         275 :         RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
    1098         275 :         YOffset* yoffset = head->yoffsets();
    1099         275 :         uint8_t* data = head->data();
    1100         275 :         uint8_t* baseData = data;
    1101             : 
    1102         275 :         row = fRows.begin();
    1103         275 :         SkDEBUGCODE(int prevY = row->fY - 1;)
    1104        3601 :         while (row < stop) {
    1105        1663 :             SkASSERT(prevY < row->fY);  // must be monotonic
    1106        1663 :             SkDEBUGCODE(prevY = row->fY);
    1107             : 
    1108        1663 :             yoffset->fY = row->fY - adjustY;
    1109        1663 :             yoffset->fOffset = SkToU32(data - baseData);
    1110        1663 :             yoffset += 1;
    1111             : 
    1112        1663 :             size_t n = row->fData->count();
    1113        1663 :             memcpy(data, row->fData->begin(), n);
    1114             : #ifdef SK_DEBUG
    1115        1663 :             size_t bytesNeeded = compute_row_length(data, fBounds.width());
    1116        1663 :             SkASSERT(bytesNeeded == n);
    1117             : #endif
    1118        1663 :             data += n;
    1119             : 
    1120        1663 :             row += 1;
    1121             :         }
    1122             : 
    1123         275 :         target->freeRuns();
    1124         275 :         target->fBounds = fBounds;
    1125         275 :         target->fRunHead = head;
    1126         275 :         return target->trimBounds();
    1127             :     }
    1128             : 
    1129             :     void dump() {
    1130             :         this->validate();
    1131             :         int y;
    1132             :         for (y = 0; y < fRows.count(); ++y) {
    1133             :             const Row& row = fRows[y];
    1134             :             SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
    1135             :             const SkTDArray<uint8_t>& data = *row.fData;
    1136             :             int count = data.count();
    1137             :             SkASSERT(!(count & 1));
    1138             :             const uint8_t* ptr = data.begin();
    1139             :             for (int x = 0; x < count; x += 2) {
    1140             :                 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
    1141             :                 ptr += 2;
    1142             :             }
    1143             :             SkDebugf("\n");
    1144             :         }
    1145             :     }
    1146             : 
    1147             :     void validate() {
    1148             : #ifdef SK_DEBUG
    1149             :         if (false) { // avoid bit rot, suppress warning
    1150             :             test_count_left_right_zeros();
    1151             :         }
    1152             :         int prevY = -1;
    1153             :         for (int i = 0; i < fRows.count(); ++i) {
    1154             :             const Row& row = fRows[i];
    1155             :             SkASSERT(prevY < row.fY);
    1156             :             SkASSERT(fWidth == row.fWidth);
    1157             :             int count = row.fData->count();
    1158             :             const uint8_t* ptr = row.fData->begin();
    1159             :             SkASSERT(!(count & 1));
    1160             :             int w = 0;
    1161             :             for (int x = 0; x < count; x += 2) {
    1162             :                 int n = ptr[0];
    1163             :                 SkASSERT(n > 0);
    1164             :                 w += n;
    1165             :                 SkASSERT(w <= fWidth);
    1166             :                 ptr += 2;
    1167             :             }
    1168             :             SkASSERT(w == fWidth);
    1169             :             prevY = row.fY;
    1170             :         }
    1171             : #endif
    1172             :     }
    1173             : 
    1174             :     // only called by BuilderBlitter
    1175         152 :     void setMinY(int y) {
    1176         152 :         fMinY = y;
    1177         152 :     }
    1178             : 
    1179             : private:
    1180        2868 :     void flushRowH(Row* row) {
    1181             :         // flush current row if needed
    1182        2868 :         if (row->fWidth < fWidth) {
    1183         278 :             AppendRun(*row->fData, 0, fWidth - row->fWidth);
    1184         278 :             row->fWidth = fWidth;
    1185             :         }
    1186        2868 :     }
    1187             : 
    1188        3021 :     Row* flushRow(bool readyForAnother) {
    1189        3021 :         Row* next = nullptr;
    1190        3021 :         int count = fRows.count();
    1191        3021 :         if (count > 0) {
    1192        2746 :             this->flushRowH(&fRows[count - 1]);
    1193             :         }
    1194        3021 :         if (count > 1) {
    1195             :             // are our last two runs the same?
    1196        2471 :             Row* prev = &fRows[count - 2];
    1197        2471 :             Row* curr = &fRows[count - 1];
    1198        2471 :             SkASSERT(prev->fWidth == fWidth);
    1199        2471 :             SkASSERT(curr->fWidth == fWidth);
    1200        2471 :             if (*prev->fData == *curr->fData) {
    1201        1083 :                 prev->fY = curr->fY;
    1202        1083 :                 if (readyForAnother) {
    1203        1063 :                     curr->fData->rewind();
    1204        1063 :                     next = curr;
    1205             :                 } else {
    1206          20 :                     delete curr->fData;
    1207          20 :                     fRows.removeShuffle(count - 1);
    1208             :                 }
    1209             :             } else {
    1210        1388 :                 if (readyForAnother) {
    1211        1280 :                     next = fRows.append();
    1212        1280 :                     next->fData = new SkTDArray<uint8_t>;
    1213             :                 }
    1214             :             }
    1215             :         } else {
    1216         550 :             if (readyForAnother) {
    1217         403 :                 next = fRows.append();
    1218         403 :                 next->fData = new SkTDArray<uint8_t>;
    1219             :             }
    1220             :         }
    1221        3021 :         return next;
    1222             :     }
    1223             : 
    1224       19462 :     static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
    1225        6169 :         do {
    1226       19462 :             int n = count;
    1227       19462 :             if (n > 255) {
    1228        6169 :                 n = 255;
    1229             :             }
    1230       19462 :             uint8_t* ptr = data.append(2);
    1231       19462 :             ptr[0] = n;
    1232       19462 :             ptr[1] = alpha;
    1233       19462 :             count -= n;
    1234       19462 :         } while (count > 0);
    1235       13293 :     }
    1236             : };
    1237             : 
    1238         152 : class SkAAClip::BuilderBlitter : public SkBlitter {
    1239             :     int fLastY;
    1240             : 
    1241             :     /*
    1242             :         If we see a gap of 1 or more empty scanlines while building in Y-order,
    1243             :         we inject an explicit empty scanline (alpha==0)
    1244             : 
    1245             :         See AAClipTest.cpp : test_path_with_hole()
    1246             :      */
    1247        2710 :     void checkForYGap(int y) {
    1248        2710 :         SkASSERT(y >= fLastY);
    1249        2710 :         if (fLastY > -SK_MaxS32) {
    1250        2558 :             int gap = y - fLastY;
    1251        2558 :             if (gap > 1) {
    1252           1 :                 fBuilder->addRun(fLeft, y - 1, 0, fRight - fLeft);
    1253             :             }
    1254             :         }
    1255        2710 :         fLastY = y;
    1256        2710 :     }
    1257             : 
    1258             : public:
    1259             : 
    1260         152 :     BuilderBlitter(Builder* builder) {
    1261         152 :         fBuilder = builder;
    1262         152 :         fLeft = builder->getBounds().fLeft;
    1263         152 :         fRight = builder->getBounds().fRight;
    1264         152 :         fMinY = SK_MaxS32;
    1265         152 :         fLastY = -SK_MaxS32;    // sentinel
    1266         152 :     }
    1267             : 
    1268         152 :     void finish() {
    1269         152 :         if (fMinY < SK_MaxS32) {
    1270         152 :             fBuilder->setMinY(fMinY);
    1271             :         }
    1272         152 :     }
    1273             : 
    1274             :     /**
    1275             :        Must evaluate clips in scan-line order, so don't want to allow blitV(),
    1276             :        but an AAClip can be clipped down to a single pixel wide, so we
    1277             :        must support it (given AntiRect semantics: minimum width is 2).
    1278             :        Instead we'll rely on the runtime asserts to guarantee Y monotonicity;
    1279             :        any failure cases that misses may have minor artifacts.
    1280             :     */
    1281         364 :     void blitV(int x, int y, int height, SkAlpha alpha) override {
    1282         364 :         if (height == 1) {
    1283             :             // We're still in scan-line order if height is 1
    1284             :             // This is useful for Analytic AA
    1285         364 :             const SkAlpha alphas[2] = {alpha, 0};
    1286         364 :             const int16_t runs[2] = {1, 0};
    1287         364 :             this->blitAntiH(x, y, alphas, runs);
    1288             :         } else {
    1289           0 :             this->recordMinY(y);
    1290           0 :             fBuilder->addColumn(x, y, alpha, height);
    1291           0 :             fLastY = y + height - 1;
    1292             :         }
    1293         364 :     }
    1294             : 
    1295           3 :     void blitRect(int x, int y, int width, int height) override {
    1296           3 :         this->recordMinY(y);
    1297           3 :         this->checkForYGap(y);
    1298           3 :         fBuilder->addRectRun(x, y, width, height);
    1299           3 :         fLastY = y + height - 1;
    1300           3 :     }
    1301             : 
    1302         119 :     virtual void blitAntiRect(int x, int y, int width, int height,
    1303             :                      SkAlpha leftAlpha, SkAlpha rightAlpha) override {
    1304         119 :         this->recordMinY(y);
    1305         119 :         this->checkForYGap(y);
    1306         119 :         fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha);
    1307         119 :         fLastY = y + height - 1;
    1308         119 :     }
    1309             : 
    1310           0 :     void blitMask(const SkMask&, const SkIRect& clip) override
    1311           0 :         { unexpected(); }
    1312             : 
    1313           0 :     const SkPixmap* justAnOpaqueColor(uint32_t*) override {
    1314           0 :         return nullptr;
    1315             :     }
    1316             : 
    1317         426 :     void blitH(int x, int y, int width) override {
    1318         426 :         this->recordMinY(y);
    1319         426 :         this->checkForYGap(y);
    1320         426 :         fBuilder->addRun(x, y, 0xFF, width);
    1321         426 :     }
    1322             : 
    1323        2162 :     virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
    1324             :                            const int16_t runs[]) override {
    1325        2162 :         this->recordMinY(y);
    1326        2162 :         this->checkForYGap(y);
    1327             :         for (;;) {
    1328        7777 :             int count = *runs;
    1329        7777 :             if (count <= 0) {
    1330        4324 :                 return;
    1331             :             }
    1332             : 
    1333             :             // The supersampler's buffer can be the width of the device, so
    1334             :             // we may have to trim the run to our bounds. Previously, we assert that
    1335             :             // the extra spans are always alpha==0.
    1336             :             // However, the analytic AA is too sensitive to precision errors
    1337             :             // so it may have extra spans with very tiny alpha because after several
    1338             :             // arithmatic operations, the edge may bleed the path boundary a little bit.
    1339             :             // Therefore, instead of always asserting alpha==0, we assert alpha < 0x10.
    1340        5615 :             int localX = x;
    1341        5615 :             int localCount = count;
    1342        5615 :             if (x < fLeft) {
    1343           0 :                 SkASSERT(0x10 > *alpha);
    1344           0 :                 int gap = fLeft - x;
    1345           0 :                 SkASSERT(gap <= count);
    1346           0 :                 localX += gap;
    1347           0 :                 localCount -= gap;
    1348             :             }
    1349        5615 :             int right = x + count;
    1350        5615 :             if (right > fRight) {
    1351           0 :                 SkASSERT(0x10 > *alpha);
    1352           0 :                 localCount -= right - fRight;
    1353           0 :                 SkASSERT(localCount >= 0);
    1354             :             }
    1355             : 
    1356        5615 :             if (localCount) {
    1357        5615 :                 fBuilder->addRun(localX, y, *alpha, localCount);
    1358             :             }
    1359             :             // Next run
    1360        5615 :             runs += count;
    1361        5615 :             alpha += count;
    1362        5615 :             x += count;
    1363        5615 :         }
    1364             :     }
    1365             : 
    1366             : private:
    1367             :     Builder* fBuilder;
    1368             :     int      fLeft; // cache of builder's bounds' left edge
    1369             :     int      fRight;
    1370             :     int      fMinY;
    1371             : 
    1372             :     /*
    1373             :      *  We track this, in case the scan converter skipped some number of
    1374             :      *  scanlines at the (relative to the bounds it was given). This allows
    1375             :      *  the builder, during its finish, to trip its bounds down to the "real"
    1376             :      *  top.
    1377             :      */
    1378        2710 :     void recordMinY(int y) {
    1379        2710 :         if (y < fMinY) {
    1380         152 :             fMinY = y;
    1381             :         }
    1382        2710 :     }
    1383             : 
    1384           0 :     void unexpected() {
    1385           0 :         SkDebugf("---- did not expect to get called here");
    1386           0 :         sk_throw();
    1387           0 :     }
    1388             : };
    1389             : 
    1390         152 : bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
    1391         304 :     AUTO_AACLIP_VALIDATE(*this);
    1392             : 
    1393         152 :     if (clip && clip->isEmpty()) {
    1394           0 :         return this->setEmpty();
    1395             :     }
    1396             : 
    1397             :     SkIRect ibounds;
    1398         152 :     path.getBounds().roundOut(&ibounds);
    1399             : 
    1400         304 :     SkRegion tmpClip;
    1401         152 :     if (nullptr == clip) {
    1402         113 :         tmpClip.setRect(ibounds);
    1403         113 :         clip = &tmpClip;
    1404             :     }
    1405             : 
    1406             :     // Since we assert that the BuilderBlitter will never blit outside the intersection
    1407             :     // of clip and ibounds, we create this snugClip to be that intersection and send it
    1408             :     // to the scan-converter.
    1409         304 :     SkRegion snugClip(*clip);
    1410             : 
    1411         152 :     if (path.isInverseFillType()) {
    1412           0 :         ibounds = clip->getBounds();
    1413             :     } else {
    1414         152 :         if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
    1415           0 :             return this->setEmpty();
    1416             :         }
    1417         152 :         snugClip.op(ibounds, SkRegion::kIntersect_Op);
    1418             :     }
    1419             : 
    1420         304 :     Builder        builder(ibounds);
    1421         304 :     BuilderBlitter blitter(&builder);
    1422             : 
    1423         152 :     if (doAA) {
    1424         150 :         if (gSkUseAnalyticAA.load()) {
    1425         150 :             SkScan::AAAFillPath(path, snugClip, &blitter, true);
    1426             :         } else {
    1427           0 :             SkScan::AntiFillPath(path, snugClip, &blitter, true);
    1428             :         }
    1429             :     } else {
    1430           2 :         SkScan::FillPath(path, snugClip, &blitter);
    1431             :     }
    1432             : 
    1433         152 :     blitter.finish();
    1434         152 :     return builder.finish(this);
    1435             : }
    1436             : 
    1437             : ///////////////////////////////////////////////////////////////////////////////
    1438             : 
    1439             : typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
    1440             :                         const uint8_t* rowA, const SkIRect& rectA,
    1441             :                         const uint8_t* rowB, const SkIRect& rectB);
    1442             : 
    1443             : typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
    1444             : 
    1445        6675 : static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
    1446             :     // Multiply
    1447        6675 :     return SkMulDiv255Round(alphaA, alphaB);
    1448             : }
    1449             : 
    1450           0 : static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
    1451             :     // SrcOver
    1452           0 :     return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
    1453             : }
    1454             : 
    1455           0 : static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
    1456             :     // SrcOut
    1457           0 :     return SkMulDiv255Round(alphaA, 0xFF - alphaB);
    1458             : }
    1459             : 
    1460           0 : static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
    1461             :     // XOR
    1462           0 :     return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
    1463             : }
    1464             : 
    1465         123 : static AlphaProc find_alpha_proc(SkRegion::Op op) {
    1466         123 :     switch (op) {
    1467             :         case SkRegion::kIntersect_Op:
    1468         123 :             return sectAlphaProc;
    1469             :         case SkRegion::kDifference_Op:
    1470           0 :             return diffAlphaProc;
    1471             :         case SkRegion::kUnion_Op:
    1472           0 :             return unionAlphaProc;
    1473             :         case SkRegion::kXOR_Op:
    1474           0 :             return xorAlphaProc;
    1475             :         default:
    1476           0 :             SkDEBUGFAIL("unexpected region op");
    1477           0 :             return sectAlphaProc;
    1478             :     }
    1479             : }
    1480             : 
    1481             : class RowIter {
    1482             : public:
    1483        1482 :     RowIter(const uint8_t* row, const SkIRect& bounds) {
    1484        1482 :         fRow = row;
    1485        1482 :         fLeft = bounds.fLeft;
    1486        1482 :         fBoundsRight = bounds.fRight;
    1487        1482 :         if (row) {
    1488        1482 :             fRight = bounds.fLeft + row[0];
    1489        1482 :             SkASSERT(fRight <= fBoundsRight);
    1490        1482 :             fAlpha = row[1];
    1491        1482 :             fDone = false;
    1492             :         } else {
    1493           0 :             fDone = true;
    1494           0 :             fRight = kMaxInt32;
    1495           0 :             fAlpha = 0;
    1496             :         }
    1497        1482 :     }
    1498             : 
    1499        7555 :     bool done() const { return fDone; }
    1500       10164 :     int left() const { return fLeft; }
    1501       10164 :     int right() const { return fRight; }
    1502       13906 :     U8CPU alpha() const { return fAlpha; }
    1503        8682 :     void next() {
    1504        8682 :         if (!fDone) {
    1505        8682 :             fLeft = fRight;
    1506        8682 :             if (fRight == fBoundsRight) {
    1507        1343 :                 fDone = true;
    1508        1343 :                 fRight = kMaxInt32;
    1509        1343 :                 fAlpha = 0;
    1510             :             } else {
    1511        7339 :                 fRow += 2;
    1512        7339 :                 fRight += fRow[0];
    1513        7339 :                 fAlpha = fRow[1];
    1514        7339 :                 SkASSERT(fRight <= fBoundsRight);
    1515             :             }
    1516             :         }
    1517        8682 :     }
    1518             : 
    1519             : private:
    1520             :     const uint8_t*  fRow;
    1521             :     int             fLeft;
    1522             :     int             fRight;
    1523             :     int             fBoundsRight;
    1524             :     bool            fDone;
    1525             :     uint8_t         fAlpha;
    1526             : };
    1527             : 
    1528       13906 : static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
    1529       13906 :     if (rite == riteA) {
    1530        8682 :         iter.next();
    1531        8682 :         leftA = iter.left();
    1532        8682 :         riteA = iter.right();
    1533             :     }
    1534       13906 : }
    1535             : 
    1536             : #if 0 // UNUSED
    1537             : static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
    1538             :     SkASSERT(min < max);
    1539             :     SkASSERT(boundsMin < boundsMax);
    1540             :     if (min >= boundsMax || max <= boundsMin) {
    1541             :         return false;
    1542             :     }
    1543             :     if (min < boundsMin) {
    1544             :         min = boundsMin;
    1545             :     }
    1546             :     if (max > boundsMax) {
    1547             :         max = boundsMax;
    1548             :     }
    1549             :     return true;
    1550             : }
    1551             : #endif
    1552             : 
    1553         741 : static void operatorX(SkAAClip::Builder& builder, int lastY,
    1554             :                       RowIter& iterA, RowIter& iterB,
    1555             :                       AlphaProc proc, const SkIRect& bounds) {
    1556         741 :     int leftA = iterA.left();
    1557         741 :     int riteA = iterA.right();
    1558         741 :     int leftB = iterB.left();
    1559         741 :     int riteB = iterB.right();
    1560             : 
    1561         741 :     int prevRite = bounds.fLeft;
    1562             : 
    1563        6953 :     do {
    1564        7092 :         U8CPU alphaA = 0;
    1565        7092 :         U8CPU alphaB = 0;
    1566             :         int left, rite;
    1567             : 
    1568        7092 :         if (leftA < leftB) {
    1569         278 :             left = leftA;
    1570         278 :             alphaA = iterA.alpha();
    1571         278 :             if (riteA <= leftB) {
    1572         165 :                 rite = riteA;
    1573             :             } else {
    1574         113 :                 rite = leftA = leftB;
    1575             :             }
    1576        6814 :         } else if (leftB < leftA) {
    1577           0 :             left = leftB;
    1578           0 :             alphaB = iterB.alpha();
    1579           0 :             if (riteB <= leftA) {
    1580           0 :                 rite = riteB;
    1581             :             } else {
    1582           0 :                 rite = leftB = leftA;
    1583             :             }
    1584             :         } else {
    1585        6814 :             left = leftA;   // or leftB, since leftA == leftB
    1586        6814 :             rite = leftA = leftB = SkMin32(riteA, riteB);
    1587        6814 :             alphaA = iterA.alpha();
    1588        6814 :             alphaB = iterB.alpha();
    1589             :         }
    1590             : 
    1591        7092 :         if (left >= bounds.fRight) {
    1592         139 :             break;
    1593             :         }
    1594        6953 :         if (rite > bounds.fRight) {
    1595           0 :             rite = bounds.fRight;
    1596             :         }
    1597             : 
    1598        6953 :         if (left >= bounds.fLeft) {
    1599        6675 :             SkASSERT(rite > left);
    1600        6675 :             builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
    1601        6675 :             prevRite = rite;
    1602             :         }
    1603             : 
    1604        6953 :         adjust_row(iterA, leftA, riteA, rite);
    1605        6953 :         adjust_row(iterB, leftB, riteB, rite);
    1606        6953 :     } while (!iterA.done() || !iterB.done());
    1607             : 
    1608         741 :     if (prevRite < bounds.fRight) {
    1609           0 :         builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
    1610             :     }
    1611         741 : }
    1612             : 
    1613        1586 : static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
    1614        1586 :     if (bot == botA) {
    1615         894 :         iter.next();
    1616         894 :         topA = botA;
    1617         894 :         SkASSERT(botA == iter.top());
    1618         894 :         botA = iter.bottom();
    1619             :     }
    1620        1586 : }
    1621             : 
    1622         123 : static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
    1623             :                      const SkAAClip& B, SkRegion::Op op) {
    1624         123 :     AlphaProc proc = find_alpha_proc(op);
    1625         123 :     const SkIRect& bounds = builder.getBounds();
    1626             : 
    1627         123 :     SkAAClip::Iter iterA(A);
    1628         123 :     SkAAClip::Iter iterB(B);
    1629             : 
    1630         123 :     SkASSERT(!iterA.done());
    1631         123 :     int topA = iterA.top();
    1632         123 :     int botA = iterA.bottom();
    1633         123 :     SkASSERT(!iterB.done());
    1634         123 :     int topB = iterB.top();
    1635         123 :     int botB = iterB.bottom();
    1636             : 
    1637         793 :     do {
    1638         826 :         const uint8_t* rowA = nullptr;
    1639         826 :         const uint8_t* rowB = nullptr;
    1640             :         int top, bot;
    1641             : 
    1642         826 :         if (topA < topB) {
    1643          52 :             top = topA;
    1644          52 :             rowA = iterA.data();
    1645          52 :             if (botA <= topB) {
    1646          33 :                 bot = botA;
    1647             :             } else {
    1648          19 :                 bot = topA = topB;
    1649             :             }
    1650             : 
    1651         774 :         } else if (topB < topA) {
    1652           0 :             top = topB;
    1653           0 :             rowB = iterB.data();
    1654           0 :             if (botB <= topA) {
    1655           0 :                 bot = botB;
    1656             :             } else {
    1657           0 :                 bot = topB = topA;
    1658             :             }
    1659             :         } else {
    1660         774 :             top = topA;   // or topB, since topA == topB
    1661         774 :             bot = topA = topB = SkMin32(botA, botB);
    1662         774 :             rowA = iterA.data();
    1663         774 :             rowB = iterB.data();
    1664             :         }
    1665             : 
    1666         826 :         if (top >= bounds.fBottom) {
    1667          33 :             break;
    1668             :         }
    1669             : 
    1670         793 :         if (bot > bounds.fBottom) {
    1671           0 :             bot = bounds.fBottom;
    1672             :         }
    1673         793 :         SkASSERT(top < bot);
    1674             : 
    1675         793 :         if (!rowA && !rowB) {
    1676           0 :             builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
    1677         793 :         } else if (top >= bounds.fTop) {
    1678         741 :             SkASSERT(bot <= bounds.fBottom);
    1679         741 :             RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
    1680         741 :             RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
    1681         741 :             operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
    1682             :         }
    1683             : 
    1684         793 :         adjust_iter(iterA, topA, botA, bot);
    1685         793 :         adjust_iter(iterB, topB, botB, bot);
    1686         793 :     } while (!iterA.done() || !iterB.done());
    1687         123 : }
    1688             : 
    1689         123 : bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
    1690             :                   SkRegion::Op op) {
    1691         246 :     AUTO_AACLIP_VALIDATE(*this);
    1692             : 
    1693         123 :     if (SkRegion::kReplace_Op == op) {
    1694           0 :         return this->set(clipBOrig);
    1695             :     }
    1696             : 
    1697         123 :     const SkAAClip* clipA = &clipAOrig;
    1698         123 :     const SkAAClip* clipB = &clipBOrig;
    1699             : 
    1700         123 :     if (SkRegion::kReverseDifference_Op == op) {
    1701           0 :         SkTSwap(clipA, clipB);
    1702           0 :         op = SkRegion::kDifference_Op;
    1703             :     }
    1704             : 
    1705         123 :     bool a_empty = clipA->isEmpty();
    1706         123 :     bool b_empty = clipB->isEmpty();
    1707             : 
    1708             :     SkIRect bounds;
    1709         123 :     switch (op) {
    1710             :         case SkRegion::kDifference_Op:
    1711           0 :             if (a_empty) {
    1712           0 :                 return this->setEmpty();
    1713             :             }
    1714           0 :             if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
    1715           0 :                 return this->set(*clipA);
    1716             :             }
    1717           0 :             bounds = clipA->fBounds;
    1718           0 :             break;
    1719             : 
    1720             :         case SkRegion::kIntersect_Op:
    1721         246 :             if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
    1722         123 :                                                          clipB->fBounds)) {
    1723           0 :                 return this->setEmpty();
    1724             :             }
    1725         123 :             break;
    1726             : 
    1727             :         case SkRegion::kUnion_Op:
    1728             :         case SkRegion::kXOR_Op:
    1729           0 :             if (a_empty) {
    1730           0 :                 return this->set(*clipB);
    1731             :             }
    1732           0 :             if (b_empty) {
    1733           0 :                 return this->set(*clipA);
    1734             :             }
    1735           0 :             bounds = clipA->fBounds;
    1736           0 :             bounds.join(clipB->fBounds);
    1737           0 :             break;
    1738             : 
    1739             :         default:
    1740           0 :             SkDEBUGFAIL("unknown region op");
    1741           0 :             return !this->isEmpty();
    1742             :     }
    1743             : 
    1744         123 :     SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
    1745         123 :     SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
    1746             : 
    1747         246 :     Builder builder(bounds);
    1748         123 :     operateY(builder, *clipA, *clipB, op);
    1749             : 
    1750         123 :     return builder.finish(this);
    1751             : }
    1752             : 
    1753             : /*
    1754             :  *  It can be expensive to build a local aaclip before applying the op, so
    1755             :  *  we first see if we can restrict the bounds of new rect to our current
    1756             :  *  bounds, or note that the new rect subsumes our current clip.
    1757             :  */
    1758             : 
    1759           0 : bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
    1760             :     SkIRect        rStorage;
    1761           0 :     const SkIRect* r = &rOrig;
    1762             : 
    1763           0 :     switch (op) {
    1764             :         case SkRegion::kIntersect_Op:
    1765           0 :             if (!rStorage.intersect(rOrig, fBounds)) {
    1766             :                 // no overlap, so we're empty
    1767           0 :                 return this->setEmpty();
    1768             :             }
    1769           0 :             if (rStorage == fBounds) {
    1770             :                 // we were wholly inside the rect, no change
    1771           0 :                 return !this->isEmpty();
    1772             :             }
    1773           0 :             if (this->quickContains(rStorage)) {
    1774             :                 // the intersection is wholly inside us, we're a rect
    1775           0 :                 return this->setRect(rStorage);
    1776             :             }
    1777           0 :             r = &rStorage;   // use the intersected bounds
    1778           0 :             break;
    1779             :         case SkRegion::kDifference_Op:
    1780           0 :             break;
    1781             :         case SkRegion::kUnion_Op:
    1782           0 :             if (rOrig.contains(fBounds)) {
    1783           0 :                 return this->setRect(rOrig);
    1784             :             }
    1785           0 :             break;
    1786             :         default:
    1787           0 :             break;
    1788             :     }
    1789             : 
    1790           0 :     SkAAClip clip;
    1791           0 :     clip.setRect(*r);
    1792           0 :     return this->op(*this, clip, op);
    1793             : }
    1794             : 
    1795         113 : bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
    1796             :     SkRect        rStorage, boundsStorage;
    1797         113 :     const SkRect* r = &rOrig;
    1798             : 
    1799         113 :     boundsStorage.set(fBounds);
    1800         113 :     switch (op) {
    1801             :         case SkRegion::kIntersect_Op:
    1802             :         case SkRegion::kDifference_Op:
    1803         113 :             if (!rStorage.intersect(rOrig, boundsStorage)) {
    1804           0 :                 if (SkRegion::kIntersect_Op == op) {
    1805           0 :                     return this->setEmpty();
    1806             :                 } else {    // kDifference
    1807           0 :                     return !this->isEmpty();
    1808             :                 }
    1809             :             }
    1810         113 :             r = &rStorage;   // use the intersected bounds
    1811         113 :             break;
    1812             :         case SkRegion::kUnion_Op:
    1813           0 :             if (rOrig.contains(boundsStorage)) {
    1814           0 :                 return this->setRect(rOrig);
    1815             :             }
    1816           0 :             break;
    1817             :         default:
    1818           0 :             break;
    1819             :     }
    1820             : 
    1821         226 :     SkAAClip clip;
    1822         113 :     clip.setRect(*r, doAA);
    1823         113 :     return this->op(*this, clip, op);
    1824             : }
    1825             : 
    1826          10 : bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
    1827          10 :     return this->op(*this, clip, op);
    1828             : }
    1829             : 
    1830             : ///////////////////////////////////////////////////////////////////////////////
    1831             : 
    1832           0 : bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
    1833           0 :     if (nullptr == dst) {
    1834           0 :         return !this->isEmpty();
    1835             :     }
    1836             : 
    1837           0 :     if (this->isEmpty()) {
    1838           0 :         return dst->setEmpty();
    1839             :     }
    1840             : 
    1841           0 :     if (this != dst) {
    1842           0 :         sk_atomic_inc(&fRunHead->fRefCnt);
    1843           0 :         dst->freeRuns();
    1844           0 :         dst->fRunHead = fRunHead;
    1845           0 :         dst->fBounds = fBounds;
    1846             :     }
    1847           0 :     dst->fBounds.offset(dx, dy);
    1848           0 :     return true;
    1849             : }
    1850             : 
    1851           0 : static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
    1852             :                                const uint8_t* SK_RESTRICT row,
    1853             :                                int width) {
    1854           0 :     while (width > 0) {
    1855           0 :         int n = row[0];
    1856           0 :         SkASSERT(width >= n);
    1857           0 :         memset(mask, row[1], n);
    1858           0 :         mask += n;
    1859           0 :         row += 2;
    1860           0 :         width -= n;
    1861             :     }
    1862           0 :     SkASSERT(0 == width);
    1863           0 : }
    1864             : 
    1865           0 : void SkAAClip::copyToMask(SkMask* mask) const {
    1866           0 :     mask->fFormat = SkMask::kA8_Format;
    1867           0 :     if (this->isEmpty()) {
    1868           0 :         mask->fBounds.setEmpty();
    1869           0 :         mask->fImage = nullptr;
    1870           0 :         mask->fRowBytes = 0;
    1871           0 :         return;
    1872             :     }
    1873             : 
    1874           0 :     mask->fBounds = fBounds;
    1875           0 :     mask->fRowBytes = fBounds.width();
    1876           0 :     size_t size = mask->computeImageSize();
    1877           0 :     mask->fImage = SkMask::AllocImage(size);
    1878             : 
    1879           0 :     Iter iter(*this);
    1880           0 :     uint8_t* dst = mask->fImage;
    1881           0 :     const int width = fBounds.width();
    1882             : 
    1883           0 :     int y = fBounds.fTop;
    1884           0 :     while (!iter.done()) {
    1885           0 :         do {
    1886           0 :             expand_row_to_mask(dst, iter.data(), width);
    1887           0 :             dst += mask->fRowBytes;
    1888           0 :         } while (++y < iter.bottom());
    1889           0 :         iter.next();
    1890             :     }
    1891             : }
    1892             : 
    1893             : ///////////////////////////////////////////////////////////////////////////////
    1894             : ///////////////////////////////////////////////////////////////////////////////
    1895             : 
    1896        3496 : static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
    1897             :                          int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
    1898             :     // we don't read our initial n from data, since the caller may have had to
    1899             :     // clip it, hence the initialCount parameter.
    1900        3496 :     int n = initialCount;
    1901             :     for (;;) {
    1902       37780 :         if (n > width) {
    1903         908 :             n = width;
    1904             :         }
    1905       20638 :         SkASSERT(n > 0);
    1906       20638 :         runs[0] = n;
    1907       20638 :         runs += n;
    1908             : 
    1909       20638 :         aa[0] = data[1];
    1910       20638 :         aa += n;
    1911             : 
    1912       20638 :         data += 2;
    1913       20638 :         width -= n;
    1914       20638 :         if (0 == width) {
    1915        3496 :             break;
    1916             :         }
    1917             :         // load the next count
    1918       17142 :         n = data[0];
    1919             :     }
    1920        3496 :     runs[0] = 0;    // sentinel
    1921        3496 : }
    1922             : 
    1923         394 : SkAAClipBlitter::~SkAAClipBlitter() {
    1924         197 :     sk_free(fScanlineScratch);
    1925         197 : }
    1926             : 
    1927        3806 : void SkAAClipBlitter::ensureRunsAndAA() {
    1928        3806 :     if (nullptr == fScanlineScratch) {
    1929             :         // add 1 so we can store the terminating run count of 0
    1930         119 :         int count = fAAClipBounds.width() + 1;
    1931             :         // we use this either for fRuns + fAA, or a scaline of a mask
    1932             :         // which may be as deep as 32bits
    1933         119 :         fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
    1934         119 :         fRuns = (int16_t*)fScanlineScratch;
    1935         119 :         fAA = (SkAlpha*)(fRuns + count);
    1936             :     }
    1937        3806 : }
    1938             : 
    1939        4836 : void SkAAClipBlitter::blitH(int x, int y, int width) {
    1940        4836 :     SkASSERT(width > 0);
    1941        4836 :     SkASSERT(fAAClipBounds.contains(x, y));
    1942        4836 :     SkASSERT(fAAClipBounds.contains(x + width  - 1, y));
    1943             : 
    1944        4836 :     const uint8_t* row = fAAClip->findRow(y);
    1945             :     int initialCount;
    1946        4836 :     row = fAAClip->findX(row, x, &initialCount);
    1947             : 
    1948        4836 :     if (initialCount >= width) {
    1949        1340 :         SkAlpha alpha = row[1];
    1950        1340 :         if (0 == alpha) {
    1951        1354 :             return;
    1952             :         }
    1953        1326 :         if (0xFF == alpha) {
    1954        1326 :             fBlitter->blitH(x, y, width);
    1955        1326 :             return;
    1956             :         }
    1957             :     }
    1958             : 
    1959        3496 :     this->ensureRunsAndAA();
    1960        3496 :     expandToRuns(row, initialCount, width, fRuns, fAA);
    1961             : 
    1962        3496 :     fBlitter->blitAntiH(x, y, fAA, fRuns);
    1963             : }
    1964             : 
    1965         302 : static void merge(const uint8_t* SK_RESTRICT row, int rowN,
    1966             :                   const SkAlpha* SK_RESTRICT srcAA,
    1967             :                   const int16_t* SK_RESTRICT srcRuns,
    1968             :                   SkAlpha* SK_RESTRICT dstAA,
    1969             :                   int16_t* SK_RESTRICT dstRuns,
    1970             :                   int width) {
    1971         302 :     SkDEBUGCODE(int accumulated = 0;)
    1972         302 :     int srcN = srcRuns[0];
    1973             :     // do we need this check?
    1974         302 :     if (0 == srcN) {
    1975           0 :         return;
    1976             :     }
    1977             : 
    1978             :     for (;;) {
    1979        2865 :         SkASSERT(rowN > 0);
    1980        2865 :         SkASSERT(srcN > 0);
    1981             : 
    1982        2865 :         unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
    1983        2865 :         int minN = SkMin32(srcN, rowN);
    1984        2865 :         dstRuns[0] = minN;
    1985        2865 :         dstRuns += minN;
    1986        2865 :         dstAA[0] = newAlpha;
    1987        2865 :         dstAA += minN;
    1988             : 
    1989        2865 :         if (0 == (srcN -= minN)) {
    1990        1087 :             srcN = srcRuns[0];  // refresh
    1991        1087 :             srcRuns += srcN;
    1992        1087 :             srcAA += srcN;
    1993        1087 :             srcN = srcRuns[0];  // reload
    1994        1087 :             if (0 == srcN) {
    1995         302 :                 break;
    1996             :             }
    1997             :         }
    1998        2563 :         if (0 == (rowN -= minN)) {
    1999        1778 :             row += 2;
    2000        1778 :             rowN = row[0];  // reload
    2001             :         }
    2002             : 
    2003        2563 :         SkDEBUGCODE(accumulated += minN;)
    2004        2563 :         SkASSERT(accumulated <= width);
    2005        2563 :     }
    2006         302 :     dstRuns[0] = 0;
    2007             : }
    2008             : 
    2009         302 : void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
    2010             :                                 const int16_t runs[]) {
    2011             : 
    2012         302 :     const uint8_t* row = fAAClip->findRow(y);
    2013             :     int initialCount;
    2014         302 :     row = fAAClip->findX(row, x, &initialCount);
    2015             : 
    2016         302 :     this->ensureRunsAndAA();
    2017             : 
    2018         302 :     merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
    2019         302 :     fBlitter->blitAntiH(x, y, fAA, fRuns);
    2020         302 : }
    2021             : 
    2022           0 : void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
    2023           0 :     if (fAAClip->quickContains(x, y, x + 1, y + height)) {
    2024           0 :         fBlitter->blitV(x, y, height, alpha);
    2025           0 :         return;
    2026             :     }
    2027             : 
    2028             :     for (;;) {
    2029           0 :         int lastY SK_INIT_TO_AVOID_WARNING;
    2030           0 :         const uint8_t* row = fAAClip->findRow(y, &lastY);
    2031           0 :         int dy = lastY - y + 1;
    2032           0 :         if (dy > height) {
    2033           0 :             dy = height;
    2034             :         }
    2035           0 :         height -= dy;
    2036             : 
    2037           0 :         row = fAAClip->findX(row, x);
    2038           0 :         SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
    2039           0 :         if (newAlpha) {
    2040           0 :             fBlitter->blitV(x, y, dy, newAlpha);
    2041             :         }
    2042           0 :         SkASSERT(height >= 0);
    2043           0 :         if (height <= 0) {
    2044           0 :             break;
    2045             :         }
    2046           0 :         y = lastY + 1;
    2047           0 :     }
    2048             : }
    2049             : 
    2050         149 : void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
    2051         149 :     if (fAAClip->quickContains(x, y, x + width, y + height)) {
    2052          13 :         fBlitter->blitRect(x, y, width, height);
    2053          13 :         return;
    2054             :     }
    2055             : 
    2056        9808 :     while (--height >= 0) {
    2057        4836 :         this->blitH(x, y, width);
    2058        4836 :         y += 1;
    2059             :     }
    2060             : }
    2061             : 
    2062             : typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
    2063             :                             int initialRowCount, void* dst);
    2064             : 
    2065         276 : static void small_memcpy(void* dst, const void* src, size_t n) {
    2066         276 :     memcpy(dst, src, n);
    2067         276 : }
    2068             : 
    2069           0 : static void small_bzero(void* dst, size_t n) {
    2070           0 :     sk_bzero(dst, n);
    2071           0 : }
    2072             : 
    2073           0 : static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
    2074           0 :     return SkMulDiv255Round(value, alpha);
    2075             : }
    2076             : 
    2077           0 : static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
    2078           0 :     unsigned r = SkGetPackedR16(value);
    2079           0 :     unsigned g = SkGetPackedG16(value);
    2080           0 :     unsigned b = SkGetPackedB16(value);
    2081           0 :     return SkPackRGB16(SkMulDiv255Round(r, alpha),
    2082             :                        SkMulDiv255Round(g, alpha),
    2083           0 :                        SkMulDiv255Round(b, alpha));
    2084             : }
    2085             : 
    2086             : template <typename T>
    2087         156 : void mergeT(const void* inSrc, int srcN, const uint8_t* SK_RESTRICT row, int rowN, void* inDst) {
    2088         156 :     const T* SK_RESTRICT src = static_cast<const T*>(inSrc);
    2089         156 :     T* SK_RESTRICT       dst = static_cast<T*>(inDst);
    2090         120 :     for (;;) {
    2091         276 :         SkASSERT(rowN > 0);
    2092         276 :         SkASSERT(srcN > 0);
    2093             : 
    2094         276 :         int n = SkMin32(rowN, srcN);
    2095         276 :         unsigned rowA = row[1];
    2096         276 :         if (0xFF == rowA) {
    2097         276 :             small_memcpy(dst, src, n * sizeof(T));
    2098           0 :         } else if (0 == rowA) {
    2099           0 :             small_bzero(dst, n * sizeof(T));
    2100             :         } else {
    2101           0 :             for (int i = 0; i < n; ++i) {
    2102           0 :                 dst[i] = mergeOne(src[i], rowA);
    2103             :             }
    2104             :         }
    2105             : 
    2106         276 :         if (0 == (srcN -= n)) {
    2107         156 :             break;
    2108             :         }
    2109             : 
    2110         120 :         src += n;
    2111         120 :         dst += n;
    2112             : 
    2113         120 :         SkASSERT(rowN == n);
    2114         120 :         row += 2;
    2115         120 :         rowN = row[0];
    2116             :     }
    2117         156 : }
    2118             : 
    2119           8 : static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
    2120           8 :     switch (format) {
    2121             :         case SkMask::kBW_Format:
    2122           0 :             SkDEBUGFAIL("unsupported");
    2123           0 :             return nullptr;
    2124             :         case SkMask::kA8_Format:
    2125             :         case SkMask::k3D_Format:
    2126           2 :             return mergeT<uint8_t> ;
    2127             :         case SkMask::kLCD16_Format:
    2128           6 :             return mergeT<uint16_t>;
    2129             :         default:
    2130           0 :             SkDEBUGFAIL("unsupported");
    2131           0 :             return nullptr;
    2132             :     }
    2133             : }
    2134             : 
    2135           0 : static U8CPU bit2byte(int bitInAByte) {
    2136           0 :     SkASSERT(bitInAByte <= 0xFF);
    2137             :     // negation turns any non-zero into 0xFFFFFF??, so we just shift down
    2138             :     // some value >= 8 to get a full FF value
    2139           0 :     return -bitInAByte >> 8;
    2140             : }
    2141             : 
    2142           0 : static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
    2143           0 :     SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
    2144           0 :     SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
    2145             : 
    2146           0 :     const int width = srcMask.fBounds.width();
    2147           0 :     const int height = srcMask.fBounds.height();
    2148             : 
    2149           0 :     const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
    2150           0 :     const size_t srcRB = srcMask.fRowBytes;
    2151           0 :     uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
    2152           0 :     const size_t dstRB = dstMask->fRowBytes;
    2153             : 
    2154           0 :     const int wholeBytes = width >> 3;
    2155           0 :     const int leftOverBits = width & 7;
    2156             : 
    2157           0 :     for (int y = 0; y < height; ++y) {
    2158           0 :         uint8_t* SK_RESTRICT d = dst;
    2159           0 :         for (int i = 0; i < wholeBytes; ++i) {
    2160           0 :             int srcByte = src[i];
    2161           0 :             d[0] = bit2byte(srcByte & (1 << 7));
    2162           0 :             d[1] = bit2byte(srcByte & (1 << 6));
    2163           0 :             d[2] = bit2byte(srcByte & (1 << 5));
    2164           0 :             d[3] = bit2byte(srcByte & (1 << 4));
    2165           0 :             d[4] = bit2byte(srcByte & (1 << 3));
    2166           0 :             d[5] = bit2byte(srcByte & (1 << 2));
    2167           0 :             d[6] = bit2byte(srcByte & (1 << 1));
    2168           0 :             d[7] = bit2byte(srcByte & (1 << 0));
    2169           0 :             d += 8;
    2170             :         }
    2171           0 :         if (leftOverBits) {
    2172           0 :             int srcByte = src[wholeBytes];
    2173           0 :             for (int x = 0; x < leftOverBits; ++x) {
    2174           0 :                 *d++ = bit2byte(srcByte & 0x80);
    2175           0 :                 srcByte <<= 1;
    2176             :             }
    2177             :         }
    2178           0 :         src += srcRB;
    2179           0 :         dst += dstRB;
    2180             :     }
    2181           0 : }
    2182             : 
    2183         106 : void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
    2184         106 :     SkASSERT(fAAClip->getBounds().contains(clip));
    2185             : 
    2186         106 :     if (fAAClip->quickContains(clip)) {
    2187          98 :         fBlitter->blitMask(origMask, clip);
    2188          98 :         return;
    2189             :     }
    2190             : 
    2191           8 :     const SkMask* mask = &origMask;
    2192             : 
    2193             :     // if we're BW, we need to upscale to A8 (ugh)
    2194           8 :     SkMask  grayMask;
    2195           8 :     if (SkMask::kBW_Format == origMask.fFormat) {
    2196           0 :         grayMask.fFormat = SkMask::kA8_Format;
    2197           0 :         grayMask.fBounds = origMask.fBounds;
    2198           0 :         grayMask.fRowBytes = origMask.fBounds.width();
    2199           0 :         size_t size = grayMask.computeImageSize();
    2200           0 :         grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
    2201             :                                                SkAutoMalloc::kReuse_OnShrink);
    2202             : 
    2203           0 :         upscaleBW2A8(&grayMask, origMask);
    2204           0 :         mask = &grayMask;
    2205             :     }
    2206             : 
    2207           8 :     this->ensureRunsAndAA();
    2208             : 
    2209             :     // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
    2210             :     // data into a temp block to support it better (ugh)
    2211             : 
    2212           8 :     const void* src = mask->getAddr(clip.fLeft, clip.fTop);
    2213           8 :     const size_t srcRB = mask->fRowBytes;
    2214           8 :     const int width = clip.width();
    2215           8 :     MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
    2216             : 
    2217           8 :     SkMask rowMask;
    2218           8 :     rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
    2219           8 :     rowMask.fBounds.fLeft = clip.fLeft;
    2220           8 :     rowMask.fBounds.fRight = clip.fRight;
    2221           8 :     rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
    2222           8 :     rowMask.fImage = (uint8_t*)fScanlineScratch;
    2223             : 
    2224           8 :     int y = clip.fTop;
    2225           8 :     const int stopY = y + clip.height();
    2226             : 
    2227           0 :     do {
    2228           8 :         int localStopY SK_INIT_TO_AVOID_WARNING;
    2229           8 :         const uint8_t* row = fAAClip->findRow(y, &localStopY);
    2230             :         // findRow returns last Y, not stop, so we add 1
    2231           8 :         localStopY = SkMin32(localStopY + 1, stopY);
    2232             : 
    2233             :         int initialCount;
    2234           8 :         row = fAAClip->findX(row, clip.fLeft, &initialCount);
    2235         312 :         do {
    2236         156 :             mergeProc(src, width, row, initialCount, rowMask.fImage);
    2237         156 :             rowMask.fBounds.fTop = y;
    2238         156 :             rowMask.fBounds.fBottom = y + 1;
    2239         156 :             fBlitter->blitMask(rowMask, rowMask.fBounds);
    2240         156 :             src = (const void*)((const char*)src + srcRB);
    2241         156 :         } while (++y < localStopY);
    2242           8 :     } while (y < stopY);
    2243             : }
    2244             : 
    2245           0 : const SkPixmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
    2246           0 :     return nullptr;
    2247             : }

Generated by: LCOV version 1.13