aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed <reed@google.com>2014-11-24 14:41:51 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2014-11-24 14:41:51 -0800
commit1bdfd3f4f09e47364f76d3f08177b1ce844ac786 (patch)
tree91b83cdc89f884513bacac06ee8f008f4e8276f8
parent89ff0846fd9dacf5f081373746624d450a5f8c26 (diff)
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
-rw-r--r--include/core/SkPicture.h7
-rw-r--r--include/core/SkPictureRecorder.h36
-rw-r--r--samplecode/SampleArc.cpp51
-rw-r--r--src/core/SkCanvasDrawable.cpp8
-rw-r--r--src/core/SkCanvasDrawable.h9
-rw-r--r--src/core/SkPicture.cpp8
-rw-r--r--src/core/SkPictureRecorder.cpp104
-rw-r--r--src/core/SkRecord.h4
-rw-r--r--src/core/SkRecordDraw.cpp51
-rw-r--r--src/core/SkRecordDraw.h13
-rw-r--r--src/core/SkRecorder.cpp49
-rw-r--r--src/core/SkRecorder.h25
-rw-r--r--src/gpu/GrRecordReplaceDraw.cpp2
-rw-r--r--tests/PictureTest.cpp18
-rw-r--r--tests/RecordDrawTest.cpp10
-rw-r--r--tools/DumpRecord.cpp2
16 files changed, 280 insertions, 117 deletions
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index ebaeef0b7e..07eca144b8 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -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);
diff --git a/include/core/SkPictureRecorder.h b/include/core/SkPictureRecorder.h
index 528472bc22..37cbe8692a 100644
--- a/include/core/SkPictureRecorder.h
+++ b/include/core/SkPictureRecorder.h
@@ -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;
};
diff --git a/samplecode/SampleArc.cpp b/samplecode/SampleArc.cpp
index a44eeb59ba..6943eb7a6c 100644
--- a/samplecode/SampleArc.cpp
+++ b/samplecode/SampleArc.cpp
@@ -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;
diff --git a/src/core/SkCanvasDrawable.cpp b/src/core/SkCanvasDrawable.cpp
index e0120f0bb1..99a4996bc9 100644
--- a/src/core/SkCanvasDrawable.cpp
+++ b/src/core/SkCanvasDrawable.cpp
@@ -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);
diff --git a/src/core/SkCanvasDrawable.h b/src/core/SkCanvasDrawable.h
index f189f2d2cc..bc5b4fd351 100644
--- a/src/core/SkCanvasDrawable.h
+++ b/src/core/SkCanvasDrawable.h
@@ -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;
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index b4c3063991..3e006c1672 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -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)
{}
diff --git a/src/core/SkPictureRecorder.cpp b/src/core/SkPictureRecorder.cpp
index 3262938ed1..d64390c6ef 100644
--- a/src/core/SkPictureRecorder.cpp
+++ b/src/core/SkPictureRecorder.cpp
@@ -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)));
}
diff --git a/src/core/SkRecord.h b/src/core/SkRecord.h
index 403110d385..8179b06376 100644
--- a/src/core/SkRecord.h
+++ b/src/core/SkRecord.h
@@ -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
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 7e35d8a2c7..5e1fe7f0aa 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -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);
diff --git a/src/core/SkRecordDraw.h b/src/core/SkRecordDraw.h
index 8ea1bbd72f..e95123bbe6 100644
--- a/src/core/SkRecordDraw.h
+++ b/src/core/SkRecordDraw.h
@@ -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) {
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 22d742f3e7..3548851a72 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -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) {
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index b532c89060..be67dddd2e 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -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
diff --git a/src/gpu/GrRecordReplaceDraw.cpp b/src/gpu/GrRecordReplaceDraw.cpp
index 49ddf9a76c..dd686d33b9 100644
--- a/src/gpu/GrRecordReplaceDraw.cpp
+++ b/src/gpu/GrRecordReplaceDraw.cpp
@@ -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)
diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp
index ab2fcb7239..64073d3b00 100644
--- a/tests/PictureTest.cpp
+++ b/tests/PictureTest.cpp
@@ -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());
diff --git a/tests/RecordDrawTest.cpp b/tests/RecordDrawTest.cpp
index b7538f1e9a..48981ef0a2 100644
--- a/tests/RecordDrawTest.cpp
+++ b/tests/RecordDrawTest.cpp
@@ -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);
diff --git a/tools/DumpRecord.cpp b/tools/DumpRecord.cpp
index 2d055169c1..4f05fd46c1 100644
--- a/tools/DumpRecord.cpp
+++ b/tools/DumpRecord.cpp
@@ -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;