option to return drawable from recording

patch from issue 747033005 at patchset 80001 (http://crrev.com/747033005#ps80001)

BUG=skia:

Review URL: https://codereview.chromium.org/732653004
This commit is contained in:
reed 2014-11-24 14:41:51 -08:00 committed by Commit bot
parent 89ff0846fd
commit 1bdfd3f4f0
16 changed files with 280 additions and 117 deletions

View File

@ -268,9 +268,9 @@ private:
const uint32_t fUniqueID;
const SkRect fCullRect;
mutable SkAutoTUnref<const AccelData> fAccelData;
SkAutoTDelete<const SkRecord> fRecord;
SkAutoTUnref<const SkBBoxHierarchy> fBBH;
SkAutoTDelete<const SnapshotArray> fDrawablePicts;
SkAutoTUnref<const SkRecord> fRecord;
SkAutoTUnref<const SkBBoxHierarchy> fBBH;
SkAutoTDelete<const SnapshotArray> fDrawablePicts;
// helpers for fDrawablePicts
int drawableCount() const;
@ -298,6 +298,7 @@ private:
friend class GrLayerHoister; // access to fRecord
friend class ReplaceDraw;
friend class SkPictureUtils;
friend class SkRecordedDrawable;
};
SK_COMPILE_ASSERT(sizeof(SkPicture) <= 96, SkPictureSize);

View File

@ -19,6 +19,7 @@ namespace android {
#endif
class SkCanvas;
class SkCanvasDrawable;
class SkPictureRecord;
class SkRecord;
class SkRecorder;
@ -65,12 +66,32 @@ public:
*/
SkCanvas* getRecordingCanvas();
/** Signal that the caller is done recording. This invalidates the canvas
returned by beginRecording/getRecordingCanvas, and returns the
created SkPicture. Note that the returned picture has its creation
ref which the caller must take ownership of.
*/
SkPicture* endRecording();
/**
* Signal that the caller is done recording. This invalidates the canvas returned by
* beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who
* must call unref() when they are done using it.
*
* The returned picture is immutable. If during recording drawables were added to the canvas,
* these will have been "drawn" into a recording canvas, so that this resulting picture will
* reflect their current state, but will not contain a live reference to the drawables
* themselves.
*/
SkPicture* endRecordingAsPicture();
/**
* Signal that the caller is done recording. This invalidates the canvas returned by
* beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who
* must call unref() when they are done using it.
*
* Unlike endRecordingAsPicture(), which returns an immutable picture, the returned drawable
* may contain live references to other drawables (if they were added to the recording canvas)
* and therefore this drawable will reflect the current state of those nested drawables anytime
* it is drawn or a new picture is snapped from it (by calling drawable->newPictureSnapshot()).
*/
SkCanvasDrawable* EXPERIMENTAL_endRecordingAsDrawable();
// Legacy API -- use endRecordingAsPicture instead.
SkPicture* endRecording() { return this->endRecordingAsPicture(); }
private:
void reset();
@ -88,7 +109,8 @@ private:
SkRect fCullRect;
SkAutoTUnref<SkBBoxHierarchy> fBBH;
SkAutoTUnref<SkRecorder> fRecorder;
SkAutoTDelete<SkRecord> fRecord;
SkAutoTUnref<SkRecord> fRecord;
SkBBHFactory* fBBHFactory;
typedef SkNoncopyable INHERITED;
};

View File

