add saveBehind to canvas
Bug: skia:
Change-Id: I62e48b116b2d7efef585d4f465441f24ae4d2b29
Reviewed-on: https://skia-review.googlesource.com/c/177892
Reviewed-by: Derek Sollenberger <djsollen@google.com>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/gm/savelayer.cpp b/gm/savelayer.cpp
index 7721820..bf59c31 100644
--- a/gm/savelayer.cpp
+++ b/gm/savelayer.cpp
@@ -277,3 +277,74 @@
canvas->restore();
}
+#include "SkFont.h"
+#include "SkGradientShader.h"
+#include "SkTextBlob.h"
+
+static void draw_cell(SkCanvas* canvas, sk_sp<SkTextBlob> blob, SkColor c, SkScalar w, SkScalar h) {
+ SkRect r = SkRect::MakeWH(w, h);
+ SkPaint p;
+ p.setColor(c);
+ p.setBlendMode(SkBlendMode::kSrc);
+ canvas->drawRect(r, p);
+ p.setBlendMode(SkBlendMode::kSrcOver);
+
+ const SkScalar margin = 80;
+ r.fLeft = w - margin;
+
+ // save the behind image
+ SkDEBUGCODE(int sc0 =) canvas->getSaveCount();
+ SkDEBUGCODE(int sc1 =) SkCanvasPriv::SaveBehind(canvas, &r);
+ SkDEBUGCODE(int sc2 =) canvas->getSaveCount();
+ SkASSERT(sc0 == sc1);
+ SkASSERT(sc0 + 1 == sc2);
+
+ // draw the foreground (including over the 'behind' section)
+ p.setColor(SK_ColorBLACK);
+ canvas->drawTextBlob(blob, 10, 30, p);
+
+ // draw the treatment
+ const SkPoint pts[] = { {r.fLeft,0}, {r.fRight, 0} };
+ const SkColor colors[] = { 0x88000000, 0x0 };
+ auto sh = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
+ p.setShader(sh);
+ p.setBlendMode(SkBlendMode::kDstIn);
+ canvas->drawRect(r, p);
+
+ // this should restore the behind image
+ canvas->restore();
+ SkDEBUGCODE(int sc3 =) canvas->getSaveCount();
+ SkASSERT(sc3 == sc0);
+
+ // just outline where we expect the treatment to appear
+ p.reset();
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setAlpha(0x40);
+ canvas->drawRect(r, p);
+}
+
+static void draw_list(SkCanvas* canvas, sk_sp<SkTextBlob> blob) {
+ SkAutoCanvasRestore acr(canvas, true);
+
+ SkRandom rand;
+ SkScalar w = 400;
+ SkScalar h = 40;
+ for (int i = 0; i < 8; ++i) {
+ SkColor c = rand.nextU(); // ensure we're opaque
+ c = (c & 0xFFFFFF) | 0x80000000;
+ draw_cell(canvas, blob, c, w, h);
+ canvas->translate(0, h);
+ }
+}
+
+DEF_SIMPLE_GM(save_behind, canvas, 400, 670) {
+ SkFont font;
+ font.setSize(30);
+ const char text[] = "This is a very long line of text";
+ auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
+
+ draw_list(canvas, blob);
+ canvas->translate(0, 350);
+ canvas->saveLayer({0, 0, 400, 320}, nullptr);
+ draw_list(canvas, blob);
+}
diff --git a/include/android/SkAndroidFrameworkUtils.h b/include/android/SkAndroidFrameworkUtils.h
index 9df1c84..67b8492 100644
--- a/include/android/SkAndroidFrameworkUtils.h
+++ b/include/android/SkAndroidFrameworkUtils.h
@@ -14,6 +14,7 @@
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
class SkCanvas;
+struct SkRect;
class SkSurface;
/**
@@ -37,6 +38,8 @@
static void SafetyNetLog(const char*);
static sk_sp<SkSurface> getSurfaceFromCanvas(SkCanvas* canvas);
+
+ static int SaveBehind(SkCanvas* canvas, const SkRect* subset);
};
#endif // SK_BUILD_FOR_ANDROID_ANDROID
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 020ee81..fd7dd84 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -722,7 +722,7 @@
Call restoreToCount() with returned value to restore this and subsequent saves.
@param layerRec layer state
- @return depth of save state stack
+ @return depth of save state stack before this call was made.
*/
int saveLayer(const SaveLayerRec& layerRec);
@@ -2420,6 +2420,8 @@
virtual SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& ) {
return kFullLayer_SaveLayerStrategy;
}
+ // returns true if we should actually perform the saveBehind, or false if we should just save.
+ virtual bool onDoSaveBehind(const SkRect*) { return true; }
virtual void willRestore() {}
virtual void didRestore() {}
virtual void didConcat(const SkMatrix& ) {}
@@ -2631,6 +2633,16 @@
SkCanvas& operator=(SkCanvas&&) = delete;
SkCanvas& operator=(const SkCanvas&) = delete;
+ /** Experimental
+ * Saves the specified subset of the current pixels in the current layer,
+ * and then clears those pixels to transparent black.
+ * Restores the pixels on restore() by drawing them in SkBlendMode::kDstOver.
+ *
+ * @param subset conservative bounds of the area to be saved / restored.
+ * @return depth of save state stack before this call was made.
+ */
+ int only_axis_aligned_saveBehind(const SkRect* subset);
+
void resetForNextPicture(const SkIRect& bounds);
// needs gettotalclip()
@@ -2654,6 +2666,7 @@
SrcRectConstraint);
void internalDrawPaint(const SkPaint& paint);
void internalSaveLayer(const SaveLayerRec&, SaveLayerStrategy);
+ void internalSaveBehind(const SkRect*);
void internalDrawDevice(SkBaseDevice*, int x, int y, const SkPaint*, SkImage* clipImage,
const SkMatrix& clipMatrix);
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index fd055fe..70f26f2 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -263,10 +263,12 @@
// V62: Don't negate size of custom encoded images (don't write origin x,y either)
// V63: Store image bounds (including origin) instead of just width/height to support subsets
// V64: Remove occluder feature from blur maskFilter
+ // V65: Float4 paint color
+ // V66: Add saveBehind
// Only SKPs within the min/current picture version range (inclusive) can be read.
static const uint32_t MIN_PICTURE_VERSION = 56; // august 2017
- static const uint32_t CURRENT_PICTURE_VERSION = 65;
+ static const uint32_t CURRENT_PICTURE_VERSION = 66;
static_assert(MIN_PICTURE_VERSION <= 62, "Remove kFontAxes_bad from SkFontDescriptor.cpp");
diff --git a/include/core/SkRect.h b/include/core/SkRect.h
index 1748955..863a5fb 100644
--- a/include/core/SkRect.h
+++ b/include/core/SkRect.h
@@ -142,6 +142,9 @@
*/
int32_t y() const { return fTop; }
+ // Experimental
+ SkIPoint topLeft() const { return {fLeft, fTop}; }
+
/** Returns span on the x-axis. This does not check if SkIRect is sorted, or if
result fits in 32-bit signed integer; result may be negative.
diff --git a/include/utils/SkLuaCanvas.h b/include/utils/SkLuaCanvas.h
index ddefdcc..b039269 100644
--- a/include/utils/SkLuaCanvas.h
+++ b/include/utils/SkLuaCanvas.h
@@ -24,6 +24,7 @@
protected:
void willSave() override;
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
+ bool onDoSaveBehind(const SkRect*) override;
void willRestore() override;
void didConcat(const SkMatrix&) override;
diff --git a/include/utils/SkNWayCanvas.h b/include/utils/SkNWayCanvas.h
index d20759f..398c905 100644
--- a/include/utils/SkNWayCanvas.h
+++ b/include/utils/SkNWayCanvas.h
@@ -27,6 +27,7 @@
void willSave() override;
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
+ bool onDoSaveBehind(const SkRect*) override;
void willRestore() override;
void didConcat(const SkMatrix&) override;
diff --git a/include/utils/SkNoDrawCanvas.h b/include/utils/SkNoDrawCanvas.h
index a2110c2..e6a219a 100644
--- a/include/utils/SkNoDrawCanvas.h
+++ b/include/utils/SkNoDrawCanvas.h
@@ -38,6 +38,7 @@
protected:
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override;
+ bool onDoSaveBehind(const SkRect*) override;
// No-op overrides for aborting rasterization earlier than SkNullBlitter.
void onDrawAnnotation(const SkRect&, const char[], SkData*) override {}
diff --git a/src/android/SkAndroidFrameworkUtils.cpp b/src/android/SkAndroidFrameworkUtils.cpp
index 8920e67..d0f4499 100644
--- a/src/android/SkAndroidFrameworkUtils.cpp
+++ b/src/android/SkAndroidFrameworkUtils.cpp
@@ -63,5 +63,9 @@
sk_sp<SkSurface> surface(SkSafeRef(canvas->getSurfaceBase()));
return surface;
}
+
+int SkAndroidFrameworkUtils::SaveBehind(SkCanvas* canvas, const SkRect* subset) {
+ return canvas->only_axis_aligned_saveBehind(subset);
+}
#endif // SK_BUILD_FOR_ANDROID_FRAMEWORK
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index b51f28a..4f38b56 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -710,6 +710,10 @@
return this->makeSpecial(fBitmap);
}
+sk_sp<SkSpecialImage> SkBitmapDevice::snapBackImage(const SkIRect& bounds) {
+ return SkSpecialImage::CopyFromRaster(bounds, fBitmap, &this->surfaceProps());
+}
+
///////////////////////////////////////////////////////////////////////////////
sk_sp<SkSurface> SkBitmapDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
diff --git a/src/core/SkBitmapDevice.h b/src/core/SkBitmapDevice.h
index 7a0d947..e6f64b6 100644
--- a/src/core/SkBitmapDevice.h
+++ b/src/core/SkBitmapDevice.h
@@ -113,6 +113,8 @@
sk_sp<SkSpecialImage> snapSpecial() override;
void setImmutable() override { fBitmap.setImmutable(); }
+ sk_sp<SkSpecialImage> snapBackImage(const SkIRect&) override;
+
///////////////////////////////////////////////////////////////////////////
bool onReadPixels(const SkPixmap&, int x, int y) override;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index bdd330e..59511c7 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -208,6 +208,14 @@
}
};
+namespace {
+// Encapsulate state needed to restore from saveBehind()
+struct BackImage {
+ sk_sp<SkSpecialImage> fImage;
+ SkIPoint fLoc;
+};
+}
+
/* This is the record we keep for each save/restore level in the stack.
Since a level optionally copies the matrix and/or stack, we have pointers
for these fields. If the value is copied for this level, the copy is
@@ -217,17 +225,18 @@
*/
class SkCanvas::MCRec {
public:
- DeviceCM* fLayer;
+ DeviceCM* fLayer;
/* If there are any layers in the stack, this points to the top-most
one that is at or below this level in the stack (so we know what
bitmap/device to draw into from this level. This value is NOT
reference counted, since the real owner is either our fLayer field,
or a previous one in a lower level.)
*/
- DeviceCM* fTopLayer;
- SkConservativeClip fRasterClip;
- SkMatrix fMatrix;
- int fDeferredSaveCount;
+ DeviceCM* fTopLayer;
+ std::unique_ptr<BackImage> fBackImage;
+ SkConservativeClip fRasterClip;
+ SkMatrix fMatrix;
+ int fDeferredSaveCount;
MCRec() {
fLayer = nullptr;
@@ -919,6 +928,22 @@
return this->getSaveCount() - 1;
}
+int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
+ if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
+ // Assuming clips never expand, if the request bounds is outside of the current clip
+ // there is no need to copy/restore the area, so just devolve back to a regular save.
+ this->save();
+ } else {
+ bool doTheWork = this->onDoSaveBehind(bounds);
+ fSaveCount += 1;
+ this->internalSave();
+ if (doTheWork) {
+ this->internalSaveBehind(bounds);
+ }
+ }
+ return this->getSaveCount() - 1;
+}
+
void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
SkBaseDevice* dst, const SkIPoint& dstOrigin,
const SkMatrix& ctm) {
@@ -1090,6 +1115,48 @@
}
}
+void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
+ SkIRect devBounds;
+ if (localBounds) {
+ SkRect tmp;
+ fMCRec->fMatrix.mapRect(&tmp, *localBounds);
+ if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
+ devBounds.setEmpty();
+ }
+ } else {
+ devBounds = this->getDeviceClipBounds();
+ }
+ if (devBounds.isEmpty()) {
+ return;
+ }
+
+ SkBaseDevice* device = this->getTopDevice();
+ if (nullptr == device) { // Do we still need this check???
+ return;
+ }
+
+ // need the bounds relative to the device itself
+ devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
+
+ auto backImage = device->snapBackImage(devBounds);
+ if (!backImage) {
+ return;
+ }
+
+ // we really need the save, so we can wack the fMCRec
+ this->checkForDeferredSave();
+
+ fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
+
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kClear);
+ if (localBounds) {
+ this->drawRect(*localBounds, paint);
+ } else {
+ this->drawPaint(paint);
+ }
+}
+
void SkCanvas::internalRestore() {
SkASSERT(fMCStack.count() != 0);
@@ -1098,6 +1165,9 @@
// now detach it from fMCRec so we can pop(). Gets freed after its drawn
fMCRec->fLayer = nullptr;
+ // move this out before we do the actual restore
+ auto backImage = std::move(fMCRec->fBackImage);
+
// now do the normal restore()
fMCRec->~MCRec(); // balanced in save()
fMCStack.pop_back();
@@ -1107,6 +1177,15 @@
FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
}
+ if (backImage) {
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kDstOver);
+ const int x = backImage->fLoc.x();
+ const int y = backImage->fLoc.y();
+ this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
+ nullptr, SkMatrix::I());
+ }
+
/* Time to draw the layer's offscreen. We can't call the public drawSprite,
since if we're being recorded, we don't want to record this (the
recorder will have already recorded the restore).
@@ -2828,6 +2907,10 @@
return kNoLayer_SaveLayerStrategy;
}
+bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
+ return false;
+}
+
///////////////////////////////////////////////////////////////////////////////
static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
diff --git a/src/core/SkCanvasPriv.h b/src/core/SkCanvasPriv.h
index 3e1ca16..cb25401 100644
--- a/src/core/SkCanvasPriv.h
+++ b/src/core/SkCanvasPriv.h
@@ -40,6 +40,9 @@
static SkCanvas::SaveLayerFlags LegacySaveFlagsToSaveLayerFlags(uint32_t legacySaveFlags);
+ static int SaveBehind(SkCanvas* canvas, const SkRect* subset) {
+ return canvas->only_axis_aligned_saveBehind(subset);
+ }
};
#endif
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 687d064..3428da9 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -368,6 +368,10 @@
return nullptr;
}
+sk_sp<SkSpecialImage> SkBaseDevice::snapBackImage(const SkIRect&) {
+ return nullptr;
+}
+
//////////////////////////////////////////////////////////////////////////////////////////
void SkBaseDevice::LogDrawScaleFactor(const SkMatrix& matrix, SkFilterQuality filterQuality) {
diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h
index 9082fd4..b1390fe 100644
--- a/src/core/SkDevice.h
+++ b/src/core/SkDevice.h
@@ -248,6 +248,8 @@
bool readPixels(const SkPixmap&, int x, int y);
+ virtual sk_sp<SkSpecialImage> snapBackImage(const SkIRect&); // default returns null
+
///////////////////////////////////////////////////////////////////////////
virtual GrContext* context() const { return nullptr; }
diff --git a/src/core/SkLiteDL.cpp b/src/core/SkLiteDL.cpp
index 053d0d5..1cc6c1e 100644
--- a/src/core/SkLiteDL.cpp
+++ b/src/core/SkLiteDL.cpp
@@ -8,6 +8,7 @@
#include "SkLiteDL.h"
#include <algorithm>
#include "SkCanvas.h"
+#include "SkCanvasPriv.h"
#include "SkData.h"
#include "SkDrawShadowInfo.h"
#include "SkImage.h"
@@ -48,7 +49,7 @@
namespace {
#define TYPES(M) \
- M(Flush) M(Save) M(Restore) M(SaveLayer) \
+ 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(DrawRegion) M(DrawOval) M(DrawArc) \
@@ -103,7 +104,16 @@
clipMatrix.isIdentity() ? nullptr : &clipMatrix, flags });
}
};
-
+ struct SaveBehind final : Op {
+ static const auto kType = Type::SaveBehind;
+ SaveBehind(const SkRect* subset) {
+ if (subset) { this->subset = *subset; }
+ }
+ SkRect subset = kUnset;
+ void draw(SkCanvas* c, const SkMatrix&) const {
+ SkCanvasPriv::SaveBehind(c, maybe_unset(subset));
+ }
+ };
struct Concat final : Op {
static const auto kType = Type::Concat;
Concat(const SkMatrix& matrix) : matrix(matrix) {}
@@ -498,6 +508,9 @@
const SkMatrix* clipMatrix, SkCanvas::SaveLayerFlags flags) {
this->push<SaveLayer>(0, bounds, paint, backdrop, clipMask, clipMatrix, flags);
}
+void SkLiteDL::saveBehind(const SkRect* subset) {
+ this->push<SaveBehind>(0, subset);
+}
void SkLiteDL:: concat(const SkMatrix& matrix) { this->push <Concat>(0, matrix); }
void SkLiteDL::setMatrix(const SkMatrix& matrix) { this->push<SetMatrix>(0, matrix); }
diff --git a/src/core/SkLiteDL.h b/src/core/SkLiteDL.h
index 261ef94..00f6e76 100644
--- a/src/core/SkLiteDL.h
+++ b/src/core/SkLiteDL.h
@@ -30,6 +30,7 @@
void save();
void saveLayer(const SkRect*, const SkPaint*, const SkImageFilter*, const SkImage*,
const SkMatrix*, SkCanvas::SaveLayerFlags);
+ void saveBehind(const SkRect*);
void restore();
void concat (const SkMatrix&);
diff --git a/src/core/SkLiteRecorder.cpp b/src/core/SkLiteRecorder.cpp
index 9f01fd2..e61d8be 100644
--- a/src/core/SkLiteRecorder.cpp
+++ b/src/core/SkLiteRecorder.cpp
@@ -30,6 +30,10 @@
rec.fSaveLayerFlags);
return SkCanvas::kNoLayer_SaveLayerStrategy;
}
+bool SkLiteRecorder::onDoSaveBehind(const SkRect* subset) {
+ fDL->saveBehind(subset);
+ return false;
+}
void SkLiteRecorder::willRestore() { fDL->restore(); }
void SkLiteRecorder::didConcat (const SkMatrix& matrix) { fDL-> concat(matrix); }
diff --git a/src/core/SkLiteRecorder.h b/src/core/SkLiteRecorder.h
index 4901631..e8073a4 100644
--- a/src/core/SkLiteRecorder.h
+++ b/src/core/SkLiteRecorder.h
@@ -22,6 +22,7 @@
void willSave() override;
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
+ bool onDoSaveBehind(const SkRect*) override;
void willRestore() override;
void onFlush() override;
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index ddf3b8d..e8368ca 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -98,7 +98,9 @@
FLUSH,
DRAW_IMAGE_SET,
- LAST_DRAWTYPE_ENUM = DRAW_IMAGE_SET
+
+ SAVE_BEHIND,
+ LAST_DRAWTYPE_ENUM = SAVE_BEHIND,
};
enum DrawVertexFlags {
@@ -126,6 +128,10 @@
SAVELAYERREC_HAS_CLIPMATRIX = 1 << 5,
};
+enum SaveBehindFlatFlags {
+ SAVEBEHIND_HAS_SUBSET = 1 << 0,
+};
+
///////////////////////////////////////////////////////////////////////////////
// clipparams are packed in 5 bits
// doAA:1 | clipOp:4
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 553a461..26163e9 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -647,6 +647,16 @@
case SAVE:
canvas->save();
break;
+ case SAVE_BEHIND: {
+ uint32_t flags = reader->readInt();
+ const SkRect* subset = nullptr;
+ SkRect storage;
+ if (flags & SAVEBEHIND_HAS_SUBSET) {
+ reader->readRect(&storage);
+ subset = &storage;
+ }
+ SkCanvasPriv::SaveBehind(canvas, subset);
+ } break;
case SAVE_LAYER_SAVEFLAGS_DEPRECATED: {
SkRect storage;
const SkRect* boundsPtr = get_rect_ptr(reader, &storage);
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index a2d5c97..7cbfb8c 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -75,6 +75,26 @@
return kNoLayer_SaveLayerStrategy;
}
+bool SkPictureRecord::onDoSaveBehind(const SkRect* subset) {
+ fRestoreOffsetStack.push_back(-(int32_t)fWriter.bytesWritten());
+
+ size_t size = sizeof(kUInt32Size) + sizeof(uint32_t); // op + flags
+ uint32_t flags = 0;
+ if (subset) {
+ flags |= SAVEBEHIND_HAS_SUBSET;
+ size += sizeof(*subset);
+ }
+
+ size_t initialOffset = this->addDraw(SAVE_BEHIND, &size);
+ this->addInt(flags);
+ if (subset) {
+ this->addRect(*subset);
+ }
+
+ this->validate(initialOffset, size);
+ return false;
+}
+
void SkPictureRecord::recordSaveLayer(const SaveLayerRec& rec) {
// op + flatflags
size_t size = 2 * kUInt32Size;
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index 4f1c48c..d9506d6 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -157,6 +157,7 @@
void willSave() override;
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
+ bool onDoSaveBehind(const SkRect*) override;
void willRestore() override;
void didConcat(const SkMatrix&) override;
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index 21e61c2..a9b0d02 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -43,6 +43,7 @@
kStoreImageBounds_Version = 63,
kRemoveOccluderFromBlurMaskFilter = 64,
kFloat4PaintColor_Version = 65,
+ kSaveBehind_Version = 66,
};
/**
@@ -245,6 +246,7 @@
kStoreImageBounds_Version = 63,
kRemoveOccluderFromBlurMaskFilter = 64,
kFloat4PaintColor_Version = 65,
+ kSaveBehind_Version = 66,
};
bool isVersionLT(Version) const { return false; }
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 938c4c7..15a72a5 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -6,6 +6,7 @@
*/
#include "SkRecordDraw.h"
+#include "SkCanvasPriv.h"
#include "SkImage.h"
#include "SkPatchUtils.h"
@@ -82,6 +83,11 @@
r.clipMask.get(),
r.clipMatrix,
r.saveLayerFlags)));
+
+template <> void Draw::draw(const SaveBehind& r) {
+ SkCanvasPriv::SaveBehind(fCanvas, r.subset);
+}
+
DRAW(SetMatrix, setMatrix(SkMatrix::Concat(fInitialCTM, r.matrix)));
DRAW(Concat, concat(r.matrix));
DRAW(Translate, translate(r.dx, r.dy));
@@ -244,6 +250,7 @@
// from the bounds of the ops in the same Save block.
void trackBounds(const Save&) { this->pushSaveBlock(nullptr); }
void trackBounds(const SaveLayer& op) { this->pushSaveBlock(op.paint); }
+ void trackBounds(const SaveBehind&) { this->pushSaveBlock(nullptr); }
void trackBounds(const Restore&) { fBounds[fCurrentOp] = this->popSaveBlock(); }
void trackBounds(const SetMatrix&) { this->pushControl(); }
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index b887654..5d5a421 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -347,6 +347,11 @@
return SkCanvas::kNoLayer_SaveLayerStrategy;
}
+bool SkRecorder::onDoSaveBehind(const SkRect* subset) {
+ this->append<SkRecords::SaveBehind>(this->copy(subset));
+ return false;
+}
+
void SkRecorder::didRestore() {
this->append<SkRecords::Restore>(this->getTotalMatrix());
}
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index 2fa2291..766064d 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -58,6 +58,7 @@
void willSave() override;
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
+ bool onDoSaveBehind(const SkRect*) override;
void willRestore() override {}
void didRestore() override;
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index bc1226e..c442930 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -43,6 +43,7 @@
M(Restore) \
M(Save) \
M(SaveLayer) \
+ M(SaveBehind) \
M(SetMatrix) \
M(Translate) \
M(Concat) \
@@ -177,6 +178,9 @@
Optional<SkMatrix> clipMatrix;
SkCanvas::SaveLayerFlags saveLayerFlags);
+RECORD(SaveBehind, 0,
+ Optional<SkRect> subset);
+
RECORD(SetMatrix, 0,
TypedMatrix matrix);
RECORD(Concat, 0,
diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp
index 5bee1c4..95b57e2 100644
--- a/src/core/SkRemoteGlyphCache.cpp
+++ b/src/core/SkRemoteGlyphCache.cpp
@@ -240,6 +240,10 @@
return kFullLayer_SaveLayerStrategy;
}
+bool SkTextBlobCacheDiffCanvas::onDoSaveBehind(const SkRect*) {
+ return false;
+}
+
void SkTextBlobCacheDiffCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) {
SkCanvas::onDrawTextBlob(blob, x, y, paint);
diff --git a/src/core/SkRemoteGlyphCache.h b/src/core/SkRemoteGlyphCache.h
index 32dd48e..e4ea6e7 100644
--- a/src/core/SkRemoteGlyphCache.h
+++ b/src/core/SkRemoteGlyphCache.h
@@ -72,6 +72,7 @@
protected:
SkCanvas::SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override;
+ bool onDoSaveBehind(const SkRect*) override;
void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) override;
diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp
index a1db765..6e4b2d8 100644
--- a/src/core/SkSpecialImage.cpp
+++ b/src/core/SkSpecialImage.cpp
@@ -338,6 +338,25 @@
return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
}
+sk_sp<SkSpecialImage> SkSpecialImage::CopyFromRaster(const SkIRect& subset,
+ const SkBitmap& bm,
+ const SkSurfaceProps* props) {
+ SkASSERT(rect_fits(subset, bm.width(), bm.height()));
+
+ if (!bm.pixelRef()) {
+ return nullptr;
+ }
+
+ SkBitmap tmp;
+ if (!tmp.tryAllocPixels(bm.info().makeWH(subset.width(), subset.height()))) {
+ return nullptr;
+ }
+ if (!bm.readPixels(tmp.info(), tmp.getPixels(), tmp.rowBytes(), subset.x(), subset.y())) {
+ return nullptr;
+ }
+ return sk_make_sp<SkSpecialImage_Raster>(subset, tmp, props);
+}
+
#if SK_SUPPORT_GPU
///////////////////////////////////////////////////////////////////////////////
static sk_sp<SkImage> wrap_proxy_in_image(GrContext* context, sk_sp<GrTextureProxy> proxy,
diff --git a/src/core/SkSpecialImage.h b/src/core/SkSpecialImage.h
index 9379708..30f74b4 100644
--- a/src/core/SkSpecialImage.h
+++ b/src/core/SkSpecialImage.h
@@ -75,6 +75,9 @@
static sk_sp<SkSpecialImage> MakeFromRaster(const SkIRect& subset,
const SkBitmap&,
const SkSurfaceProps* = nullptr);
+ static sk_sp<SkSpecialImage> CopyFromRaster(const SkIRect& subset,
+ const SkBitmap&,
+ const SkSurfaceProps* = nullptr);
#if SK_SUPPORT_GPU
static sk_sp<SkSpecialImage> MakeDeferredFromGpu(GrContext*,
const SkIRect& subset,
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index e82edbe..d413b3d 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1255,6 +1255,32 @@
&this->surfaceProps());
}
+sk_sp<SkSpecialImage> SkGpuDevice::snapBackImage(const SkIRect& subset) {
+ GrRenderTargetContext* rtc = this->accessRenderTargetContext();
+ if (!rtc) {
+ return nullptr;
+ }
+
+ GrContext* ctx = this->context();
+ if (!rtc->asSurfaceProxy()) {
+ return nullptr;
+ }
+
+ auto srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->mipMapped(), subset,
+ rtc->asSurfaceProxy()->isBudgeted());
+ if (!srcProxy) {
+ return nullptr;
+ }
+
+ // Note, can't move srcProxy since we also refer to this in the 2nd parameter
+ return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
+ SkIRect::MakeSize(srcProxy->isize()),
+ kNeedNewImageUniqueID_SpecialImage,
+ srcProxy,
+ this->imageInfo().refColorSpace(),
+ &this->surfaceProps());
+}
+
void SkGpuDevice::drawDevice(SkBaseDevice* device,
int left, int top, const SkPaint& paint) {
SkASSERT(!paint.getImageFilter());
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index dfc5fc7..d14572a 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -115,6 +115,7 @@
sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
sk_sp<SkSpecialImage> snapSpecial() override;
+ sk_sp<SkSpecialImage> snapBackImage(const SkIRect&) override;
void flush() override;
GrSemaphoresSubmitted flushAndSignalSemaphores(int numSemaphores,
diff --git a/src/utils/SkLuaCanvas.cpp b/src/utils/SkLuaCanvas.cpp
index d38e68f..3046a62 100644
--- a/src/utils/SkLuaCanvas.cpp
+++ b/src/utils/SkLuaCanvas.cpp
@@ -100,6 +100,11 @@
return kNoLayer_SaveLayerStrategy;
}
+bool SkLuaCanvas::onDoSaveBehind(const SkRect*) {
+ // TODO
+ return false;
+}
+
void SkLuaCanvas::willRestore() {
AUTO_LUA("restore");
this->INHERITED::willRestore();
diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp
index 422b851..7f214af 100644
--- a/src/utils/SkNWayCanvas.cpp
+++ b/src/utils/SkNWayCanvas.cpp
@@ -4,7 +4,9 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+
#include "SkNWayCanvas.h"
+#include "SkCanvasPriv.h"
SkNWayCanvas::SkNWayCanvas(int width, int height) : INHERITED(width, height) {}
@@ -45,6 +47,7 @@
return false;
}
SkCanvas* operator->() { return fCanvas; }
+ SkCanvas* get() const { return fCanvas; }
private:
const SkTDArray<SkCanvas*>& fList;
@@ -72,6 +75,15 @@
return kNoLayer_SaveLayerStrategy;
}
+bool SkNWayCanvas::onDoSaveBehind(const SkRect* bounds) {
+ Iter iter(fList);
+ while (iter.next()) {
+ SkCanvasPriv::SaveBehind(iter.get(), bounds);
+ }
+ this->INHERITED::onDoSaveBehind(bounds);
+ return false;
+}
+
void SkNWayCanvas::willRestore() {
Iter iter(fList);
while (iter.next()) {
diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp
index d7ff8a4..f9fb2c5 100644
--- a/tests/PictureTest.cpp
+++ b/tests/PictureTest.cpp
@@ -108,6 +108,7 @@
: INHERITED(width, height)
, fSaveCount(0)
, fSaveLayerCount(0)
+ , fSaveBehindCount(0)
, fRestoreCount(0){
}
@@ -116,6 +117,11 @@
return this->INHERITED::getSaveLayerStrategy(rec);
}
+ bool onDoSaveBehind(const SkRect* subset) override {
+ ++fSaveBehindCount;
+ return this->INHERITED::onDoSaveBehind(subset);
+ }
+
void willSave() override {
++fSaveCount;
this->INHERITED::willSave();
@@ -128,11 +134,13 @@
unsigned int getSaveCount() const { return fSaveCount; }
unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
+ unsigned int getSaveBehindCount() const { return fSaveBehindCount; }
unsigned int getRestoreCount() const { return fRestoreCount; }
private:
unsigned int fSaveCount;
unsigned int fSaveLayerCount;
+ unsigned int fSaveBehindCount;
unsigned int fRestoreCount;
typedef SkCanvas INHERITED;
diff --git a/tools/debugger/SkDebugCanvas.cpp b/tools/debugger/SkDebugCanvas.cpp
index 450af1a..9d018f1 100644
--- a/tools/debugger/SkDebugCanvas.cpp
+++ b/tools/debugger/SkDebugCanvas.cpp
@@ -467,6 +467,11 @@
return kNoLayer_SaveLayerStrategy;
}
+bool SkDebugCanvas::onDoSaveBehind(const SkRect* subset) {
+ // TODO
+ return false;
+}
+
void SkDebugCanvas::didSetMatrix(const SkMatrix& matrix) {
this->addDrawCommand(new SkSetMatrixCommand(matrix));
this->INHERITED::didSetMatrix(matrix);
diff --git a/tools/debugger/SkDebugCanvas.h b/tools/debugger/SkDebugCanvas.h
index ca54415..2a5c3de 100644
--- a/tools/debugger/SkDebugCanvas.h
+++ b/tools/debugger/SkDebugCanvas.h
@@ -113,9 +113,8 @@
protected:
void willSave() override;
-
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec &) override;
-
+ bool onDoSaveBehind(const SkRect*) override;
void willRestore() override;
void didConcat(const SkMatrix &) override;