Remove support for deprecated kDontClipToLayer_SaveLayerFlag

This removes the conditional behavior based on #defines, and the private
flag definitions. It removes GMs and updates tests that tested the
feature. Follow-up CLs will go through and simplify the internals of
SkCanvas to take advantage of this support removal.

Bug: skia:10986
Change-Id: Id42c9e7d134dd06507fabf6577e7872942ef9077
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/339988
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Mike Reed <reed@google.com>
This commit is contained in:
Michael Ludwig 2020-12-04 12:59:39 -05:00 committed by Skia Commit-Bot
parent 3021795041
commit e0dee01043
10 changed files with 24 additions and 239 deletions

View File

@ -6,6 +6,9 @@ This file includes a list of high level updates for each milestone release.
Milestone 89 Milestone 89
------------ ------------
* Remove support for deprecated kDontClipToLayer_SaveLayerFlag in SkCanvas::SaveLayerRec
https://review.skia.org/339988
* Expose more info in SkCodec::FrameInfo * Expose more info in SkCodec::FrameInfo
https://review.skia.org/339857 https://review.skia.org/339857

View File

@ -19,65 +19,6 @@
#include "src/core/SkCanvasPriv.h" #include "src/core/SkCanvasPriv.h"
#include "tools/ToolUtils.h" #include "tools/ToolUtils.h"
static void do_draw(SkCanvas* canvas, const SkRect& r) {
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
paint.setColor(0x800000FF);
canvas->drawRect(r, paint);
}
/**
* Exercise SkCanvasPriv::kDontClipToLayer_SaveLayerFlag flag, which does not limit the clip to the
* layer's bounds. Thus when a draw occurs, it can (depending on "where" it is) draw into the layer
* and/or draw onto the surrounding portions of the canvas, or both.
*
* This GM has a 100x100 rectangle (r), which its going to draw. However first it creates a layer
* with this flag covering 1/2 of the rectangle (upper half). Then it draws the rect in SRC mode.
*
* The portion of the draw that intersects the layer should see the SRC draw, apply it to the layer
* and then during restore, it will SRC_OVER that layer onto the canvas (SRC_OVER since the layer
* has no paint, so it gets the default xfermode during restore).
*
* Note: when we talk about drawing directly into the "canvas", in fact we are drawing into an
* "outer" layer we created (filled with red). This is a testing detail, so that our final
* output image is itself opaque, otherwise we make it harder to view the GM as a PNG.
*
* The portion of the draw below the layer draws directly into the canvas. Since it is in SRC mode,
* it will write 0x80 to the canvas' alpha, overwriting the "red", which then gets blended with
* the GM's white background.
*
* The portion in the layer, will end up SRC_OVERing the 0x80 layer pixels onto the canvas' red
* pixels, making magenta.
*
* Thus the expected result is the upper half to be magenta 0xFF7F0080, and the lower half to be
* light blue 0xFF7F7FFF.
*/
DEF_SIMPLE_GM(dont_clip_to_layer, canvas, 120, 120) {
const SkRect r { 10, 10, 110, 110 };
// Wrap the entire test inside a red layer, so we don't punch the actual gm's alpha with
// kSrc_Mode, which makes it hard to view (we like our GMs to have opaque pixels).
canvas->saveLayer(&r, nullptr);
canvas->drawColor(SK_ColorRED);
SkRect r0 = { 20, 20, 100, 55 };
SkRect r1 = { 20, 65, 100, 100 };
SkCanvas::SaveLayerRec rec;
rec.fPaint = nullptr;
rec.fBounds = &r0;
rec.fBackdrop = nullptr;
rec.fSaveLayerFlags = SkCanvasPriv::kDontClipToLayer_SaveLayerFlag;
canvas->saveLayer(rec);
rec.fBounds = &r1;
canvas->saveLayer(rec);
do_draw(canvas, r);
canvas->restore();
canvas->restore();
canvas->restore(); // red-layer
}
/** Draw a 2px border around the target, then red behind the target; /** Draw a 2px border around the target, then red behind the target;
set the clip to match the target, then draw >> the target in blue. set the clip to match the target, then draw >> the target in blue.
*/ */

View File

