void SkTableMaskFilter::MakeClipTable(uint8_t table[256], uint8_t min, uint8_t max) { if (0 == max) { max = 1; } if (min >= max) { min = max - 1; } SkASSERT(min < max); SkFixed scale = (1 << 16) * 255 / (max - min); memset(table, 0, min + 1); for (int i = min + 1; i < max; i++) { int value = SkFixedRoundToInt(scale * (i - min)); SkASSERT(value <= 255); table[i] = value; } memset(table + max, 255, 256 - max); #if 0 int j; for (j = 0; j < 256; j++) { if (table[j]) { break; } } SkDebugf("%d %d start [%d]", min, max, j); for (; j < 256; j++) { SkDebugf(" %d", table[j]); } SkDebugf("\n\n"); #endif }
static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType, SkBlitter* blitter, int start_y, int stop_y, PrePostProc proc, int rightClip) { validate_sort(prevHead->fNext); int curr_y = start_y; // returns 1 for evenodd, -1 for winding, regardless of inverse-ness int windingMask = (fillType & 1) ? 1 : -1; for (;;) { int w = 0; int left SK_INIT_TO_AVOID_WARNING; bool in_interval = false; SkEdge* currE = prevHead->fNext; SkFixed prevX = prevHead->fX; validate_edges_for_y(currE, curr_y); if (proc) { proc(blitter, curr_y, PREPOST_START); // pre-proc } while (currE->fFirstY <= curr_y) { SkASSERT(currE->fLastY >= curr_y); int x = SkFixedRoundToInt(currE->fX); w += currE->fWinding; if ((w & windingMask) == 0) { // we finished an interval SkASSERT(in_interval); int width = x - left; SkASSERT(width >= 0); if (width) blitter->blitH(left, curr_y, width); in_interval = false; } else if (!in_interval) { left = x; in_interval = true; } SkEdge* next = currE->fNext; SkFixed newX; if (currE->fLastY == curr_y) { // are we done with this edge? if (currE->fCurveCount < 0) { if (((SkCubicEdge*)currE)->updateCubic()) { SkASSERT(currE->fFirstY == curr_y + 1); newX = currE->fX; goto NEXT_X; } } else if (currE->fCurveCount > 0) { if (((SkQuadraticEdge*)currE)->updateQuadratic()) { newX = currE->fX; goto NEXT_X; } } remove_edge(currE); } else { SkASSERT(currE->fLastY > curr_y); newX = currE->fX + currE->fDX; currE->fX = newX; NEXT_X: if (newX < prevX) { // ripple currE backwards until it is x-sorted backward_insert_edge_based_on_x(currE); } else { prevX = newX; } } currE = next; SkASSERT(currE); } // was our right-edge culled away? if (in_interval) { int width = rightClip - left; if (width > 0) { blitter->blitH(left, curr_y, width); } } if (proc) { proc(blitter, curr_y, PREPOST_END); // post-proc } curr_y += 1; if (curr_y >= stop_y) { break; } // now currE points to the first edge with a Yint larger than curr_y insert_new_edges(currE, curr_y); } }
// Needs Y to only change once (looser than convex in X) static void walk_simple_edges(SkEdge* prevHead, SkBlitter* blitter, int start_y, int stop_y) { validate_sort(prevHead->fNext); SkEdge* leftE = prevHead->fNext; SkEdge* riteE = leftE->fNext; SkEdge* currE = riteE->fNext; #if 0 int local_top = leftE->fFirstY; SkASSERT(local_top == riteE->fFirstY); #else // our edge choppers for curves can result in the initial edges // not lining up, so we take the max. int local_top = SkMax32(leftE->fFirstY, riteE->fFirstY); #endif ASSERT_RETURN(local_top >= start_y); while (local_top < stop_y) { SkASSERT(leftE->fFirstY <= stop_y); SkASSERT(riteE->fFirstY <= stop_y); int local_bot = SkMin32(leftE->fLastY, riteE->fLastY); local_bot = SkMin32(local_bot, stop_y - 1); ASSERT_RETURN(local_top <= local_bot); SkFixed left = leftE->fX; SkFixed dLeft = leftE->fDX; SkFixed rite = riteE->fX; SkFixed dRite = riteE->fDX; int count = local_bot - local_top; ASSERT_RETURN(count >= 0); if (0 == (dLeft | dRite)) { int L = SkFixedRoundToInt(left); int R = SkFixedRoundToInt(rite); if (L > R) { std::swap(L, R); } if (L < R) { count += 1; blitter->blitRect(L, local_top, R - L, count); } local_top = local_bot + 1; } else { do { int L = SkFixedRoundToInt(left); int R = SkFixedRoundToInt(rite); if (L > R) { std::swap(L, R); } if (L < R) { blitter->blitH(L, local_top, R - L); } // Either/both of these might overflow, since we perform this step even if // (later) we determine that we are done with the edge, and so the computed // left or rite edge will not be used (see update_edge). Use this helper to // silence UBSAN when we perform the add. left = Sk32_can_overflow_add(left, dLeft); rite = Sk32_can_overflow_add(rite, dRite); local_top += 1; } while (--count >= 0); } leftE->fX = left; riteE->fX = rite; if (!update_edge(leftE, local_bot)) { if (currE->fFirstY >= stop_y) { return; // we're done } leftE = currE; currE = currE->fNext; ASSERT_RETURN(leftE->fFirstY == local_top); } if (!update_edge(riteE, local_bot)) { if (currE->fFirstY >= stop_y) { return; // we're done } riteE = currE; currE = currE->fNext; ASSERT_RETURN(riteE->fFirstY == local_top); } } }