// Modify pts[] in place so that it is clipped in Y to the clip rect static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) { SkScalar t; SkPoint tmp[7]; // for SkChopCubicAt // are we partially above if (pts[0].fY < clip.fTop) { if (chopMonoCubicAtY(pts, clip.fTop, &t)) { SkChopCubicAt(pts, tmp, t); // given the imprecision of computing t, we just slam our Y coord // to the top of the clip. This also saves us in the bad case where // the t was soooo bad that the entire segment could have been // below fBottom tmp[3].fY = clip.fTop; clamp_ge(tmp[4].fY, clip.fTop); clamp_ge(tmp[5].fY, clip.fTop); pts[0] = tmp[3]; pts[1] = tmp[4]; pts[2] = tmp[5]; } else { // if chopMonoCubicAtY failed, then we may have hit inexact numerics // so we just clamp against the top for (int i = 0; i < 4; i++) { clamp_ge(pts[i].fY, clip.fTop); } } } // are we partially below if (pts[3].fY > clip.fBottom) { if (chopMonoCubicAtY(pts, clip.fBottom, &t)) { SkChopCubicAt(pts, tmp, t); clamp_le(tmp[1].fY, clip.fBottom); clamp_le(tmp[2].fY, clip.fBottom); clamp_le(tmp[3].fY, clip.fBottom); pts[1] = tmp[1]; pts[2] = tmp[2]; pts[3] = tmp[3]; } else { // if chopMonoCubicAtY failed, then we may have hit inexact numerics // so we just clamp against the bottom for (int i = 0; i < 4; i++) { clamp_le(pts[i].fY, clip.fBottom); } } } }
// Modify pts[] in place so that it is clipped in Y to the clip rect static void chop_quad_in_Y(SkPoint pts[3], const SkRect& clip) { SkScalar t; SkPoint tmp[5]; // for SkChopQuadAt // are we partially above if (pts[0].fY < clip.fTop) { if (chopMonoQuadAtY(pts, clip.fTop, &t)) { // take the 2nd chopped quad SkChopQuadAt(pts, tmp, t); clamp_ge(tmp[2].fY, clip.fTop); clamp_ge(tmp[3].fY, clip.fTop); pts[0] = tmp[2]; pts[1] = tmp[3]; } else { // if chopMonoQuadAtY failed, then we may have hit inexact numerics // so we just clamp against the top for (int i = 0; i < 3; i++) { if (pts[i].fY < clip.fTop) { pts[i].fY = clip.fTop; } } } } // are we partially below if (pts[2].fY > clip.fBottom) { if (chopMonoQuadAtY(pts, clip.fBottom, &t)) { SkChopQuadAt(pts, tmp, t); clamp_le(tmp[1].fY, clip.fBottom); clamp_le(tmp[2].fY, clip.fBottom); pts[1] = tmp[1]; pts[2] = tmp[2]; } else { // if chopMonoQuadAtY failed, then we may have hit inexact numerics // so we just clamp against the bottom for (int i = 0; i < 3; i++) { if (pts[i].fY > clip.fBottom) { pts[i].fY = clip.fBottom; } } } } }
// srcPts[] must be monotonic in X and Y void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) { SkPoint pts[4]; bool reverse = sort_increasing_Y(pts, src, 4); // are we completely above or below if (pts[3].fY <= clip.fTop || pts[0].fY >= clip.fBottom) { return; } // Now chop so that pts is contained within clip in Y chop_cubic_in_Y(pts, clip); if (pts[0].fX > pts[3].fX) { SkTSwap<SkPoint>(pts[0], pts[3]); SkTSwap<SkPoint>(pts[1], pts[2]); reverse = !reverse; } // Now chop in X has needed, and record the segments if (pts[3].fX <= clip.fLeft) { // wholly to the left this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse); return; } if (pts[0].fX >= clip.fRight) { // wholly to the right this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse); return; } SkScalar t; SkPoint tmp[7]; // are we partially to the left if (pts[0].fX < clip.fLeft) { if (chopMonoCubicAtX(pts, clip.fLeft, &t)) { SkChopCubicAt(pts, tmp, t); this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse); clamp_ge(tmp[3].fX, clip.fLeft); clamp_ge(tmp[4].fX, clip.fLeft); clamp_ge(tmp[5].fX, clip.fLeft); pts[0] = tmp[3]; pts[1] = tmp[4]; pts[2] = tmp[5]; } else { // if chopMonocubicAtY failed, then we may have hit inexact numerics // so we just clamp against the left this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse); return; } } // are we partially to the right if (pts[3].fX > clip.fRight) { if (chopMonoCubicAtX(pts, clip.fRight, &t)) { SkChopCubicAt(pts, tmp, t); clamp_le(tmp[1].fX, clip.fRight); clamp_le(tmp[2].fX, clip.fRight); clamp_le(tmp[3].fX, clip.fRight); this->appendCubic(tmp, reverse); this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse); } else { // if chopMonoCubicAtX failed, then we may have hit inexact numerics // so we just clamp against the right this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse); } } else { // wholly inside the clip this->appendCubic(pts, reverse); } }
// srcPts[] must be monotonic in X and Y void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) { SkPoint pts[4]; bool reverse = sort_increasing_Y(pts, src, 4); // are we completely above or below if (pts[3].fY <= clip.fTop || pts[0].fY >= clip.fBottom) { return; } // Now chop so that pts is contained within clip in Y chop_cubic_in_Y(pts, clip); if (pts[0].fX > pts[3].fX) { SkTSwap<SkPoint>(pts[0], pts[3]); SkTSwap<SkPoint>(pts[1], pts[2]); reverse = !reverse; } // Now chop in X has needed, and record the segments if (pts[3].fX <= clip.fLeft) { // wholly to the left this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse); return; } if (pts[0].fX >= clip.fRight) { // wholly to the right if (!this->canCullToTheRight()) { this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse); } return; } // are we partially to the left if (pts[0].fX < clip.fLeft) { SkPoint tmp[7]; chop_mono_cubic_at_x(pts, clip.fLeft, tmp); this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse); // tmp[3, 4].fX should all be to the right of clip.fLeft. // Since we can't trust the numerics of // the chopper, we force those conditions now tmp[3].fX = clip.fLeft; clamp_ge(tmp[4].fX, clip.fLeft); pts[0] = tmp[3]; pts[1] = tmp[4]; pts[2] = tmp[5]; } // are we partially to the right if (pts[3].fX > clip.fRight) { SkPoint tmp[7]; chop_mono_cubic_at_x(pts, clip.fRight, tmp); tmp[3].fX = clip.fRight; clamp_le(tmp[2].fX, clip.fRight); this->appendCubic(tmp, reverse); this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse); } else { // wholly inside the clip this->appendCubic(pts, reverse); } }
// srcPts[] must be monotonic in X and Y void SkEdgeClipper::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) { SkPoint pts[3]; bool reverse = sort_increasing_Y(pts, srcPts, 3); // are we completely above or below if (pts[2].fY <= clip.fTop || pts[0].fY >= clip.fBottom) { return; } // Now chop so that pts is contained within clip in Y chop_quad_in_Y(pts, clip); if (pts[0].fX > pts[2].fX) { SkTSwap<SkPoint>(pts[0], pts[2]); reverse = !reverse; } SkASSERT(pts[0].fX <= pts[1].fX); SkASSERT(pts[1].fX <= pts[2].fX); // Now chop in X has needed, and record the segments if (pts[2].fX <= clip.fLeft) { // wholly to the left this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse); return; } if (pts[0].fX >= clip.fRight) { // wholly to the right if (!this->canCullToTheRight()) { this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse); } return; } SkScalar t; SkPoint tmp[5]; // for SkChopQuadAt // are we partially to the left if (pts[0].fX < clip.fLeft) { if (chopMonoQuadAtX(pts, clip.fLeft, &t)) { SkChopQuadAt(pts, tmp, t); this->appendVLine(clip.fLeft, tmp[0].fY, tmp[2].fY, reverse); // clamp to clean up imprecise numerics in the chop tmp[2].fX = clip.fLeft; clamp_ge(tmp[3].fX, clip.fLeft); pts[0] = tmp[2]; pts[1] = tmp[3]; } else { // if chopMonoQuadAtY failed, then we may have hit inexact numerics // so we just clamp against the left this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse); return; } } // are we partially to the right if (pts[2].fX > clip.fRight) { if (chopMonoQuadAtX(pts, clip.fRight, &t)) { SkChopQuadAt(pts, tmp, t); // clamp to clean up imprecise numerics in the chop clamp_le(tmp[1].fX, clip.fRight); tmp[2].fX = clip.fRight; this->appendQuad(tmp, reverse); this->appendVLine(clip.fRight, tmp[2].fY, tmp[4].fY, reverse); } else { // if chopMonoQuadAtY failed, then we may have hit inexact numerics // so we just clamp against the right this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse); } } else { // wholly inside the clip this->appendQuad(pts, reverse); } }