1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkScan_Path.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,729 @@ 1.4 +/* 1.5 + * Copyright 2006 The Android Open Source Project 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkScanPriv.h" 1.12 +#include "SkBlitter.h" 1.13 +#include "SkEdge.h" 1.14 +#include "SkEdgeBuilder.h" 1.15 +#include "SkGeometry.h" 1.16 +#include "SkPath.h" 1.17 +#include "SkQuadClipper.h" 1.18 +#include "SkRasterClip.h" 1.19 +#include "SkRegion.h" 1.20 +#include "SkTemplates.h" 1.21 +#include "SkTSort.h" 1.22 + 1.23 +#ifdef SK_USE_LEGACY_AA_COVERAGE 1.24 + #define SK_USE_STD_SORT_FOR_EDGES 1.25 +#endif 1.26 + 1.27 +#define kEDGE_HEAD_Y SK_MinS32 1.28 +#define kEDGE_TAIL_Y SK_MaxS32 1.29 + 1.30 +#ifdef SK_DEBUG 1.31 + static void validate_sort(const SkEdge* edge) { 1.32 + int y = kEDGE_HEAD_Y; 1.33 + 1.34 + while (edge->fFirstY != SK_MaxS32) { 1.35 + edge->validate(); 1.36 + SkASSERT(y <= edge->fFirstY); 1.37 + 1.38 + y = edge->fFirstY; 1.39 + edge = edge->fNext; 1.40 + } 1.41 + } 1.42 +#else 1.43 + #define validate_sort(edge) 1.44 +#endif 1.45 + 1.46 +static inline void remove_edge(SkEdge* edge) { 1.47 + edge->fPrev->fNext = edge->fNext; 1.48 + edge->fNext->fPrev = edge->fPrev; 1.49 +} 1.50 + 1.51 +static inline void swap_edges(SkEdge* prev, SkEdge* next) { 1.52 + SkASSERT(prev->fNext == next && next->fPrev == prev); 1.53 + 1.54 + // remove prev from the list 1.55 + prev->fPrev->fNext = next; 1.56 + next->fPrev = prev->fPrev; 1.57 + 1.58 + // insert prev after next 1.59 + prev->fNext = next->fNext; 1.60 + next->fNext->fPrev = prev; 1.61 + next->fNext = prev; 1.62 + prev->fPrev = next; 1.63 +} 1.64 + 1.65 +static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, curr_y)) { 1.66 + SkFixed x = edge->fX; 1.67 + 1.68 + for (;;) { 1.69 + SkEdge* prev = edge->fPrev; 1.70 + 1.71 + // add 1 to curr_y since we may have added new edges (built from curves) 1.72 + // that start on the next scanline 1.73 + SkASSERT(prev && prev->fFirstY <= curr_y + 1); 1.74 + 1.75 + if (prev->fX <= x) { 1.76 + break; 1.77 + } 1.78 + swap_edges(prev, edge); 1.79 + } 1.80 +} 1.81 + 1.82 +static void insert_new_edges(SkEdge* newEdge, int curr_y) { 1.83 + SkASSERT(newEdge->fFirstY >= curr_y); 1.84 + 1.85 + while (newEdge->fFirstY == curr_y) { 1.86 + SkEdge* next = newEdge->fNext; 1.87 + backward_insert_edge_based_on_x(newEdge SkPARAM(curr_y)); 1.88 + newEdge = next; 1.89 + } 1.90 +} 1.91 + 1.92 +#ifdef SK_DEBUG 1.93 +static void validate_edges_for_y(const SkEdge* edge, int curr_y) { 1.94 + while (edge->fFirstY <= curr_y) { 1.95 + SkASSERT(edge->fPrev && edge->fNext); 1.96 + SkASSERT(edge->fPrev->fNext == edge); 1.97 + SkASSERT(edge->fNext->fPrev == edge); 1.98 + SkASSERT(edge->fFirstY <= edge->fLastY); 1.99 + 1.100 + SkASSERT(edge->fPrev->fX <= edge->fX); 1.101 + edge = edge->fNext; 1.102 + } 1.103 +} 1.104 +#else 1.105 + #define validate_edges_for_y(edge, curr_y) 1.106 +#endif 1.107 + 1.108 +#if defined _WIN32 && _MSC_VER >= 1300 // disable warning : local variable used without having been initialized 1.109 +#pragma warning ( push ) 1.110 +#pragma warning ( disable : 4701 ) 1.111 +#endif 1.112 + 1.113 +typedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline); 1.114 +#define PREPOST_START true 1.115 +#define PREPOST_END false 1.116 + 1.117 +static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType, 1.118 + SkBlitter* blitter, int start_y, int stop_y, 1.119 + PrePostProc proc) { 1.120 + validate_sort(prevHead->fNext); 1.121 + 1.122 + int curr_y = start_y; 1.123 + // returns 1 for evenodd, -1 for winding, regardless of inverse-ness 1.124 + int windingMask = (fillType & 1) ? 1 : -1; 1.125 + 1.126 + for (;;) { 1.127 + int w = 0; 1.128 + int left SK_INIT_TO_AVOID_WARNING; 1.129 + bool in_interval = false; 1.130 + SkEdge* currE = prevHead->fNext; 1.131 + SkFixed prevX = prevHead->fX; 1.132 + 1.133 + validate_edges_for_y(currE, curr_y); 1.134 + 1.135 + if (proc) { 1.136 + proc(blitter, curr_y, PREPOST_START); // pre-proc 1.137 + } 1.138 + 1.139 + while (currE->fFirstY <= curr_y) { 1.140 + SkASSERT(currE->fLastY >= curr_y); 1.141 + 1.142 + int x = SkFixedRoundToInt(currE->fX); 1.143 + w += currE->fWinding; 1.144 + if ((w & windingMask) == 0) { // we finished an interval 1.145 + SkASSERT(in_interval); 1.146 + int width = x - left; 1.147 + SkASSERT(width >= 0); 1.148 + if (width) 1.149 + blitter->blitH(left, curr_y, width); 1.150 + in_interval = false; 1.151 + } else if (!in_interval) { 1.152 + left = x; 1.153 + in_interval = true; 1.154 + } 1.155 + 1.156 + SkEdge* next = currE->fNext; 1.157 + SkFixed newX; 1.158 + 1.159 + if (currE->fLastY == curr_y) { // are we done with this edge? 1.160 + if (currE->fCurveCount < 0) { 1.161 + if (((SkCubicEdge*)currE)->updateCubic()) { 1.162 + SkASSERT(currE->fFirstY == curr_y + 1); 1.163 + 1.164 + newX = currE->fX; 1.165 + goto NEXT_X; 1.166 + } 1.167 + } else if (currE->fCurveCount > 0) { 1.168 + if (((SkQuadraticEdge*)currE)->updateQuadratic()) { 1.169 + newX = currE->fX; 1.170 + goto NEXT_X; 1.171 + } 1.172 + } 1.173 + remove_edge(currE); 1.174 + } else { 1.175 + SkASSERT(currE->fLastY > curr_y); 1.176 + newX = currE->fX + currE->fDX; 1.177 + currE->fX = newX; 1.178 + NEXT_X: 1.179 + if (newX < prevX) { // ripple currE backwards until it is x-sorted 1.180 + backward_insert_edge_based_on_x(currE SkPARAM(curr_y)); 1.181 + } else { 1.182 + prevX = newX; 1.183 + } 1.184 + } 1.185 + currE = next; 1.186 + SkASSERT(currE); 1.187 + } 1.188 + 1.189 + if (proc) { 1.190 + proc(blitter, curr_y, PREPOST_END); // post-proc 1.191 + } 1.192 + 1.193 + curr_y += 1; 1.194 + if (curr_y >= stop_y) { 1.195 + break; 1.196 + } 1.197 + // now currE points to the first edge with a Yint larger than curr_y 1.198 + insert_new_edges(currE, curr_y); 1.199 + } 1.200 +} 1.201 + 1.202 +// return true if we're done with this edge 1.203 +static bool update_edge(SkEdge* edge, int last_y) { 1.204 + SkASSERT(edge->fLastY >= last_y); 1.205 + if (last_y == edge->fLastY) { 1.206 + if (edge->fCurveCount < 0) { 1.207 + if (((SkCubicEdge*)edge)->updateCubic()) { 1.208 + SkASSERT(edge->fFirstY == last_y + 1); 1.209 + return false; 1.210 + } 1.211 + } else if (edge->fCurveCount > 0) { 1.212 + if (((SkQuadraticEdge*)edge)->updateQuadratic()) { 1.213 + SkASSERT(edge->fFirstY == last_y + 1); 1.214 + return false; 1.215 + } 1.216 + } 1.217 + return true; 1.218 + } 1.219 + return false; 1.220 +} 1.221 + 1.222 +static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType, 1.223 + SkBlitter* blitter, int start_y, int stop_y, 1.224 + PrePostProc proc) { 1.225 + validate_sort(prevHead->fNext); 1.226 + 1.227 + SkEdge* leftE = prevHead->fNext; 1.228 + SkEdge* riteE = leftE->fNext; 1.229 + SkEdge* currE = riteE->fNext; 1.230 + 1.231 +#if 0 1.232 + int local_top = leftE->fFirstY; 1.233 + SkASSERT(local_top == riteE->fFirstY); 1.234 +#else 1.235 + // our edge choppers for curves can result in the initial edges 1.236 + // not lining up, so we take the max. 1.237 + int local_top = SkMax32(leftE->fFirstY, riteE->fFirstY); 1.238 +#endif 1.239 + SkASSERT(local_top >= start_y); 1.240 + 1.241 + for (;;) { 1.242 + SkASSERT(leftE->fFirstY <= stop_y); 1.243 + SkASSERT(riteE->fFirstY <= stop_y); 1.244 + 1.245 + if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX && 1.246 + leftE->fDX > riteE->fDX)) { 1.247 + SkTSwap(leftE, riteE); 1.248 + } 1.249 + 1.250 + int local_bot = SkMin32(leftE->fLastY, riteE->fLastY); 1.251 + local_bot = SkMin32(local_bot, stop_y - 1); 1.252 + SkASSERT(local_top <= local_bot); 1.253 + 1.254 + SkFixed left = leftE->fX; 1.255 + SkFixed dLeft = leftE->fDX; 1.256 + SkFixed rite = riteE->fX; 1.257 + SkFixed dRite = riteE->fDX; 1.258 + int count = local_bot - local_top; 1.259 + SkASSERT(count >= 0); 1.260 + if (0 == (dLeft | dRite)) { 1.261 + int L = SkFixedRoundToInt(left); 1.262 + int R = SkFixedRoundToInt(rite); 1.263 + if (L < R) { 1.264 + count += 1; 1.265 + blitter->blitRect(L, local_top, R - L, count); 1.266 + left += count * dLeft; 1.267 + rite += count * dRite; 1.268 + } 1.269 + local_top = local_bot + 1; 1.270 + } else { 1.271 + do { 1.272 + int L = SkFixedRoundToInt(left); 1.273 + int R = SkFixedRoundToInt(rite); 1.274 + if (L < R) { 1.275 + blitter->blitH(L, local_top, R - L); 1.276 + } 1.277 + left += dLeft; 1.278 + rite += dRite; 1.279 + local_top += 1; 1.280 + } while (--count >= 0); 1.281 + } 1.282 + 1.283 + leftE->fX = left; 1.284 + riteE->fX = rite; 1.285 + 1.286 + if (update_edge(leftE, local_bot)) { 1.287 + if (currE->fFirstY >= stop_y) { 1.288 + break; 1.289 + } 1.290 + leftE = currE; 1.291 + currE = currE->fNext; 1.292 + } 1.293 + if (update_edge(riteE, local_bot)) { 1.294 + if (currE->fFirstY >= stop_y) { 1.295 + break; 1.296 + } 1.297 + riteE = currE; 1.298 + currE = currE->fNext; 1.299 + } 1.300 + 1.301 + SkASSERT(leftE); 1.302 + SkASSERT(riteE); 1.303 + 1.304 + // check our bottom clip 1.305 + SkASSERT(local_top == local_bot + 1); 1.306 + if (local_top >= stop_y) { 1.307 + break; 1.308 + } 1.309 + } 1.310 +} 1.311 + 1.312 +/////////////////////////////////////////////////////////////////////////////// 1.313 + 1.314 +// this guy overrides blitH, and will call its proxy blitter with the inverse 1.315 +// of the spans it is given (clipped to the left/right of the cliprect) 1.316 +// 1.317 +// used to implement inverse filltypes on paths 1.318 +// 1.319 +class InverseBlitter : public SkBlitter { 1.320 +public: 1.321 + void setBlitter(SkBlitter* blitter, const SkIRect& clip, int shift) { 1.322 + fBlitter = blitter; 1.323 + fFirstX = clip.fLeft << shift; 1.324 + fLastX = clip.fRight << shift; 1.325 + } 1.326 + void prepost(int y, bool isStart) { 1.327 + if (isStart) { 1.328 + fPrevX = fFirstX; 1.329 + } else { 1.330 + int invWidth = fLastX - fPrevX; 1.331 + if (invWidth > 0) { 1.332 + fBlitter->blitH(fPrevX, y, invWidth); 1.333 + } 1.334 + } 1.335 + } 1.336 + 1.337 + // overrides 1.338 + virtual void blitH(int x, int y, int width) { 1.339 + int invWidth = x - fPrevX; 1.340 + if (invWidth > 0) { 1.341 + fBlitter->blitH(fPrevX, y, invWidth); 1.342 + } 1.343 + fPrevX = x + width; 1.344 + } 1.345 + 1.346 + // we do not expect to get called with these entrypoints 1.347 + virtual void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) { 1.348 + SkDEBUGFAIL("blitAntiH unexpected"); 1.349 + } 1.350 + virtual void blitV(int x, int y, int height, SkAlpha alpha) { 1.351 + SkDEBUGFAIL("blitV unexpected"); 1.352 + } 1.353 + virtual void blitRect(int x, int y, int width, int height) { 1.354 + SkDEBUGFAIL("blitRect unexpected"); 1.355 + } 1.356 + virtual void blitMask(const SkMask&, const SkIRect& clip) { 1.357 + SkDEBUGFAIL("blitMask unexpected"); 1.358 + } 1.359 + virtual const SkBitmap* justAnOpaqueColor(uint32_t* value) { 1.360 + SkDEBUGFAIL("justAnOpaqueColor unexpected"); 1.361 + return NULL; 1.362 + } 1.363 + 1.364 +private: 1.365 + SkBlitter* fBlitter; 1.366 + int fFirstX, fLastX, fPrevX; 1.367 +}; 1.368 + 1.369 +static void PrePostInverseBlitterProc(SkBlitter* blitter, int y, bool isStart) { 1.370 + ((InverseBlitter*)blitter)->prepost(y, isStart); 1.371 +} 1.372 + 1.373 +/////////////////////////////////////////////////////////////////////////////// 1.374 + 1.375 +#if defined _WIN32 && _MSC_VER >= 1300 1.376 +#pragma warning ( pop ) 1.377 +#endif 1.378 + 1.379 +#ifdef SK_USE_STD_SORT_FOR_EDGES 1.380 +extern "C" { 1.381 + static int edge_compare(const void* a, const void* b) { 1.382 + const SkEdge* edgea = *(const SkEdge**)a; 1.383 + const SkEdge* edgeb = *(const SkEdge**)b; 1.384 + 1.385 + int valuea = edgea->fFirstY; 1.386 + int valueb = edgeb->fFirstY; 1.387 + 1.388 + if (valuea == valueb) { 1.389 + valuea = edgea->fX; 1.390 + valueb = edgeb->fX; 1.391 + } 1.392 + 1.393 + // this overflows if valuea >>> valueb or vice-versa 1.394 + // return valuea - valueb; 1.395 + // do perform the slower but safe compares 1.396 + return (valuea < valueb) ? -1 : (valuea > valueb); 1.397 + } 1.398 +} 1.399 +#else 1.400 +static bool operator<(const SkEdge& a, const SkEdge& b) { 1.401 + int valuea = a.fFirstY; 1.402 + int valueb = b.fFirstY; 1.403 + 1.404 + if (valuea == valueb) { 1.405 + valuea = a.fX; 1.406 + valueb = b.fX; 1.407 + } 1.408 + 1.409 + return valuea < valueb; 1.410 +} 1.411 +#endif 1.412 + 1.413 +static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) { 1.414 +#ifdef SK_USE_STD_SORT_FOR_EDGES 1.415 + qsort(list, count, sizeof(SkEdge*), edge_compare); 1.416 +#else 1.417 + SkTQSort(list, list + count - 1); 1.418 +#endif 1.419 + 1.420 + // now make the edges linked in sorted order 1.421 + for (int i = 1; i < count; i++) { 1.422 + list[i - 1]->fNext = list[i]; 1.423 + list[i]->fPrev = list[i - 1]; 1.424 + } 1.425 + 1.426 + *last = list[count - 1]; 1.427 + return list[0]; 1.428 +} 1.429 + 1.430 +// clipRect may be null, even though we always have a clip. This indicates that 1.431 +// the path is contained in the clip, and so we can ignore it during the blit 1.432 +// 1.433 +// clipRect (if no null) has already been shifted up 1.434 +// 1.435 +void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitter, 1.436 + int start_y, int stop_y, int shiftEdgesUp, 1.437 + const SkRegion& clipRgn) { 1.438 + SkASSERT(&path && blitter); 1.439 + 1.440 + SkEdgeBuilder builder; 1.441 + 1.442 + int count = builder.build(path, clipRect, shiftEdgesUp); 1.443 + SkEdge** list = builder.edgeList(); 1.444 + 1.445 + if (count < 2) { 1.446 + if (path.isInverseFillType()) { 1.447 + /* 1.448 + * Since we are in inverse-fill, our caller has already drawn above 1.449 + * our top (start_y) and will draw below our bottom (stop_y). Thus 1.450 + * we need to restrict our drawing to the intersection of the clip 1.451 + * and those two limits. 1.452 + */ 1.453 + SkIRect rect = clipRgn.getBounds(); 1.454 + if (rect.fTop < start_y) { 1.455 + rect.fTop = start_y; 1.456 + } 1.457 + if (rect.fBottom > stop_y) { 1.458 + rect.fBottom = stop_y; 1.459 + } 1.460 + if (!rect.isEmpty()) { 1.461 + blitter->blitRect(rect.fLeft << shiftEdgesUp, 1.462 + rect.fTop << shiftEdgesUp, 1.463 + rect.width() << shiftEdgesUp, 1.464 + rect.height() << shiftEdgesUp); 1.465 + } 1.466 + } 1.467 + 1.468 + return; 1.469 + } 1.470 + 1.471 + SkEdge headEdge, tailEdge, *last; 1.472 + // this returns the first and last edge after they're sorted into a dlink list 1.473 + SkEdge* edge = sort_edges(list, count, &last); 1.474 + 1.475 + headEdge.fPrev = NULL; 1.476 + headEdge.fNext = edge; 1.477 + headEdge.fFirstY = kEDGE_HEAD_Y; 1.478 + headEdge.fX = SK_MinS32; 1.479 + edge->fPrev = &headEdge; 1.480 + 1.481 + tailEdge.fPrev = last; 1.482 + tailEdge.fNext = NULL; 1.483 + tailEdge.fFirstY = kEDGE_TAIL_Y; 1.484 + last->fNext = &tailEdge; 1.485 + 1.486 + // now edge is the head of the sorted linklist 1.487 + 1.488 + start_y <<= shiftEdgesUp; 1.489 + stop_y <<= shiftEdgesUp; 1.490 + if (clipRect && start_y < clipRect->fTop) { 1.491 + start_y = clipRect->fTop; 1.492 + } 1.493 + if (clipRect && stop_y > clipRect->fBottom) { 1.494 + stop_y = clipRect->fBottom; 1.495 + } 1.496 + 1.497 + InverseBlitter ib; 1.498 + PrePostProc proc = NULL; 1.499 + 1.500 + if (path.isInverseFillType()) { 1.501 + ib.setBlitter(blitter, clipRgn.getBounds(), shiftEdgesUp); 1.502 + blitter = &ib; 1.503 + proc = PrePostInverseBlitterProc; 1.504 + } 1.505 + 1.506 + if (path.isConvex() && (NULL == proc)) { 1.507 + walk_convex_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, NULL); 1.508 + } else { 1.509 + walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc); 1.510 + } 1.511 +} 1.512 + 1.513 +void sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) { 1.514 + const SkIRect& cr = clip.getBounds(); 1.515 + SkIRect tmp; 1.516 + 1.517 + tmp.fLeft = cr.fLeft; 1.518 + tmp.fRight = cr.fRight; 1.519 + tmp.fTop = cr.fTop; 1.520 + tmp.fBottom = ir.fTop; 1.521 + if (!tmp.isEmpty()) { 1.522 + blitter->blitRectRegion(tmp, clip); 1.523 + } 1.524 +} 1.525 + 1.526 +void sk_blit_below(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) { 1.527 + const SkIRect& cr = clip.getBounds(); 1.528 + SkIRect tmp; 1.529 + 1.530 + tmp.fLeft = cr.fLeft; 1.531 + tmp.fRight = cr.fRight; 1.532 + tmp.fTop = ir.fBottom; 1.533 + tmp.fBottom = cr.fBottom; 1.534 + if (!tmp.isEmpty()) { 1.535 + blitter->blitRectRegion(tmp, clip); 1.536 + } 1.537 +} 1.538 + 1.539 +/////////////////////////////////////////////////////////////////////////////// 1.540 + 1.541 +/** 1.542 + * If the caller is drawing an inverse-fill path, then it pass true for 1.543 + * skipRejectTest, so we don't abort drawing just because the src bounds (ir) 1.544 + * is outside of the clip. 1.545 + */ 1.546 +SkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip, 1.547 + const SkIRect& ir, bool skipRejectTest) { 1.548 + fBlitter = NULL; // null means blit nothing 1.549 + fClipRect = NULL; 1.550 + 1.551 + if (clip) { 1.552 + fClipRect = &clip->getBounds(); 1.553 + if (!skipRejectTest && !SkIRect::Intersects(*fClipRect, ir)) { // completely clipped out 1.554 + return; 1.555 + } 1.556 + 1.557 + if (clip->isRect()) { 1.558 + if (fClipRect->contains(ir)) { 1.559 + fClipRect = NULL; 1.560 + } else { 1.561 + // only need a wrapper blitter if we're horizontally clipped 1.562 + if (fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight) { 1.563 + fRectBlitter.init(blitter, *fClipRect); 1.564 + blitter = &fRectBlitter; 1.565 + } 1.566 + } 1.567 + } else { 1.568 + fRgnBlitter.init(blitter, clip); 1.569 + blitter = &fRgnBlitter; 1.570 + } 1.571 + } 1.572 + fBlitter = blitter; 1.573 +} 1.574 + 1.575 +/////////////////////////////////////////////////////////////////////////////// 1.576 + 1.577 +static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) { 1.578 + const int32_t limit = 32767; 1.579 + 1.580 + SkIRect limitR; 1.581 + limitR.set(-limit, -limit, limit, limit); 1.582 + if (limitR.contains(orig.getBounds())) { 1.583 + return false; 1.584 + } 1.585 + reduced->op(orig, limitR, SkRegion::kIntersect_Op); 1.586 + return true; 1.587 +} 1.588 + 1.589 +void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, 1.590 + SkBlitter* blitter) { 1.591 + if (origClip.isEmpty()) { 1.592 + return; 1.593 + } 1.594 + 1.595 + // Our edges are fixed-point, and don't like the bounds of the clip to 1.596 + // exceed that. Here we trim the clip just so we don't overflow later on 1.597 + const SkRegion* clipPtr = &origClip; 1.598 + SkRegion finiteClip; 1.599 + if (clip_to_limit(origClip, &finiteClip)) { 1.600 + if (finiteClip.isEmpty()) { 1.601 + return; 1.602 + } 1.603 + clipPtr = &finiteClip; 1.604 + } 1.605 + // don't reference "origClip" any more, just use clipPtr 1.606 + 1.607 + SkIRect ir; 1.608 + path.getBounds().roundOut(&ir); 1.609 + if (ir.isEmpty()) { 1.610 + if (path.isInverseFillType()) { 1.611 + blitter->blitRegion(*clipPtr); 1.612 + } 1.613 + return; 1.614 + } 1.615 + 1.616 + SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType()); 1.617 + 1.618 + blitter = clipper.getBlitter(); 1.619 + if (blitter) { 1.620 + // we have to keep our calls to blitter in sorted order, so we 1.621 + // must blit the above section first, then the middle, then the bottom. 1.622 + if (path.isInverseFillType()) { 1.623 + sk_blit_above(blitter, ir, *clipPtr); 1.624 + } 1.625 + sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom, 1.626 + 0, *clipPtr); 1.627 + if (path.isInverseFillType()) { 1.628 + sk_blit_below(blitter, ir, *clipPtr); 1.629 + } 1.630 + } else { 1.631 + // what does it mean to not have a blitter if path.isInverseFillType??? 1.632 + } 1.633 +} 1.634 + 1.635 +void SkScan::FillPath(const SkPath& path, const SkIRect& ir, 1.636 + SkBlitter* blitter) { 1.637 + SkRegion rgn(ir); 1.638 + FillPath(path, rgn, blitter); 1.639 +} 1.640 + 1.641 +/////////////////////////////////////////////////////////////////////////////// 1.642 + 1.643 +static int build_tri_edges(SkEdge edge[], const SkPoint pts[], 1.644 + const SkIRect* clipRect, SkEdge* list[]) { 1.645 + SkEdge** start = list; 1.646 + 1.647 + if (edge->setLine(pts[0], pts[1], clipRect, 0)) { 1.648 + *list++ = edge; 1.649 + edge = (SkEdge*)((char*)edge + sizeof(SkEdge)); 1.650 + } 1.651 + if (edge->setLine(pts[1], pts[2], clipRect, 0)) { 1.652 + *list++ = edge; 1.653 + edge = (SkEdge*)((char*)edge + sizeof(SkEdge)); 1.654 + } 1.655 + if (edge->setLine(pts[2], pts[0], clipRect, 0)) { 1.656 + *list++ = edge; 1.657 + } 1.658 + return (int)(list - start); 1.659 +} 1.660 + 1.661 + 1.662 +static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect, 1.663 + SkBlitter* blitter, const SkIRect& ir) { 1.664 + SkASSERT(pts && blitter); 1.665 + 1.666 + SkEdge edgeStorage[3]; 1.667 + SkEdge* list[3]; 1.668 + 1.669 + int count = build_tri_edges(edgeStorage, pts, clipRect, list); 1.670 + if (count < 2) { 1.671 + return; 1.672 + } 1.673 + 1.674 + SkEdge headEdge, tailEdge, *last; 1.675 + 1.676 + // this returns the first and last edge after they're sorted into a dlink list 1.677 + SkEdge* edge = sort_edges(list, count, &last); 1.678 + 1.679 + headEdge.fPrev = NULL; 1.680 + headEdge.fNext = edge; 1.681 + headEdge.fFirstY = kEDGE_HEAD_Y; 1.682 + headEdge.fX = SK_MinS32; 1.683 + edge->fPrev = &headEdge; 1.684 + 1.685 + tailEdge.fPrev = last; 1.686 + tailEdge.fNext = NULL; 1.687 + tailEdge.fFirstY = kEDGE_TAIL_Y; 1.688 + last->fNext = &tailEdge; 1.689 + 1.690 + // now edge is the head of the sorted linklist 1.691 + int stop_y = ir.fBottom; 1.692 + if (clipRect && stop_y > clipRect->fBottom) { 1.693 + stop_y = clipRect->fBottom; 1.694 + } 1.695 + int start_y = ir.fTop; 1.696 + if (clipRect && start_y < clipRect->fTop) { 1.697 + start_y = clipRect->fTop; 1.698 + } 1.699 + walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, NULL); 1.700 +// walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, NULL); 1.701 +} 1.702 + 1.703 +void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip, 1.704 + SkBlitter* blitter) { 1.705 + if (clip.isEmpty()) { 1.706 + return; 1.707 + } 1.708 + 1.709 + SkRect r; 1.710 + SkIRect ir; 1.711 + r.set(pts, 3); 1.712 + r.round(&ir); 1.713 + if (ir.isEmpty() || !SkIRect::Intersects(ir, clip.getBounds())) { 1.714 + return; 1.715 + } 1.716 + 1.717 + SkAAClipBlitterWrapper wrap; 1.718 + const SkRegion* clipRgn; 1.719 + if (clip.isBW()) { 1.720 + clipRgn = &clip.bwRgn(); 1.721 + } else { 1.722 + wrap.init(clip, blitter); 1.723 + clipRgn = &wrap.getRgn(); 1.724 + blitter = wrap.getBlitter(); 1.725 + } 1.726 + 1.727 + SkScanClipper clipper(blitter, clipRgn, ir); 1.728 + blitter = clipper.getBlitter(); 1.729 + if (NULL != blitter) { 1.730 + sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir); 1.731 + } 1.732 +}