123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- /*
- * 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 "include/core/SkCanvas.h"
- #include "include/core/SkPicture.h"
- #include "include/core/SkTextBlob.h"
- #include "include/private/SkOnce.h"
- #include "src/core/SkMiniRecorder.h"
- #include "src/core/SkPictureCommon.h"
- #include "src/core/SkRecordDraw.h"
- #include "src/core/SkRectPriv.h"
- #include "src/core/SkTLazy.h"
- #include <new>
- using namespace SkRecords;
- class SkEmptyPicture final : 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(); }
- };
- // Calculate conservative bounds for each type of draw op that can be its own mini picture.
- // These are fairly easy because we know they can't be affected by any matrix or saveLayers.
- static SkRect adjust_for_paint(SkRect bounds, const SkPaint& paint) {
- return paint.canComputeFastBounds() ? paint.computeFastBounds(bounds, &bounds)
- : SkRectPriv::MakeLargest();
- }
- static SkRect bounds(const DrawRect& op) {
- return adjust_for_paint(op.rect, op.paint);
- }
- static SkRect bounds(const DrawPath& op) {
- return op.path.isInverseFillType() ? SkRectPriv::MakeLargest()
- : adjust_for_paint(op.path.getBounds(), op.paint);
- }
- static SkRect bounds(const DrawTextBlob& op) {
- return adjust_for_paint(op.blob->bounds().makeOffset(op.x, op.y), op.paint);
- }
- template <typename T>
- class SkMiniPicture final : public SkPicture {
- public:
- SkMiniPicture(const SkRect* cull, T* op) : fCull(cull ? *cull : bounds(*op)) {
- 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; }
- private:
- SkRect fCull;
- T fOp;
- };
- SkMiniRecorder::SkMiniRecorder() : fState(State::kEmpty) {}
- SkMiniRecorder::~SkMiniRecorder() {
- if (fState != State::kEmpty) {
- // We have internal state pending.
- // Detaching then deleting a picture is an easy way to clean up.
- (void)this->detachAsPicture(nullptr);
- }
- SkASSERT(fState == State::kEmpty);
- }
- #define TRY_TO_STORE(Type, ...) \
- if (fState != State::kEmpty) { return false; } \
- fState = State::k##Type; \
- new (fBuffer.get()) 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, sk_ref_sp(b), x, y);
- }
- #undef TRY_TO_STORE
- sk_sp<SkPicture> SkMiniRecorder::detachAsPicture(const SkRect* cull) {
- #define CASE(Type) \
- case State::k##Type: \
- fState = State::kEmpty; \
- return sk_make_sp<SkMiniPicture<Type>>(cull, reinterpret_cast<Type*>(fBuffer.get()))
- static SkOnce once;
- static SkPicture* empty;
- switch (fState) {
- case State::kEmpty:
- once([]{ empty = new SkEmptyPicture; });
- return sk_ref_sp(empty);
- CASE(DrawPath);
- CASE(DrawRect);
- CASE(DrawTextBlob);
- }
- SkASSERT(false);
- return nullptr;
- #undef CASE
- }
- void SkMiniRecorder::flushAndReset(SkCanvas* canvas) {
- #define CASE(Type) \
- case State::k##Type: { \
- fState = State::kEmpty; \
- Type* op = reinterpret_cast<Type*>(fBuffer.get()); \
- SkRecords::Draw(canvas, nullptr, nullptr, 0, nullptr)(*op); \
- op->~Type(); \
- } return
- switch (fState) {
- case State::kEmpty: return;
- CASE(DrawPath);
- CASE(DrawRect);
- CASE(DrawTextBlob);
- }
- SkASSERT(false);
- #undef CASE
- }
|