@ -42,80 +42,6 @@
#include <string.h> #include <string.h>
#include <initializer_list> #include <initializer_list>
// This GM tests out the deprecated Android-specific unclipped saveLayer "feature".
// In particular, it attempts to compare the performance of unclipped saveLayers with alternatives.
static void save_layer_unclipped(SkCanvas* canvas,
SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
SkPaint paint;
paint.setAlphaf(0.25f);
SkRect rect = SkRect::MakeLTRB(l, t, r, b);
canvas->saveLayer({ &rect, &paint, nullptr,
(SkCanvas::SaveLayerFlags) SkCanvasPriv::kDontClipToLayer_SaveLayerFlag });
}
static void do_draw(SkCanvas* canvas) {
SkPaint paint;
paint.setColor(0xFFFF0000);
for (int i = 0; i < 20; ++i) {
canvas->drawRect({ 15, 15, 290, 40 }, paint);
canvas->translate(0, 30);
}
}
class UnclippedSaveLayerGM : public skiagm::GM {
public:
UnclippedSaveLayerGM() { this->setBGColor(SK_ColorWHITE); }
protected:
bool runAsBench() const override { return true; }
SkString onShortName() override {
return SkString("savelayer_unclipped");
}
SkISize onISize() override { return SkISize::Make(320, 640); }
void onDraw(SkCanvas* canvas) override {
const SkScalar L = 10;
const SkScalar T = 10;
const SkScalar R = 310;
const SkScalar B = 630;
canvas->clipRect({ L, T, R, B });
SkAutoCanvasRestore acr(canvas, true);
save_layer_unclipped(canvas, L, T, R, T + 100);
save_layer_unclipped(canvas, L, B - 100, R, B);
do_draw(canvas);
}
private:
using INHERITED = skiagm::GM;
};
DEF_GM(return new UnclippedSaveLayerGM;)
DEF_SIMPLE_GM(picture_savelayer, canvas, 320, 640) {
SkPaint paint1, paint2, paint3;
paint1.setAlphaf(0.5f);
paint2.setAlphaf(0.25f);
paint3.setColor(0xFFFF0000);
SkRect rect1{40, 5, 80, 70}, rect2{5, 40, 70, 80}, rect3{10, 10, 70, 70};
// In the future, we might also test the clipped case by allowing i = 0
for(int i = 1; i < 2; ++i) {
canvas->translate(100 * i, 0);
auto flag = i ?
(SkCanvas::SaveLayerFlags) SkCanvasPriv::kDontClipToLayer_SaveLayerFlag : 0;
canvas->saveLayer(SkCanvas::SaveLayerRec(&rect1, &paint1, nullptr, flag));
canvas->saveLayer(SkCanvas::SaveLayerRec(&rect2, &paint2, nullptr, flag));
canvas->drawRect(rect3, paint3);
canvas->restore();
canvas->restore();
}
};
// Test kInitWithPrevious_SaveLayerFlag by drawing an image, save a layer with the flag, which // Test kInitWithPrevious_SaveLayerFlag by drawing an image, save a layer with the flag, which
// should seed the layer with the image (from below). Then we punch a hole in the layer and // should seed the layer with the image (from below). Then we punch a hole in the layer and
// restore with kPlus mode, which should show the mandrill super-bright on the outside, but // restore with kPlus mode, which should show the mandrill super-bright on the outside, but

View File

