summaryrefslogtreecommitdiff
path: root/record
diff options
context:
space:
mode:
Diffstat (limited to 'record')
-rw-r--r--record/SkRecord.h37
-rw-r--r--record/SkRecordDraw.cpp86
-rw-r--r--record/SkRecordOpts.cpp217
-rw-r--r--record/SkRecordOpts.h6
-rw-r--r--record/SkRecordTraits.h31
-rw-r--r--record/SkRecorder.cpp4
-rw-r--r--record/SkRecorder.h3
-rw-r--r--record/SkRecording.cpp35
-rw-r--r--record/SkRecords.h10
9 files changed, 206 insertions, 223 deletions
diff --git a/record/SkRecord.h b/record/SkRecord.h
index ddf1b3d9..b1e4ae24 100644
--- a/record/SkRecord.h
+++ b/record/SkRecord.h
@@ -82,20 +82,31 @@ public:
// Replace the i-th command with a new command of type T.
// You are expected to placement new an object of type T onto this pointer.
- // References to the old command remain valid for the life of the SkRecord, but
- // you must destroy the old command. (It's okay to destroy it first before calling replace.)
+ // References to the original command are invalidated.
template <typename T>
T* replace(unsigned i) {
SkASSERT(i < this->count());
+
+ Destroyer destroyer;
+ this->mutate(i, destroyer);
+
fTypes[i] = T::kType;
return fRecords[i].set(this->alloc<T>());
}
- // A mutator that can be used with replace to destroy canvas commands.
- struct Destroyer {
- template <typename T>
- void operator()(T* record) { record->~T(); }
- };
+ // Replace the i-th command with a new command of type T.
+ // You are expected to placement new an object of type T onto this pointer.
+ // You must show proof that you've already adopted the existing command.
+ template <typename T, typename Existing>
+ T* replace(unsigned i, const SkRecords::Adopted<Existing>& proofOfAdoption) {
+ SkASSERT(i < this->count());
+
+ SkASSERT(Existing::kType == fTypes[i]);
+ SkASSERT(proofOfAdoption == fRecords[i].ptr<Existing>());
+
+ fTypes[i] = T::kType;
+ return fRecords[i].set(this->alloc<T>());
+ }
private:
// Implementation notes!
@@ -134,6 +145,11 @@ private:
//
// The cost to append a T into this structure is 1 + sizeof(void*) + sizeof(T).
+ // A mutator that can be used with replace to destroy canvas commands.
+ struct Destroyer {
+ template <typename T>
+ void operator()(T* record) { record->~T(); }
+ };
// Logically the same as SkRecords::Type, but packed into 8 bits.
struct Type8 {
@@ -157,6 +173,10 @@ private:
return ptr;
}
+ // Get the data in fAlloc, assuming it's of type T.
+ template <typename T>
+ T* ptr() const { return (T*)fPtr; }
+
// Visit this record with functor F (see public API above) assuming the record we're
// pointing to has this type.
template <typename F>
@@ -176,9 +196,6 @@ private:
}
private:
- template <typename T>
- T* ptr() const { return (T*)fPtr; }
-
void* fPtr;
};
diff --git a/record/SkRecordDraw.cpp b/record/SkRecordDraw.cpp
index 21b2c7a8..4878b3f4 100644
--- a/record/SkRecordDraw.cpp
+++ b/record/SkRecordDraw.cpp
@@ -12,7 +12,7 @@ namespace {
// This is an SkRecord visitor that will draw that SkRecord to an SkCanvas.
class Draw : SkNoncopyable {
public:
- explicit Draw(SkCanvas* canvas) : fCanvas(canvas), fIndex(0), fClipEmpty(false) {}
+ explicit Draw(SkCanvas* canvas) : fCanvas(canvas), fIndex(0) {}
unsigned index() const { return fIndex; }
void next() { ++fIndex; }
@@ -20,65 +20,36 @@ public:
template <typename T> void operator()(const T& r) {
if (!this->skip(r)) {
this->draw(r);
- this->updateClip<T>();
}
}
private:
- // Return true if we can skip this command, false if not.
- // Update fIndex here directly to skip more than just this one command.
- template <typename T> bool skip(const T&) {
- // We can skip most commands if the clip is empty. Exceptions are specialized below.
- return fClipEmpty;
- }
-
// No base case, so we'll be compile-time checked that we implemented all possibilities below.
template <typename T> void draw(const T&);
- // Update fClipEmpty if necessary.
- template <typename T> void updateClip() {
- // Most commands don't change the clip. Exceptions are specialized below.
+ // skip() should return true if we can skip this command, false if not.
+ // It may update fIndex directly to skip more than just this one command.
+
+ // Mostly we just blindly call fCanvas and let it handle quick rejects itself.
+ template <typename T> bool skip(const T&) { return false; }
+
+ // We add our own quick rejects for commands added by optimizations.
+ bool skip(const SkRecords::PairedPushCull& r) {
+ if (fCanvas->quickReject(r.base->rect)) {
+ fIndex += r.skip;
+ return true;
+ }
+ return false;
+ }
+ bool skip(const SkRecords::BoundedDrawPosTextH& r) {
+ return fCanvas->quickRejectY(r.minY, r.maxY);
}
SkCanvas* fCanvas;
unsigned fIndex;
- bool fClipEmpty;
};
-// TODO(mtklein): do this specialization with template traits instead of macros
-
-// These commands may change the clip.
-#define UPDATE_CLIP(T) template <> void Draw::updateClip<SkRecords::T>() \
- { fClipEmpty = fCanvas->isClipEmpty(); }
-UPDATE_CLIP(Restore);
-UPDATE_CLIP(SaveLayer);
-UPDATE_CLIP(ClipPath);
-UPDATE_CLIP(ClipRRect);
-UPDATE_CLIP(ClipRect);
-UPDATE_CLIP(ClipRegion);
-#undef UPDATE_CLIP
-
-// These commands must always run.
-#define SKIP(T) template <> bool Draw::skip(const SkRecords::T&) { return false; }
-SKIP(Restore);
-SKIP(Save);
-SKIP(SaveLayer);
-SKIP(Clear);
-SKIP(PushCull);
-SKIP(PopCull);
-#undef SKIP
-
-// We can skip these commands if they're intersecting with a clip that's already empty.
-#define SKIP(T) template <> bool Draw::skip(const SkRecords::T& r) \
- { return fClipEmpty && SkRegion::kIntersect_Op == r.op; }
-SKIP(ClipPath);
-SKIP(ClipRRect);
-SKIP(ClipRect);
-SKIP(ClipRegion);
-#undef SKIP
-
-// NoOps can always be skipped and draw nothing.
-template <> bool Draw::skip(const SkRecords::NoOp&) { return true; }
+// NoOps draw nothing.
template <> void Draw::draw(const SkRecords::NoOp&) {}
#define DRAW(T, call) template <> void Draw::draw(const SkRecords::T& r) { fCanvas->call; }
@@ -116,25 +87,8 @@ DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co
r.xmode.get(), r.indices, r.indexCount, r.paint));
#undef DRAW
-// Added by SkRecordAnnotateCullingPairs.
-template <> bool Draw::skip(const SkRecords::PairedPushCull& r) {
- if (fCanvas->quickReject(r.base->rect)) {
- fIndex += r.skip;
- return true;
- }
- return false;
-}
-
-// Added by SkRecordBoundDrawPosTextH
-template <> bool Draw::skip(const SkRecords::BoundedDrawPosTextH& r) {
- return fClipEmpty || fCanvas->quickRejectY(r.minY, r.maxY);
-}
-
-// These draw by proxying to the commands they wrap. (All the optimization is for skip().)
-#define DRAW(T) template <> void Draw::draw(const SkRecords::T& r) { this->draw(*r.base); }
-DRAW(PairedPushCull);
-DRAW(BoundedDrawPosTextH);
-#undef DRAW
+template <> void Draw::draw(const SkRecords::PairedPushCull& r) { this->draw(*r.base); }
+template <> void Draw::draw(const SkRecords::BoundedDrawPosTextH& r) { this->draw(*r.base); }
} // namespace
diff --git a/record/SkRecordOpts.cpp b/record/SkRecordOpts.cpp
index 3cf135fb..5b537de0 100644
--- a/record/SkRecordOpts.cpp
+++ b/record/SkRecordOpts.cpp
@@ -7,6 +7,7 @@
#include "SkRecordOpts.h"
+#include "SkRecordTraits.h"
#include "SkRecords.h"
#include "SkTDArray.h"
@@ -18,10 +19,6 @@ void SkRecordOptimize(SkRecord* record) {
SkRecordBoundDrawPosTextH(record);
}
-// Streamline replacing one command with another.
-#define REPLACE(record, index, T, ...) \
- SkNEW_PLACEMENT_ARGS(record->replace<SkRecords::T>(index), SkRecords::T, (__VA_ARGS__))
-
namespace {
// Convenience base class to share some common implementation code.
@@ -44,9 +41,28 @@ public:
explicit SaveRestoreNooper(SkRecord* record)
: Common(record), fSave(kInactive), fChanged(false) {}
- // Most drawing commands reset to inactive state without nooping anything.
+ // Drawing commands reset state to inactive without nooping.
+ template <typename T>
+ SK_WHEN(SkRecords::IsDraw<T>, void) operator()(T*) { fSave = kInactive; }
+
+ // Most non-drawing commands can be ignored.
template <typename T>
- void operator()(T*) { fSave = kInactive; }
+ SK_WHEN(!SkRecords::IsDraw<T>, void) operator()(T*) {}
+
+ void operator()(SkRecords::Save* r) {
+ fSave = SkCanvas::kMatrixClip_SaveFlag == r->flags ? this->index() : kInactive;
+ }
+
+ void operator()(SkRecords::Restore* r) {
+ if (fSave != kInactive) {
+ // Remove everything between the save and restore, inclusive on both sides.
+ fChanged = true;
+ for (unsigned i = fSave; i <= this->index(); i++) {
+ fRecord->replace<SkRecords::NoOp>(i);
+ }
+ fSave = kInactive;
+ }
+ }
bool changed() const { return fChanged; }
@@ -56,41 +72,6 @@ private:
bool fChanged;
};
-// If the command doesn't draw anything, that doesn't reset the state back to inactive.
-// TODO(mtklein): do this with some sort of template-based trait mechanism instead of macros
-#define DOESNT_DRAW(T) template <> void SaveRestoreNooper::operator()(SkRecords::T*) {}
-DOESNT_DRAW(NoOp)
-DOESNT_DRAW(Concat)
-DOESNT_DRAW(SetMatrix)
-DOESNT_DRAW(ClipRect)
-DOESNT_DRAW(ClipRRect)
-DOESNT_DRAW(ClipPath)
-DOESNT_DRAW(ClipRegion)
-DOESNT_DRAW(PairedPushCull)
-DOESNT_DRAW(PushCull)
-DOESNT_DRAW(PopCull)
-#undef DOESNT_DRAW
-
-template <>
-void SaveRestoreNooper::operator()(SkRecords::Save* r) {
- fSave = SkCanvas::kMatrixClip_SaveFlag == r->flags ? this->index() : kInactive;
-}
-
-template <>
-void SaveRestoreNooper::operator()(SkRecords::Restore* r) {
- if (fSave != kInactive) {
- // Remove everything between the save and restore, inclusive on both sides.
- fChanged = true;
- SkRecord::Destroyer destroyer;
- for (unsigned i = fSave; i <= this->index(); i++) {
- fRecord->mutate(i, destroyer);
- REPLACE(fRecord, i, NoOp);
- }
- fSave = kInactive;
- }
-}
-
-
// Tries to replace PushCull with PairedPushCull, which lets us skip to the paired PopCull
// when the canvas can quickReject the cull rect.
class CullAnnotator : public Common {
@@ -98,8 +79,24 @@ public:
explicit CullAnnotator(SkRecord* record) : Common(record) {}
// Do nothing to most ops.
- template <typename T>
- void operator()(T*) {}
+ template <typename T> void operator()(T*) {}
+
+ void operator()(SkRecords::PushCull* push) {
+ Pair pair = { this->index(), push };
+ fPushStack.push(pair);
+ }
+
+ void operator()(SkRecords::PopCull* pop) {
+ Pair push = fPushStack.top();
+ fPushStack.pop();
+
+ SkASSERT(this->index() > push.index);
+ unsigned skip = this->index() - push.index;
+
+ SkRecords::Adopted<SkRecords::PushCull> adopted(push.command);
+ SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::PairedPushCull>(push.index, adopted),
+ SkRecords::PairedPushCull, (&adopted, skip));
+ }
private:
struct Pair {
@@ -110,66 +107,46 @@ private:
SkTDArray<Pair> fPushStack;
};
-template <>
-void CullAnnotator::operator()(SkRecords::PushCull* push) {
- Pair pair = { this->index(), push };
- fPushStack.push(pair);
-}
-
-template <>
-void CullAnnotator::operator()(SkRecords::PopCull* pop) {
- Pair push = fPushStack.top();
- fPushStack.pop();
-
- SkASSERT(this->index() > push.index);
- unsigned skip = this->index() - push.index;
-
- // PairedPushCull adopts push.command.
- REPLACE(fRecord, push.index, PairedPushCull, push.command, skip);
-}
-
// Replaces DrawPosText with DrawPosTextH when all Y coordinates are equal.
class StrengthReducer : public Common {
public:
explicit StrengthReducer(SkRecord* record) : Common(record) {}
// Do nothing to most ops.
- template <typename T>
- void operator()(T*) {}
-};
+ template <typename T> void operator()(T*) {}
-template <>
-void StrengthReducer::operator()(SkRecords::DrawPosText* r) {
- const unsigned points = r->paint.countText(r->text, r->byteLength);
- if (points == 0) {
- // No point (ha!).
- return;
- }
-
- const SkScalar firstY = r->pos[0].fY;
- for (unsigned i = 1; i < points; i++) {
- if (r->pos[i].fY != firstY) {
- // Needs the full strength of DrawPosText.
+ void operator()(SkRecords::DrawPosText* r) {
+ const unsigned points = r->paint.countText(r->text, r->byteLength);
+ if (points == 0) {
+ // No point (ha!).
return;
}
- }
- // All ys are the same. We can replace DrawPosText with DrawPosTextH.
-
- // r->pos is points SkPoints, [(x,y),(x,y),(x,y),(x,y), ... ].
- // We're going to squint and look at that as 2*points SkScalars, [x,y,x,y,x,y,x,y, ...].
- // Then we'll rearrange things so all the xs are in order up front, clobbering the ys.
- SK_COMPILE_ASSERT(sizeof(SkPoint) == 2 * sizeof(SkScalar), SquintingIsNotSafe);
- SkScalar* scalars = &r->pos[0].fX;
- for (unsigned i = 0; i < 2*points; i += 2) {
- scalars[i/2] = scalars[i];
- }
- SkRecord::Destroyer destroyer;
- fRecord->mutate(this->index(), destroyer);
- REPLACE(fRecord, this->index(),
- DrawPosTextH, (char*)r->text, r->byteLength, scalars, firstY, r->paint);
-}
+ const SkScalar firstY = r->pos[0].fY;
+ for (unsigned i = 1; i < points; i++) {
+ if (r->pos[i].fY != firstY) {
+ // Needs the full strength of DrawPosText.
+ return;
+ }
+ }
+ // All ys are the same. We can replace DrawPosText with DrawPosTextH.
+
+ // r->pos is points SkPoints, [(x,y),(x,y),(x,y),(x,y), ... ].
+ // We're going to squint and look at that as 2*points SkScalars, [x,y,x,y,x,y,x,y, ...].
+ // Then we'll rearrange things so all the xs are in order up front, clobbering the ys.
+ SK_COMPILE_ASSERT(sizeof(SkPoint) == 2 * sizeof(SkScalar), SquintingIsNotSafe);
+ SkScalar* scalars = &r->pos[0].fX;
+ for (unsigned i = 0; i < 2*points; i += 2) {
+ scalars[i/2] = scalars[i];
+ }
+ // Extend lifetime of r to the end of the method so we can copy its parts.
+ SkRecords::Adopted<SkRecords::DrawPosText> adopted(r);
+ SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::DrawPosTextH>(this->index(), adopted),
+ SkRecords::DrawPosTextH,
+ (r->text, r->byteLength, scalars, firstY, r->paint));
+ }
+};
// Tries to replace DrawPosTextH with BoundedDrawPosTextH, which knows conservative upper and lower
// bounds to use with SkCanvas::quickRejectY.
@@ -178,35 +155,37 @@ public:
explicit TextBounder(SkRecord* record) : Common(record) {}
// Do nothing to most ops.
- template <typename T>
- void operator()(T*) {}
-};
+ template <typename T> void operator()(T*) {}
-template <>
-void TextBounder::operator()(SkRecords::DrawPosTextH* r) {
- // If we're drawing vertical text, none of the checks we're about to do make any sense.
- // We'll need to call SkPaint::computeFastBounds() later, so bail if that's not possible.
- if (r->paint.isVerticalText() || !r->paint.canComputeFastBounds()) {
- return;
+ void operator()(SkRecords::DrawPosTextH* r) {
+ // If we're drawing vertical text, none of the checks we're about to do make any sense.
+ // We'll need to call SkPaint::computeFastBounds() later, so bail if that's not possible.
+ if (r->paint.isVerticalText() || !r->paint.canComputeFastBounds()) {
+ return;
+ }
+
+ // Rather than checking the top and bottom font metrics, we guess. Actually looking up the
+ // top and bottom metrics is slow, and this overapproximation should be good enough.
+ const SkScalar buffer = r->paint.getTextSize() * 1.5f;
+ SkDEBUGCODE(SkPaint::FontMetrics metrics;)
+ SkDEBUGCODE(r->paint.getFontMetrics(&metrics);)
+ SkASSERT(-buffer <= metrics.fTop);
+ SkASSERT(+buffer >= metrics.fBottom);
+
+ // Let the paint adjust the text bounds. We don't care about left and right here, so we use
+ // 0 and 1 respectively just so the bounds rectangle isn't empty.
+ SkRect bounds;
+ bounds.set(0, r->y - buffer, SK_Scalar1, r->y + buffer);
+ SkRect adjusted = r->paint.computeFastBounds(bounds, &bounds);
+
+ SkRecords::Adopted<SkRecords::DrawPosTextH> adopted(r);
+ SkNEW_PLACEMENT_ARGS(
+ fRecord->replace<SkRecords::BoundedDrawPosTextH>(this->index(), adopted),
+ SkRecords::BoundedDrawPosTextH,
+ (&adopted, adjusted.fTop, adjusted.fBottom));
}
+};
- // Rather than checking the top and bottom font metrics, we guess. Actually looking up the
- // top and bottom metrics is slow, and this overapproximation should be good enough.
- const SkScalar buffer = r->paint.getTextSize() * 1.5f;
- SkDEBUGCODE(SkPaint::FontMetrics metrics;)
- SkDEBUGCODE(r->paint.getFontMetrics(&metrics);)
- SkASSERT(-buffer <= metrics.fTop);
- SkASSERT(+buffer >= metrics.fBottom);
-
- // Let the paint adjust the text bounds. We don't care about left and right here, so we use
- // 0 and 1 respectively just so the bounds rectangle isn't empty.
- SkRect bounds;
- bounds.set(0, r->y - buffer, SK_Scalar1, r->y + buffer);
- SkRect adjusted = r->paint.computeFastBounds(bounds, &bounds);
-
- // BoundedDrawPosTextH adopts r.
- REPLACE(fRecord, this->index(), BoundedDrawPosTextH, r, adjusted.fTop, adjusted.fBottom);
-}
template <typename Pass>
static void run_pass(Pass& pass, SkRecord* record) {
@@ -242,5 +221,3 @@ void SkRecordBoundDrawPosTextH(SkRecord* record) {
TextBounder bounder(record);
run_pass(bounder, record);
}
-
-#undef REPLACE
diff --git a/record/SkRecordOpts.h b/record/SkRecordOpts.h
index c9cbccf9..6db7abca 100644
--- a/record/SkRecordOpts.h
+++ b/record/SkRecordOpts.h
@@ -15,15 +15,15 @@ void SkRecordOptimize(SkRecord*);
// Turns logical no-op Save-[non-drawing command]*-Restore patterns into actual no-ops.
-void SkRecordNoopSaveRestores(SkRecord*); // TODO(mtklein): add unit tests
+void SkRecordNoopSaveRestores(SkRecord*);
// Annotates PushCull commands with the relative offset of their paired PopCull.
void SkRecordAnnotateCullingPairs(SkRecord*);
// Convert DrawPosText to DrawPosTextH when all the Y coordinates are equal.
-void SkRecordReduceDrawPosTextStrength(SkRecord*); // TODO(mtklein): add unit tests
+void SkRecordReduceDrawPosTextStrength(SkRecord*);
// Calculate min and max Y bounds for DrawPosTextH commands, for use with SkCanvas::quickRejectY.
-void SkRecordBoundDrawPosTextH(SkRecord*); // TODO(mtklein): add unit tests
+void SkRecordBoundDrawPosTextH(SkRecord*);
#endif//SkRecordOpts_DEFINED
diff --git a/record/SkRecordTraits.h b/record/SkRecordTraits.h
new file mode 100644
index 00000000..570a717e
--- /dev/null
+++ b/record/SkRecordTraits.h
@@ -0,0 +1,31 @@
+#include "SkRecords.h"
+#include "SkTLogic.h"
+
+// Type traits that are useful for working with SkRecords.
+
+namespace SkRecords {
+
+namespace {
+
+// Abstracts away whether the T is optional or not.
+template <typename T> const T* as_ptr(const SkRecords::Optional<T>& x) { return x; }
+template <typename T> const T* as_ptr(const T& x) { return &x; }
+
+} // namespace
+
+// Gets the paint from any command that may have one.
+template <typename Command> const SkPaint* GetPaint(const Command& x) { return as_ptr(x.paint); }
+
+// Have a paint? You are a draw command!
+template <typename Command> struct IsDraw {
+ SK_CREATE_MEMBER_DETECTOR(paint);
+ static const bool value = HasMember_paint<Command>::value;
+};
+
+// Have a clip op? You are a clip command.
+template <typename Command> struct IsClip {
+ SK_CREATE_MEMBER_DETECTOR(op);
+ static const bool value = HasMember_op<Command>::value;
+};
+
+} // namespace SkRecords
diff --git a/record/SkRecorder.cpp b/record/SkRecorder.cpp
index 345597c5..fe4f35f5 100644
--- a/record/SkRecorder.cpp
+++ b/record/SkRecorder.cpp
@@ -12,6 +12,10 @@
SkRecorder::SkRecorder(SkRecorder::Mode mode, SkRecord* record, int width, int height)
: SkCanvas(width, height), fMode(mode), fRecord(record) {}
+void SkRecorder::forgetRecord() {
+ fRecord = NULL;
+}
+
// To make appending to fRecord a little less verbose.
#define APPEND(T, ...) \
SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__))
diff --git a/record/SkRecorder.h b/record/SkRecorder.h
index dc3de294..e6bddd75 100644
--- a/record/SkRecorder.h
+++ b/record/SkRecorder.h
@@ -28,6 +28,9 @@ public:
// Does not take ownership of the SkRecord.
SkRecorder(Mode mode, SkRecord*, int width, int height);
+ // Make SkRecorder forget entirely about its SkRecord*; all calls to SkRecorder will fail.
+ void forgetRecord();
+
void clear(SkColor) SK_OVERRIDE;
void drawPaint(const SkPaint& paint) SK_OVERRIDE;
void drawPoints(PointMode mode,
diff --git a/record/SkRecording.cpp b/record/SkRecording.cpp
index 6af19593..57743622 100644
--- a/record/SkRecording.cpp
+++ b/record/SkRecording.cpp
@@ -16,38 +16,29 @@ namespace EXPERIMENTAL {
SkPlayback::SkPlayback(const SkRecord* record) : fRecord(record) {}
-SkPlayback::~SkPlayback() {
- SkDELETE(fRecord);
-}
+SkPlayback::~SkPlayback() {}
void SkPlayback::draw(SkCanvas* canvas) const {
- SkASSERT(fRecord != NULL);
+ SkASSERT(fRecord.get() != NULL);
SkRecordDraw(*fRecord, canvas);
}
-/*static*/ SkRecording* SkRecording::Create(int width, int height) {
- return SkNEW_ARGS(SkRecording, (width, height));
-}
+SkRecording::SkRecording(int width, int height)
+ : fRecord(SkNEW(SkRecord))
+ , fRecorder(SkNEW_ARGS(SkRecorder, (SkRecorder::kReadWrite_Mode, fRecord.get(), width, height)))
+ {}
-SkRecording::SkRecording(int width, int height) {
- SkRecord* record = SkNEW(SkRecord);
- fRecorder = SkNEW_ARGS(SkRecorder, (SkRecorder::kReadWrite_Mode, record, width, height));
- fRecord = record;
+SkPlayback* SkRecording::releasePlayback() {
+ SkASSERT(fRecorder->unique());
+ fRecorder->forgetRecord();
+ SkRecordOptimize(fRecord.get());
+ return SkNEW_ARGS(SkPlayback, (fRecord.detach()));
}
-/*static*/ const SkPlayback* SkRecording::Delete(SkRecording* recording) {
- SkRecord* record = recording->fRecord;
- SkRecordOptimize(record);
- SkDELETE(recording);
- return SkNEW_ARGS(SkPlayback, (record));
-}
-
-SkRecording::~SkRecording() {
- SkDELETE(fRecorder);
-}
+SkRecording::~SkRecording() {}
SkCanvas* SkRecording::canvas() {
- return fRecorder;
+ return fRecord.get() ? fRecorder.get() : NULL;
}
} // namespace EXPERIMENTAL
diff --git a/record/SkRecords.h b/record/SkRecords.h
index 8b96e8d9..bfa15496 100644
--- a/record/SkRecords.h
+++ b/record/SkRecords.h
@@ -133,7 +133,12 @@ template <typename T>
class Adopted : SkNoncopyable {
public:
Adopted(T* ptr) : fPtr(ptr) { SkASSERT(fPtr); }
- ~Adopted() { fPtr->~T(); }
+ Adopted(Adopted* source) {
+ // Transfer ownership from source to this.
+ fPtr = source->fPtr;
+ source->fPtr = NULL;
+ }
+ ~Adopted() { if (fPtr) fPtr->~T(); }
ACT_AS_PTR(fPtr);
private:
@@ -142,9 +147,10 @@ private:
// PODArray doesn't own the pointer's memory, and we assume the data is POD.
template <typename T>
-class PODArray : SkNoncopyable {
+class PODArray {
public:
PODArray(T* ptr) : fPtr(ptr) {}
+ // Default copy and assign.
ACT_AS_PTR(fPtr);
private: