Index: src/core/SkScan_Path.cpp |
diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp |
index 884f785299925794ee747828ef7d2c6dd4b0ebec..40e3e241f2be13ae59d902fb46ff88b5860fb630 100644 |
--- a/src/core/SkScan_Path.cpp |
+++ b/src/core/SkScan_Path.cpp |
@@ -545,26 +545,27 @@ void sk_blit_below(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) |
/** |
* If the caller is drawing an inverse-fill path, then it pass true for |
- * skipRejectTest, so we don't abort drawing just because the src bounds (ir) |
+ * skipRejectTest, so we don't abort drawing just because the src bounds |
* is outside of the clip. |
*/ |
SkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip, |
- const SkIRect& ir, bool skipRejectTest) { |
+ const SkIRect& bounds, bool skipRejectTest, bool boundsIsTruncated) { |
fBlitter = nullptr; // null means blit nothing |
fClipRect = nullptr; |
if (clip) { |
fClipRect = &clip->getBounds(); |
- if (!skipRejectTest && !SkIRect::Intersects(*fClipRect, ir)) { // completely clipped out |
+ if (!skipRejectTest && !SkIRect::Intersects(*fClipRect, bounds)) { // completely clipped out |
return; |
} |
if (clip->isRect()) { |
- if (fClipRect->contains(ir)) { |
+ if (!boundsIsTruncated && fClipRect->contains(bounds)) { |
fClipRect = nullptr; |
} else { |
// only need a wrapper blitter if we're horizontally clipped |
- if (fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight) { |
+ if (boundsIsTruncated || |
+ fClipRect->fLeft > bounds.fLeft || fClipRect->fRight < bounds.fRight) { |
fRectBlitter.init(blitter, *fClipRect); |
blitter = &fRectBlitter; |
} |
@@ -609,6 +610,8 @@ static inline int round_down_to_int(SkScalar x) { |
* which may be slower than calling SkScalarRountToInt(), but gives slightly more accurate |
* results. Also rounds top and left using double, flooring when the fraction is exactly 0.5f. |
* |
+ * When src has huge coordinates, clips dst by clip and returns true. |
+ * |
* e.g. |
* SkScalar left = 0.5f; |
* int ileft = SkScalarRoundToInt(left); |
@@ -621,10 +624,23 @@ static inline int round_down_to_int(SkScalar x) { |
* iright = SkDScalarRoundToInt(right); |
* SkASSERT(0 == iright); // <--- succeeds |
*/ |
-static void round_asymmetric_to_int(const SkRect& src, SkIRect* dst) { |
+static bool round_asymmetric_to_int(const SkRect& src, const SkIRect& clip, SkIRect* dst) { |
SkASSERT(dst); |
- dst->set(round_down_to_int(src.fLeft), round_down_to_int(src.fTop), |
- SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBottom)); |
+ static const int32_t kLimit = 32767; |
+ const SkIRect max = SkIRect::MakeLTRB(-kLimit, -kLimit, kLimit, kLimit); |
+ if (max.contains(src)) { |
+ dst->set(round_down_to_int(src.fLeft), round_down_to_int(src.fTop), |
+ SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBottom)); |
+ return false; |
+ } |
+ SkRect clipped; |
+ if (clipped.intersect(src, SkRect::Make(clip))) { |
+ dst->set(round_down_to_int(clipped.fLeft), round_down_to_int(clipped.fTop), |
+ SkDScalarRoundToInt(clipped.fRight), SkDScalarRoundToInt(clipped.fBottom)); |
+ } else { |
+ dst->setEmpty(); |
+ } |
+ return true; |
} |
void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, |
@@ -650,7 +666,7 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, |
// to generate a bounds that is tighter than the corresponding SkEdges. The edge code basically |
// converts the floats to fixed, and then "rounds". If we called round() instead of |
// round_asymmetric_to_int() here, we could generate the wrong ir for values like 0.4999997. |
- round_asymmetric_to_int(path.getBounds(), &ir); |
+ bool irIsClipped = round_asymmetric_to_int(path.getBounds(), clipPtr->getBounds(), &ir); |
if (ir.isEmpty()) { |
if (path.isInverseFillType()) { |
blitter->blitRegion(*clipPtr); |
@@ -658,7 +674,7 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, |
return; |
} |
- SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType()); |
+ SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType(), irIsClipped); |
blitter = clipper.getBlitter(); |
if (blitter) { |