1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkAAClip.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2169 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 +#include "SkAAClip.h" 1.13 +#include "SkBlitter.h" 1.14 +#include "SkColorPriv.h" 1.15 +#include "SkPath.h" 1.16 +#include "SkScan.h" 1.17 +#include "SkThread.h" 1.18 +#include "SkUtils.h" 1.19 + 1.20 +class AutoAAClipValidate { 1.21 +public: 1.22 + AutoAAClipValidate(const SkAAClip& clip) : fClip(clip) { 1.23 + fClip.validate(); 1.24 + } 1.25 + ~AutoAAClipValidate() { 1.26 + fClip.validate(); 1.27 + } 1.28 +private: 1.29 + const SkAAClip& fClip; 1.30 +}; 1.31 + 1.32 +#ifdef SK_DEBUG 1.33 + #define AUTO_AACLIP_VALIDATE(clip) AutoAAClipValidate acv(clip) 1.34 +#else 1.35 + #define AUTO_AACLIP_VALIDATE(clip) 1.36 +#endif 1.37 + 1.38 +/////////////////////////////////////////////////////////////////////////////// 1.39 + 1.40 +#define kMaxInt32 0x7FFFFFFF 1.41 + 1.42 +#ifdef SK_DEBUG 1.43 +static inline bool x_in_rect(int x, const SkIRect& rect) { 1.44 + return (unsigned)(x - rect.fLeft) < (unsigned)rect.width(); 1.45 +} 1.46 +#endif 1.47 + 1.48 +static inline bool y_in_rect(int y, const SkIRect& rect) { 1.49 + return (unsigned)(y - rect.fTop) < (unsigned)rect.height(); 1.50 +} 1.51 + 1.52 +/* 1.53 + * Data runs are packed [count, alpha] 1.54 + */ 1.55 + 1.56 +struct SkAAClip::YOffset { 1.57 + int32_t fY; 1.58 + uint32_t fOffset; 1.59 +}; 1.60 + 1.61 +struct SkAAClip::RunHead { 1.62 + int32_t fRefCnt; 1.63 + int32_t fRowCount; 1.64 + size_t fDataSize; 1.65 + 1.66 + YOffset* yoffsets() { 1.67 + return (YOffset*)((char*)this + sizeof(RunHead)); 1.68 + } 1.69 + const YOffset* yoffsets() const { 1.70 + return (const YOffset*)((const char*)this + sizeof(RunHead)); 1.71 + } 1.72 + uint8_t* data() { 1.73 + return (uint8_t*)(this->yoffsets() + fRowCount); 1.74 + } 1.75 + const uint8_t* data() const { 1.76 + return (const uint8_t*)(this->yoffsets() + fRowCount); 1.77 + } 1.78 + 1.79 + static RunHead* Alloc(int rowCount, size_t dataSize) { 1.80 + size_t size = sizeof(RunHead) + rowCount * sizeof(YOffset) + dataSize; 1.81 + RunHead* head = (RunHead*)sk_malloc_throw(size); 1.82 + head->fRefCnt = 1; 1.83 + head->fRowCount = rowCount; 1.84 + head->fDataSize = dataSize; 1.85 + return head; 1.86 + } 1.87 + 1.88 + static int ComputeRowSizeForWidth(int width) { 1.89 + // 2 bytes per segment, where each segment can store up to 255 for count 1.90 + int segments = 0; 1.91 + while (width > 0) { 1.92 + segments += 1; 1.93 + int n = SkMin32(width, 255); 1.94 + width -= n; 1.95 + } 1.96 + return segments * 2; // each segment is row[0] + row[1] (n + alpha) 1.97 + } 1.98 + 1.99 + static RunHead* AllocRect(const SkIRect& bounds) { 1.100 + SkASSERT(!bounds.isEmpty()); 1.101 + int width = bounds.width(); 1.102 + size_t rowSize = ComputeRowSizeForWidth(width); 1.103 + RunHead* head = RunHead::Alloc(1, rowSize); 1.104 + YOffset* yoff = head->yoffsets(); 1.105 + yoff->fY = bounds.height() - 1; 1.106 + yoff->fOffset = 0; 1.107 + uint8_t* row = head->data(); 1.108 + while (width > 0) { 1.109 + int n = SkMin32(width, 255); 1.110 + row[0] = n; 1.111 + row[1] = 0xFF; 1.112 + width -= n; 1.113 + row += 2; 1.114 + } 1.115 + return head; 1.116 + } 1.117 +}; 1.118 + 1.119 +class SkAAClip::Iter { 1.120 +public: 1.121 + Iter(const SkAAClip&); 1.122 + 1.123 + bool done() const { return fDone; } 1.124 + int top() const { return fTop; } 1.125 + int bottom() const { return fBottom; } 1.126 + const uint8_t* data() const { return fData; } 1.127 + void next(); 1.128 + 1.129 +private: 1.130 + const YOffset* fCurrYOff; 1.131 + const YOffset* fStopYOff; 1.132 + const uint8_t* fData; 1.133 + 1.134 + int fTop, fBottom; 1.135 + bool fDone; 1.136 +}; 1.137 + 1.138 +SkAAClip::Iter::Iter(const SkAAClip& clip) { 1.139 + if (clip.isEmpty()) { 1.140 + fDone = true; 1.141 + fTop = fBottom = clip.fBounds.fBottom; 1.142 + fData = NULL; 1.143 + fCurrYOff = NULL; 1.144 + fStopYOff = NULL; 1.145 + return; 1.146 + } 1.147 + 1.148 + const RunHead* head = clip.fRunHead; 1.149 + fCurrYOff = head->yoffsets(); 1.150 + fStopYOff = fCurrYOff + head->fRowCount; 1.151 + fData = head->data() + fCurrYOff->fOffset; 1.152 + 1.153 + // setup first value 1.154 + fTop = clip.fBounds.fTop; 1.155 + fBottom = clip.fBounds.fTop + fCurrYOff->fY + 1; 1.156 + fDone = false; 1.157 +} 1.158 + 1.159 +void SkAAClip::Iter::next() { 1.160 + if (!fDone) { 1.161 + const YOffset* prev = fCurrYOff; 1.162 + const YOffset* curr = prev + 1; 1.163 + SkASSERT(curr <= fStopYOff); 1.164 + 1.165 + fTop = fBottom; 1.166 + if (curr >= fStopYOff) { 1.167 + fDone = true; 1.168 + fBottom = kMaxInt32; 1.169 + fData = NULL; 1.170 + } else { 1.171 + fBottom += curr->fY - prev->fY; 1.172 + fData += curr->fOffset - prev->fOffset; 1.173 + fCurrYOff = curr; 1.174 + } 1.175 + } 1.176 +} 1.177 + 1.178 +#ifdef SK_DEBUG 1.179 +// assert we're exactly width-wide, and then return the number of bytes used 1.180 +static size_t compute_row_length(const uint8_t row[], int width) { 1.181 + const uint8_t* origRow = row; 1.182 + while (width > 0) { 1.183 + int n = row[0]; 1.184 + SkASSERT(n > 0); 1.185 + SkASSERT(n <= width); 1.186 + row += 2; 1.187 + width -= n; 1.188 + } 1.189 + SkASSERT(0 == width); 1.190 + return row - origRow; 1.191 +} 1.192 + 1.193 +void SkAAClip::validate() const { 1.194 + if (NULL == fRunHead) { 1.195 + SkASSERT(fBounds.isEmpty()); 1.196 + return; 1.197 + } 1.198 + 1.199 + const RunHead* head = fRunHead; 1.200 + SkASSERT(head->fRefCnt > 0); 1.201 + SkASSERT(head->fRowCount > 0); 1.202 + 1.203 + const YOffset* yoff = head->yoffsets(); 1.204 + const YOffset* ystop = yoff + head->fRowCount; 1.205 + const int lastY = fBounds.height() - 1; 1.206 + 1.207 + // Y and offset must be monotonic 1.208 + int prevY = -1; 1.209 + int32_t prevOffset = -1; 1.210 + while (yoff < ystop) { 1.211 + SkASSERT(prevY < yoff->fY); 1.212 + SkASSERT(yoff->fY <= lastY); 1.213 + prevY = yoff->fY; 1.214 + SkASSERT(prevOffset < (int32_t)yoff->fOffset); 1.215 + prevOffset = yoff->fOffset; 1.216 + const uint8_t* row = head->data() + yoff->fOffset; 1.217 + size_t rowLength = compute_row_length(row, fBounds.width()); 1.218 + SkASSERT(yoff->fOffset + rowLength <= head->fDataSize); 1.219 + yoff += 1; 1.220 + } 1.221 + // check the last entry; 1.222 + --yoff; 1.223 + SkASSERT(yoff->fY == lastY); 1.224 +} 1.225 +#endif 1.226 + 1.227 +/////////////////////////////////////////////////////////////////////////////// 1.228 + 1.229 +// Count the number of zeros on the left and right edges of the passed in 1.230 +// RLE row. If 'row' is all zeros return 'width' in both variables. 1.231 +static void count_left_right_zeros(const uint8_t* row, int width, 1.232 + int* leftZ, int* riteZ) { 1.233 + int zeros = 0; 1.234 + do { 1.235 + if (row[1]) { 1.236 + break; 1.237 + } 1.238 + int n = row[0]; 1.239 + SkASSERT(n > 0); 1.240 + SkASSERT(n <= width); 1.241 + zeros += n; 1.242 + row += 2; 1.243 + width -= n; 1.244 + } while (width > 0); 1.245 + *leftZ = zeros; 1.246 + 1.247 + if (0 == width) { 1.248 + // this line is completely empty return 'width' in both variables 1.249 + *riteZ = *leftZ; 1.250 + return; 1.251 + } 1.252 + 1.253 + zeros = 0; 1.254 + while (width > 0) { 1.255 + int n = row[0]; 1.256 + SkASSERT(n > 0); 1.257 + if (0 == row[1]) { 1.258 + zeros += n; 1.259 + } else { 1.260 + zeros = 0; 1.261 + } 1.262 + row += 2; 1.263 + width -= n; 1.264 + } 1.265 + *riteZ = zeros; 1.266 +} 1.267 + 1.268 +#ifdef SK_DEBUG 1.269 +static void test_count_left_right_zeros() { 1.270 + static bool gOnce; 1.271 + if (gOnce) { 1.272 + return; 1.273 + } 1.274 + gOnce = true; 1.275 + 1.276 + const uint8_t data0[] = { 0, 0, 10, 0xFF }; 1.277 + const uint8_t data1[] = { 0, 0, 5, 0xFF, 2, 0, 3, 0xFF }; 1.278 + const uint8_t data2[] = { 7, 0, 5, 0, 2, 0, 3, 0xFF }; 1.279 + const uint8_t data3[] = { 0, 5, 5, 0xFF, 2, 0, 3, 0 }; 1.280 + const uint8_t data4[] = { 2, 3, 2, 0, 5, 0xFF, 3, 0 }; 1.281 + const uint8_t data5[] = { 10, 10, 10, 0 }; 1.282 + const uint8_t data6[] = { 2, 2, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 }; 1.283 + 1.284 + const uint8_t* array[] = { 1.285 + data0, data1, data2, data3, data4, data5, data6 1.286 + }; 1.287 + 1.288 + for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) { 1.289 + const uint8_t* data = array[i]; 1.290 + const int expectedL = *data++; 1.291 + const int expectedR = *data++; 1.292 + int L = 12345, R = 12345; 1.293 + count_left_right_zeros(data, 10, &L, &R); 1.294 + SkASSERT(expectedL == L); 1.295 + SkASSERT(expectedR == R); 1.296 + } 1.297 +} 1.298 +#endif 1.299 + 1.300 +// modify row in place, trimming off (zeros) from the left and right sides. 1.301 +// return the number of bytes that were completely eliminated from the left 1.302 +static int trim_row_left_right(uint8_t* row, int width, int leftZ, int riteZ) { 1.303 + int trim = 0; 1.304 + while (leftZ > 0) { 1.305 + SkASSERT(0 == row[1]); 1.306 + int n = row[0]; 1.307 + SkASSERT(n > 0); 1.308 + SkASSERT(n <= width); 1.309 + width -= n; 1.310 + row += 2; 1.311 + if (n > leftZ) { 1.312 + row[-2] = n - leftZ; 1.313 + break; 1.314 + } 1.315 + trim += 2; 1.316 + leftZ -= n; 1.317 + SkASSERT(leftZ >= 0); 1.318 + } 1.319 + 1.320 + if (riteZ) { 1.321 + // walk row to the end, and then we'll back up to trim riteZ 1.322 + while (width > 0) { 1.323 + int n = row[0]; 1.324 + SkASSERT(n <= width); 1.325 + width -= n; 1.326 + row += 2; 1.327 + } 1.328 + // now skip whole runs of zeros 1.329 + do { 1.330 + row -= 2; 1.331 + SkASSERT(0 == row[1]); 1.332 + int n = row[0]; 1.333 + SkASSERT(n > 0); 1.334 + if (n > riteZ) { 1.335 + row[0] = n - riteZ; 1.336 + break; 1.337 + } 1.338 + riteZ -= n; 1.339 + SkASSERT(riteZ >= 0); 1.340 + } while (riteZ > 0); 1.341 + } 1.342 + 1.343 + return trim; 1.344 +} 1.345 + 1.346 +#ifdef SK_DEBUG 1.347 +// assert that this row is exactly this width 1.348 +static void assert_row_width(const uint8_t* row, int width) { 1.349 + while (width > 0) { 1.350 + int n = row[0]; 1.351 + SkASSERT(n > 0); 1.352 + SkASSERT(n <= width); 1.353 + width -= n; 1.354 + row += 2; 1.355 + } 1.356 + SkASSERT(0 == width); 1.357 +} 1.358 + 1.359 +static void test_trim_row_left_right() { 1.360 + static bool gOnce; 1.361 + if (gOnce) { 1.362 + return; 1.363 + } 1.364 + gOnce = true; 1.365 + 1.366 + uint8_t data0[] = { 0, 0, 0, 10, 10, 0xFF }; 1.367 + uint8_t data1[] = { 2, 0, 0, 10, 5, 0, 2, 0, 3, 0xFF }; 1.368 + uint8_t data2[] = { 5, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF }; 1.369 + uint8_t data3[] = { 6, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF }; 1.370 + uint8_t data4[] = { 0, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 }; 1.371 + uint8_t data5[] = { 1, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 }; 1.372 + uint8_t data6[] = { 0, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 }; 1.373 + uint8_t data7[] = { 1, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 }; 1.374 + uint8_t data8[] = { 2, 2, 2, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 }; 1.375 + uint8_t data9[] = { 5, 2, 4, 10, 2, 0, 2, 0, 2, 0, 2, 0xFF, 2, 0 }; 1.376 + uint8_t data10[] ={ 74, 0, 4, 150, 9, 0, 65, 0, 76, 0xFF }; 1.377 + 1.378 + uint8_t* array[] = { 1.379 + data0, data1, data2, data3, data4, 1.380 + data5, data6, data7, data8, data9, 1.381 + data10 1.382 + }; 1.383 + 1.384 + for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) { 1.385 + uint8_t* data = array[i]; 1.386 + const int trimL = *data++; 1.387 + const int trimR = *data++; 1.388 + const int expectedSkip = *data++; 1.389 + const int origWidth = *data++; 1.390 + assert_row_width(data, origWidth); 1.391 + int skip = trim_row_left_right(data, origWidth, trimL, trimR); 1.392 + SkASSERT(expectedSkip == skip); 1.393 + int expectedWidth = origWidth - trimL - trimR; 1.394 + assert_row_width(data + skip, expectedWidth); 1.395 + } 1.396 +} 1.397 +#endif 1.398 + 1.399 +bool SkAAClip::trimLeftRight() { 1.400 + SkDEBUGCODE(test_trim_row_left_right();) 1.401 + 1.402 + if (this->isEmpty()) { 1.403 + return false; 1.404 + } 1.405 + 1.406 + AUTO_AACLIP_VALIDATE(*this); 1.407 + 1.408 + const int width = fBounds.width(); 1.409 + RunHead* head = fRunHead; 1.410 + YOffset* yoff = head->yoffsets(); 1.411 + YOffset* stop = yoff + head->fRowCount; 1.412 + uint8_t* base = head->data(); 1.413 + 1.414 + // After this loop, 'leftZeros' & 'rightZeros' will contain the minimum 1.415 + // number of zeros on the left and right of the clip. This information 1.416 + // can be used to shrink the bounding box. 1.417 + int leftZeros = width; 1.418 + int riteZeros = width; 1.419 + while (yoff < stop) { 1.420 + int L, R; 1.421 + count_left_right_zeros(base + yoff->fOffset, width, &L, &R); 1.422 + SkASSERT(L + R < width || (L == width && R == width)); 1.423 + if (L < leftZeros) { 1.424 + leftZeros = L; 1.425 + } 1.426 + if (R < riteZeros) { 1.427 + riteZeros = R; 1.428 + } 1.429 + if (0 == (leftZeros | riteZeros)) { 1.430 + // no trimming to do 1.431 + return true; 1.432 + } 1.433 + yoff += 1; 1.434 + } 1.435 + 1.436 + SkASSERT(leftZeros || riteZeros); 1.437 + if (width == leftZeros) { 1.438 + SkASSERT(width == riteZeros); 1.439 + return this->setEmpty(); 1.440 + } 1.441 + 1.442 + this->validate(); 1.443 + 1.444 + fBounds.fLeft += leftZeros; 1.445 + fBounds.fRight -= riteZeros; 1.446 + SkASSERT(!fBounds.isEmpty()); 1.447 + 1.448 + // For now we don't realloc the storage (for time), we just shrink in place 1.449 + // This means we don't have to do any memmoves either, since we can just 1.450 + // play tricks with the yoff->fOffset for each row 1.451 + yoff = head->yoffsets(); 1.452 + while (yoff < stop) { 1.453 + uint8_t* row = base + yoff->fOffset; 1.454 + SkDEBUGCODE((void)compute_row_length(row, width);) 1.455 + yoff->fOffset += trim_row_left_right(row, width, leftZeros, riteZeros); 1.456 + SkDEBUGCODE((void)compute_row_length(base + yoff->fOffset, width - leftZeros - riteZeros);) 1.457 + yoff += 1; 1.458 + } 1.459 + return true; 1.460 +} 1.461 + 1.462 +static bool row_is_all_zeros(const uint8_t* row, int width) { 1.463 + SkASSERT(width > 0); 1.464 + do { 1.465 + if (row[1]) { 1.466 + return false; 1.467 + } 1.468 + int n = row[0]; 1.469 + SkASSERT(n <= width); 1.470 + width -= n; 1.471 + row += 2; 1.472 + } while (width > 0); 1.473 + SkASSERT(0 == width); 1.474 + return true; 1.475 +} 1.476 + 1.477 +bool SkAAClip::trimTopBottom() { 1.478 + if (this->isEmpty()) { 1.479 + return false; 1.480 + } 1.481 + 1.482 + this->validate(); 1.483 + 1.484 + const int width = fBounds.width(); 1.485 + RunHead* head = fRunHead; 1.486 + YOffset* yoff = head->yoffsets(); 1.487 + YOffset* stop = yoff + head->fRowCount; 1.488 + const uint8_t* base = head->data(); 1.489 + 1.490 + // Look to trim away empty rows from the top. 1.491 + // 1.492 + int skip = 0; 1.493 + while (yoff < stop) { 1.494 + const uint8_t* data = base + yoff->fOffset; 1.495 + if (!row_is_all_zeros(data, width)) { 1.496 + break; 1.497 + } 1.498 + skip += 1; 1.499 + yoff += 1; 1.500 + } 1.501 + SkASSERT(skip <= head->fRowCount); 1.502 + if (skip == head->fRowCount) { 1.503 + return this->setEmpty(); 1.504 + } 1.505 + if (skip > 0) { 1.506 + // adjust fRowCount and fBounds.fTop, and slide all the data up 1.507 + // as we remove [skip] number of YOffset entries 1.508 + yoff = head->yoffsets(); 1.509 + int dy = yoff[skip - 1].fY + 1; 1.510 + for (int i = skip; i < head->fRowCount; ++i) { 1.511 + SkASSERT(yoff[i].fY >= dy); 1.512 + yoff[i].fY -= dy; 1.513 + } 1.514 + YOffset* dst = head->yoffsets(); 1.515 + size_t size = head->fRowCount * sizeof(YOffset) + head->fDataSize; 1.516 + memmove(dst, dst + skip, size - skip * sizeof(YOffset)); 1.517 + 1.518 + fBounds.fTop += dy; 1.519 + SkASSERT(!fBounds.isEmpty()); 1.520 + head->fRowCount -= skip; 1.521 + SkASSERT(head->fRowCount > 0); 1.522 + 1.523 + this->validate(); 1.524 + // need to reset this after the memmove 1.525 + base = head->data(); 1.526 + } 1.527 + 1.528 + // Look to trim away empty rows from the bottom. 1.529 + // We know that we have at least one non-zero row, so we can just walk 1.530 + // backwards without checking for running past the start. 1.531 + // 1.532 + stop = yoff = head->yoffsets() + head->fRowCount; 1.533 + do { 1.534 + yoff -= 1; 1.535 + } while (row_is_all_zeros(base + yoff->fOffset, width)); 1.536 + skip = SkToInt(stop - yoff - 1); 1.537 + SkASSERT(skip >= 0 && skip < head->fRowCount); 1.538 + if (skip > 0) { 1.539 + // removing from the bottom is easier than from the top, as we don't 1.540 + // have to adjust any of the Y values, we just have to trim the array 1.541 + memmove(stop - skip, stop, head->fDataSize); 1.542 + 1.543 + fBounds.fBottom = fBounds.fTop + yoff->fY + 1; 1.544 + SkASSERT(!fBounds.isEmpty()); 1.545 + head->fRowCount -= skip; 1.546 + SkASSERT(head->fRowCount > 0); 1.547 + } 1.548 + this->validate(); 1.549 + 1.550 + return true; 1.551 +} 1.552 + 1.553 +// can't validate before we're done, since trimming is part of the process of 1.554 +// making us valid after the Builder. Since we build from top to bottom, its 1.555 +// possible our fBounds.fBottom is bigger than our last scanline of data, so 1.556 +// we trim fBounds.fBottom back up. 1.557 +// 1.558 +// TODO: check for duplicates in X and Y to further compress our data 1.559 +// 1.560 +bool SkAAClip::trimBounds() { 1.561 + if (this->isEmpty()) { 1.562 + return false; 1.563 + } 1.564 + 1.565 + const RunHead* head = fRunHead; 1.566 + const YOffset* yoff = head->yoffsets(); 1.567 + 1.568 + SkASSERT(head->fRowCount > 0); 1.569 + const YOffset& lastY = yoff[head->fRowCount - 1]; 1.570 + SkASSERT(lastY.fY + 1 <= fBounds.height()); 1.571 + fBounds.fBottom = fBounds.fTop + lastY.fY + 1; 1.572 + SkASSERT(lastY.fY + 1 == fBounds.height()); 1.573 + SkASSERT(!fBounds.isEmpty()); 1.574 + 1.575 + return this->trimTopBottom() && this->trimLeftRight(); 1.576 +} 1.577 + 1.578 +/////////////////////////////////////////////////////////////////////////////// 1.579 + 1.580 +void SkAAClip::freeRuns() { 1.581 + if (fRunHead) { 1.582 + SkASSERT(fRunHead->fRefCnt >= 1); 1.583 + if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) { 1.584 + sk_free(fRunHead); 1.585 + } 1.586 + } 1.587 +} 1.588 + 1.589 +SkAAClip::SkAAClip() { 1.590 + fBounds.setEmpty(); 1.591 + fRunHead = NULL; 1.592 +} 1.593 + 1.594 +SkAAClip::SkAAClip(const SkAAClip& src) { 1.595 + SkDEBUGCODE(fBounds.setEmpty();) // need this for validate 1.596 + fRunHead = NULL; 1.597 + *this = src; 1.598 +} 1.599 + 1.600 +SkAAClip::~SkAAClip() { 1.601 + this->freeRuns(); 1.602 +} 1.603 + 1.604 +SkAAClip& SkAAClip::operator=(const SkAAClip& src) { 1.605 + AUTO_AACLIP_VALIDATE(*this); 1.606 + src.validate(); 1.607 + 1.608 + if (this != &src) { 1.609 + this->freeRuns(); 1.610 + fBounds = src.fBounds; 1.611 + fRunHead = src.fRunHead; 1.612 + if (fRunHead) { 1.613 + sk_atomic_inc(&fRunHead->fRefCnt); 1.614 + } 1.615 + } 1.616 + return *this; 1.617 +} 1.618 + 1.619 +bool operator==(const SkAAClip& a, const SkAAClip& b) { 1.620 + a.validate(); 1.621 + b.validate(); 1.622 + 1.623 + if (&a == &b) { 1.624 + return true; 1.625 + } 1.626 + if (a.fBounds != b.fBounds) { 1.627 + return false; 1.628 + } 1.629 + 1.630 + const SkAAClip::RunHead* ah = a.fRunHead; 1.631 + const SkAAClip::RunHead* bh = b.fRunHead; 1.632 + 1.633 + // this catches empties and rects being equal 1.634 + if (ah == bh) { 1.635 + return true; 1.636 + } 1.637 + 1.638 + // now we insist that both are complex (but different ptrs) 1.639 + if (!a.fRunHead || !b.fRunHead) { 1.640 + return false; 1.641 + } 1.642 + 1.643 + return ah->fRowCount == bh->fRowCount && 1.644 + ah->fDataSize == bh->fDataSize && 1.645 + !memcmp(ah->data(), bh->data(), ah->fDataSize); 1.646 +} 1.647 + 1.648 +void SkAAClip::swap(SkAAClip& other) { 1.649 + AUTO_AACLIP_VALIDATE(*this); 1.650 + other.validate(); 1.651 + 1.652 + SkTSwap(fBounds, other.fBounds); 1.653 + SkTSwap(fRunHead, other.fRunHead); 1.654 +} 1.655 + 1.656 +bool SkAAClip::set(const SkAAClip& src) { 1.657 + *this = src; 1.658 + return !this->isEmpty(); 1.659 +} 1.660 + 1.661 +bool SkAAClip::setEmpty() { 1.662 + this->freeRuns(); 1.663 + fBounds.setEmpty(); 1.664 + fRunHead = NULL; 1.665 + return false; 1.666 +} 1.667 + 1.668 +bool SkAAClip::setRect(const SkIRect& bounds) { 1.669 + if (bounds.isEmpty()) { 1.670 + return this->setEmpty(); 1.671 + } 1.672 + 1.673 + AUTO_AACLIP_VALIDATE(*this); 1.674 + 1.675 +#if 0 1.676 + SkRect r; 1.677 + r.set(bounds); 1.678 + SkPath path; 1.679 + path.addRect(r); 1.680 + return this->setPath(path); 1.681 +#else 1.682 + this->freeRuns(); 1.683 + fBounds = bounds; 1.684 + fRunHead = RunHead::AllocRect(bounds); 1.685 + SkASSERT(!this->isEmpty()); 1.686 + return true; 1.687 +#endif 1.688 +} 1.689 + 1.690 +bool SkAAClip::setRect(const SkRect& r, bool doAA) { 1.691 + if (r.isEmpty()) { 1.692 + return this->setEmpty(); 1.693 + } 1.694 + 1.695 + AUTO_AACLIP_VALIDATE(*this); 1.696 + 1.697 + // TODO: special case this 1.698 + 1.699 + SkPath path; 1.700 + path.addRect(r); 1.701 + return this->setPath(path, NULL, doAA); 1.702 +} 1.703 + 1.704 +static void append_run(SkTDArray<uint8_t>& array, uint8_t value, int count) { 1.705 + SkASSERT(count >= 0); 1.706 + while (count > 0) { 1.707 + int n = count; 1.708 + if (n > 255) { 1.709 + n = 255; 1.710 + } 1.711 + uint8_t* data = array.append(2); 1.712 + data[0] = n; 1.713 + data[1] = value; 1.714 + count -= n; 1.715 + } 1.716 +} 1.717 + 1.718 +bool SkAAClip::setRegion(const SkRegion& rgn) { 1.719 + if (rgn.isEmpty()) { 1.720 + return this->setEmpty(); 1.721 + } 1.722 + if (rgn.isRect()) { 1.723 + return this->setRect(rgn.getBounds()); 1.724 + } 1.725 + 1.726 +#if 0 1.727 + SkAAClip clip; 1.728 + SkRegion::Iterator iter(rgn); 1.729 + for (; !iter.done(); iter.next()) { 1.730 + clip.op(iter.rect(), SkRegion::kUnion_Op); 1.731 + } 1.732 + this->swap(clip); 1.733 + return !this->isEmpty(); 1.734 +#else 1.735 + const SkIRect& bounds = rgn.getBounds(); 1.736 + const int offsetX = bounds.fLeft; 1.737 + const int offsetY = bounds.fTop; 1.738 + 1.739 + SkTDArray<YOffset> yArray; 1.740 + SkTDArray<uint8_t> xArray; 1.741 + 1.742 + yArray.setReserve(SkMin32(bounds.height(), 1024)); 1.743 + xArray.setReserve(SkMin32(bounds.width() * 128, 64 * 1024)); 1.744 + 1.745 + SkRegion::Iterator iter(rgn); 1.746 + int prevRight = 0; 1.747 + int prevBot = 0; 1.748 + YOffset* currY = NULL; 1.749 + 1.750 + for (; !iter.done(); iter.next()) { 1.751 + const SkIRect& r = iter.rect(); 1.752 + SkASSERT(bounds.contains(r)); 1.753 + 1.754 + int bot = r.fBottom - offsetY; 1.755 + SkASSERT(bot >= prevBot); 1.756 + if (bot > prevBot) { 1.757 + if (currY) { 1.758 + // flush current row 1.759 + append_run(xArray, 0, bounds.width() - prevRight); 1.760 + } 1.761 + // did we introduce an empty-gap from the prev row? 1.762 + int top = r.fTop - offsetY; 1.763 + if (top > prevBot) { 1.764 + currY = yArray.append(); 1.765 + currY->fY = top - 1; 1.766 + currY->fOffset = xArray.count(); 1.767 + append_run(xArray, 0, bounds.width()); 1.768 + } 1.769 + // create a new record for this Y value 1.770 + currY = yArray.append(); 1.771 + currY->fY = bot - 1; 1.772 + currY->fOffset = xArray.count(); 1.773 + prevRight = 0; 1.774 + prevBot = bot; 1.775 + } 1.776 + 1.777 + int x = r.fLeft - offsetX; 1.778 + append_run(xArray, 0, x - prevRight); 1.779 + 1.780 + int w = r.fRight - r.fLeft; 1.781 + append_run(xArray, 0xFF, w); 1.782 + prevRight = x + w; 1.783 + SkASSERT(prevRight <= bounds.width()); 1.784 + } 1.785 + // flush last row 1.786 + append_run(xArray, 0, bounds.width() - prevRight); 1.787 + 1.788 + // now pack everything into a RunHead 1.789 + RunHead* head = RunHead::Alloc(yArray.count(), xArray.bytes()); 1.790 + memcpy(head->yoffsets(), yArray.begin(), yArray.bytes()); 1.791 + memcpy(head->data(), xArray.begin(), xArray.bytes()); 1.792 + 1.793 + this->setEmpty(); 1.794 + fBounds = bounds; 1.795 + fRunHead = head; 1.796 + this->validate(); 1.797 + return true; 1.798 +#endif 1.799 +} 1.800 + 1.801 +/////////////////////////////////////////////////////////////////////////////// 1.802 + 1.803 +const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const { 1.804 + SkASSERT(fRunHead); 1.805 + 1.806 + if (!y_in_rect(y, fBounds)) { 1.807 + return NULL; 1.808 + } 1.809 + y -= fBounds.y(); // our yoffs values are relative to the top 1.810 + 1.811 + const YOffset* yoff = fRunHead->yoffsets(); 1.812 + while (yoff->fY < y) { 1.813 + yoff += 1; 1.814 + SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount); 1.815 + } 1.816 + 1.817 + if (lastYForRow) { 1.818 + *lastYForRow = fBounds.y() + yoff->fY; 1.819 + } 1.820 + return fRunHead->data() + yoff->fOffset; 1.821 +} 1.822 + 1.823 +const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const { 1.824 + SkASSERT(x_in_rect(x, fBounds)); 1.825 + x -= fBounds.x(); 1.826 + 1.827 + // first skip up to X 1.828 + for (;;) { 1.829 + int n = data[0]; 1.830 + if (x < n) { 1.831 + if (initialCount) { 1.832 + *initialCount = n - x; 1.833 + } 1.834 + break; 1.835 + } 1.836 + data += 2; 1.837 + x -= n; 1.838 + } 1.839 + return data; 1.840 +} 1.841 + 1.842 +bool SkAAClip::quickContains(int left, int top, int right, int bottom) const { 1.843 + if (this->isEmpty()) { 1.844 + return false; 1.845 + } 1.846 + if (!fBounds.contains(left, top, right, bottom)) { 1.847 + return false; 1.848 + } 1.849 +#if 0 1.850 + if (this->isRect()) { 1.851 + return true; 1.852 + } 1.853 +#endif 1.854 + 1.855 + int lastY SK_INIT_TO_AVOID_WARNING; 1.856 + const uint8_t* row = this->findRow(top, &lastY); 1.857 + if (lastY < bottom) { 1.858 + return false; 1.859 + } 1.860 + // now just need to check in X 1.861 + int count; 1.862 + row = this->findX(row, left, &count); 1.863 +#if 0 1.864 + return count >= (right - left) && 0xFF == row[1]; 1.865 +#else 1.866 + int rectWidth = right - left; 1.867 + while (0xFF == row[1]) { 1.868 + if (count >= rectWidth) { 1.869 + return true; 1.870 + } 1.871 + rectWidth -= count; 1.872 + row += 2; 1.873 + count = row[0]; 1.874 + } 1.875 + return false; 1.876 +#endif 1.877 +} 1.878 + 1.879 +/////////////////////////////////////////////////////////////////////////////// 1.880 + 1.881 +class SkAAClip::Builder { 1.882 + SkIRect fBounds; 1.883 + struct Row { 1.884 + int fY; 1.885 + int fWidth; 1.886 + SkTDArray<uint8_t>* fData; 1.887 + }; 1.888 + SkTDArray<Row> fRows; 1.889 + Row* fCurrRow; 1.890 + int fPrevY; 1.891 + int fWidth; 1.892 + int fMinY; 1.893 + 1.894 +public: 1.895 + Builder(const SkIRect& bounds) : fBounds(bounds) { 1.896 + fPrevY = -1; 1.897 + fWidth = bounds.width(); 1.898 + fCurrRow = NULL; 1.899 + fMinY = bounds.fTop; 1.900 + } 1.901 + 1.902 + ~Builder() { 1.903 + Row* row = fRows.begin(); 1.904 + Row* stop = fRows.end(); 1.905 + while (row < stop) { 1.906 + delete row->fData; 1.907 + row += 1; 1.908 + } 1.909 + } 1.910 + 1.911 + const SkIRect& getBounds() const { return fBounds; } 1.912 + 1.913 + void addRun(int x, int y, U8CPU alpha, int count) { 1.914 + SkASSERT(count > 0); 1.915 + SkASSERT(fBounds.contains(x, y)); 1.916 + SkASSERT(fBounds.contains(x + count - 1, y)); 1.917 + 1.918 + x -= fBounds.left(); 1.919 + y -= fBounds.top(); 1.920 + 1.921 + Row* row = fCurrRow; 1.922 + if (y != fPrevY) { 1.923 + SkASSERT(y > fPrevY); 1.924 + fPrevY = y; 1.925 + row = this->flushRow(true); 1.926 + row->fY = y; 1.927 + row->fWidth = 0; 1.928 + SkASSERT(row->fData); 1.929 + SkASSERT(0 == row->fData->count()); 1.930 + fCurrRow = row; 1.931 + } 1.932 + 1.933 + SkASSERT(row->fWidth <= x); 1.934 + SkASSERT(row->fWidth < fBounds.width()); 1.935 + 1.936 + SkTDArray<uint8_t>& data = *row->fData; 1.937 + 1.938 + int gap = x - row->fWidth; 1.939 + if (gap) { 1.940 + AppendRun(data, 0, gap); 1.941 + row->fWidth += gap; 1.942 + SkASSERT(row->fWidth < fBounds.width()); 1.943 + } 1.944 + 1.945 + AppendRun(data, alpha, count); 1.946 + row->fWidth += count; 1.947 + SkASSERT(row->fWidth <= fBounds.width()); 1.948 + } 1.949 + 1.950 + void addColumn(int x, int y, U8CPU alpha, int height) { 1.951 + SkASSERT(fBounds.contains(x, y + height - 1)); 1.952 + 1.953 + this->addRun(x, y, alpha, 1); 1.954 + this->flushRowH(fCurrRow); 1.955 + y -= fBounds.fTop; 1.956 + SkASSERT(y == fCurrRow->fY); 1.957 + fCurrRow->fY = y + height - 1; 1.958 + } 1.959 + 1.960 + void addRectRun(int x, int y, int width, int height) { 1.961 + SkASSERT(fBounds.contains(x + width - 1, y + height - 1)); 1.962 + this->addRun(x, y, 0xFF, width); 1.963 + 1.964 + // we assum the rect must be all we'll see for these scanlines 1.965 + // so we ensure our row goes all the way to our right 1.966 + this->flushRowH(fCurrRow); 1.967 + 1.968 + y -= fBounds.fTop; 1.969 + SkASSERT(y == fCurrRow->fY); 1.970 + fCurrRow->fY = y + height - 1; 1.971 + } 1.972 + 1.973 + void addAntiRectRun(int x, int y, int width, int height, 1.974 + SkAlpha leftAlpha, SkAlpha rightAlpha) { 1.975 + SkASSERT(fBounds.contains(x + width - 1 + 1.976 + (leftAlpha > 0 ? 1 : 0) + (rightAlpha > 0 ? 1 : 0), 1.977 + y + height - 1)); 1.978 + SkASSERT(width >= 0); 1.979 + 1.980 + // Conceptually we're always adding 3 runs, but we should 1.981 + // merge or omit them if possible. 1.982 + if (leftAlpha == 0xFF) { 1.983 + width++; 1.984 + } else if (leftAlpha > 0) { 1.985 + this->addRun(x++, y, leftAlpha, 1); 1.986 + } 1.987 + if (rightAlpha == 0xFF) { 1.988 + width++; 1.989 + } 1.990 + if (width > 0) { 1.991 + this->addRun(x, y, 0xFF, width); 1.992 + } 1.993 + if (rightAlpha > 0 && rightAlpha < 255) { 1.994 + this->addRun(x + width, y, rightAlpha, 1); 1.995 + } 1.996 + 1.997 + // we assume the rect must be all we'll see for these scanlines 1.998 + // so we ensure our row goes all the way to our right 1.999 + this->flushRowH(fCurrRow); 1.1000 + 1.1001 + y -= fBounds.fTop; 1.1002 + SkASSERT(y == fCurrRow->fY); 1.1003 + fCurrRow->fY = y + height - 1; 1.1004 + } 1.1005 + 1.1006 + bool finish(SkAAClip* target) { 1.1007 + this->flushRow(false); 1.1008 + 1.1009 + const Row* row = fRows.begin(); 1.1010 + const Row* stop = fRows.end(); 1.1011 + 1.1012 + size_t dataSize = 0; 1.1013 + while (row < stop) { 1.1014 + dataSize += row->fData->count(); 1.1015 + row += 1; 1.1016 + } 1.1017 + 1.1018 + if (0 == dataSize) { 1.1019 + return target->setEmpty(); 1.1020 + } 1.1021 + 1.1022 + SkASSERT(fMinY >= fBounds.fTop); 1.1023 + SkASSERT(fMinY < fBounds.fBottom); 1.1024 + int adjustY = fMinY - fBounds.fTop; 1.1025 + fBounds.fTop = fMinY; 1.1026 + 1.1027 + RunHead* head = RunHead::Alloc(fRows.count(), dataSize); 1.1028 + YOffset* yoffset = head->yoffsets(); 1.1029 + uint8_t* data = head->data(); 1.1030 + uint8_t* baseData = data; 1.1031 + 1.1032 + row = fRows.begin(); 1.1033 + SkDEBUGCODE(int prevY = row->fY - 1;) 1.1034 + while (row < stop) { 1.1035 + SkASSERT(prevY < row->fY); // must be monotonic 1.1036 + SkDEBUGCODE(prevY = row->fY); 1.1037 + 1.1038 + yoffset->fY = row->fY - adjustY; 1.1039 + yoffset->fOffset = SkToU32(data - baseData); 1.1040 + yoffset += 1; 1.1041 + 1.1042 + size_t n = row->fData->count(); 1.1043 + memcpy(data, row->fData->begin(), n); 1.1044 +#ifdef SK_DEBUG 1.1045 + size_t bytesNeeded = compute_row_length(data, fBounds.width()); 1.1046 + SkASSERT(bytesNeeded == n); 1.1047 +#endif 1.1048 + data += n; 1.1049 + 1.1050 + row += 1; 1.1051 + } 1.1052 + 1.1053 + target->freeRuns(); 1.1054 + target->fBounds = fBounds; 1.1055 + target->fRunHead = head; 1.1056 + return target->trimBounds(); 1.1057 + } 1.1058 + 1.1059 + void dump() { 1.1060 + this->validate(); 1.1061 + int y; 1.1062 + for (y = 0; y < fRows.count(); ++y) { 1.1063 + const Row& row = fRows[y]; 1.1064 + SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth); 1.1065 + const SkTDArray<uint8_t>& data = *row.fData; 1.1066 + int count = data.count(); 1.1067 + SkASSERT(!(count & 1)); 1.1068 + const uint8_t* ptr = data.begin(); 1.1069 + for (int x = 0; x < count; x += 2) { 1.1070 + SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]); 1.1071 + ptr += 2; 1.1072 + } 1.1073 + SkDebugf("\n"); 1.1074 + } 1.1075 + } 1.1076 + 1.1077 + void validate() { 1.1078 +#ifdef SK_DEBUG 1.1079 + if (false) { // avoid bit rot, suppress warning 1.1080 + test_count_left_right_zeros(); 1.1081 + } 1.1082 + int prevY = -1; 1.1083 + for (int i = 0; i < fRows.count(); ++i) { 1.1084 + const Row& row = fRows[i]; 1.1085 + SkASSERT(prevY < row.fY); 1.1086 + SkASSERT(fWidth == row.fWidth); 1.1087 + int count = row.fData->count(); 1.1088 + const uint8_t* ptr = row.fData->begin(); 1.1089 + SkASSERT(!(count & 1)); 1.1090 + int w = 0; 1.1091 + for (int x = 0; x < count; x += 2) { 1.1092 + int n = ptr[0]; 1.1093 + SkASSERT(n > 0); 1.1094 + w += n; 1.1095 + SkASSERT(w <= fWidth); 1.1096 + ptr += 2; 1.1097 + } 1.1098 + SkASSERT(w == fWidth); 1.1099 + prevY = row.fY; 1.1100 + } 1.1101 +#endif 1.1102 + } 1.1103 + 1.1104 + // only called by BuilderBlitter 1.1105 + void setMinY(int y) { 1.1106 + fMinY = y; 1.1107 + } 1.1108 + 1.1109 +private: 1.1110 + void flushRowH(Row* row) { 1.1111 + // flush current row if needed 1.1112 + if (row->fWidth < fWidth) { 1.1113 + AppendRun(*row->fData, 0, fWidth - row->fWidth); 1.1114 + row->fWidth = fWidth; 1.1115 + } 1.1116 + } 1.1117 + 1.1118 + Row* flushRow(bool readyForAnother) { 1.1119 + Row* next = NULL; 1.1120 + int count = fRows.count(); 1.1121 + if (count > 0) { 1.1122 + this->flushRowH(&fRows[count - 1]); 1.1123 + } 1.1124 + if (count > 1) { 1.1125 + // are our last two runs the same? 1.1126 + Row* prev = &fRows[count - 2]; 1.1127 + Row* curr = &fRows[count - 1]; 1.1128 + SkASSERT(prev->fWidth == fWidth); 1.1129 + SkASSERT(curr->fWidth == fWidth); 1.1130 + if (*prev->fData == *curr->fData) { 1.1131 + prev->fY = curr->fY; 1.1132 + if (readyForAnother) { 1.1133 + curr->fData->rewind(); 1.1134 + next = curr; 1.1135 + } else { 1.1136 + delete curr->fData; 1.1137 + fRows.removeShuffle(count - 1); 1.1138 + } 1.1139 + } else { 1.1140 + if (readyForAnother) { 1.1141 + next = fRows.append(); 1.1142 + next->fData = new SkTDArray<uint8_t>; 1.1143 + } 1.1144 + } 1.1145 + } else { 1.1146 + if (readyForAnother) { 1.1147 + next = fRows.append(); 1.1148 + next->fData = new SkTDArray<uint8_t>; 1.1149 + } 1.1150 + } 1.1151 + return next; 1.1152 + } 1.1153 + 1.1154 + static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) { 1.1155 + do { 1.1156 + int n = count; 1.1157 + if (n > 255) { 1.1158 + n = 255; 1.1159 + } 1.1160 + uint8_t* ptr = data.append(2); 1.1161 + ptr[0] = n; 1.1162 + ptr[1] = alpha; 1.1163 + count -= n; 1.1164 + } while (count > 0); 1.1165 + } 1.1166 +}; 1.1167 + 1.1168 +class SkAAClip::BuilderBlitter : public SkBlitter { 1.1169 + int fLastY; 1.1170 + 1.1171 + /* 1.1172 + If we see a gap of 1 or more empty scanlines while building in Y-order, 1.1173 + we inject an explicit empty scanline (alpha==0) 1.1174 + 1.1175 + See AAClipTest.cpp : test_path_with_hole() 1.1176 + */ 1.1177 + void checkForYGap(int y) { 1.1178 + SkASSERT(y >= fLastY); 1.1179 + if (fLastY > -SK_MaxS32) { 1.1180 + int gap = y - fLastY; 1.1181 + if (gap > 1) { 1.1182 + fBuilder->addRun(fLeft, y - 1, 0, fRight - fLeft); 1.1183 + } 1.1184 + } 1.1185 + fLastY = y; 1.1186 + } 1.1187 + 1.1188 +public: 1.1189 + 1.1190 + BuilderBlitter(Builder* builder) { 1.1191 + fBuilder = builder; 1.1192 + fLeft = builder->getBounds().fLeft; 1.1193 + fRight = builder->getBounds().fRight; 1.1194 + fMinY = SK_MaxS32; 1.1195 + fLastY = -SK_MaxS32; // sentinel 1.1196 + } 1.1197 + 1.1198 + void finish() { 1.1199 + if (fMinY < SK_MaxS32) { 1.1200 + fBuilder->setMinY(fMinY); 1.1201 + } 1.1202 + } 1.1203 + 1.1204 + /** 1.1205 + Must evaluate clips in scan-line order, so don't want to allow blitV(), 1.1206 + but an AAClip can be clipped down to a single pixel wide, so we 1.1207 + must support it (given AntiRect semantics: minimum width is 2). 1.1208 + Instead we'll rely on the runtime asserts to guarantee Y monotonicity; 1.1209 + any failure cases that misses may have minor artifacts. 1.1210 + */ 1.1211 + virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE { 1.1212 + this->recordMinY(y); 1.1213 + fBuilder->addColumn(x, y, alpha, height); 1.1214 + fLastY = y + height - 1; 1.1215 + } 1.1216 + 1.1217 + virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE { 1.1218 + this->recordMinY(y); 1.1219 + this->checkForYGap(y); 1.1220 + fBuilder->addRectRun(x, y, width, height); 1.1221 + fLastY = y + height - 1; 1.1222 + } 1.1223 + 1.1224 + virtual void blitAntiRect(int x, int y, int width, int height, 1.1225 + SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE { 1.1226 + this->recordMinY(y); 1.1227 + this->checkForYGap(y); 1.1228 + fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha); 1.1229 + fLastY = y + height - 1; 1.1230 + } 1.1231 + 1.1232 + virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE 1.1233 + { unexpected(); } 1.1234 + 1.1235 + virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE { 1.1236 + return NULL; 1.1237 + } 1.1238 + 1.1239 + virtual void blitH(int x, int y, int width) SK_OVERRIDE { 1.1240 + this->recordMinY(y); 1.1241 + this->checkForYGap(y); 1.1242 + fBuilder->addRun(x, y, 0xFF, width); 1.1243 + } 1.1244 + 1.1245 + virtual void blitAntiH(int x, int y, const SkAlpha alpha[], 1.1246 + const int16_t runs[]) SK_OVERRIDE { 1.1247 + this->recordMinY(y); 1.1248 + this->checkForYGap(y); 1.1249 + for (;;) { 1.1250 + int count = *runs; 1.1251 + if (count <= 0) { 1.1252 + return; 1.1253 + } 1.1254 + 1.1255 + // The supersampler's buffer can be the width of the device, so 1.1256 + // we may have to trim the run to our bounds. If so, we assert that 1.1257 + // the extra spans are always alpha==0 1.1258 + int localX = x; 1.1259 + int localCount = count; 1.1260 + if (x < fLeft) { 1.1261 + SkASSERT(0 == *alpha); 1.1262 + int gap = fLeft - x; 1.1263 + SkASSERT(gap <= count); 1.1264 + localX += gap; 1.1265 + localCount -= gap; 1.1266 + } 1.1267 + int right = x + count; 1.1268 + if (right > fRight) { 1.1269 + SkASSERT(0 == *alpha); 1.1270 + localCount -= right - fRight; 1.1271 + SkASSERT(localCount >= 0); 1.1272 + } 1.1273 + 1.1274 + if (localCount) { 1.1275 + fBuilder->addRun(localX, y, *alpha, localCount); 1.1276 + } 1.1277 + // Next run 1.1278 + runs += count; 1.1279 + alpha += count; 1.1280 + x += count; 1.1281 + } 1.1282 + } 1.1283 + 1.1284 +private: 1.1285 + Builder* fBuilder; 1.1286 + int fLeft; // cache of builder's bounds' left edge 1.1287 + int fRight; 1.1288 + int fMinY; 1.1289 + 1.1290 + /* 1.1291 + * We track this, in case the scan converter skipped some number of 1.1292 + * scanlines at the (relative to the bounds it was given). This allows 1.1293 + * the builder, during its finish, to trip its bounds down to the "real" 1.1294 + * top. 1.1295 + */ 1.1296 + void recordMinY(int y) { 1.1297 + if (y < fMinY) { 1.1298 + fMinY = y; 1.1299 + } 1.1300 + } 1.1301 + 1.1302 + void unexpected() { 1.1303 + SkDebugf("---- did not expect to get called here"); 1.1304 + sk_throw(); 1.1305 + } 1.1306 +}; 1.1307 + 1.1308 +bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) { 1.1309 + AUTO_AACLIP_VALIDATE(*this); 1.1310 + 1.1311 + if (clip && clip->isEmpty()) { 1.1312 + return this->setEmpty(); 1.1313 + } 1.1314 + 1.1315 + SkIRect ibounds; 1.1316 + path.getBounds().roundOut(&ibounds); 1.1317 + 1.1318 + SkRegion tmpClip; 1.1319 + if (NULL == clip) { 1.1320 + tmpClip.setRect(ibounds); 1.1321 + clip = &tmpClip; 1.1322 + } 1.1323 + 1.1324 + if (path.isInverseFillType()) { 1.1325 + ibounds = clip->getBounds(); 1.1326 + } else { 1.1327 + if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) { 1.1328 + return this->setEmpty(); 1.1329 + } 1.1330 + } 1.1331 + 1.1332 + Builder builder(ibounds); 1.1333 + BuilderBlitter blitter(&builder); 1.1334 + 1.1335 + if (doAA) { 1.1336 + SkScan::AntiFillPath(path, *clip, &blitter, true); 1.1337 + } else { 1.1338 + SkScan::FillPath(path, *clip, &blitter); 1.1339 + } 1.1340 + 1.1341 + blitter.finish(); 1.1342 + return builder.finish(this); 1.1343 +} 1.1344 + 1.1345 +/////////////////////////////////////////////////////////////////////////////// 1.1346 + 1.1347 +typedef void (*RowProc)(SkAAClip::Builder&, int bottom, 1.1348 + const uint8_t* rowA, const SkIRect& rectA, 1.1349 + const uint8_t* rowB, const SkIRect& rectB); 1.1350 + 1.1351 +typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB); 1.1352 + 1.1353 +static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) { 1.1354 + // Multiply 1.1355 + return SkMulDiv255Round(alphaA, alphaB); 1.1356 +} 1.1357 + 1.1358 +static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) { 1.1359 + // SrcOver 1.1360 + return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB); 1.1361 +} 1.1362 + 1.1363 +static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) { 1.1364 + // SrcOut 1.1365 + return SkMulDiv255Round(alphaA, 0xFF - alphaB); 1.1366 +} 1.1367 + 1.1368 +static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) { 1.1369 + // XOR 1.1370 + return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB); 1.1371 +} 1.1372 + 1.1373 +static AlphaProc find_alpha_proc(SkRegion::Op op) { 1.1374 + switch (op) { 1.1375 + case SkRegion::kIntersect_Op: 1.1376 + return sectAlphaProc; 1.1377 + case SkRegion::kDifference_Op: 1.1378 + return diffAlphaProc; 1.1379 + case SkRegion::kUnion_Op: 1.1380 + return unionAlphaProc; 1.1381 + case SkRegion::kXOR_Op: 1.1382 + return xorAlphaProc; 1.1383 + default: 1.1384 + SkDEBUGFAIL("unexpected region op"); 1.1385 + return sectAlphaProc; 1.1386 + } 1.1387 +} 1.1388 + 1.1389 +class RowIter { 1.1390 +public: 1.1391 + RowIter(const uint8_t* row, const SkIRect& bounds) { 1.1392 + fRow = row; 1.1393 + fLeft = bounds.fLeft; 1.1394 + fBoundsRight = bounds.fRight; 1.1395 + if (row) { 1.1396 + fRight = bounds.fLeft + row[0]; 1.1397 + SkASSERT(fRight <= fBoundsRight); 1.1398 + fAlpha = row[1]; 1.1399 + fDone = false; 1.1400 + } else { 1.1401 + fDone = true; 1.1402 + fRight = kMaxInt32; 1.1403 + fAlpha = 0; 1.1404 + } 1.1405 + } 1.1406 + 1.1407 + bool done() const { return fDone; } 1.1408 + int left() const { return fLeft; } 1.1409 + int right() const { return fRight; } 1.1410 + U8CPU alpha() const { return fAlpha; } 1.1411 + void next() { 1.1412 + if (!fDone) { 1.1413 + fLeft = fRight; 1.1414 + if (fRight == fBoundsRight) { 1.1415 + fDone = true; 1.1416 + fRight = kMaxInt32; 1.1417 + fAlpha = 0; 1.1418 + } else { 1.1419 + fRow += 2; 1.1420 + fRight += fRow[0]; 1.1421 + fAlpha = fRow[1]; 1.1422 + SkASSERT(fRight <= fBoundsRight); 1.1423 + } 1.1424 + } 1.1425 + } 1.1426 + 1.1427 +private: 1.1428 + const uint8_t* fRow; 1.1429 + int fLeft; 1.1430 + int fRight; 1.1431 + int fBoundsRight; 1.1432 + bool fDone; 1.1433 + uint8_t fAlpha; 1.1434 +}; 1.1435 + 1.1436 +static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) { 1.1437 + if (rite == riteA) { 1.1438 + iter.next(); 1.1439 + leftA = iter.left(); 1.1440 + riteA = iter.right(); 1.1441 + } 1.1442 +} 1.1443 + 1.1444 +#if 0 // UNUSED 1.1445 +static bool intersect(int& min, int& max, int boundsMin, int boundsMax) { 1.1446 + SkASSERT(min < max); 1.1447 + SkASSERT(boundsMin < boundsMax); 1.1448 + if (min >= boundsMax || max <= boundsMin) { 1.1449 + return false; 1.1450 + } 1.1451 + if (min < boundsMin) { 1.1452 + min = boundsMin; 1.1453 + } 1.1454 + if (max > boundsMax) { 1.1455 + max = boundsMax; 1.1456 + } 1.1457 + return true; 1.1458 +} 1.1459 +#endif 1.1460 + 1.1461 +static void operatorX(SkAAClip::Builder& builder, int lastY, 1.1462 + RowIter& iterA, RowIter& iterB, 1.1463 + AlphaProc proc, const SkIRect& bounds) { 1.1464 + int leftA = iterA.left(); 1.1465 + int riteA = iterA.right(); 1.1466 + int leftB = iterB.left(); 1.1467 + int riteB = iterB.right(); 1.1468 + 1.1469 + int prevRite = bounds.fLeft; 1.1470 + 1.1471 + do { 1.1472 + U8CPU alphaA = 0; 1.1473 + U8CPU alphaB = 0; 1.1474 + int left, rite; 1.1475 + 1.1476 + if (leftA < leftB) { 1.1477 + left = leftA; 1.1478 + alphaA = iterA.alpha(); 1.1479 + if (riteA <= leftB) { 1.1480 + rite = riteA; 1.1481 + } else { 1.1482 + rite = leftA = leftB; 1.1483 + } 1.1484 + } else if (leftB < leftA) { 1.1485 + left = leftB; 1.1486 + alphaB = iterB.alpha(); 1.1487 + if (riteB <= leftA) { 1.1488 + rite = riteB; 1.1489 + } else { 1.1490 + rite = leftB = leftA; 1.1491 + } 1.1492 + } else { 1.1493 + left = leftA; // or leftB, since leftA == leftB 1.1494 + rite = leftA = leftB = SkMin32(riteA, riteB); 1.1495 + alphaA = iterA.alpha(); 1.1496 + alphaB = iterB.alpha(); 1.1497 + } 1.1498 + 1.1499 + if (left >= bounds.fRight) { 1.1500 + break; 1.1501 + } 1.1502 + if (rite > bounds.fRight) { 1.1503 + rite = bounds.fRight; 1.1504 + } 1.1505 + 1.1506 + if (left >= bounds.fLeft) { 1.1507 + SkASSERT(rite > left); 1.1508 + builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left); 1.1509 + prevRite = rite; 1.1510 + } 1.1511 + 1.1512 + adjust_row(iterA, leftA, riteA, rite); 1.1513 + adjust_row(iterB, leftB, riteB, rite); 1.1514 + } while (!iterA.done() || !iterB.done()); 1.1515 + 1.1516 + if (prevRite < bounds.fRight) { 1.1517 + builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite); 1.1518 + } 1.1519 +} 1.1520 + 1.1521 +static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) { 1.1522 + if (bot == botA) { 1.1523 + iter.next(); 1.1524 + topA = botA; 1.1525 + SkASSERT(botA == iter.top()); 1.1526 + botA = iter.bottom(); 1.1527 + } 1.1528 +} 1.1529 + 1.1530 +static void operateY(SkAAClip::Builder& builder, const SkAAClip& A, 1.1531 + const SkAAClip& B, SkRegion::Op op) { 1.1532 + AlphaProc proc = find_alpha_proc(op); 1.1533 + const SkIRect& bounds = builder.getBounds(); 1.1534 + 1.1535 + SkAAClip::Iter iterA(A); 1.1536 + SkAAClip::Iter iterB(B); 1.1537 + 1.1538 + SkASSERT(!iterA.done()); 1.1539 + int topA = iterA.top(); 1.1540 + int botA = iterA.bottom(); 1.1541 + SkASSERT(!iterB.done()); 1.1542 + int topB = iterB.top(); 1.1543 + int botB = iterB.bottom(); 1.1544 + 1.1545 + do { 1.1546 + const uint8_t* rowA = NULL; 1.1547 + const uint8_t* rowB = NULL; 1.1548 + int top, bot; 1.1549 + 1.1550 + if (topA < topB) { 1.1551 + top = topA; 1.1552 + rowA = iterA.data(); 1.1553 + if (botA <= topB) { 1.1554 + bot = botA; 1.1555 + } else { 1.1556 + bot = topA = topB; 1.1557 + } 1.1558 + 1.1559 + } else if (topB < topA) { 1.1560 + top = topB; 1.1561 + rowB = iterB.data(); 1.1562 + if (botB <= topA) { 1.1563 + bot = botB; 1.1564 + } else { 1.1565 + bot = topB = topA; 1.1566 + } 1.1567 + } else { 1.1568 + top = topA; // or topB, since topA == topB 1.1569 + bot = topA = topB = SkMin32(botA, botB); 1.1570 + rowA = iterA.data(); 1.1571 + rowB = iterB.data(); 1.1572 + } 1.1573 + 1.1574 + if (top >= bounds.fBottom) { 1.1575 + break; 1.1576 + } 1.1577 + 1.1578 + if (bot > bounds.fBottom) { 1.1579 + bot = bounds.fBottom; 1.1580 + } 1.1581 + SkASSERT(top < bot); 1.1582 + 1.1583 + if (!rowA && !rowB) { 1.1584 + builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width()); 1.1585 + } else if (top >= bounds.fTop) { 1.1586 + SkASSERT(bot <= bounds.fBottom); 1.1587 + RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds); 1.1588 + RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds); 1.1589 + operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds); 1.1590 + } 1.1591 + 1.1592 + adjust_iter(iterA, topA, botA, bot); 1.1593 + adjust_iter(iterB, topB, botB, bot); 1.1594 + } while (!iterA.done() || !iterB.done()); 1.1595 +} 1.1596 + 1.1597 +bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig, 1.1598 + SkRegion::Op op) { 1.1599 + AUTO_AACLIP_VALIDATE(*this); 1.1600 + 1.1601 + if (SkRegion::kReplace_Op == op) { 1.1602 + return this->set(clipBOrig); 1.1603 + } 1.1604 + 1.1605 + const SkAAClip* clipA = &clipAOrig; 1.1606 + const SkAAClip* clipB = &clipBOrig; 1.1607 + 1.1608 + if (SkRegion::kReverseDifference_Op == op) { 1.1609 + SkTSwap(clipA, clipB); 1.1610 + op = SkRegion::kDifference_Op; 1.1611 + } 1.1612 + 1.1613 + bool a_empty = clipA->isEmpty(); 1.1614 + bool b_empty = clipB->isEmpty(); 1.1615 + 1.1616 + SkIRect bounds; 1.1617 + switch (op) { 1.1618 + case SkRegion::kDifference_Op: 1.1619 + if (a_empty) { 1.1620 + return this->setEmpty(); 1.1621 + } 1.1622 + if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) { 1.1623 + return this->set(*clipA); 1.1624 + } 1.1625 + bounds = clipA->fBounds; 1.1626 + break; 1.1627 + 1.1628 + case SkRegion::kIntersect_Op: 1.1629 + if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds, 1.1630 + clipB->fBounds)) { 1.1631 + return this->setEmpty(); 1.1632 + } 1.1633 + break; 1.1634 + 1.1635 + case SkRegion::kUnion_Op: 1.1636 + case SkRegion::kXOR_Op: 1.1637 + if (a_empty) { 1.1638 + return this->set(*clipB); 1.1639 + } 1.1640 + if (b_empty) { 1.1641 + return this->set(*clipA); 1.1642 + } 1.1643 + bounds = clipA->fBounds; 1.1644 + bounds.join(clipB->fBounds); 1.1645 + break; 1.1646 + 1.1647 + default: 1.1648 + SkDEBUGFAIL("unknown region op"); 1.1649 + return !this->isEmpty(); 1.1650 + } 1.1651 + 1.1652 + SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds)); 1.1653 + SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds)); 1.1654 + 1.1655 + Builder builder(bounds); 1.1656 + operateY(builder, *clipA, *clipB, op); 1.1657 + 1.1658 + return builder.finish(this); 1.1659 +} 1.1660 + 1.1661 +/* 1.1662 + * It can be expensive to build a local aaclip before applying the op, so 1.1663 + * we first see if we can restrict the bounds of new rect to our current 1.1664 + * bounds, or note that the new rect subsumes our current clip. 1.1665 + */ 1.1666 + 1.1667 +bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) { 1.1668 + SkIRect rStorage; 1.1669 + const SkIRect* r = &rOrig; 1.1670 + 1.1671 + switch (op) { 1.1672 + case SkRegion::kIntersect_Op: 1.1673 + if (!rStorage.intersect(rOrig, fBounds)) { 1.1674 + // no overlap, so we're empty 1.1675 + return this->setEmpty(); 1.1676 + } 1.1677 + if (rStorage == fBounds) { 1.1678 + // we were wholly inside the rect, no change 1.1679 + return !this->isEmpty(); 1.1680 + } 1.1681 + if (this->quickContains(rStorage)) { 1.1682 + // the intersection is wholly inside us, we're a rect 1.1683 + return this->setRect(rStorage); 1.1684 + } 1.1685 + r = &rStorage; // use the intersected bounds 1.1686 + break; 1.1687 + case SkRegion::kDifference_Op: 1.1688 + break; 1.1689 + case SkRegion::kUnion_Op: 1.1690 + if (rOrig.contains(fBounds)) { 1.1691 + return this->setRect(rOrig); 1.1692 + } 1.1693 + break; 1.1694 + default: 1.1695 + break; 1.1696 + } 1.1697 + 1.1698 + SkAAClip clip; 1.1699 + clip.setRect(*r); 1.1700 + return this->op(*this, clip, op); 1.1701 +} 1.1702 + 1.1703 +bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) { 1.1704 + SkRect rStorage, boundsStorage; 1.1705 + const SkRect* r = &rOrig; 1.1706 + 1.1707 + boundsStorage.set(fBounds); 1.1708 + switch (op) { 1.1709 + case SkRegion::kIntersect_Op: 1.1710 + case SkRegion::kDifference_Op: 1.1711 + if (!rStorage.intersect(rOrig, boundsStorage)) { 1.1712 + if (SkRegion::kIntersect_Op == op) { 1.1713 + return this->setEmpty(); 1.1714 + } else { // kDifference 1.1715 + return !this->isEmpty(); 1.1716 + } 1.1717 + } 1.1718 + r = &rStorage; // use the intersected bounds 1.1719 + break; 1.1720 + case SkRegion::kUnion_Op: 1.1721 + if (rOrig.contains(boundsStorage)) { 1.1722 + return this->setRect(rOrig); 1.1723 + } 1.1724 + break; 1.1725 + default: 1.1726 + break; 1.1727 + } 1.1728 + 1.1729 + SkAAClip clip; 1.1730 + clip.setRect(*r, doAA); 1.1731 + return this->op(*this, clip, op); 1.1732 +} 1.1733 + 1.1734 +bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) { 1.1735 + return this->op(*this, clip, op); 1.1736 +} 1.1737 + 1.1738 +/////////////////////////////////////////////////////////////////////////////// 1.1739 + 1.1740 +bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const { 1.1741 + if (NULL == dst) { 1.1742 + return !this->isEmpty(); 1.1743 + } 1.1744 + 1.1745 + if (this->isEmpty()) { 1.1746 + return dst->setEmpty(); 1.1747 + } 1.1748 + 1.1749 + if (this != dst) { 1.1750 + sk_atomic_inc(&fRunHead->fRefCnt); 1.1751 + dst->freeRuns(); 1.1752 + dst->fRunHead = fRunHead; 1.1753 + dst->fBounds = fBounds; 1.1754 + } 1.1755 + dst->fBounds.offset(dx, dy); 1.1756 + return true; 1.1757 +} 1.1758 + 1.1759 +static void expand_row_to_mask(uint8_t* SK_RESTRICT mask, 1.1760 + const uint8_t* SK_RESTRICT row, 1.1761 + int width) { 1.1762 + while (width > 0) { 1.1763 + int n = row[0]; 1.1764 + SkASSERT(width >= n); 1.1765 + memset(mask, row[1], n); 1.1766 + mask += n; 1.1767 + row += 2; 1.1768 + width -= n; 1.1769 + } 1.1770 + SkASSERT(0 == width); 1.1771 +} 1.1772 + 1.1773 +void SkAAClip::copyToMask(SkMask* mask) const { 1.1774 + mask->fFormat = SkMask::kA8_Format; 1.1775 + if (this->isEmpty()) { 1.1776 + mask->fBounds.setEmpty(); 1.1777 + mask->fImage = NULL; 1.1778 + mask->fRowBytes = 0; 1.1779 + return; 1.1780 + } 1.1781 + 1.1782 + mask->fBounds = fBounds; 1.1783 + mask->fRowBytes = fBounds.width(); 1.1784 + size_t size = mask->computeImageSize(); 1.1785 + mask->fImage = SkMask::AllocImage(size); 1.1786 + 1.1787 + Iter iter(*this); 1.1788 + uint8_t* dst = mask->fImage; 1.1789 + const int width = fBounds.width(); 1.1790 + 1.1791 + int y = fBounds.fTop; 1.1792 + while (!iter.done()) { 1.1793 + do { 1.1794 + expand_row_to_mask(dst, iter.data(), width); 1.1795 + dst += mask->fRowBytes; 1.1796 + } while (++y < iter.bottom()); 1.1797 + iter.next(); 1.1798 + } 1.1799 +} 1.1800 + 1.1801 +/////////////////////////////////////////////////////////////////////////////// 1.1802 +/////////////////////////////////////////////////////////////////////////////// 1.1803 + 1.1804 +static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width, 1.1805 + int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) { 1.1806 + // we don't read our initial n from data, since the caller may have had to 1.1807 + // clip it, hence the initialCount parameter. 1.1808 + int n = initialCount; 1.1809 + for (;;) { 1.1810 + if (n > width) { 1.1811 + n = width; 1.1812 + } 1.1813 + SkASSERT(n > 0); 1.1814 + runs[0] = n; 1.1815 + runs += n; 1.1816 + 1.1817 + aa[0] = data[1]; 1.1818 + aa += n; 1.1819 + 1.1820 + data += 2; 1.1821 + width -= n; 1.1822 + if (0 == width) { 1.1823 + break; 1.1824 + } 1.1825 + // load the next count 1.1826 + n = data[0]; 1.1827 + } 1.1828 + runs[0] = 0; // sentinel 1.1829 +} 1.1830 + 1.1831 +SkAAClipBlitter::~SkAAClipBlitter() { 1.1832 + sk_free(fScanlineScratch); 1.1833 +} 1.1834 + 1.1835 +void SkAAClipBlitter::ensureRunsAndAA() { 1.1836 + if (NULL == fScanlineScratch) { 1.1837 + // add 1 so we can store the terminating run count of 0 1.1838 + int count = fAAClipBounds.width() + 1; 1.1839 + // we use this either for fRuns + fAA, or a scaline of a mask 1.1840 + // which may be as deep as 32bits 1.1841 + fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor)); 1.1842 + fRuns = (int16_t*)fScanlineScratch; 1.1843 + fAA = (SkAlpha*)(fRuns + count); 1.1844 + } 1.1845 +} 1.1846 + 1.1847 +void SkAAClipBlitter::blitH(int x, int y, int width) { 1.1848 + SkASSERT(width > 0); 1.1849 + SkASSERT(fAAClipBounds.contains(x, y)); 1.1850 + SkASSERT(fAAClipBounds.contains(x + width - 1, y)); 1.1851 + 1.1852 + const uint8_t* row = fAAClip->findRow(y); 1.1853 + int initialCount; 1.1854 + row = fAAClip->findX(row, x, &initialCount); 1.1855 + 1.1856 + if (initialCount >= width) { 1.1857 + SkAlpha alpha = row[1]; 1.1858 + if (0 == alpha) { 1.1859 + return; 1.1860 + } 1.1861 + if (0xFF == alpha) { 1.1862 + fBlitter->blitH(x, y, width); 1.1863 + return; 1.1864 + } 1.1865 + } 1.1866 + 1.1867 + this->ensureRunsAndAA(); 1.1868 + expandToRuns(row, initialCount, width, fRuns, fAA); 1.1869 + 1.1870 + fBlitter->blitAntiH(x, y, fAA, fRuns); 1.1871 +} 1.1872 + 1.1873 +static void merge(const uint8_t* SK_RESTRICT row, int rowN, 1.1874 + const SkAlpha* SK_RESTRICT srcAA, 1.1875 + const int16_t* SK_RESTRICT srcRuns, 1.1876 + SkAlpha* SK_RESTRICT dstAA, 1.1877 + int16_t* SK_RESTRICT dstRuns, 1.1878 + int width) { 1.1879 + SkDEBUGCODE(int accumulated = 0;) 1.1880 + int srcN = srcRuns[0]; 1.1881 + // do we need this check? 1.1882 + if (0 == srcN) { 1.1883 + return; 1.1884 + } 1.1885 + 1.1886 + for (;;) { 1.1887 + SkASSERT(rowN > 0); 1.1888 + SkASSERT(srcN > 0); 1.1889 + 1.1890 + unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]); 1.1891 + int minN = SkMin32(srcN, rowN); 1.1892 + dstRuns[0] = minN; 1.1893 + dstRuns += minN; 1.1894 + dstAA[0] = newAlpha; 1.1895 + dstAA += minN; 1.1896 + 1.1897 + if (0 == (srcN -= minN)) { 1.1898 + srcN = srcRuns[0]; // refresh 1.1899 + srcRuns += srcN; 1.1900 + srcAA += srcN; 1.1901 + srcN = srcRuns[0]; // reload 1.1902 + if (0 == srcN) { 1.1903 + break; 1.1904 + } 1.1905 + } 1.1906 + if (0 == (rowN -= minN)) { 1.1907 + row += 2; 1.1908 + rowN = row[0]; // reload 1.1909 + } 1.1910 + 1.1911 + SkDEBUGCODE(accumulated += minN;) 1.1912 + SkASSERT(accumulated <= width); 1.1913 + } 1.1914 + dstRuns[0] = 0; 1.1915 +} 1.1916 + 1.1917 +void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[], 1.1918 + const int16_t runs[]) { 1.1919 + 1.1920 + const uint8_t* row = fAAClip->findRow(y); 1.1921 + int initialCount; 1.1922 + row = fAAClip->findX(row, x, &initialCount); 1.1923 + 1.1924 + this->ensureRunsAndAA(); 1.1925 + 1.1926 + merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width()); 1.1927 + fBlitter->blitAntiH(x, y, fAA, fRuns); 1.1928 +} 1.1929 + 1.1930 +void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) { 1.1931 + if (fAAClip->quickContains(x, y, x + 1, y + height)) { 1.1932 + fBlitter->blitV(x, y, height, alpha); 1.1933 + return; 1.1934 + } 1.1935 + 1.1936 + for (;;) { 1.1937 + int lastY SK_INIT_TO_AVOID_WARNING; 1.1938 + const uint8_t* row = fAAClip->findRow(y, &lastY); 1.1939 + int dy = lastY - y + 1; 1.1940 + if (dy > height) { 1.1941 + dy = height; 1.1942 + } 1.1943 + height -= dy; 1.1944 + 1.1945 + row = fAAClip->findX(row, x); 1.1946 + SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]); 1.1947 + if (newAlpha) { 1.1948 + fBlitter->blitV(x, y, dy, newAlpha); 1.1949 + } 1.1950 + SkASSERT(height >= 0); 1.1951 + if (height <= 0) { 1.1952 + break; 1.1953 + } 1.1954 + y = lastY + 1; 1.1955 + } 1.1956 +} 1.1957 + 1.1958 +void SkAAClipBlitter::blitRect(int x, int y, int width, int height) { 1.1959 + if (fAAClip->quickContains(x, y, x + width, y + height)) { 1.1960 + fBlitter->blitRect(x, y, width, height); 1.1961 + return; 1.1962 + } 1.1963 + 1.1964 + while (--height >= 0) { 1.1965 + this->blitH(x, y, width); 1.1966 + y += 1; 1.1967 + } 1.1968 +} 1.1969 + 1.1970 +typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row, 1.1971 + int initialRowCount, void* dst); 1.1972 + 1.1973 +static void small_memcpy(void* dst, const void* src, size_t n) { 1.1974 + memcpy(dst, src, n); 1.1975 +} 1.1976 + 1.1977 +static void small_bzero(void* dst, size_t n) { 1.1978 + sk_bzero(dst, n); 1.1979 +} 1.1980 + 1.1981 +static inline uint8_t mergeOne(uint8_t value, unsigned alpha) { 1.1982 + return SkMulDiv255Round(value, alpha); 1.1983 +} 1.1984 +static inline uint16_t mergeOne(uint16_t value, unsigned alpha) { 1.1985 + unsigned r = SkGetPackedR16(value); 1.1986 + unsigned g = SkGetPackedG16(value); 1.1987 + unsigned b = SkGetPackedB16(value); 1.1988 + return SkPackRGB16(SkMulDiv255Round(r, alpha), 1.1989 + SkMulDiv255Round(g, alpha), 1.1990 + SkMulDiv255Round(b, alpha)); 1.1991 +} 1.1992 +static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) { 1.1993 + unsigned a = SkGetPackedA32(value); 1.1994 + unsigned r = SkGetPackedR32(value); 1.1995 + unsigned g = SkGetPackedG32(value); 1.1996 + unsigned b = SkGetPackedB32(value); 1.1997 + return SkPackARGB32(SkMulDiv255Round(a, alpha), 1.1998 + SkMulDiv255Round(r, alpha), 1.1999 + SkMulDiv255Round(g, alpha), 1.2000 + SkMulDiv255Round(b, alpha)); 1.2001 +} 1.2002 + 1.2003 +template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN, 1.2004 + const uint8_t* SK_RESTRICT row, int rowN, 1.2005 + T* SK_RESTRICT dst) { 1.2006 + for (;;) { 1.2007 + SkASSERT(rowN > 0); 1.2008 + SkASSERT(srcN > 0); 1.2009 + 1.2010 + int n = SkMin32(rowN, srcN); 1.2011 + unsigned rowA = row[1]; 1.2012 + if (0xFF == rowA) { 1.2013 + small_memcpy(dst, src, n * sizeof(T)); 1.2014 + } else if (0 == rowA) { 1.2015 + small_bzero(dst, n * sizeof(T)); 1.2016 + } else { 1.2017 + for (int i = 0; i < n; ++i) { 1.2018 + dst[i] = mergeOne(src[i], rowA); 1.2019 + } 1.2020 + } 1.2021 + 1.2022 + if (0 == (srcN -= n)) { 1.2023 + break; 1.2024 + } 1.2025 + 1.2026 + src += n; 1.2027 + dst += n; 1.2028 + 1.2029 + SkASSERT(rowN == n); 1.2030 + row += 2; 1.2031 + rowN = row[0]; 1.2032 + } 1.2033 +} 1.2034 + 1.2035 +static MergeAAProc find_merge_aa_proc(SkMask::Format format) { 1.2036 + switch (format) { 1.2037 + case SkMask::kBW_Format: 1.2038 + SkDEBUGFAIL("unsupported"); 1.2039 + return NULL; 1.2040 + case SkMask::kA8_Format: 1.2041 + case SkMask::k3D_Format: { 1.2042 + void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT; 1.2043 + return (MergeAAProc)proc8; 1.2044 + } 1.2045 + case SkMask::kLCD16_Format: { 1.2046 + void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT; 1.2047 + return (MergeAAProc)proc16; 1.2048 + } 1.2049 + case SkMask::kLCD32_Format: { 1.2050 + void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT; 1.2051 + return (MergeAAProc)proc32; 1.2052 + } 1.2053 + default: 1.2054 + SkDEBUGFAIL("unsupported"); 1.2055 + return NULL; 1.2056 + } 1.2057 +} 1.2058 + 1.2059 +static U8CPU bit2byte(int bitInAByte) { 1.2060 + SkASSERT(bitInAByte <= 0xFF); 1.2061 + // negation turns any non-zero into 0xFFFFFF??, so we just shift down 1.2062 + // some value >= 8 to get a full FF value 1.2063 + return -bitInAByte >> 8; 1.2064 +} 1.2065 + 1.2066 +static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) { 1.2067 + SkASSERT(SkMask::kBW_Format == srcMask.fFormat); 1.2068 + SkASSERT(SkMask::kA8_Format == dstMask->fFormat); 1.2069 + 1.2070 + const int width = srcMask.fBounds.width(); 1.2071 + const int height = srcMask.fBounds.height(); 1.2072 + 1.2073 + const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage; 1.2074 + const size_t srcRB = srcMask.fRowBytes; 1.2075 + uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage; 1.2076 + const size_t dstRB = dstMask->fRowBytes; 1.2077 + 1.2078 + const int wholeBytes = width >> 3; 1.2079 + const int leftOverBits = width & 7; 1.2080 + 1.2081 + for (int y = 0; y < height; ++y) { 1.2082 + uint8_t* SK_RESTRICT d = dst; 1.2083 + for (int i = 0; i < wholeBytes; ++i) { 1.2084 + int srcByte = src[i]; 1.2085 + d[0] = bit2byte(srcByte & (1 << 7)); 1.2086 + d[1] = bit2byte(srcByte & (1 << 6)); 1.2087 + d[2] = bit2byte(srcByte & (1 << 5)); 1.2088 + d[3] = bit2byte(srcByte & (1 << 4)); 1.2089 + d[4] = bit2byte(srcByte & (1 << 3)); 1.2090 + d[5] = bit2byte(srcByte & (1 << 2)); 1.2091 + d[6] = bit2byte(srcByte & (1 << 1)); 1.2092 + d[7] = bit2byte(srcByte & (1 << 0)); 1.2093 + d += 8; 1.2094 + } 1.2095 + if (leftOverBits) { 1.2096 + int srcByte = src[wholeBytes]; 1.2097 + for (int x = 0; x < leftOverBits; ++x) { 1.2098 + *d++ = bit2byte(srcByte & 0x80); 1.2099 + srcByte <<= 1; 1.2100 + } 1.2101 + } 1.2102 + src += srcRB; 1.2103 + dst += dstRB; 1.2104 + } 1.2105 +} 1.2106 + 1.2107 +void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) { 1.2108 + SkASSERT(fAAClip->getBounds().contains(clip)); 1.2109 + 1.2110 + if (fAAClip->quickContains(clip)) { 1.2111 + fBlitter->blitMask(origMask, clip); 1.2112 + return; 1.2113 + } 1.2114 + 1.2115 + const SkMask* mask = &origMask; 1.2116 + 1.2117 + // if we're BW, we need to upscale to A8 (ugh) 1.2118 + SkMask grayMask; 1.2119 + grayMask.fImage = NULL; 1.2120 + if (SkMask::kBW_Format == origMask.fFormat) { 1.2121 + grayMask.fFormat = SkMask::kA8_Format; 1.2122 + grayMask.fBounds = origMask.fBounds; 1.2123 + grayMask.fRowBytes = origMask.fBounds.width(); 1.2124 + size_t size = grayMask.computeImageSize(); 1.2125 + grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size, 1.2126 + SkAutoMalloc::kReuse_OnShrink); 1.2127 + 1.2128 + upscaleBW2A8(&grayMask, origMask); 1.2129 + mask = &grayMask; 1.2130 + } 1.2131 + 1.2132 + this->ensureRunsAndAA(); 1.2133 + 1.2134 + // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D 1.2135 + // data into a temp block to support it better (ugh) 1.2136 + 1.2137 + const void* src = mask->getAddr(clip.fLeft, clip.fTop); 1.2138 + const size_t srcRB = mask->fRowBytes; 1.2139 + const int width = clip.width(); 1.2140 + MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat); 1.2141 + 1.2142 + SkMask rowMask; 1.2143 + rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat; 1.2144 + rowMask.fBounds.fLeft = clip.fLeft; 1.2145 + rowMask.fBounds.fRight = clip.fRight; 1.2146 + rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1 1.2147 + rowMask.fImage = (uint8_t*)fScanlineScratch; 1.2148 + 1.2149 + int y = clip.fTop; 1.2150 + const int stopY = y + clip.height(); 1.2151 + 1.2152 + do { 1.2153 + int localStopY SK_INIT_TO_AVOID_WARNING; 1.2154 + const uint8_t* row = fAAClip->findRow(y, &localStopY); 1.2155 + // findRow returns last Y, not stop, so we add 1 1.2156 + localStopY = SkMin32(localStopY + 1, stopY); 1.2157 + 1.2158 + int initialCount; 1.2159 + row = fAAClip->findX(row, clip.fLeft, &initialCount); 1.2160 + do { 1.2161 + mergeProc(src, width, row, initialCount, rowMask.fImage); 1.2162 + rowMask.fBounds.fTop = y; 1.2163 + rowMask.fBounds.fBottom = y + 1; 1.2164 + fBlitter->blitMask(rowMask, rowMask.fBounds); 1.2165 + src = (const void*)((const char*)src + srcRB); 1.2166 + } while (++y < localStopY); 1.2167 + } while (y < stopY); 1.2168 +} 1.2169 + 1.2170 +const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) { 1.2171 + return NULL; 1.2172 +}