Chromium Code Reviews| Index: src/core/SkMiniRecorder.cpp |
| diff --git a/src/core/SkMiniRecorder.cpp b/src/core/SkMiniRecorder.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..cefc6567ce57635f0646cc974a8c239fb5cd9d1f |
| --- /dev/null |
| +++ b/src/core/SkMiniRecorder.cpp |
| @@ -0,0 +1,107 @@ |
| +/* |
| + * Copyright 2015 Google Inc. |
| + * |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the LICENSE file. |
| + */ |
| + |
| +#include "SkCanvas.h" |
| +#include "SkLazyPtr.h" |
| +#include "SkMiniRecorder.h" |
| +#include "SkPicture.h" |
| +#include "SkRecordDraw.h" |
| +#include "SkRecords.h" |
| +#include "SkTextBlob.h" |
| + |
| +using namespace SkRecords; |
| + |
| +class SkEmptyPicture : public SkPicture { |
| +public: |
| + void playback(SkCanvas*, AbortCallback*) const override { } |
| + |
| + size_t approximateBytesUsed() const override { return sizeof(*this); } |
| + int approximateOpCount() const override { return 0; } |
| + SkRect cullRect() const override { return SkRect::MakeEmpty(); } |
| + bool hasText() const override { return false; } |
| + int numSlowPaths() const override { return 0; } |
| + bool willPlayBackBitmaps() const override { return false; } |
| + bool suitableForGpuRasterization(GrContext*, const char**) const override { return true; } |
| +}; |
| +SK_DECLARE_STATIC_LAZY_PTR(SkEmptyPicture, gEmptyPicture); |
| + |
| +template <typename T> |
| +class SkMiniPicture : public SkPicture { |
| +public: |
| + SkMiniPicture(SkRect cull, T* op) : fCull(cull) { |
| + memcpy(&fOp, op, sizeof(fOp)); // We take ownership of op's guts. |
| + } |
| + |
| + void playback(SkCanvas* c, AbortCallback*) const override { |
| + SkRecords::Draw(c, nullptr, nullptr, 0, nullptr)(fOp); |
| + } |
| + |
| + size_t approximateBytesUsed() const override { return sizeof(*this); } |
| + int approximateOpCount() const override { return 1; } |
| + SkRect cullRect() const override { return fCull; } |
| + |
| + // TODO: These trivial implementations are not all correct for all types. |
| + // But I suspect these will never be called on SkMiniPictures, so assert for now. |
| + bool hasText() const override { SkASSERT(false); return false; } |
| + int numSlowPaths() const override { SkASSERT(false); return 0; } |
| + bool willPlayBackBitmaps() const override { SkASSERT(false); return false; } |
| + bool suitableForGpuRasterization(GrContext*, const char**) const override { |
| + SkASSERT(false); |
| + return true; |
| + } |
| + |
| +private: |
| + SkRect fCull; |
| + T fOp; |
| +}; |
| + |
| + |
| +SkMiniRecorder::SkMiniRecorder() : fState(State::kEmpty) {} |
| +SkMiniRecorder::~SkMiniRecorder() { |
| + // We've done something wrong if no one's called detachAsPicture() or flushToCanvas(). |
| + SkASSERT(fState == State::kEmpty); |
| +} |
| + |
| +#define TRY_TO_STORE(Type, ...) \ |
| + if (fState != State::kEmpty) { return false; } \ |
| + fState = State::k##Type; \ |
| + new (fBuffer) Type(__VA_ARGS__); \ |
| + return true |
| + |
| +bool SkMiniRecorder::drawRect(const SkRect& rect, const SkPaint& paint) { |
| + TRY_TO_STORE(DrawRect, paint, rect); |
| +} |
| + |
| +bool SkMiniRecorder::drawPath(const SkPath& path, const SkPaint& paint) { |
| + TRY_TO_STORE(DrawPath, paint, path); |
| +} |
| + |
| +bool SkMiniRecorder::drawTextBlob(const SkTextBlob* b, SkScalar x, SkScalar y, const SkPaint& p) { |
| + TRY_TO_STORE(DrawTextBlob, p, b, x, y); |
| +} |
| +#undef TRY_TO_STORE |
| + |
| +#define CASE(Type) \ |
| + case State::k##Type: \ |
| + fState = State::kEmpty; \ |
| + return SkNEW_ARGS(SkMiniPicture<Type>, (cull, reinterpret_cast<Type*>(fBuffer))) |
| + |
| +SkPicture* SkMiniRecorder::detachAsPicture(const SkRect& cull) { |
| + switch (fState) { |
| + case State::kEmpty: return SkRef(gEmptyPicture.get()); |
| + CASE(DrawPath); |
| + CASE(DrawRect); |
| + CASE(DrawTextBlob); |
| + } |
|
reed1
2015/05/04 13:26:34
return NULL; ?
mtklein
2015/05/04 15:52:45
Done.
|
| +} |
| +#undef CASE |
| + |
| +void SkMiniRecorder::flushToCanvas(SkCanvas* canvas) { |
| + // TODO: This method could be made quite a bit more efficient. It's lazy, but correct. |
| + SkAutoTUnref<SkPicture> p(this->detachAsPicture(SkRect::MakeEmpty())); |
| + p->playback(canvas); |
| +} |