Tighten SkAAClip Bounds by Path Bounds

This bug chromium:662780 exists after our original fix (https://codereview.chromium.org/2477393002/) because this path (added in unit test) is calling blitAntiRect rather than blitAntiH when the path is drifted across the boundary. (The quadratic edge drifts across the boundary after an update and sets a dX=0 line segment which triggers blitAntiRect.)

Note that I didn't assert for the dLeft = dRite = 0 case because the left/right there won't drift after the SkTMin/SkTMax in line 964/966.

Theoretically we can revert the relaxation in https://codereview.chromium.org/2477393002/ (that's only a relaxation for analytic AA, not supersampled AA). However, consider that the initial landing of analytic AA is so painful, I decide to revert that relaxation only after our successful landing...

BUG=chromium:662780, chromium:662862
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2482193004

Review-Url: https://codereview.chromium.org/2482193004
diff --git a/src/core/SkScan_AAAPath.cpp b/src/core/SkScan_AAAPath.cpp
index 4bbeccf..aab253c 100644
--- a/src/core/SkScan_AAAPath.cpp
+++ b/src/core/SkScan_AAAPath.cpp
@@ -190,8 +190,8 @@
     int         fY;
 };
 
-MaskAdditiveBlitter::MaskAdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip,
-                                         bool isInverse) {
+MaskAdditiveBlitter::MaskAdditiveBlitter(
+        SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, bool isInverse) {
     SkASSERT(canHandleRect(ir));
     SkASSERT(!isInverse);
 
@@ -367,8 +367,8 @@
     }
 };
 
-RunBasedAdditiveBlitter::RunBasedAdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip,
-                                 bool isInverse) {
+RunBasedAdditiveBlitter::RunBasedAdditiveBlitter(
+        SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, bool isInverse) {
     fRealBlitter = realBlitter;
 
     SkIRect sectBounds;
@@ -533,7 +533,8 @@
 }
 
 // Here we always send in l < SK_Fixed1, and the first alpha we want to compute is alphas[0]
-static inline void computeAlphaBelowLine(SkAlpha* alphas, SkFixed l, SkFixed r, SkFixed dY, SkAlpha fullAlpha) {
+static inline void computeAlphaBelowLine(
+        SkAlpha* alphas, SkFixed l, SkFixed r, SkFixed dY, SkAlpha fullAlpha) {
     SkASSERT(l <= r);
     SkASSERT(l >> 16 == 0);
     int R = SkFixedCeilToInt(r);
@@ -965,9 +966,9 @@
         }
         local_bot_fixed = SkMin32(local_bot_fixed, SkIntToFixed(stop_y));
 
-        SkFixed left = leftE->fX;
+        SkFixed left = SkTMax(leftBound, leftE->fX);
         SkFixed dLeft = leftE->fDX;
-        SkFixed rite = riteE->fX;
+        SkFixed rite = SkTMin(riteBound, riteE->fX);
         SkFixed dRite = riteE->fDX;
         if (0 == (dLeft | dRite)) {
             int     fullLeft    = SkFixedCeilToInt(left);
@@ -1077,6 +1078,9 @@
                     SkFixed dY = nextY - y;
                     SkFixed nextLeft = left + SkFixedMul_lowprec(dLeft, dY);
                     SkFixed nextRite = rite + SkFixedMul_lowprec(dRite, dY);
+                    SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
+                            (nextLeft & kSnapMask) >= leftBound &&
+                            (nextRite & kSnapMask) <= riteBound);
                     blit_trapezoid_row(blitter, y >> 16, left & kSnapMask, rite & kSnapMask,
                             nextLeft & kSnapMask, nextRite & kSnapMask, leftE->fDY, riteE->fDY,
                             getPartialAlpha(0xFF, dY), maskRow, isUsingMask);
@@ -1092,6 +1096,9 @@
                         maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16);
                     }
                     SkFixed nextY = y + SK_Fixed1, nextLeft = left + dLeft, nextRite = rite + dRite;