@ -82,10 +82,6 @@ class SkVertices;
This approach may be deprecated in the future. This approach may be deprecated in the future.
*/ */
class SK_API SkCanvas { class SK_API SkCanvas {
enum PrivateSaveLayerFlags {
kDontClipToLayer_PrivateSaveLayerFlag = 1U << 31,
};
public: public:
/** Allocates raster SkCanvas that will draw directly into pixels. /** Allocates raster SkCanvas that will draw directly into pixels.
@ -637,10 +633,6 @@ public:
1 << 3, //!< experimental: do not use 1 << 3, //!< experimental: do not use
// instead of matching previous layer's colortype, use F16 // instead of matching previous layer's colortype, use F16
kF16ColorType = 1 << 4, kF16ColorType = 1 << 4,
#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
kDontClipToLayer_Legacy_SaveLayerFlag =
kDontClipToLayer_PrivateSaveLayerFlag, //!< deprecated
#endif
}; };
typedef uint32_t SaveLayerFlags; typedef uint32_t SaveLayerFlags;

View File

@ -1146,30 +1146,27 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
newDevice.reset(priorDevice->onCreateDevice(createInfo, paint)); newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
} }
bool boundsAffectsClip = !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
if (!newDevice) { if (!newDevice) {
if (modifiedRec) { if (modifiedRec) {
// In this case there will be no layer in which to stash the matrix so we need to // In this case there will be no layer in which to stash the matrix so we need to
// revert the prior MCRec to its earlier state. // revert the prior MCRec to its earlier state.
modifiedRec->fMatrix = SkM44(stashedMatrix); modifiedRec->fMatrix = SkM44(stashedMatrix);
} }
if (boundsAffectsClip) { if (strategy == kNoLayer_SaveLayerStrategy) {
if (strategy == kNoLayer_SaveLayerStrategy) { // replaceClip() serves two purposes here:
// replaceClip() serves two purposes here: // 1. When 'ir' is empty, it forces the top level device to reject all subsequent
// 1. When 'ir' is empty, it forces the top level device to reject all subsequent // nested draw calls.
// nested draw calls. // 2. When 'ir' is not empty, this canvas represents a recording canvas, so the
// 2. When 'ir' is not empty, this canvas represents a recording canvas, so the // replaceClip() simulates what a new top-level device's canvas would be in
// replaceClip() simulates what a new top-level device's canvas would be in // the non-recording scenario. This allows the canvas to report the expanding
// the non-recording scenario. This allows the canvas to report the expanding // effects of image filters on the temporary clip bounds.
// effects of image filters on the temporary clip bounds. UPDATE_DEVICE_CLIP(device->replaceClip(ir));
UPDATE_DEVICE_CLIP(device->replaceClip(ir)); } else {
} else { // else the layer device failed to be created, so the saveLayer() effectively
// else the layer device failed to be created, so the saveLayer() effectively // becomes just a save(). The clipRegion() explicitly applies the bounds of the
// becomes just a save(). The clipRegion() explicitly applies the bounds of the // failed layer, without resetting the clip of the prior device that all subsequent
// failed layer, without resetting the clip of the prior device that all subsequent // nested draw calls need to respect.
// nested draw calls need to respect. UPDATE_DEVICE_CLIP(device->clipRegion(SkRegion(ir), SkClipOp::kIntersect));
UPDATE_DEVICE_CLIP(device->clipRegion(SkRegion(ir), SkClipOp::kIntersect));
}
} }
return; return;
} }
@ -1177,8 +1174,7 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
newDevice->setMarkerStack(fMarkerStack.get()); newDevice->setMarkerStack(fMarkerStack.get());
DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix); DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix);
// only have a "next" if this new layer doesn't affect the clip (rare) layer->fNext = nullptr;
layer->fNext = boundsAffectsClip ? nullptr : fMCRec->fTopLayer;
fMCRec->fLayer = layer; fMCRec->fLayer = layer;
fMCRec->fTopLayer = layer; // this field is NOT an owner of layer fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
@ -1189,17 +1185,6 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop); newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect); newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
if (layer->fNext) {
// need to punch a hole in the previous device, so we don't draw there, given that
// the new top-layer will allow drawing to happen "below" it.
SkRegion hole(ir);
do {
layer = layer->fNext;
layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
} while (layer->fNext);
}
fQuickRejectBounds = qr_clip_bounds(this->computeDeviceClipBounds()); fQuickRejectBounds = qr_clip_bounds(this->computeDeviceClipBounds());
} }

View File

@ -26,10 +26,6 @@ private:
class SkCanvasPriv { class SkCanvasPriv {
public: public:
enum {
kDontClipToLayer_SaveLayerFlag = SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag,
};
// The lattice has pointers directly into the readbuffer // The lattice has pointers directly into the readbuffer
static bool ReadLattice(SkReadBuffer&, SkCanvas::Lattice*); static bool ReadLattice(SkReadBuffer&, SkCanvas::Lattice*);
@ -39,8 +35,6 @@ public:
// storage must be 4-byte aligned // storage must be 4-byte aligned
static size_t WriteLattice(void* storage, const SkCanvas::Lattice&); static size_t WriteLattice(void* storage, const SkCanvas::Lattice&);
static SkCanvas::SaveLayerFlags LegacySaveFlagsToSaveLayerFlags(uint32_t legacySaveFlags);
static int SaveBehind(SkCanvas* canvas, const SkRect* subset) { static int SaveBehind(SkCanvas* canvas, const SkRect* subset) {
return canvas->only_axis_aligned_saveBehind(subset); return canvas->only_axis_aligned_saveBehind(subset);
} }

View File

@ -55,7 +55,7 @@ enum DrawType {
RESTORE, RESTORE,
ROTATE, ROTATE,
SAVE, SAVE,
SAVE_LAYER_SAVEFLAGS_DEPRECATED, SAVE_LAYER_SAVEFLAGS_DEPRECATED_2015_REMOVED_12_2020,
SCALE, SCALE,
SET_MATRIX, SET_MATRIX,
SKEW, SKEW,

View File

@ -22,20 +22,6 @@
#include "src/core/SkVerticesPriv.h" #include "src/core/SkVerticesPriv.h"
#include "src/utils/SkPatchUtils.h" #include "src/utils/SkPatchUtils.h"
// matches old SkCanvas::SaveFlags
enum LegacySaveFlags {
kClipToLayer_LegacySaveFlags = 0x10,
};
SkCanvas::SaveLayerFlags SkCanvasPriv::LegacySaveFlagsToSaveLayerFlags(uint32_t flags) {
uint32_t layerFlags = 0;
if (0 == (flags & kClipToLayer_LegacySaveFlags)) {
layerFlags |= kDontClipToLayer_SaveLayerFlag;
}
return layerFlags;
}
static const SkRect* get_rect_ptr(SkReadBuffer* reader, SkRect* storage) { static const SkRect* get_rect_ptr(SkReadBuffer* reader, SkRect* storage) {
if (reader->readBool()) { if (reader->readBool()) {
reader->readRect(storage); reader->readRect(storage);
@ -559,15 +545,6 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
} }
SkCanvasPriv::SaveBehind(canvas, subset); SkCanvasPriv::SaveBehind(canvas, subset);
} break; } break;
case SAVE_LAYER_SAVEFLAGS_DEPRECATED: {
SkRect storage;
const SkRect* boundsPtr = get_rect_ptr(reader, &storage);
const SkPaint* paint = fPictureData->optionalPaint(reader);
auto flags = SkCanvasPriv::LegacySaveFlagsToSaveLayerFlags(reader->readInt());
BREAK_ON_READ_ERROR(reader);
canvas->saveLayer(SkCanvas::SaveLayerRec(boundsPtr, paint, flags));
} break;
case SAVE_LAYER_SAVELAYERREC: { case SAVE_LAYER_SAVELAYERREC: {
SkCanvas::SaveLayerRec rec(nullptr, nullptr, nullptr, 0); SkCanvas::SaveLayerRec rec(nullptr, nullptr, nullptr, 0);
const uint32_t flatFlags = reader->readInt(); const uint32_t flatFlags = reader->readInt();

View File

@ -190,12 +190,6 @@ struct SaveLayerDrawRestoreNooper {
return false; return false;
} }
if (match->first<SaveLayer>()->saveLayerFlags &
SkCanvasPriv::kDontClipToLayer_SaveLayerFlag) {
// can't throw away the layer if set
return false;
}
// A SaveLayer's bounds field is just a hint, so we should be free to ignore it. // A SaveLayer's bounds field is just a hint, so we should be free to ignore it.
SkPaint* layerPaint = match->first<SaveLayer>()->paint; SkPaint* layerPaint = match->first<SaveLayer>()->paint;
SkPaint* drawPaint = match->second<SkPaint>(); SkPaint* drawPaint = match->second<SkPaint>();

View File

@ -125,12 +125,6 @@ DEF_TEST(CanvasState_test_complex_layers, reporter) {
}; };
const int layerAlpha[] = { 255, 255, 0 }; const int layerAlpha[] = { 255, 255, 0 };
const SkCanvas::SaveLayerFlags flags[] = {
static_cast<SkCanvas::SaveLayerFlags>(SkCanvasPriv::kDontClipToLayer_SaveLayerFlag),
0,
static_cast<SkCanvas::SaveLayerFlags>(SkCanvasPriv::kDontClipToLayer_SaveLayerFlag),
};
REPORTER_ASSERT(reporter, sizeof(layerAlpha) == sizeof(flags));
bool (*drawFn)(SkCanvasState* state, float l, float t, bool (*drawFn)(SkCanvasState* state, float l, float t,
float r, float b, int32_t s); float r, float b, int32_t s);
@ -164,7 +158,7 @@ DEF_TEST(CanvasState_test_complex_layers, reporter) {
} }
// draw a rect within the layer's bounds and again outside the layer's bounds // draw a rect within the layer's bounds and again outside the layer's bounds
canvas->saveLayer(SkCanvas::SaveLayerRec(&rect, paint.getMaybeNull(), flags[k])); canvas->saveLayer(SkCanvas::SaveLayerRec(&rect, paint.getMaybeNull()));
if (j) { if (j) {
// Capture from the first Skia. // Capture from the first Skia.
@ -225,12 +219,6 @@ DEF_TEST(CanvasState_test_complex_clips, reporter) {
SkRegion::kIntersect_Op, SkRegion::kIntersect_Op,
SkRegion::kDifference_Op, SkRegion::kDifference_Op,
}; };
const SkCanvas::SaveLayerFlags flags[] = {
static_cast<SkCanvas::SaveLayerFlags>(SkCanvasPriv::kDontClipToLayer_SaveLayerFlag),
0,
static_cast<SkCanvas::SaveLayerFlags>(SkCanvasPriv::kDontClipToLayer_SaveLayerFlag),
};
REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags));
bool (*drawFn)(SkCanvasState* state, int32_t l, int32_t t, bool (*drawFn)(SkCanvasState* state, int32_t l, int32_t t,
int32_t r, int32_t b, int32_t clipOp, int32_t r, int32_t b, int32_t clipOp,
@ -261,7 +249,7 @@ DEF_TEST(CanvasState_test_complex_clips, reporter) {
paint.setAlpha(128); paint.setAlpha(128);
for (size_t j = 0; j < SK_ARRAY_COUNT(clipOps); ++j) { for (size_t j = 0; j < SK_ARRAY_COUNT(clipOps); ++j) {
SkRect layerBounds = SkRect::Make(layerRect); SkRect layerBounds = SkRect::Make(layerRect);
canvas->saveLayer(SkCanvas::SaveLayerRec(&layerBounds, &paint, flags[j])); canvas->saveLayer(SkCanvas::SaveLayerRec(&layerBounds, &paint));
if (i) { if (i) {
SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(canvas); SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(canvas);
@ -317,10 +305,6 @@ DEF_TEST(CanvasState_test_soft_clips, reporter) {
} }
DEF_TEST(CanvasState_test_saveLayer_clip, reporter) { DEF_TEST(CanvasState_test_saveLayer_clip, reporter) {
#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
static_assert(SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag ==
SkCanvasPriv::kDontClipToLayer_SaveLayerFlag, "");
#endif
const int WIDTH = 100; const int WIDTH = 100;
const int HEIGHT = 100; const int HEIGHT = 100;
const int LAYER_WIDTH = 50; const int LAYER_WIDTH = 50;
@ -333,20 +317,9 @@ DEF_TEST(CanvasState_test_saveLayer_clip, reporter) {
SkRect bounds = SkRect::MakeWH(SkIntToScalar(LAYER_WIDTH), SkIntToScalar(LAYER_HEIGHT)); SkRect bounds = SkRect::MakeWH(SkIntToScalar(LAYER_WIDTH), SkIntToScalar(LAYER_HEIGHT));
canvas.clipRect(SkRect::MakeWH(SkIntToScalar(WIDTH), SkIntToScalar(HEIGHT))); canvas.clipRect(SkRect::MakeWH(SkIntToScalar(WIDTH), SkIntToScalar(HEIGHT)));
SkIRect devClip; // Check that saveLayer sets the clip stack to the layer bounds.
// Check that saveLayer without the kClipToLayer_SaveFlag leaves the clip unchanged.
canvas.saveLayer(SkCanvas::SaveLayerRec(&bounds, nullptr,
(SkCanvas::SaveLayerFlags) SkCanvasPriv::kDontClipToLayer_SaveLayerFlag));
devClip = canvas.getDeviceClipBounds();
REPORTER_ASSERT(reporter, canvas.isClipRect());
REPORTER_ASSERT(reporter, devClip.width() == WIDTH);
REPORTER_ASSERT(reporter, devClip.height() == HEIGHT);
canvas.restore();
// Check that saveLayer with the kClipToLayer_SaveFlag sets the clip
// stack to the layer bounds.
canvas.saveLayer(&bounds, nullptr); canvas.saveLayer(&bounds, nullptr);
devClip = canvas.getDeviceClipBounds(); SkIRect devClip = canvas.getDeviceClipBounds();
REPORTER_ASSERT(reporter, canvas.isClipRect()); REPORTER_ASSERT(reporter, canvas.isClipRect());
REPORTER_ASSERT(reporter, devClip.width() == LAYER_WIDTH); REPORTER_ASSERT(reporter, devClip.width() == LAYER_WIDTH);
REPORTER_ASSERT(reporter, devClip.height() == LAYER_HEIGHT); REPORTER_ASSERT(reporter, devClip.height() == LAYER_HEIGHT);