Add secret draw-behind method

This is a variant of drawPaint but is automatically clipped
to the bounds of the most recent saveBehind buffer (axis-aligned bounds).

No public exposure.

Impl is pretty simple (its a variant of drawPaint)
- find the most recent saveBehind device bounds
- if there is none, draw nothing, else
  - temporarily intersect the device's clip with that bounds
  - drawPaint
  - restore the clip

See https://buganizer.corp.google.com/issues/129117085

Change-Id: I7c532e63a80b118fb2416c572b8e0d2abf8cf59a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/209166
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 0fddd6b..a0c956b 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1710,6 +1710,11 @@
     this->onDrawRect(r.makeSorted(), paint);
 }
 
+void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
+    TRACE_EVENT0("skia", TRACE_FUNC);
+    this->onDrawBehind(paint);
+}
+
 void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
     TRACE_EVENT0("skia", TRACE_FUNC);
     if (region.isEmpty()) {
@@ -2120,6 +2125,41 @@
     LOOPER_END
 }
 
+void SkCanvas::onDrawBehind(const SkPaint& paint) {
+    SkIRect bounds;
+    SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
+    for (;;) {
+        const MCRec* rec = (const MCRec*)iter.prev();
+        if (!rec) {
+            return; // no backimages, so nothing to draw
+        }
+        if (rec->fBackImage) {
+            bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
+                                       rec->fBackImage->fImage->width(),
+                                       rec->fBackImage->fImage->height());
+            break;
+        }
+    }
+
+    LOOPER_BEGIN(paint, nullptr)
+
+    while (iter.next()) {
+        SkBaseDevice* dev = iter.fDevice;
+
+        SkMatrix ctm = dev->ctm();
+        dev->save();
+        // We use clipRegion because it is already defined to operate in dev-space
+        // (i.e. ignores the ctm). However, it is going to first translate by -origin,
+        // but we don't want that, so we undo that before calling in.
+        SkRegion rgn(bounds.makeOffset(dev->fOrigin.fX, dev->fOrigin.fY));
+        dev->clipRegion(rgn, SkClipOp::kIntersect);
+        dev->drawPaint(looper.paint());
+        dev->restore(ctm);
+    }
+
+    LOOPER_END
+}
+
 void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
     SkASSERT(oval.isSorted());
     if (paint.canComputeFastBounds()) {
diff --git a/src/core/SkCanvasPriv.h b/src/core/SkCanvasPriv.h
index e06e06a..d7d086d 100644
--- a/src/core/SkCanvasPriv.h
+++ b/src/core/SkCanvasPriv.h
@@ -43,6 +43,9 @@
     static int SaveBehind(SkCanvas* canvas, const SkRect* subset) {
         return canvas->only_axis_aligned_saveBehind(subset);
     }
+    static void DrawBehind(SkCanvas* canvas, const SkPaint& paint) {
+        canvas->drawClippedToSaveBehind(paint);
+    }
 
     // The experimental_DrawEdgeAAImageSet API accepts separate dstClips and preViewMatrices arrays,
     // where entries refer into them, but no explicit size is provided. Given a set of entries,
diff --git a/src/core/SkLiteDL.cpp b/src/core/SkLiteDL.cpp
index 7083a7a..0e098cd 100644
--- a/src/core/SkLiteDL.cpp
+++ b/src/core/SkLiteDL.cpp
@@ -52,7 +52,7 @@
     M(Flush) M(Save) M(Restore) M(SaveLayer) M(SaveBehind)                             \
     M(Concat) M(SetMatrix) M(Translate)                                                \
     M(ClipPath) M(ClipRect) M(ClipRRect) M(ClipRegion)                                 \
-    M(DrawPaint) M(DrawPath) M(DrawRect)                                               \
+    M(DrawPaint) M(DrawBehind) M(DrawPath) M(DrawRect)                                 \
     M(DrawRegion) M(DrawOval) M(DrawArc)                                               \
     M(DrawRRect) M(DrawDRRect) M(DrawAnnotation) M(DrawDrawable) M(DrawPicture)        \
     M(DrawImage) M(DrawImageNine) M(DrawImageRect) M(DrawImageLattice)                 \
@@ -177,6 +177,12 @@
         SkPaint paint;
         void draw(SkCanvas* c, const SkMatrix&) const { c->drawPaint(paint); }
     };
