chop down huge rects before hairlining

Bug: 826166
Change-Id: I18f4b1dc4f279e37832d4bced0a66b5c356d09c0
Reviewed-on: https://skia-review.googlesource.com/112572
Reviewed-by: Yuqian Li <liyuqian@google.com>
Commit-Queue: Mike Reed <reed@google.com>
(cherry picked from commit c7fbda95404a9422d0dd762d35383d5a61e89440)
Reviewed-on: https://skia-review.googlesource.com/118720
Reviewed-by: Kevin Lubick <kjlubick@google.com>
diff --git a/src/core/SkScan_Hairline.cpp b/src/core/SkScan_Hairline.cpp
index 1f12efe..7954ccc 100644
--- a/src/core/SkScan_Hairline.cpp
+++ b/src/core/SkScan_Hairline.cpp
@@ -144,14 +144,25 @@
 
 // we don't just draw 4 lines, 'cause that can leave a gap in the bottom-right
 // and double-hit the top-left.
-void SkScan::HairRect(const SkRect& rect, const SkRasterClip& clip,
-                      SkBlitter* blitter) {
+void SkScan::HairRect(const SkRect& rect, const SkRasterClip& clip, SkBlitter* blitter) {
     SkAAClipBlitterWrapper wrapper;
     SkBlitterClipper clipper;
-    const SkIRect r = SkIRect::MakeLTRB(SkScalarFloorToInt(rect.fLeft),
-                                        SkScalarFloorToInt(rect.fTop),
-                                        SkScalarFloorToInt(rect.fRight) + 1,
-                                        SkScalarFloorToInt(rect.fBottom) + 1);
+    // Create the enclosing bounds of the hairrect. i.e. we will stroke the interior of r.
+    SkIRect r = SkIRect::MakeLTRB(SkScalarFloorToInt(rect.fLeft),
+                                  SkScalarFloorToInt(rect.fTop),
+                                  SkScalarFloorToInt(rect.fRight + 1),
+                                  SkScalarFloorToInt(rect.fBottom + 1));
+
+    // Note: r might be crazy big, if rect was huge, possibly getting pinned to max/min s32.
+    // We need to trim it back to something reasonable before we can query its width etc.
+    // since r.fRight - r.fLeft might wrap around to negative even if fRight > fLeft.
+    //
+    // We outset the clip bounds by 1 before intersecting, since r is being stroked and not filled
+    // so we don't want to pin an edge of it to the clip. The intersect's job is mostly to just
+    // get the actual edge values into a reasonable range (e.g. so width() can't overflow).
+    if (!r.intersect(clip.getBounds().makeOutset(1, 1))) {
+        return;
+    }
 
     if (clip.quickReject(r)) {
         return;