bool SkEdgeClipper::clipQuad(const SkPoint srcPts[3], const SkRect& clip) { fCurrPoint = fPoints; fCurrVerb = fVerbs; SkRect bounds; bounds.set(srcPts, 3); if (!quick_reject(bounds, clip)) { SkPoint monoY[5]; int countY = SkChopQuadAtYExtrema(srcPts, monoY); for (int y = 0; y <= countY; y++) { SkPoint monoX[5]; int countX = SkChopQuadAtXExtrema(&monoY[y * 2], monoX); for (int x = 0; x <= countX; x++) { this->clipMonoQuad(&monoX[x * 2], clip); SkASSERT(fCurrVerb - fVerbs < kMaxVerbs); SkASSERT(fCurrPoint - fPoints <= kMaxPoints); } } } *fCurrVerb = SkPath::kDone_Verb; fCurrPoint = fPoints; fCurrVerb = fVerbs; return SkPath::kDone_Verb != fVerbs[0]; }
static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y) { SkPoint dst[5]; int n = 0; if (!is_mono(pts[0].fY, pts[1].fY, pts[2].fY)) { n = SkChopQuadAtYExtrema(pts, dst); pts = dst; } int w = winding_mono_quad(pts, x, y); if (n > 0) { w += winding_mono_quad(&pts[2], x, y); } return w; }
/* Returns 0 for 1 quad, and 1 for two quads, either way the answer is stored in dst[]. Guarantees that the 1/2 quads will be monotonic. */ int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5]) { SkASSERT(src); SkASSERT(dst); #if 0 static bool once = true; if (once) { once = false; SkPoint s[3] = { 0, 26398, 0, 26331, 0, 20621428 }; SkPoint d[6]; int n = SkChopQuadAtYExtrema(s, d); SkDebugf("chop=%d, Y=[%x %x %x %x %x %x]\n", n, d[0].fY, d[1].fY, d[2].fY, d[3].fY, d[4].fY, d[5].fY); } #endif SkScalar a = src[0].fY; SkScalar b = src[1].fY; SkScalar c = src[2].fY; if (is_not_monotonic(a, b, c)) { SkScalar tValue; if (valid_unit_divide(a - b, a - b - b + c, &tValue)) { SkChopQuadAt(src, dst, tValue); flatten_double_quad_extrema(&dst[0].fY); return 1; } // if we get here, we need to force dst to be monotonic, even though // we couldn't compute a unit_divide value (probably underflow). b = SkScalarAbs(a - b) < SkScalarAbs(b - c) ? a : c; } dst[0].set(src[0].fX, a); dst[1].set(src[1].fX, b); dst[2].set(src[2].fX, c); return 0; }