aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/imagefilters.cpp74
-rw-r--r--include/core/SkCanvas.h19
-rw-r--r--include/private/SkRecords.h2
-rw-r--r--samplecode/SampleApp.cpp9
-rw-r--r--samplecode/SampleLayers.cpp76
-rw-r--r--src/core/SkCanvas.cpp18
-rw-r--r--src/core/SkPictureFlat.h12
-rw-r--r--src/core/SkPicturePlayback.cpp20
-rw-r--r--src/core/SkPictureRecord.cpp46
-rw-r--r--src/core/SkRecordDraw.cpp2
-rw-r--r--src/core/SkRecordOpts.cpp10
-rw-r--r--src/core/SkRecorder.cpp3
-rw-r--r--tests/RecordOptsTest.cpp73
13 files changed, 316 insertions, 48 deletions
diff --git a/gm/imagefilters.cpp b/gm/imagefilters.cpp
index 5f1ae84949..951a934d82 100644
--- a/gm/imagefilters.cpp
+++ b/gm/imagefilters.cpp
@@ -104,3 +104,77 @@ DEF_SIMPLE_GM(fast_slow_blurimagefilter, canvas, 620, 260) {
canvas->translate(r.width() + 20, 0);
}
}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#include "Resources.h"
+#include "SkBlurImageFilter.h"
+#include "SkMatrixConvolutionImageFilter.h"
+#include "SkMorphologyImageFilter.h"
+#include "SkColorMatrixFilter.h"
+#include "SkColorFilterImageFilter.h"
+#include "SkRRect.h"
+
+static void draw_set(SkCanvas* canvas, SkImageFilter* filters[], int count) {
+ const SkRect r = SkRect::MakeXYWH(30, 30, 200, 200);
+ const SkScalar offset = 250;
+ SkScalar dx = 0, dy = 0;
+
+ for (int i = 0; i < count; ++i) {
+ canvas->save();
+ SkRRect rr = SkRRect::MakeRectXY(r.makeOffset(dx, dy), 20, 20);
+ canvas->clipRRect(rr, SkRegion::kIntersect_Op, true);
+ canvas->saveLayer({ &rr.getBounds(), nullptr, filters[i], 0 });
+ canvas->drawColor(0x40FFFFFF);
+ canvas->restore();
+ canvas->restore();
+
+ if (0 == dx) {
+ dx = offset;
+ } else {
+ dx = 0;
+ dy = offset;
+ }
+ }
+}
+
+DEF_SIMPLE_GM(savelayer_with_backdrop, canvas, 830, 550) {
+ SkColorMatrix cm;
+ cm.setSaturation(10);
+ SkAutoTUnref<SkColorFilter> cf(SkColorMatrixFilter::Create(cm));
+ const SkScalar kernel[] = { 4, 0, 4, 0, -15, 0, 4, 0, 4 };
+ SkImageFilter* filters[] = {
+ SkBlurImageFilter::Create(10, 10),
+ SkDilateImageFilter::Create(8, 8),
+ SkMatrixConvolutionImageFilter::Create({ 3, 3 }, kernel, 1, 0, { 0, 0 },
+ SkMatrixConvolutionImageFilter::kClampToBlack_TileMode,
+ true),
+ SkColorFilterImageFilter::Create(cf),
+ };
+
+ const struct {
+ SkScalar fSx, fSy, fTx, fTy;
+ } xforms[] = {
+ { 1, 1, 0, 0 },
+ { 0.5f, 0.5f, 530, 0 },
+ { 0.25f, 0.25f, 530, 275 },
+ { 0.125f, 0.125f, 530, 420 },
+ };
+
+ SkPaint paint;
+ paint.setFilterQuality(kMedium_SkFilterQuality);
+ SkAutoTUnref<SkImage> image(GetResourceAsImage("mandrill_512.png"));
+
+ canvas->translate(20, 20);
+ for (const auto& xform : xforms) {
+ canvas->save();
+ canvas->translate(xform.fTx, xform.fTy);
+ canvas->scale(xform.fSx, xform.fSy);
+ canvas->drawImage(image, 0, 0, &paint);
+ draw_set(canvas, filters, SK_ARRAY_COUNT(filters));
+ canvas->restore();
+ }
+
+ for (auto& filter : filters) {
+ filter->unref();
+ }
+}
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index d046b8ef4c..d1de626315 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -422,16 +422,27 @@ public:
typedef uint32_t SaveLayerFlags;
struct SaveLayerRec {
- SaveLayerRec() : fBounds(nullptr), fPaint(nullptr), fSaveLayerFlags(0) {}
+ SaveLayerRec()
+ : fBounds(nullptr), fPaint(nullptr), fBackdrop(nullptr), fSaveLayerFlags(0)
+ {}
SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0)
: fBounds(bounds)
, fPaint(paint)
+ , fBackdrop(nullptr)
+ , fSaveLayerFlags(saveLayerFlags)
+ {}
+ SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop,
+ SaveLayerFlags saveLayerFlags)
+ : fBounds(bounds)
+ , fPaint(paint)
+ , fBackdrop(backdrop)
, fSaveLayerFlags(saveLayerFlags)
{}
- const SkRect* fBounds; // optional
- const SkPaint* fPaint; // optional
- SaveLayerFlags fSaveLayerFlags;
+ const SkRect* fBounds; // optional
+ const SkPaint* fPaint; // optional
+ const SkImageFilter* fBackdrop; // optional
+ SaveLayerFlags fSaveLayerFlags;
};
int saveLayer(const SaveLayerRec&);
diff --git a/include/private/SkRecords.h b/include/private/SkRecords.h
index a2e9030b23..ecd73a12d9 100644
--- a/include/private/SkRecords.h
+++ b/include/private/SkRecords.h
@@ -10,6 +10,7 @@
#include "SkCanvas.h"
#include "SkDrawable.h"
+#include "SkImageFilter.h"
#include "SkMatrix.h"
#include "SkPath.h"
#include "SkPicture.h"
@@ -197,6 +198,7 @@ RECORD(Save, 0);
RECORD(SaveLayer, 0,
Optional<SkRect> bounds;
Optional<SkPaint> paint;
+ RefBox<const SkImageFilter> backdrop;
SkCanvas::SaveLayerFlags saveLayerFlags);
RECORD(SetMatrix, 0,
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index d200e295fb..c7a37e786c 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -1396,6 +1396,15 @@ void SampleWindow::afterChildren(SkCanvas* orig) {
if (fUseMPD) {
SkAutoTUnref<const SkPicture> picture(fRecorder.endRecording());
+
+ if (false) {
+ SkDynamicMemoryWStream wstream;
+ picture->serialize(&wstream);
+
+ SkAutoTDelete<SkStream> rstream(wstream.detachAsStream());
+ picture.reset(SkPicture::CreateFromStream(rstream));
+ }
+
if (true) {
if (true) {
SkImageInfo info;
diff --git a/samplecode/SampleLayers.cpp b/samplecode/SampleLayers.cpp
index 52bf5b357b..f8ebd7c94f 100644
--- a/samplecode/SampleLayers.cpp
+++ b/samplecode/SampleLayers.cpp
@@ -232,8 +232,80 @@ protected:
private:
typedef SkView INHERITED;
};
+DEF_SAMPLE( return new LayersView; )
//////////////////////////////////////////////////////////////////////////////
-static SkView* MyFactory() { return new LayersView; }
-static SkViewRegister reg(MyFactory);
+#include "SkBlurImageFilter.h"
+#include "SkMatrixConvolutionImageFilter.h"
+#include "SkMorphologyImageFilter.h"
+
+#include "Resources.h"
+#include "SkAnimTimer.h"
+
+class BackdropView : public SampleView {
+ SkPoint fCenter;
+ SkScalar fAngle;
+ SkAutoTUnref<SkImage> fImage;
+ SkAutoTUnref<SkImageFilter> fFilter;
+public:
+ BackdropView() {
+ fCenter.set(200, 150);
+ fAngle = 0;
+ fImage.reset(GetResourceAsImage("mandrill_512.png"));
+ fFilter.reset(SkDilateImageFilter::Create(8, 8));
+ }
+
+protected:
+ // overrides from SkEventSink
+ bool onQuery(SkEvent* evt) override {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Backdrop");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void onDrawContent(SkCanvas* canvas) override {
+ canvas->drawImage(fImage, 0, 0, nullptr);
+
+ const SkScalar w = 250;
+ const SkScalar h = 150;
+ SkPath path;
+ path.addOval(SkRect::MakeXYWH(-w/2, -h/2, w, h));
+ SkMatrix m;
+ m.setRotate(fAngle);
+ m.postTranslate(fCenter.x(), fCenter.y());
+ path.transform(m);
+
+ canvas->clipPath(path, SkRegion::kIntersect_Op, true);
+ const SkRect bounds = path.getBounds();
+
+ SkPaint paint;
+ paint.setAlpha(0xCC);
+ canvas->saveLayer({ &bounds, &paint, fFilter, 0 });
+
+ canvas->restore();
+ }
+
+ bool onAnimate(const SkAnimTimer& timer) override {
+ fAngle = SkDoubleToScalar(fmod(timer.secs() * 360 / 5, 360));
+ return true;
+ }
+
+ SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
+ this->inval(nullptr);
+ return new Click(this);
+ }
+
+ bool onClick(Click* click) override {
+ this->inval(nullptr);
+ fCenter = click->fCurr;
+ return this->INHERITED::onClick(click);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+DEF_SAMPLE( return new BackdropView; )
+
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index a4acbdc94d..82ceba4fa9 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -114,7 +114,6 @@ bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
// experimental for faster tiled drawing...
//#define SK_ENABLE_CLIP_QUICKREJECT
-
//#define SK_TRACE_SAVERESTORE
#ifdef SK_TRACE_SAVERESTORE
@@ -481,7 +480,7 @@ public:
// Make rawBounds include all paint outsets except for those due to image filters.
rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
}
- (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp, 0),
+ (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
SkCanvas::kFullLayer_SaveLayerStrategy);
fTempLayerForImageFilter = true;
// we remove the imagefilter/xfermode inside doNext()
@@ -1173,7 +1172,8 @@ int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
return this->getSaveCount() - 1;
}
-static void draw_filter_into_device(SkBaseDevice* src, SkImageFilter* filter, SkBaseDevice* dst) {
+static void draw_filter_into_device(SkBaseDevice* src, const SkImageFilter* filter,
+ SkBaseDevice* dst, const SkMatrix& ctm) {
SkBitmap srcBM;
@@ -1198,9 +1198,12 @@ static void draw_filter_into_device(SkBaseDevice* src, SkImageFilter* filter, Sk
SkCanvas c(dst);
+ SkAutoTUnref<SkImageFilter> localF(filter->newWithLocalMatrix(ctm));
SkPaint p;
- p.setImageFilter(filter);
- c.drawBitmap(srcBM, 0, 0, &p);
+ p.setImageFilter(localF);
+ const SkScalar x = SkIntToScalar(src->getOrigin().x());
+ const SkScalar y = SkIntToScalar(src->getOrigin().y());
+ c.drawBitmap(srcBM, x, y, &p);
}
void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
@@ -1268,11 +1271,10 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
}
device = newDev;
}
-
device->setOrigin(ir.fLeft, ir.fTop);
- if (0) {
- draw_filter_into_device(fMCRec->fTopLayer->fDevice, nullptr, device);
+ if (rec.fBackdrop) {
+ draw_filter_into_device(fMCRec->fTopLayer->fDevice, rec.fBackdrop, device, fMCRec->fMatrix);
}
DeviceCM* layer =
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index cbacc8e664..4eee04fcda 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -75,9 +75,10 @@ enum DrawType {
DRAW_IMAGE_NINE,
DRAW_IMAGE_RECT,
- SAVE_LAYER_SAVELAYERFLAGS,
+ SAVE_LAYER_SAVELAYERFLAGS_DEPRECATED_JAN_2016,
+ SAVE_LAYER_SAVELAYERREC,
- LAST_DRAWTYPE_ENUM = SAVE_LAYER_SAVELAYERFLAGS,
+ LAST_DRAWTYPE_ENUM = SAVE_LAYER_SAVELAYERREC,
};
// In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
@@ -95,6 +96,13 @@ enum DrawAtlasFlags {
DRAW_ATLAS_HAS_CULL = 1 << 1,
};
+enum SaveLayerRecFlatFlags {
+ SAVELAYERREC_HAS_BOUNDS = 1 << 0,
+ SAVELAYERREC_HAS_PAINT = 1 << 1,
+ SAVELAYERREC_HAS_BACKDROP = 1 << 2,
+ SAVELAYERREC_HAS_FLAGS = 1 << 3,
+};
+
///////////////////////////////////////////////////////////////////////////////
// clipparams are packed in 5 bits
// doAA:1 | regionOp:4
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 82b8f0e578..4b028f714e 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -483,11 +483,29 @@ void SkPicturePlayback::handleOp(SkReader32* reader,
auto flags = SkCanvas::LegacySaveFlagsToSaveLayerFlags(reader->readInt());
canvas->saveLayer(SkCanvas::SaveLayerRec(boundsPtr, paint, flags));
} break;
- case SAVE_LAYER_SAVELAYERFLAGS: {
+ case SAVE_LAYER_SAVELAYERFLAGS_DEPRECATED_JAN_2016: {
const SkRect* boundsPtr = get_rect_ptr(reader);
const SkPaint* paint = fPictureData->getPaint(reader);
canvas->saveLayer(SkCanvas::SaveLayerRec(boundsPtr, paint, reader->readInt()));
} break;
+ case SAVE_LAYER_SAVELAYERREC: {
+ SkCanvas::SaveLayerRec rec(nullptr, nullptr, nullptr, 0);
+ const uint32_t flatFlags = reader->readInt();
+ if (flatFlags & SAVELAYERREC_HAS_BOUNDS) {
+ rec.fBounds = &reader->skipT<SkRect>();
+ }
+ if (flatFlags & SAVELAYERREC_HAS_PAINT) {
+ rec.fPaint = fPictureData->getPaint(reader);
+ }
+ if (flatFlags & SAVELAYERREC_HAS_BACKDROP) {
+ const SkPaint* paint = fPictureData->getPaint(reader);
+ rec.fBackdrop = paint->getImageFilter();
+ }
+ if (flatFlags & SAVELAYERREC_HAS_FLAGS) {
+ rec.fSaveLayerFlags = reader->readInt();
+ }
+ canvas->saveLayer(rec);
+ } break;
case SCALE: {
SkScalar sx = reader->readScalar();
SkScalar sy = reader->readScalar();
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 7907ee0d29..2822a1ac16 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -76,19 +76,44 @@ SkCanvas::SaveLayerStrategy SkPictureRecord::getSaveLayerStrategy(const SaveLaye
void SkPictureRecord::recordSaveLayer(const SaveLayerRec& rec) {
fContentInfo.onSaveLayer();
- // op + bool for 'bounds'
+ // op + flatflags
size_t size = 2 * kUInt32Size;
+ uint32_t flatFlags = 0;
+
if (rec.fBounds) {
- size += sizeof(*rec.fBounds); // + rect
+ flatFlags |= SAVELAYERREC_HAS_BOUNDS;
+ size += sizeof(*rec.fBounds);
+ }
+ if (rec.fPaint) {
+ flatFlags |= SAVELAYERREC_HAS_PAINT;
+ size += sizeof(uint32_t); // index
+ }
+ if (rec.fBackdrop) {
+ flatFlags |= SAVELAYERREC_HAS_BACKDROP;
+ size += sizeof(uint32_t); // (paint) index
+ }
+ if (rec.fSaveLayerFlags) {
+ flatFlags |= SAVELAYERREC_HAS_FLAGS;
+ size += sizeof(uint32_t);
}
- // + paint index + flags
- size += 2 * kUInt32Size;
-
- size_t initialOffset = this->addDraw(SAVE_LAYER_SAVELAYERFLAGS, &size);
- this->addRectPtr(rec.fBounds);
- this->addPaintPtr(rec.fPaint);
- this->addInt(rec.fSaveLayerFlags);
+ const size_t initialOffset = this->addDraw(SAVE_LAYER_SAVELAYERREC, &size);
+ this->addInt(flatFlags);
+ if (flatFlags & SAVELAYERREC_HAS_BOUNDS) {
+ this->addRect(*rec.fBounds);
+ }
+ if (flatFlags & SAVELAYERREC_HAS_PAINT) {
+ this->addPaintPtr(rec.fPaint);
+ }
+ if (flatFlags & SAVELAYERREC_HAS_BACKDROP) {
+ // overkill, but we didn't already track single flattenables, so using a paint for that
+ SkPaint paint;
+ paint.setImageFilter(const_cast<SkImageFilter*>(rec.fBackdrop));
+ this->addPaint(paint);
+ }
+ if (flatFlags & SAVELAYERREC_HAS_FLAGS) {
+ this->addInt(rec.fSaveLayerFlags);
+ }
this->validate(initialOffset, size);
}
@@ -224,7 +249,8 @@ void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t
uint32_t opSize;
DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
SkASSERT(SAVE_LAYER_SAVEFLAGS_DEPRECATED != drawOp);
- SkASSERT(SAVE == drawOp || SAVE_LAYER_SAVELAYERFLAGS == drawOp);
+ SkASSERT(SAVE_LAYER_SAVELAYERFLAGS_DEPRECATED_JAN_2016 != drawOp);
+ SkASSERT(SAVE == drawOp || SAVE_LAYER_SAVELAYERREC == drawOp);
}
#endif
}
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 01846676b6..5ca9517d3f 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -78,7 +78,7 @@ template <> void Draw::draw(const NoOp&) {}
#define DRAW(T, call) template <> void Draw::draw(const T& r) { fCanvas->call; }
DRAW(Restore, restore());
DRAW(Save, save());
-DRAW(SaveLayer, saveLayer(SkCanvas::SaveLayerRec(r.bounds, r.paint, r.saveLayerFlags)));
+DRAW(SaveLayer, saveLayer(SkCanvas::SaveLayerRec(r.bounds, r.paint, r.backdrop, r.saveLayerFlags)));
DRAW(SetMatrix, setMatrix(SkMatrix::Concat(fInitialCTM, r.matrix)));
DRAW(Concat, concat(r.matrix));
diff --git a/src/core/SkRecordOpts.cpp b/src/core/SkRecordOpts.cpp
index d1520adf56..0121ea54fc 100644
--- a/src/core/SkRecordOpts.cpp
+++ b/src/core/SkRecordOpts.cpp
@@ -177,6 +177,11 @@ struct SaveLayerDrawRestoreNooper {
typedef Pattern<Is<SaveLayer>, IsDraw, Is<Restore>> Match;
bool onMatch(SkRecord* record, Match* match, int begin, int end) {
+ if (match->first<SaveLayer>()->backdrop) {
+ // can't throw away the layer if we have a backdrop
+ return false;
+ }
+
// A SaveLayer's bounds field is just a hint, so we should be free to ignore it.
SkPaint* layerPaint = match->first<SaveLayer>()->paint;
if (nullptr == layerPaint) {
@@ -224,6 +229,11 @@ struct SvgOpacityAndFilterLayerMergePass {
Is<Restore>, Is<Restore>, Is<Restore>> Match;
bool onMatch(SkRecord* record, Match* match, int begin, int end) {
+ if (match->first<SaveLayer>()->backdrop) {
+ // can't throw away the layer if we have a backdrop
+ return false;
+ }
+
SkPaint* opacityPaint = match->first<SaveLayer>()->paint;
if (nullptr == opacityPaint) {
// There wasn't really any point to this SaveLayer at all.
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 67429a691e..01c28dfc2b 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -337,7 +337,8 @@ void SkRecorder::willSave() {
}
SkCanvas::SaveLayerStrategy SkRecorder::getSaveLayerStrategy(const SaveLayerRec& rec) {
- APPEND(SaveLayer, this->copy(rec.fBounds), this->copy(rec.fPaint), rec.fSaveLayerFlags);
+ APPEND(SaveLayer,
+ this->copy(rec.fBounds), this->copy(rec.fPaint), rec.fBackdrop, rec.fSaveLayerFlags);
return SkCanvas::kNoLayer_SaveLayerStrategy;
}
diff --git a/tests/RecordOptsTest.cpp b/tests/RecordOptsTest.cpp
index dd6c410ed4..027ea39f57 100644
--- a/tests/RecordOptsTest.cpp
+++ b/tests/RecordOptsTest.cpp
@@ -107,6 +107,20 @@ static void assert_savelayer_restore(skiatest::Reporter* r,
SkRecordNoopSaveLayerDrawRestores(record);
if (shouldBeNoOped) {
assert_type<SkRecords::NoOp>(r, *record, i);
+ assert_type<SkRecords::NoOp>(r, *record, i+1);
+ } else {
+ assert_type<SkRecords::SaveLayer>(r, *record, i);
+ assert_type<SkRecords::Restore>(r, *record, i+1);
+ }
+}
+
+static void assert_savelayer_draw_restore(skiatest::Reporter* r,
+ SkRecord* record,
+ int i,
+ bool shouldBeNoOped) {
+ SkRecordNoopSaveLayerDrawRestores(record);
+ if (shouldBeNoOped) {
+ assert_type<SkRecords::NoOp>(r, *record, i);
assert_type<SkRecords::NoOp>(r, *record, i+2);
} else {
assert_type<SkRecords::SaveLayer>(r, *record, i);
@@ -114,6 +128,7 @@ static void assert_savelayer_restore(skiatest::Reporter* r,
}
}
+#include "SkBlurImageFilter.h"
DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) {
SkRecord record;
SkRecorder recorder(&record, W, H);
@@ -134,13 +149,13 @@ DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) {
recorder.saveLayer(nullptr, nullptr);
recorder.drawRect(draw, opaqueDrawPaint);
recorder.restore();
- assert_savelayer_restore(r, &record, 0, true);
+ assert_savelayer_draw_restore(r, &record, 0, true);
// Bounds don't matter.
recorder.saveLayer(&bounds, nullptr);
recorder.drawRect(draw, opaqueDrawPaint);
recorder.restore();
- assert_savelayer_restore(r, &record, 3, true);
+ assert_savelayer_draw_restore(r, &record, 3, true);
// TODO(mtklein): test case with null draw paint
@@ -148,29 +163,36 @@ DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) {
recorder.saveLayer(nullptr, &translucentLayerPaint);
recorder.drawRect(draw, opaqueDrawPaint);
recorder.restore();
- assert_savelayer_restore(r, &record, 6, false);
+ assert_savelayer_draw_restore(r, &record, 6, false);
// No change: layer paint has an effect.
recorder.saveLayer(nullptr, &xfermodeLayerPaint);
recorder.drawRect(draw, opaqueDrawPaint);
recorder.restore();
- assert_savelayer_restore(r, &record, 9, false);
+ assert_savelayer_draw_restore(r, &record, 9, false);
// SaveLayer/Restore removed: we can fold in the alpha!
recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
recorder.drawRect(draw, translucentDrawPaint);
recorder.restore();
- assert_savelayer_restore(r, &record, 12, true);
+ assert_savelayer_draw_restore(r, &record, 12, true);
// SaveLayer/Restore removed: we can fold in the alpha!
recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
recorder.drawRect(draw, opaqueDrawPaint);
recorder.restore();
- assert_savelayer_restore(r, &record, 15, true);
+ assert_savelayer_draw_restore(r, &record, 15, true);
const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, record, 16);
REPORTER_ASSERT(r, drawRect != nullptr);
REPORTER_ASSERT(r, drawRect->paint.getColor() == 0x03020202);
+
+ // saveLayer w/ backdrop should NOT go away
+ SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(3, 3));
+ recorder.saveLayer({ nullptr, nullptr, filter, 0});
+ recorder.drawRect(draw, opaqueDrawPaint);
+ recorder.restore();
+ assert_savelayer_draw_restore(r, &record, 18, false);
}
static void assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter* r,
@@ -222,25 +244,38 @@ DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers, r) {
int index = 0;
{
+ SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(3, 3));
+ // first (null) should be optimized, 2nd should not
+ SkImageFilter* filters[] = { nullptr, filter.get() };
+
// Any combination of these should cause the pattern to be optimized.
SkRect* firstBounds[] = { nullptr, &bounds };
SkPaint* firstPaints[] = { nullptr, &alphaOnlyLayerPaint };
SkRect* secondBounds[] = { nullptr, &bounds };
SkPaint* secondPaints[] = { &opaqueFilterLayerPaint, &translucentFilterLayerPaint };
- for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) {
- for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) {
- for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) {
- for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) {
- recorder.saveLayer(firstBounds[i], firstPaints[j]);
- recorder.save();
- recorder.clipRect(clip);
- recorder.saveLayer(secondBounds[k], secondPaints[m]);
- recorder.restore();
- recorder.restore();
- recorder.restore();
- assert_merge_svg_opacity_and_filter_layers(r, &record, index, true);
- index += 7;
+ for (auto outerF : filters) {
+ bool outerNoOped = !outerF;
+ for (auto innerF : filters) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) {
+ for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) {
+ for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) {
+ for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) {
+ bool innerNoOped = !secondBounds[k] && !secondPaints[m] && !innerF;
+
+ recorder.saveLayer({firstBounds[i], firstPaints[j], outerF, 0});
+ recorder.save();
+ recorder.clipRect(clip);
+ recorder.saveLayer({secondBounds[k], secondPaints[m], innerF, 0});
+ recorder.restore();
+ recorder.restore();
+ recorder.restore();
+ assert_merge_svg_opacity_and_filter_layers(r, &record, index,
+ outerNoOped);
+ assert_savelayer_restore(r, &record, index + 3, innerNoOped);
+ index += 7;
+ }
+ }
}
}
}