+    struct DrawBehind final : Op {
+        static const auto kType = Type::DrawBehind;
+        DrawBehind(const SkPaint& paint) : paint(paint) {}
+        SkPaint paint;
+        void draw(SkCanvas* c, const SkMatrix&) const { SkCanvasPriv::DrawBehind(c, paint); }
+    };
     struct DrawPath final : Op {
         static const auto kType = Type::DrawPath;
         DrawPath(const SkPath& path, const SkPaint& paint) : path(path), paint(paint) {}
@@ -542,6 +548,9 @@
 void SkLiteDL::drawPaint(const SkPaint& paint) {
     this->push<DrawPaint>(0, paint);
 }
+void SkLiteDL::drawBehind(const SkPaint& paint) {
+    this->push<DrawBehind>(0, paint);
+}
 void SkLiteDL::drawPath(const SkPath& path, const SkPaint& paint) {
     this->push<DrawPath>(0, path, paint);
 }
diff --git a/src/core/SkLiteDL.h b/src/core/SkLiteDL.h
index ea9a5fa..a3a069e 100644
--- a/src/core/SkLiteDL.h
+++ b/src/core/SkLiteDL.h
@@ -44,6 +44,7 @@
     void clipRegion(const SkRegion&, SkClipOp);
 
     void drawPaint (const SkPaint&);
+    void drawBehind(const SkPaint&);
     void drawPath  (const SkPath&, const SkPaint&);
     void drawRect  (const SkRect&, const SkPaint&);
     void drawRegion(const SkRegion&, const SkPaint&);
diff --git a/src/core/SkLiteRecorder.cpp b/src/core/SkLiteRecorder.cpp
index f95dc34..a867add 100644
--- a/src/core/SkLiteRecorder.cpp
+++ b/src/core/SkLiteRecorder.cpp
@@ -60,6 +60,9 @@
 void SkLiteRecorder::onDrawPaint(const SkPaint& paint) {
     fDL->drawPaint(paint);
 }
+void SkLiteRecorder::onDrawBehind(const SkPaint& paint) {
+    fDL->drawBehind(paint);
+}
 void SkLiteRecorder::onDrawPath(const SkPath& path, const SkPaint& paint) {
     fDL->drawPath(path, paint);
 }
diff --git a/src/core/SkLiteRecorder.h b/src/core/SkLiteRecorder.h
index 7b54f89..6fc74e0 100644
--- a/src/core/SkLiteRecorder.h
+++ b/src/core/SkLiteRecorder.h
@@ -37,6 +37,7 @@
     void onClipRegion(const SkRegion&, SkClipOp) override;
 
     void onDrawPaint (const SkPaint&) override;
+    void onDrawBehind(const SkPaint&) override;
     void onDrawPath  (const SkPath&, const SkPaint&) override;
     void onDrawRect  (const SkRect&, const SkPaint&) override;
     void onDrawRegion(const SkRegion&, const SkPaint&) override;
diff --git a/src/core/SkOverdrawCanvas.cpp b/src/core/SkOverdrawCanvas.cpp
index b81b5f6..bcc999f 100644
--- a/src/core/SkOverdrawCanvas.cpp
+++ b/src/core/SkOverdrawCanvas.cpp
@@ -94,6 +94,10 @@
     }
 }
 
+void SkOverdrawCanvas::onDrawBehind(const SkPaint& paint) {
+    fList[0]->onDrawBehind(this->overdrawPaint(paint));
+}
+
 void SkOverdrawCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
     fList[0]->onDrawRect(rect, this->overdrawPaint(paint));
 }
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index 34e4dfb..606e08a 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -103,7 +103,9 @@
 
     DRAW_EDGEAA_QUAD,
 
-    LAST_DRAWTYPE_ENUM = DRAW_EDGEAA_QUAD,
+    DRAW_BEHIND_PAINT,
+
+    LAST_DRAWTYPE_ENUM = DRAW_BEHIND_PAINT,
 };
 
 enum DrawVertexFlags {
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 3646006..dd9cb54 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -419,6 +419,14 @@
                 canvas->drawPaint(*paint);
             }
         } break;
+        case DRAW_BEHIND_PAINT: {
+            const SkPaint* paint = fPictureData->getPaint(reader);
+            BREAK_ON_READ_ERROR(reader);
+
+            if (paint) {
+                SkCanvasPriv::DrawBehind(canvas, *paint);
+            }
+        } break;
         case DRAW_PATCH: {
             const SkPaint* paint = fPictureData->getPaint(reader);
 
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index d8bc36b..b82a25d 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -422,6 +422,15 @@
     this->validate(initialOffset, size);
 }
 
