Reland "Calculate draw bounds in drawEdgeAAImageSet"

This reverts commit a5fa56e910b23da4252eca526d1b805d4da91f5a.

Reason for revert: Fixes bound calculation to transform fDstRect by each entry's pre-view matrix
if needed.

Original change's description:
> Revert "Calculate draw bounds in drawEdgeAAImageSet"
>
> This reverts commit 977b50a7e0cb302208cc71dc67e04d29bf3609c4.
>
> Reason for revert: Likely broke skia_renderer bots, https://test-results.appspot.com/data/layout_results/linux-rel/177320/vulkan_swiftshader_blink_web_tests%20%28with%20patch%29/layout-test-results/results.html
>
> Original change's description:
> > Calculate draw bounds in drawEdgeAAImageSet
> >
> > This will allow SkiaRenderer to provide image filters on the SkPaint
> > instead of using an explicit saveLayer, where they must calculate the
> > draw bounds. Once SkiaRenderer provides filters that way, they will
> > automatically take advantage of any implicit layer optimizations we can
> > add down the road.
> >
> > Bug: skia:9283
> > Change-Id: I87adef336a08210d4d015e36c907e893a973947d
> > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/237477
> > Reviewed-by: Brian Salomon <bsalomon@google.com>
> > Commit-Queue: Michael Ludwig <michaelludwig@google.com>
>
> TBR=bsalomon@google.com,robertphillips@google.com,michaelludwig@google.com
>
> Change-Id: I99d90f7beae89b509c35649dcfcdf392a47b3415
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: skia:9283
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/237596
> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
> Commit-Queue: Michael Ludwig <michaelludwig@google.com>

TBR=bsalomon@google.com,robertphillips@google.com,michaelludwig@google.com

Change-Id: I1cba1e70d32abe7cd2ad3cfe478960a3670e79ca
Bug: skia:9283
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/237900
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
Auto-Submit: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 7c05e11..3951f85 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -2695,7 +2695,7 @@
         return;
     }
 
-    this->predrawNotify();
+    this->predrawNotify(&r, nullptr, false);
     SkDrawIter iter(this);
     while(iter.next()) {
         iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
@@ -2705,17 +2705,59 @@
 void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
                                     const SkPoint dstClips[], const SkMatrix preViewMatrices[],
                                     const SkPaint* paint, SrcRectConstraint constraint) {
+    if (count <= 0) {
+        // Nothing to draw
+        return;
+    }
+
     SkPaint realPaint;
     init_image_paint(&realPaint, paint);
 
-    // Looper is used when there are image filters, which drawEdgeAAImageSet needs to support
-    // for Chromium's RenderPassDrawQuads' filters.
-    DRAW_BEGIN(realPaint, nullptr)
-    while (iter.next()) {
-        iter.fDevice->drawEdgeAAImageSet(
-                imageSet, count, dstClips, preViewMatrices, draw.paint(), constraint);
+    // We could calculate the set's dstRect union to always check quickReject(), but we can't reject
+    // individual entries and Chromium's occlusion culling already makes it likely that at least one
+    // entry will be visible. So, we only calculate the draw bounds when it's trivial (count == 1),
+    // or we need it for the autolooper (since it greatly improves image filter perf).
+    bool needsAutoLooper = needs_autodrawlooper(this, realPaint);
+    bool setBoundsValid = count == 1 || needsAutoLooper;
+    SkRect setBounds = imageSet[0].fDstRect;
+    if (imageSet[0].fMatrixIndex >= 0) {
+        // Account for the per-entry transform that is applied prior to the CTM when drawing
+        preViewMatrices[imageSet[0].fMatrixIndex].mapRect(&setBounds);
     }
-    DRAW_END
+    if (needsAutoLooper) {
+        for (int i = 1; i < count; ++i) {
+            SkRect entryBounds = imageSet[i].fDstRect;
+            if (imageSet[i].fMatrixIndex >= 0) {
+                preViewMatrices[imageSet[i].fMatrixIndex].mapRect(&entryBounds);
+            }
+            setBounds.joinPossiblyEmptyRect(entryBounds);
+        }
+    }
+
+    // If we happen to have the draw bounds, though, might as well check quickReject().
+    if (setBoundsValid && realPaint.canComputeFastBounds()) {
+        SkRect tmp;
+        if (this->quickReject(realPaint.computeFastBounds(setBounds, &tmp))) {
+            return;
+        }
+    }
+
+    if (needsAutoLooper) {
+        SkASSERT(setBoundsValid);
+        DRAW_BEGIN(realPaint, &setBounds)
+        while (iter.next()) {
+            iter.fDevice->drawEdgeAAImageSet(
+                imageSet, count, dstClips, preViewMatrices, draw.paint(), constraint);
+        }
+        DRAW_END
+    } else {
+        this->predrawNotify();
+        SkDrawIter iter(this);
+        while(iter.next()) {
+            iter.fDevice->drawEdgeAAImageSet(
+                imageSet, count, dstClips, preViewMatrices, realPaint, constraint);
+        }
+    }
 }
 
 //////////////////////////////////////////////////////////////////////////////