Line data Source code
1 : /*
2 : * Copyright 2015 Google Inc.
3 : *
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 : #include "SkCanvas.h"
9 : #include "SkTLazy.h"
10 : #include "SkMiniRecorder.h"
11 : #include "SkOnce.h"
12 : #include "SkPicture.h"
13 : #include "SkPictureCommon.h"
14 : #include "SkRecordDraw.h"
15 : #include "SkTextBlob.h"
16 :
17 : using namespace SkRecords;
18 :
19 0 : class SkEmptyPicture final : public SkPicture {
20 : public:
21 0 : void playback(SkCanvas*, AbortCallback*) const override { }
22 :
23 0 : size_t approximateBytesUsed() const override { return sizeof(*this); }
24 0 : int approximateOpCount() const override { return 0; }
25 0 : SkRect cullRect() const override { return SkRect::MakeEmpty(); }
26 0 : int numSlowPaths() const override { return 0; }
27 0 : bool willPlayBackBitmaps() const override { return false; }
28 : };
29 :
30 : template <typename T>
31 0 : class SkMiniPicture final : public SkPicture {
32 : public:
33 0 : SkMiniPicture(SkRect cull, T* op) : fCull(cull) {
34 0 : memcpy(&fOp, op, sizeof(fOp)); // We take ownership of op's guts.
35 0 : }
36 :
37 0 : void playback(SkCanvas* c, AbortCallback*) const override {
38 0 : SkRecords::Draw(c, nullptr, nullptr, 0, nullptr)(fOp);
39 0 : }
40 :
41 0 : size_t approximateBytesUsed() const override { return sizeof(*this); }
42 0 : int approximateOpCount() const override { return 1; }
43 0 : SkRect cullRect() const override { return fCull; }
44 0 : bool willPlayBackBitmaps() const override { return SkBitmapHunter()(fOp); }
45 0 : int numSlowPaths() const override {
46 0 : SkPathCounter counter;
47 0 : counter(fOp);
48 0 : return counter.fNumSlowPathsAndDashEffects;
49 : }
50 :
51 : private:
52 : SkRect fCull;
53 : T fOp;
54 : };
55 :
56 :
57 0 : SkMiniRecorder::SkMiniRecorder() : fState(State::kEmpty) {}
58 0 : SkMiniRecorder::~SkMiniRecorder() {
59 0 : if (fState != State::kEmpty) {
60 : // We have internal state pending.
61 : // Detaching then deleting a picture is an easy way to clean up.
62 0 : (void)this->detachAsPicture(SkRect::MakeEmpty());
63 : }
64 0 : SkASSERT(fState == State::kEmpty);
65 0 : }
66 :
67 : #define TRY_TO_STORE(Type, ...) \
68 : if (fState != State::kEmpty) { return false; } \
69 : fState = State::k##Type; \
70 : new (fBuffer.get()) Type{__VA_ARGS__}; \
71 : return true
72 :
73 0 : bool SkMiniRecorder::drawRect(const SkRect& rect, const SkPaint& paint) {
74 0 : TRY_TO_STORE(DrawRect, paint, rect);
75 : }
76 :
77 0 : bool SkMiniRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
78 0 : TRY_TO_STORE(DrawPath, paint, path);
79 : }
80 :
81 0 : bool SkMiniRecorder::drawTextBlob(const SkTextBlob* b, SkScalar x, SkScalar y, const SkPaint& p) {
82 0 : TRY_TO_STORE(DrawTextBlob, p, sk_ref_sp(b), x, y);
83 : }
84 : #undef TRY_TO_STORE
85 :
86 :
87 0 : sk_sp<SkPicture> SkMiniRecorder::detachAsPicture(const SkRect& cull) {
88 : #define CASE(Type) \
89 : case State::k##Type: \
90 : fState = State::kEmpty; \
91 : return sk_make_sp<SkMiniPicture<Type>>(cull, reinterpret_cast<Type*>(fBuffer.get()))
92 :
93 : static SkOnce once;
94 : static SkPicture* empty;
95 :
96 0 : switch (fState) {
97 : case State::kEmpty:
98 0 : once([]{ empty = new SkEmptyPicture; });
99 0 : return sk_ref_sp(empty);
100 0 : CASE(DrawPath);
101 0 : CASE(DrawRect);
102 0 : CASE(DrawTextBlob);
103 : }
104 0 : SkASSERT(false);
105 0 : return nullptr;
106 : #undef CASE
107 : }
108 :
109 0 : void SkMiniRecorder::flushAndReset(SkCanvas* canvas) {
110 : #define CASE(Type) \
111 : case State::k##Type: { \
112 : fState = State::kEmpty; \
113 : Type* op = reinterpret_cast<Type*>(fBuffer.get()); \
114 : SkRecords::Draw(canvas, nullptr, nullptr, 0, nullptr)(*op); \
115 : op->~Type(); \
116 : } return
117 :
118 0 : switch (fState) {
119 0 : case State::kEmpty: return;
120 0 : CASE(DrawPath);
121 0 : CASE(DrawRect);
122 0 : CASE(DrawTextBlob);
123 : }
124 0 : SkASSERT(false);
125 : #undef CASE
126 : }
|