+void SkPictureRecord::onDrawBehind(const SkPaint& paint) {
+    // logically the same as drawPaint, but with a diff enum
+    // op + paint index
+    size_t size = 2 * kUInt32Size;
+    size_t initialOffset = this->addDraw(DRAW_BEHIND_PAINT, &size);
+    this->addPaint(paint);
+    this->validate(initialOffset, size);
+}
+
 void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
                                    const SkPaint& paint) {
     // op + paint index + mode + count + point data
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index f355e41..aca8b68 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -174,6 +174,7 @@
                      SkBlendMode, const SkRect*, const SkPaint*) override;
 
     void onDrawPaint(const SkPaint&) override;
+    void onDrawBehind(const SkPaint&) override;
     void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
     void onDrawRect(const SkRect&, const SkPaint&) override;
     void onDrawRegion(const SkRegion&, const SkPaint&) override;
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index b6a3033..2313246 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -88,6 +88,10 @@
     SkCanvasPriv::SaveBehind(fCanvas, r.subset);
 }
 
+template <> void Draw::draw(const DrawBehind& r) {
+    SkCanvasPriv::DrawBehind(fCanvas, r.paint);
+}
+
 DRAW(SetMatrix, setMatrix(SkMatrix::Concat(fInitialCTM, r.matrix)));
 DRAW(Concat, concat(r.matrix));
 DRAW(Translate, translate(r.dx, r.dy));
@@ -358,6 +362,7 @@
     Bounds bounds(const Flush&) const { return fCullRect; }
 
     Bounds bounds(const DrawPaint&) const { return fCullRect; }
+    Bounds bounds(const DrawBehind&) const { return fCullRect; }
     Bounds bounds(const NoOp&)  const { return Bounds::MakeEmpty(); }    // NoOps don't draw.
 
     Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect, &op.paint); }
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index ef43f81..58f367d 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -139,6 +139,10 @@
     this->append<SkRecords::DrawPaint>(paint);
 }
 
+void SkRecorder::onDrawBehind(const SkPaint& paint) {
+    this->append<SkRecords::DrawBehind>(paint);
+}
+
 void SkRecorder::onDrawPoints(PointMode mode,
                               size_t count,
                               const SkPoint pts[],
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index a1d3a69..0df2cc4 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -77,6 +77,7 @@
                      const SkPaint& paint) override;
 
     void onDrawPaint(const SkPaint&) override;
+    void onDrawBehind(const SkPaint&) override;
     void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
     void onDrawRect(const SkRect&, const SkPaint&) override;
     void onDrawRegion(const SkRegion&, const SkPaint&) override;
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index 6612a06..4ac005f 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -59,6 +59,7 @@
     M(DrawImageNine)                                                \
     M(DrawDRRect)                                                   \
     M(DrawOval)                                                     \
+    M(DrawBehind)                                                   \
     M(DrawPaint)                                                    \
     M(DrawPath)                                                     \
     M(DrawPatch)                                                    \
@@ -265,6 +266,8 @@
         SkRect oval);
 RECORD(DrawPaint, kDraw_Tag|kHasPaint_Tag,
         SkPaint paint);
+RECORD(DrawBehind, kDraw_Tag|kHasPaint_Tag,
+       SkPaint paint);
 RECORD(DrawPath, kDraw_Tag|kHasPaint_Tag,
         SkPaint paint;
         PreCachedPath path);
diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp
index 39d5a40..68aab50 100644
--- a/src/utils/SkNWayCanvas.cpp
+++ b/src/utils/SkNWayCanvas.cpp
@@ -147,6 +147,13 @@
     }
 }
 
+void SkNWayCanvas::onDrawBehind(const SkPaint& paint) {
+    Iter iter(fList);
+    while (iter.next()) {
+        SkCanvasPriv::DrawBehind(iter.get(), paint);
+    }
+}
+
 void SkNWayCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
                                 const SkPaint& paint) {
     Iter iter(fList);
diff --git a/src/utils/SkPaintFilterCanvas.cpp b/src/utils/SkPaintFilterCanvas.cpp
index 9b9d129..7cb3134 100644
--- a/src/utils/SkPaintFilterCanvas.cpp
+++ b/src/utils/SkPaintFilterCanvas.cpp
@@ -49,6 +49,13 @@
     }
 }
 
+void SkPaintFilterCanvas::onDrawBehind(const SkPaint& paint) {
+    AutoPaintFilter apf(this, paint);
+    if (apf.shouldDraw()) {
+        this->SkNWayCanvas::onDrawBehind(apf.paint());
+    }
+}
+
 void SkPaintFilterCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
                                        const SkPaint& paint) {
     AutoPaintFilter apf(this, paint);