@ -17,6 +17,7 @@
#include "Sk1DPathEffect.h"
#include "SkCornerPathEffect.h"
#include "SkPathMeasure.h"
#include "SkPictureRecorder.h"
#include "SkRandom.h"
#include "SkColorPriv.h"
#include "SkColorFilter.h"
@ -42,8 +43,7 @@ class ArcsView : public SampleView {
SkRect fR;
SkScalar fSweep;
public:
MyDrawable(const SkRect& r) : fR(r), fSweep(0) {
}
MyDrawable(const SkRect& r) : fR(r), fSweep(0) {}
void setSweep(SkScalar sweep) {
if (fSweep != sweep) {
@ -82,7 +82,8 @@ class ArcsView : public SampleView {
public:
SkRect fRect;
MyDrawable* fDrawable;
MyDrawable* fAnimatingDrawable;
SkCanvasDrawable* fRootDrawable;
ArcsView() {
testparse();
@ -91,16 +92,21 @@ public:
fRect.set(0, 0, SkIntToScalar(200), SkIntToScalar(200));
fRect.offset(SkIntToScalar(20), SkIntToScalar(20));
fDrawable = SkNEW_ARGS(MyDrawable, (fRect));
fAnimatingDrawable = SkNEW_ARGS(MyDrawable, (fRect));
SkPictureRecorder recorder;
this->drawRoot(recorder.beginRecording(SkRect::MakeWH(800, 500)));
fRootDrawable = recorder.EXPERIMENTAL_endRecordingAsDrawable();
}
virtual ~ArcsView() SK_OVERRIDE {
fDrawable->unref();
fAnimatingDrawable->unref();
fRootDrawable->unref();
}
protected:
// overrides from SkEventSink
virtual bool onQuery(SkEvent* evt) {
bool onQuery(SkEvent* evt) SK_OVERRIDE {
if (SampleCode::TitleQ(*evt)) {
SampleCode::TitleR(evt, "Arcs");
return true;
@ -108,7 +114,7 @@ protected:
return this->INHERITED::onQuery(evt);
}
static void drawRectWithLines(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
static void DrawRectWithLines(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
canvas->drawRect(r, p);
canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, p);
canvas->drawLine(r.fLeft, r.fBottom, r.fRight, r.fTop, p);
@ -116,7 +122,7 @@ protected:
canvas->drawLine(r.centerX(), r.fTop, r.centerX(), r.fBottom, p);
}
static void draw_label(SkCanvas* canvas, const SkRect& rect,
static void DrawLabel(SkCanvas* canvas, const SkRect& rect,
int start, int sweep) {
SkPaint paint;
@ -132,7 +138,7 @@ protected:
rect.fBottom + paint.getTextSize() * 5/4, paint);
}
static void drawArcs(SkCanvas* canvas) {
static void DrawArcs(SkCanvas* canvas) {
SkPaint paint;
SkRect r;
SkScalar w = SkIntToScalar(75);
@ -161,13 +167,13 @@ protected:
for (size_t i = 0; i < SK_ARRAY_COUNT(gAngles); i += 2) {
paint.setColor(SK_ColorBLACK);
drawRectWithLines(canvas, r, paint);
DrawRectWithLines(canvas, r, paint);
paint.setColor(SK_ColorRED);
canvas->drawArc(r, SkIntToScalar(gAngles[i]),
SkIntToScalar(gAngles[i+1]), false, paint);
draw_label(canvas, r, gAngles[i], gAngles[i+1]);
DrawLabel(canvas, r, gAngles[i], gAngles[i+1]);
canvas->translate(w * 8 / 7, 0);
}
@ -175,34 +181,31 @@ protected:
canvas->restore();
}
virtual void onDrawContent(SkCanvas* canvas) {
fDrawable->setSweep(SampleCode::GetAnimScalar(SkIntToScalar(360)/24,
SkIntToScalar(360)));
void drawRoot(SkCanvas* canvas) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setStrokeWidth(SkIntToScalar(2));
paint.setStyle(SkPaint::kStroke_Style);
drawRectWithLines(canvas, fRect, paint);
DrawRectWithLines(canvas, fRect, paint);
canvas->EXPERIMENTAL_drawDrawable(fDrawable);
canvas->EXPERIMENTAL_drawDrawable(fAnimatingDrawable);
drawArcs(canvas);
DrawArcs(canvas);
}
void onDrawContent(SkCanvas* canvas) SK_OVERRIDE {
fAnimatingDrawable->setSweep(SampleCode::GetAnimScalar(360/24, 360));
canvas->EXPERIMENTAL_drawDrawable(fRootDrawable);
this->inval(NULL);
}
virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
unsigned modi) {
SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) SK_OVERRIDE {
// fSweep += SK_Scalar1;
this->inval(NULL);
return this->INHERITED::onFindClickHandler(x, y, modi);
}
virtual bool onClick(Click* click) {
return this->INHERITED::onClick(click);
}
private:
SkScalar fSweep;

View File

@ -41,8 +41,8 @@ void SkCanvasDrawable::draw(SkCanvas* canvas) {
}
}
SkPicture* SkCanvasDrawable::newPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags) {
return this->onNewPictureSnapshot(bbhFactory, recordFlags);
SkPicture* SkCanvasDrawable::newPictureSnapshot() {
return this->onNewPictureSnapshot();
}
uint32_t SkCanvasDrawable::getGenerationID() {
@ -64,11 +64,11 @@ void SkCanvasDrawable::notifyDrawingChanged() {
#include "SkPictureRecorder.h"
SkPicture* SkCanvasDrawable::onNewPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags) {
SkPicture* SkCanvasDrawable::onNewPictureSnapshot() {
SkPictureRecorder recorder;
const SkRect bounds = this->getBounds();
SkCanvas* canvas = recorder.beginRecording(bounds, bbhFactory, recordFlags);
SkCanvas* canvas = recorder.beginRecording(bounds, NULL, 0);
this->draw(canvas);
if (false) {
draw_bbox(canvas, bounds);

View File

@ -10,8 +10,8 @@
#include "SkRefCnt.h"
class SkBBHFactory;
class SkCanvas;
class SkPicture;
struct SkRect;
/**
@ -32,10 +32,7 @@ public:
*/
void draw(SkCanvas*);
SkPicture* newPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags);
SkPicture* newPictureSnapshot() {
return this->newPictureSnapshot(NULL, 0);
}
SkPicture* newPictureSnapshot();
/**
* Return a unique value for this instance. If two calls to this return the same value,
@ -63,7 +60,7 @@ public:
protected:
virtual SkRect onGetBounds() = 0;
virtual void onDraw(SkCanvas*) = 0;
virtual SkPicture* onNewPictureSnapshot(SkBBHFactory*, uint32_t recordFlags);
virtual SkPicture* onNewPictureSnapshot();
private:
int32_t fGenerationID;

View File

@ -319,7 +319,7 @@ void SkPicture::playback(SkCanvas* canvas, SkDrawPictureCallback* callback) cons
(void)canvas->getClipBounds(&clipBounds);
const bool useBBH = !clipBounds.contains(this->cullRect());
SkRecordDraw(*fRecord, canvas, this->drawablePicts(), this->drawableCount(),
SkRecordDraw(*fRecord, canvas, this->drawablePicts(), NULL, this->drawableCount(),
useBBH ? fBBH.get() : NULL, callback);
}
@ -474,7 +474,7 @@ SkPictureData* SkPicture::Backport(const SkRecord& src, const SkPictInfo& info,
SkPicture const* const drawablePicts[], int drawableCount) {
SkPictureRecord rec(SkISize::Make(info.fCullRect.width(), info.fCullRect.height()), 0/*flags*/);
rec.beginRecording();
SkRecordDraw(src, &rec, drawablePicts, drawableCount, NULL/*bbh*/, NULL/*callback*/);
SkRecordDraw(src, &rec, drawablePicts, NULL, drawableCount, NULL/*bbh*/, NULL/*callback*/);
rec.endRecording();
return SkNEW_ARGS(SkPictureData, (rec, info, false/*deep copy ops?*/));
}
@ -526,8 +526,8 @@ SkPicture::SkPicture(const SkRect& cullRect, SkRecord* record, SnapshotArray* dr
SkBBoxHierarchy* bbh)
: fUniqueID(next_picture_generation_id())
, fCullRect(cullRect)
, fRecord(record)
, fRecord(SkRef(record))
, fBBH(SkSafeRef(bbh))
, fDrawablePicts(drawablePicts)
, fDrawablePicts(drawablePicts) // take ownership
, fAnalysis(*fRecord)
{}

View File

@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
#include "SkCanvasDrawable.h"
#include "SkData.h"
#include "SkLayerInfo.h"
#include "SkPictureRecorder.h"
@ -14,7 +15,7 @@
#include "SkRecordOpts.h"
#include "SkTypes.h"
SkPictureRecorder::SkPictureRecorder() {}
SkPictureRecorder::SkPictureRecorder() : fBBHFactory(NULL) {}
SkPictureRecorder::~SkPictureRecorder() {}
@ -22,6 +23,7 @@ SkCanvas* SkPictureRecorder::beginRecording(const SkRect& cullRect,
SkBBHFactory* bbhFactory /* = NULL */,
uint32_t recordFlags /* = 0 */) {
fCullRect = cullRect;
fBBHFactory = bbhFactory;
fFlags = recordFlags;
if (bbhFactory) {
@ -38,7 +40,7 @@ SkCanvas* SkPictureRecorder::getRecordingCanvas() {
return fRecorder.get();
}
SkPicture* SkPictureRecorder::endRecording() {
SkPicture* SkPictureRecorder::endRecordingAsPicture() {
// TODO: delay as much of this work until just before first playback?
SkRecordOptimize(fRecord);
@ -50,26 +52,23 @@ SkPicture* SkPictureRecorder::endRecording() {
saveLayerData.reset(SkNEW_ARGS(SkLayerInfo, (key)));
}
SkCanvasDrawableList* drawableList = fRecorder->getDrawableList();
SkPicture::SnapshotArray* pictList = drawableList ? drawableList->newDrawableSnapshot() : NULL;
if (fBBH.get()) {
if (saveLayerData) {
SkRecordComputeLayers(fCullRect, *fRecord, fBBH.get(), saveLayerData);
SkRecordComputeLayers(fCullRect, *fRecord, pictList, fBBH.get(), saveLayerData);
} else {
SkRecordFillBounds(fCullRect, *fRecord, fBBH.get());
}
}
// TODO: we should remember these from our caller
SkBBHFactory* factory = NULL;
uint32_t recordFlags = 0;
SkAutoTDelete<SkPicture::SnapshotArray> drawablePicts(
fRecorder->newDrawableSnapshot(factory, recordFlags));
SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullRect, fRecord.detach(),
drawablePicts.detach(), fBBH.get()));
SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullRect, fRecord, pictList, fBBH));
if (saveLayerData) {
pict->EXPERIMENTAL_addAccelData(saveLayerData);
}
return pict;
}
@ -79,5 +78,86 @@ void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
}
int drawableCount = 0;
SkRecordDraw(*fRecord, canvas, NULL, drawableCount, NULL/*bbh*/, NULL/*callback*/);
SkCanvasDrawable* const* drawables = NULL;
SkCanvasDrawableList* drawableList = fRecorder->getDrawableList();
if (drawableList) {
drawableCount = drawableList->count();
drawables = drawableList->begin();
}
SkRecordDraw(*fRecord, canvas, NULL, drawables, drawableCount, NULL/*bbh*/, NULL/*callback*/);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
class SkRecordedDrawable : public SkCanvasDrawable {
SkAutoTUnref<SkRecord> fRecord;
SkAutoTUnref<SkBBoxHierarchy> fBBH;
SkAutoTDelete<SkCanvasDrawableList> fDrawableList;
const SkRect fBounds;
const bool fDoSaveLayerInfo;
public:
SkRecordedDrawable(SkRecord* record, SkBBoxHierarchy* bbh, SkCanvasDrawableList* drawableList,
const SkRect& bounds, bool doSaveLayerInfo)
: fRecord(SkRef(record))
, fBBH(SkSafeRef(bbh))
, fDrawableList(drawableList) // we take ownership
, fBounds(bounds)
, fDoSaveLayerInfo(doSaveLayerInfo)
{}
protected:
SkRect onGetBounds() SK_OVERRIDE { return fBounds; }
void onDraw(SkCanvas* canvas) SK_OVERRIDE {
SkCanvasDrawable* const* drawables = NULL;
int drawableCount = 0;
if (fDrawableList) {
drawables = fDrawableList->begin();
drawableCount = fDrawableList->count();
}
SkRecordDraw(*fRecord, canvas, NULL, drawables, drawableCount, fBBH, NULL/*callback*/);
}
SkPicture* onNewPictureSnapshot() SK_OVERRIDE {
SkPicture::SnapshotArray* pictList = NULL;
if (fDrawableList) {
// TODO: should we plumb-down the BBHFactory and recordFlags from our host
// PictureRecorder?
pictList = fDrawableList->newDrawableSnapshot();
}
SkAutoTUnref<SkLayerInfo> saveLayerData;
if (fBBH && fDoSaveLayerInfo) {
SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
saveLayerData.reset(SkNEW_ARGS(SkLayerInfo, (key)));
SkBBoxHierarchy* bbh = NULL; // we've already computed fBBH (received in constructor)
// TODO: update saveLayer info computation to reuse the already computed
// bounds in 'fBBH'
SkRecordComputeLayers(fBounds, *fRecord, pictList, bbh, saveLayerData);
}
SkPicture* pict = SkNEW_ARGS(SkPicture, (fBounds, fRecord, pictList, fBBH));
if (saveLayerData) {
pict->EXPERIMENTAL_addAccelData(saveLayerData);
}
return pict;
}
};
SkCanvasDrawable* SkPictureRecorder::EXPERIMENTAL_endRecordingAsDrawable() {
// TODO: delay as much of this work until just before first playback?
SkRecordOptimize(fRecord);
if (fBBH.get()) {
SkRecordFillBounds(fCullRect, *fRecord, fBBH.get());
}
return SkNEW_ARGS(SkRecordedDrawable, (fRecord, fBBH, fRecorder->detachDrawableList(),
fCullRect,
SkToBool(fFlags & kComputeSaveLayerInfo_RecordFlag)));
}

View File

@ -25,7 +25,7 @@
// only with SkRecords::* structs defined in SkRecords.h. Your compiler will helpfully yell if you
// get this wrong.
class SkRecord : SkNoncopyable {
class SkRecord : public SkNVRefCnt<SkRecord> {
enum {
kFirstReserveCount = 64 / sizeof(void*),
};
@ -240,6 +240,6 @@ private:
// Strangely the order of these fields matters. If the unsigneds don't go first we're 56 bytes.
// tomhudson and mtklein have no idea why.
};
SK_COMPILE_ASSERT(sizeof(SkRecord) <= 48, SkRecordSize);
SK_COMPILE_ASSERT(sizeof(SkRecord) <= 56, SkRecordSize);
#endif//SkRecord_DEFINED

View File

@ -11,7 +11,9 @@
void SkRecordDraw(const SkRecord& record,
SkCanvas* canvas,
SkPicture const* const drawablePicts[], int drawableCount,
SkPicture const* const drawablePicts[],
SkCanvasDrawable* const drawables[],
int drawableCount,
const SkBBoxHierarchy* bbh,
SkDrawPictureCallback* callback) {
SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
@ -32,7 +34,7 @@ void SkRecordDraw(const SkRecord& record,
SkTDArray<unsigned> ops;
bbh->search(query, &ops);
SkRecords::Draw draw(canvas, drawablePicts, drawableCount);
SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount);
for (int i = 0; i < ops.count(); i++) {
if (callback && callback->abortDrawing()) {
return;
@ -44,7 +46,7 @@ void SkRecordDraw(const SkRecord& record,
}
} else {
// Draw all ops.
SkRecords::Draw draw(canvas, drawablePicts, drawableCount);
SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount);
for (unsigned i = 0; i < record.count(); i++) {
if (callback && callback->abortDrawing()) {
return;
@ -133,7 +135,12 @@ DRAW(DrawData, drawData(r.data, r.length));
template <> void Draw::draw(const DrawDrawable& r) {
SkASSERT(r.index >= 0);
SkASSERT(r.index < fDrawableCount);
fCanvas->drawPicture(fDrawablePicts[r.index]);
if (fDrawables) {
SkASSERT(NULL == fDrawablePicts);
fCanvas->EXPERIMENTAL_drawDrawable(fDrawables[r.index]);
} else {
fCanvas->drawPicture(fDrawablePicts[r.index]);
}
}
// This is an SkRecord visitor that fills an SkBBoxHierarchy.
@ -159,7 +166,8 @@ public:
FillBounds(const SkRect& cullRect, const SkRecord& record)
: fNumRecords(record.count())
, fCullRect(cullRect)
, fBounds(record.count()) {
, fBounds(record.count())
{
// Calculate bounds for all ops. This won't go quite in order, so we'll need
// to store the bounds separately then feed them in to the BBH later in order.
fCTM = &SkMatrix::I();
@ -591,11 +599,13 @@ private:
// SkRecord visitor to gather saveLayer/restore information.
class CollectLayers : SkNoncopyable {
public:
CollectLayers(const SkRect& cullRect, const SkRecord& record, SkLayerInfo* accelData)
CollectLayers(const SkRect& cullRect, const SkRecord& record,
const SkPicture::SnapshotArray* pictList, SkLayerInfo* accelData)
: fSaveLayersInStack(0)
, fAccelData(accelData)
, fFillBounds(cullRect, record) {
}
, fPictList(pictList)
, fFillBounds(cullRect, record)
{}
void setCurrentOp(unsigned currentOp) { fFillBounds.setCurrentOp(currentOp); }
@ -638,13 +648,13 @@ private:
void trackSaveLayers(const SaveLayer& sl) { this->pushSaveLayerInfo(true, sl.paint); }
void trackSaveLayers(const Restore& r) { this->popSaveLayerInfo(); }
void trackSaveLayers(const DrawPicture& dp) {
void trackSaveLayersForPicture(const SkPicture* picture, const SkPaint* paint) {
// For sub-pictures, we wrap their layer information within the parent
// picture's rendering hierarchy
SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
const SkLayerInfo* childData =
static_cast<const SkLayerInfo*>(dp.picture->EXPERIMENTAL_getAccelData(key));
static_cast<const SkLayerInfo*>(picture->EXPERIMENTAL_getAccelData(key));
if (!childData) {
// If the child layer hasn't been generated with saveLayer data we
// assume the worst (i.e., that it does contain layers which nest
@ -658,7 +668,7 @@ private:
for (int i = 0; i < childData->numBlocks(); ++i) {
const SkLayerInfo::BlockInfo& src = childData->block(i);
FillBounds::Bounds newBound = fFillBounds.adjustAndMap(src.fBounds, dp.paint);
FillBounds::Bounds newBound = fFillBounds.adjustAndMap(src.fBounds, paint);
if (newBound.isEmpty()) {
continue;
}
@ -669,7 +679,7 @@ private:
// If src.fPicture is NULL the layer is in dp.picture; otherwise
// it belongs to a sub-picture.
dst.fPicture = src.fPicture ? src.fPicture : static_cast<const SkPicture*>(dp.picture);
dst.fPicture = src.fPicture ? src.fPicture : picture;
dst.fPicture->ref();
dst.fBounds = newBound;
dst.fLocalMat = src.fLocalMat;
@ -685,6 +695,17 @@ private:
}
}
void trackSaveLayers(const DrawPicture& dp) {
this->trackSaveLayersForPicture(dp.picture, dp.paint);
}
void trackSaveLayers(const DrawDrawable& dp) {
SkASSERT(fPictList);
SkASSERT(dp.index >= 0 && dp.index < fPictList->count());
const SkPaint* paint = NULL; // drawables don't get a side-car paint
this->trackSaveLayersForPicture(fPictList->begin()[dp.index], paint);
}
// Inform all the saveLayers already on the stack that they now have a
// nested saveLayer inside them
void updateStackForSaveLayer() {
@ -743,6 +764,7 @@ private:
int fSaveLayersInStack;
SkTDArray<SaveLayerInfo> fSaveLayerStack;
SkLayerInfo* fAccelData;
const SkPicture::SnapshotArray* fPictList;
SkRecords::FillBounds fFillBounds;
};
@ -761,8 +783,9 @@ void SkRecordFillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHi
}
void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record,
SkBBoxHierarchy* bbh, SkLayerInfo* data) {
SkRecords::CollectLayers visitor(cullRect, record, data);
const SkPicture::SnapshotArray* pictList, SkBBoxHierarchy* bbh,
SkLayerInfo* data) {
SkRecords::CollectLayers visitor(cullRect, record, pictList, data);
for (unsigned curOp = 0; curOp < record.count(); curOp++) {
visitor.setCurrentOp(curOp);

View File

@ -14,16 +14,19 @@
#include "SkMatrix.h"
#include "SkRecord.h"
class SkCanvasDrawable;
class SkLayerInfo;
// Fill a BBH to be used by SkRecordDraw to accelerate playback.
void SkRecordFillBounds(const SkRect& cullRect, const SkRecord&, SkBBoxHierarchy*);
void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record,
const SkPicture::SnapshotArray*,
SkBBoxHierarchy* bbh, SkLayerInfo* data);
// Draw an SkRecord into an SkCanvas. A convenience wrapper around SkRecords::Draw.
void SkRecordDraw(const SkRecord&, SkCanvas*, SkPicture const* const drawablePicts[], int drawableCount,
void SkRecordDraw(const SkRecord&, SkCanvas*, SkPicture const* const drawablePicts[],
SkCanvasDrawable* const drawables[], int drawableCount,
const SkBBoxHierarchy*, SkDrawPictureCallback*);
// Draw a portion of an SkRecord into an SkCanvas while replacing clears with drawRects.
@ -41,11 +44,13 @@ namespace SkRecords {
// This is an SkRecord visitor that will draw that SkRecord to an SkCanvas.
class Draw : SkNoncopyable {
public:
explicit Draw(SkCanvas* canvas, SkPicture const* const drawablePicts[], int drawableCount,
explicit Draw(SkCanvas* canvas, SkPicture const* const drawablePicts[],
SkCanvasDrawable* const drawables[], int drawableCount,
const SkMatrix* initialCTM = NULL)
: fInitialCTM(initialCTM ? *initialCTM : canvas->getTotalMatrix())
, fCanvas(canvas)
, fDrawablePicts(drawablePicts)
, fDrawables(drawables)
, fDrawableCount(drawableCount)
{}
@ -67,6 +72,7 @@ private:
const SkMatrix fInitialCTM;
SkCanvas* fCanvas;
SkPicture const* const* fDrawablePicts;
SkCanvasDrawable* const* fDrawables;
int fDrawableCount;
};
@ -75,7 +81,8 @@ class PartialDraw : public Draw {
public:
PartialDraw(SkCanvas* canvas, SkPicture const* const drawablePicts[], int drawableCount,
const SkRect& clearRect, const SkMatrix& initialCTM)
: INHERITED(canvas, drawablePicts, drawableCount, &initialCTM), fClearRect(clearRect) {}
: INHERITED(canvas, drawablePicts, NULL, drawableCount, &initialCTM), fClearRect(clearRect)
{}
// Same as Draw for all ops except Clear.
template <typename T> void operator()(const T& r) {

View File

@ -9,6 +9,28 @@
#include "SkPatchUtils.h"
#include "SkPicture.h"
SkCanvasDrawableList::~SkCanvasDrawableList() {
fArray.unrefAll();
}
SkPicture::SnapshotArray* SkCanvasDrawableList::newDrawableSnapshot() {
const int count = fArray.count();
if (0 == count) {
return NULL;
}
SkAutoTMalloc<const SkPicture*> pics(count);
for (int i = 0; i < count; ++i) {
pics[i] = fArray[i]->newPictureSnapshot();
}
return SkNEW_ARGS(SkPicture::SnapshotArray, (pics.detach(), count));
}
void SkCanvasDrawableList::append(SkCanvasDrawable* drawable) {
*fArray.append() = SkRef(drawable);
}
///////////////////////////////////////////////////////////////////////////////////////////////
SkRecorder::SkRecorder(SkRecord* record, int width, int height)
: SkCanvas(SkIRect::MakeWH(width, height), SkCanvas::kConservativeRasterClip_InitFlag)
, fRecord(record)
@ -19,29 +41,11 @@ SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds)
, fRecord(record)
, fSaveLayerCount(0) {}
SkRecorder::~SkRecorder() {
fDrawableList.unrefAll();
}
void SkRecorder::forgetRecord() {
fDrawableList.unrefAll();
fDrawableList.reset();
fDrawableList.reset(NULL);
fRecord = NULL;
}
SkPicture::SnapshotArray* SkRecorder::newDrawableSnapshot(SkBBHFactory* factory,
uint32_t recordFlags) {
const int count = fDrawableList.count();
if (0 == count) {
return NULL;
}
SkAutoTMalloc<const SkPicture*> pics(count);
for (int i = 0; i < count; ++i) {
pics[i] = fDrawableList[i]->newPictureSnapshot(factory, recordFlags);
}
return SkNEW_ARGS(SkPicture::SnapshotArray, (pics.detach(), count));
}
// To make appending to fRecord a little less verbose.
#define APPEND(T, ...) \
SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__))
@ -146,8 +150,11 @@ void SkRecorder::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const
}
void SkRecorder::onDrawDrawable(SkCanvasDrawable* drawable) {
*fDrawableList.append() = SkRef(drawable);
APPEND(DrawDrawable, drawable->getBounds(), fDrawableList.count() - 1);
if (!fDrawableList) {
fDrawableList.reset(SkNEW(SkCanvasDrawableList));
}
fDrawableList->append(drawable);
APPEND(DrawDrawable, drawable->getBounds(), fDrawableList->count() - 1);
}
void SkRecorder::drawPath(const SkPath& path, const SkPaint& paint) {

View File

@ -13,6 +13,24 @@
#include "SkRecords.h"
#include "SkTDArray.h"
class SkBBHFactory;
class SkCanvasDrawableList : SkNoncopyable {
public:
~SkCanvasDrawableList();
int count() const { return fArray.count(); }
SkCanvasDrawable* const* begin() const { return fArray.begin(); }
void append(SkCanvasDrawable* drawable);
// Return a new or ref'd array of pictures that were snapped from our drawables.
SkPicture::SnapshotArray* newDrawableSnapshot();
private:
SkTDArray<SkCanvasDrawable*> fArray;
};
// SkRecorder provides an SkCanvas interface for recording into an SkRecord.
class SkRecorder : public SkCanvas {
@ -20,10 +38,9 @@ public:
// Does not take ownership of the SkRecord.
SkRecorder(SkRecord*, int width, int height); // legacy version
SkRecorder(SkRecord*, const SkRect& bounds);
virtual ~SkRecorder() SK_OVERRIDE;
// Return a new or ref'd array of pictures that were snapped from our drawables.
SkPicture::SnapshotArray* newDrawableSnapshot(SkBBHFactory*, uint32_t recordFlags);
SkCanvasDrawableList* getDrawableList() const { return fDrawableList.get(); }
SkCanvasDrawableList* detachDrawableList() { return fDrawableList.detach(); }
// Make SkRecorder forget entirely about its SkRecord*; all calls to SkRecorder will fail.
void forgetRecord();
@ -145,7 +162,7 @@ private:
int fSaveLayerCount;
SkTDArray<SkBool8> fSaveIsSaveLayer;
SkTDArray<SkCanvasDrawable*> fDrawableList;
SkAutoTDelete<SkCanvasDrawableList> fDrawableList;
};
#endif//SkRecorder_DEFINED

View File

@ -60,7 +60,7 @@ public:
const GrReplacements* replacements,
const SkMatrix& initialMatrix,
SkDrawPictureCallback* callback)
: INHERITED(canvas, drawablePicts, drawableCount)
: INHERITED(canvas, drawablePicts, NULL, drawableCount)
, fCanvas(canvas)
, fPicture(picture)
, fReplacements(replacements)

View File

@ -1733,7 +1733,8 @@ static void test_bytes_used(skiatest::Reporter* reporter) {
sizeof(SkPicture) + sizeof(SkRecord));
// Protect against any unintentional bloat.
REPORTER_ASSERT(reporter, SkPictureUtils::ApproximateBytesUsed(empty.get()) <= 128);
size_t approxUsed = SkPictureUtils::ApproximateBytesUsed(empty.get());
REPORTER_ASSERT(reporter, approxUsed <= 136);
// Sanity check of nested SkPictures.
SkPictureRecorder r2;
@ -1905,11 +1906,16 @@ DEF_TEST(Picture_BitmapLeak, r) {
REPORTER_ASSERT(r, mut.pixelRef()->unique());
REPORTER_ASSERT(r, immut.pixelRef()->unique());
SkPictureRecorder rec;
SkCanvas* canvas = rec.beginRecording(1920, 1200);
canvas->drawBitmap(mut, 0, 0);
canvas->drawBitmap(immut, 800, 600);
SkAutoTUnref<const SkPicture> pic(rec.endRecording());
SkAutoTUnref<const SkPicture> pic;
{
// we want the recorder to go out of scope before our subsequent checks, so we
// place it inside local braces.
SkPictureRecorder rec;
SkCanvas* canvas = rec.beginRecording(1920, 1200);
canvas->drawBitmap(mut, 0, 0);
canvas->drawBitmap(immut, 800, 600);
pic.reset(rec.endRecording());
}
// The picture shares the immutable pixels but copies the mutable ones.
REPORTER_ASSERT(r, mut.pixelRef()->unique());

View File

@ -41,7 +41,7 @@ DEF_TEST(RecordDraw_Abort, r) {
SkRecorder canvas(&rerecord, W, H);
JustOneDraw callback;
SkRecordDraw(record, &canvas, NULL, 0, NULL/*bbh*/, &callback);
SkRecordDraw(record, &canvas, NULL, NULL, 0, NULL/*bbh*/, &callback);
REPORTER_ASSERT(r, 3 == rerecord.count());
assert_type<SkRecords::Save> (r, rerecord, 0);
@ -56,7 +56,7 @@ DEF_TEST(RecordDraw_Unbalanced, r) {
SkRecord rerecord;
SkRecorder canvas(&rerecord, W, H);
SkRecordDraw(record, &canvas, NULL, 0, NULL/*bbh*/, NULL/*callback*/);
SkRecordDraw(record, &canvas, NULL, NULL, 0, NULL/*bbh*/, NULL/*callback*/);
REPORTER_ASSERT(r, 4 == rerecord.count());
assert_type<SkRecords::Save> (r, rerecord, 0);
@ -80,7 +80,7 @@ DEF_TEST(RecordDraw_SetMatrixClobber, r) {
translate.setTranslate(20, 20);
translateCanvas.setMatrix(translate);
SkRecordDraw(scaleRecord, &translateCanvas, NULL, 0, NULL/*bbh*/, NULL/*callback*/);
SkRecordDraw(scaleRecord, &translateCanvas, NULL, NULL, 0, NULL/*bbh*/, NULL/*callback*/);
REPORTER_ASSERT(r, 4 == translateRecord.count());
assert_type<SkRecords::SetMatrix>(r, translateRecord, 0);
assert_type<SkRecords::Save> (r, translateRecord, 1);
@ -320,7 +320,7 @@ DEF_TEST(RecordDraw_drawImage, r){
SkRecord record;
SkRecorder recorder(&record, 10, 10);
recorder.drawImage(image, 0, 0);
SkRecordDraw(record, &canvas, NULL, 0, NULL, 0);
SkRecordDraw(record, &canvas, NULL, NULL, 0, NULL, 0);
}
REPORTER_ASSERT(r, canvas.fDrawImageCalled);
canvas.resetTestValues();
@ -329,7 +329,7 @@ DEF_TEST(RecordDraw_drawImage, r){
SkRecord record;
SkRecorder recorder(&record, 10, 10);
recorder.drawImageRect(image, 0, SkRect::MakeWH(10, 10));
SkRecordDraw(record, &canvas, NULL, 0, NULL, 0);
SkRecordDraw(record, &canvas, NULL, NULL, 0, NULL, 0);
}
REPORTER_ASSERT(r, canvas.fDrawImageRectCalled);

View File

@ -21,7 +21,7 @@ public:
: fDigits(0)
, fIndent(0)
, fIndex(0)
, fDraw(canvas, NULL, 0, NULL)
, fDraw(canvas, NULL, NULL, 0, NULL)
, fTimeWithCommand(timeWithCommand) {
while (count > 0) {
count /= 10;