+                    SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
+                            (nextLeft & kSnapMask) >= leftBound &&
+                            (nextRite & kSnapMask) <= riteBound);
                     blit_trapezoid_row(blitter, y >> 16, left & kSnapMask, rite & kSnapMask,
                             nextLeft & kSnapMask, nextRite & kSnapMask,
                             leftE->fDY, riteE->fDY, 0xFF, maskRow, isUsingMask);
@@ -1113,6 +1120,8 @@
             // Note that we substract kSnapHalf later so we have to add them to leftBound/riteBound
             SkFixed nextLeft = SkTMax(left + SkFixedMul_lowprec(dLeft, dY), leftBound + kSnapHalf);
             SkFixed nextRite = SkTMin(rite + SkFixedMul_lowprec(dRite, dY), riteBound + kSnapHalf);
+            SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
+                    (nextLeft & kSnapMask) >= leftBound && (nextRite & kSnapMask) <= riteBound);
             blit_trapezoid_row(blitter, y >> 16, left & kSnapMask, rite & kSnapMask,
                     nextLeft & kSnapMask, nextRite & kSnapMask, leftE->fDY, riteE->fDY,
                     getPartialAlpha(0xFF, dY), maskRow, isUsingMask);
diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp
index b8247ed..85bd804 100644
--- a/tests/PathTest.cpp
+++ b/tests/PathTest.cpp
@@ -170,6 +170,34 @@
     canvas->drawPath(path, paint);
 }
 
+static void test_fuzz_crbug_662780() {
+    auto surface(SkSurface::MakeRasterN32Premul(250, 250));
+    SkCanvas* canvas = surface->getCanvas();
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    SkPath path;
+    path.moveTo(SkBits2Float(0x41000000), SkBits2Float(0x431e0000));  // 8, 158
+    path.lineTo(SkBits2Float(0x41000000), SkBits2Float(0x42f00000));  // 8, 120
+    // 8, 8, 8.00002f, 8, 0.707107f
+    path.conicTo(SkBits2Float(0x41000000), SkBits2Float(0x41000000),
+            SkBits2Float(0x41000010), SkBits2Float(0x41000000), SkBits2Float(0x3f3504f3));
+    path.lineTo(SkBits2Float(0x439a0000), SkBits2Float(0x41000000));  // 308, 8
+    // 308, 8, 308, 8, 0.707107f
+    path.conicTo(SkBits2Float(0x439a0000), SkBits2Float(0x41000000),
+            SkBits2Float(0x439a0000), SkBits2Float(0x41000000), SkBits2Float(0x3f3504f3));
+    path.lineTo(SkBits2Float(0x439a0000), SkBits2Float(0x431e0000));  // 308, 158
+    // 308, 158, 308, 158, 0.707107f
+    path.conicTo(SkBits2Float(0x439a0000), SkBits2Float(0x431e0000),
+            SkBits2Float(0x439a0000), SkBits2Float(0x431e0000), SkBits2Float(0x3f3504f3));
+    path.lineTo(SkBits2Float(0x41000000), SkBits2Float(0x431e0000));  // 8, 158
+    // 8, 158, 8, 158, 0.707107f
+    path.conicTo(SkBits2Float(0x41000000), SkBits2Float(0x431e0000),
+            SkBits2Float(0x41000000), SkBits2Float(0x431e0000), SkBits2Float(0x3f3504f3));
+    path.close();
+    canvas->clipPath(path, true);
+    canvas->drawRectCoords(0, 0, 250, 250, paint);
+}
+
 /**
  * In debug mode, this path was causing an assertion to fail in
  * SkPathStroker::preJoinTo() and, in Release, the use of an unitialized value.
@@ -4330,6 +4358,7 @@
     test_path_crbug364224();
     test_fuzz_crbug_662952(reporter);
     test_fuzz_crbug_662730(reporter);
+    test_fuzz_crbug_662780();
 
     SkTSize<SkScalar>::Make(3,4);