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>
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 824ade1..713a50e 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -2690,7 +2690,7 @@
         return;
     }
 
-    this->predrawNotify();
+    this->predrawNotify(&r, nullptr, false);
     SkDrawIter iter(this);
     while(iter.next()) {
         iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
@@ -2700,17 +2700,51 @@
 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 (needsAutoLooper) {
+        for (int i = 1; i < count; ++i) {
+            setBounds.joinPossiblyEmptyRect(imageSet[i].fDstRect);
+        }
     }
-    DRAW_END
+
+    // 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);
+        }
+    }
 }
 
 //////////////////////////////////////////////////////////////////////////////