static SkScalar sect_clamp_with_vertical(const SkPoint src[2], SkScalar x) { SkScalar y = sect_with_vertical(src, x); // Our caller expects y to be between src[0].fY and src[1].fY (unsorted), but due to the // numerics of floats/doubles, we might have computed a value slightly outside of that, // so we have to manually clamp afterwards. // See skbug.com/7491 return pin_unsorted(y, src[0].fY, src[1].fY); }
bool SkLineClipper::IntersectLine(const SkPoint src[2], const SkRect& clip, SkPoint dst[2]) { SkRect bounds; bounds.set(src, 2); if (containsNoEmptyCheck(clip, bounds)) { if (src != dst) { memcpy(dst, src, 2 * sizeof(SkPoint)); } return true; } // check for no overlap, and only permit coincident edges if the line // and the edge are colinear if (nestedLT(bounds.fRight, clip.fLeft, bounds.width()) || nestedLT(clip.fRight, bounds.fLeft, bounds.width()) || nestedLT(bounds.fBottom, clip.fTop, bounds.height()) || nestedLT(clip.fBottom, bounds.fTop, bounds.height())) { return false; } int index0, index1; if (src[0].fY < src[1].fY) { index0 = 0; index1 = 1; } else { index0 = 1; index1 = 0; } SkPoint tmp[2]; memcpy(tmp, src, sizeof(tmp)); // now compute Y intersections if (tmp[index0].fY < clip.fTop) { tmp[index0].set(sect_with_horizontal(src, clip.fTop), clip.fTop); } if (tmp[index1].fY > clip.fBottom) { tmp[index1].set(sect_with_horizontal(src, clip.fBottom), clip.fBottom); } if (tmp[0].fX < tmp[1].fX) { index0 = 0; index1 = 1; } else { index0 = 1; index1 = 0; } // check for quick-reject in X again, now that we may have been chopped if ((tmp[index1].fX <= clip.fLeft || tmp[index0].fX >= clip.fRight) && tmp[index0].fX < tmp[index1].fX) { // only reject if we have a non-zero width return false; } if (tmp[index0].fX < clip.fLeft) { tmp[index0].set(clip.fLeft, sect_with_vertical(src, clip.fLeft)); } if (tmp[index1].fX > clip.fRight) { tmp[index1].set(clip.fRight, sect_with_vertical(src, clip.fRight)); } #ifdef SK_DEBUG bounds.set(tmp, 2); SkASSERT(containsNoEmptyCheck(clip, bounds)); #endif memcpy(dst, tmp, sizeof(tmp)); return true; }
int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip, SkPoint lines[]) { #ifdef SK_SCALAR_IS_FLOAT #ifdef SK_DEBUG { static bool gOnce; if (!gOnce) { sect_with_horizontal_test_for_pin_results(); gOnce = true; } } #endif #endif int index0, index1; if (pts[0].fY < pts[1].fY) { index0 = 0; index1 = 1; } else { index0 = 1; index1 = 0; } // Check if we're completely clipped out in Y (above or below if (pts[index1].fY <= clip.fTop) { // we're above the clip return 0; } if (pts[index0].fY >= clip.fBottom) { // we're below the clip return 0; } // Chop in Y to produce a single segment, stored in tmp[0..1] SkPoint tmp[2]; memcpy(tmp, pts, sizeof(tmp)); // now compute intersections if (pts[index0].fY < clip.fTop) { tmp[index0].set(sect_with_horizontal(pts, clip.fTop), clip.fTop); SkASSERT(is_between_unsorted(tmp[index0].fX, pts[0].fX, pts[1].fX)); } if (tmp[index1].fY > clip.fBottom) { tmp[index1].set(sect_with_horizontal(pts, clip.fBottom), clip.fBottom); SkASSERT(is_between_unsorted(tmp[index1].fX, pts[0].fX, pts[1].fX)); } // Chop it into 1..3 segments that are wholly within the clip in X. // temp storage for up to 3 segments SkPoint resultStorage[kMaxPoints]; SkPoint* result; // points to our results, either tmp or resultStorage int lineCount = 1; bool reverse; if (pts[0].fX < pts[1].fX) { index0 = 0; index1 = 1; reverse = false; } else { index0 = 1; index1 = 0; reverse = true; } if (tmp[index1].fX <= clip.fLeft) { // wholly to the left tmp[0].fX = tmp[1].fX = clip.fLeft; result = tmp; reverse = false; } else if (tmp[index0].fX >= clip.fRight) { // wholly to the right tmp[0].fX = tmp[1].fX = clip.fRight; result = tmp; reverse = false; } else { result = resultStorage; SkPoint* r = result; if (tmp[index0].fX < clip.fLeft) { r->set(clip.fLeft, tmp[index0].fY); r += 1; r->set(clip.fLeft, sect_with_vertical(tmp, clip.fLeft)); SkASSERT(is_between_unsorted(r->fY, tmp[0].fY, tmp[1].fY)); } else { *r = tmp[index0]; } r += 1; if (tmp[index1].fX > clip.fRight) { r->set(clip.fRight, sect_with_vertical(tmp, clip.fRight)); SkASSERT(is_between_unsorted(r->fY, tmp[0].fY, tmp[1].fY)); r += 1; r->set(clip.fRight, tmp[index1].fY); } else { *r = tmp[index1]; } lineCount = r - result; } // Now copy the results into the caller's lines[] parameter if (reverse) { // copy the pts in reverse order to maintain winding order for (int i = 0; i <= lineCount; i++) { lines[lineCount - i] = result[i]; } } else { memcpy(lines, result, (lineCount + 1) * sizeof(SkPoint)); } return lineCount; }