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);