add backdrop option to SaveLayerRec

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1523053003

Review URL: https://codereview.chromium.org/1523053003
This commit is contained in:
reed 2016-01-07 07:44:35 -08:00 committed by Commit bot
parent 5820fe846f
commit 247415969a
11 changed files with 252 additions and 29 deletions

View File

@ -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();
}
}

View File

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

View File

@ -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,

View File

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

View File

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

View File

@ -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 =

View File

@ -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

View File

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

View File

@ -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
}

View File

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

View File

@ -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;
}