blob: 916c47730b02510820bb618a1c66b02c7136f126 [file] [log] [blame]
mtklein9db912c2015-05-19 11:11:26 -07001/*
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"
mtklein2e172ec2015-05-20 10:32:22 -07009#include "SkLazyPtr.h"
mtklein9db912c2015-05-19 11:11:26 -070010#include "SkMiniRecorder.h"
11#include "SkPicture.h"
12#include "SkPictureCommon.h"
13#include "SkRecordDraw.h"
14#include "SkTextBlob.h"
15
16using namespace SkRecords;
17
mtklein9db912c2015-05-19 11:11:26 -070018class SkEmptyPicture final : public SkPicture {
19public:
20 void playback(SkCanvas*, AbortCallback*) const override { }
21
22 size_t approximateBytesUsed() const override { return sizeof(*this); }
23 int approximateOpCount() const override { return 0; }
24 SkRect cullRect() const override { return SkRect::MakeEmpty(); }
25 bool hasText() const override { return false; }
26 int numSlowPaths() const override { return 0; }
27 bool willPlayBackBitmaps() const override { return false; }
28};
mtklein2e172ec2015-05-20 10:32:22 -070029SK_DECLARE_STATIC_LAZY_PTR(SkEmptyPicture, gEmptyPicture);
mtklein9db912c2015-05-19 11:11:26 -070030
31template <typename T>
32class SkMiniPicture final : public SkPicture {
33public:
34 SkMiniPicture(SkRect cull, T* op) : fCull(cull) {
35 memcpy(&fOp, op, sizeof(fOp)); // We take ownership of op's guts.
36 }
37
38 void playback(SkCanvas* c, AbortCallback*) const override {
39 SkRecords::Draw(c, nullptr, nullptr, 0, nullptr)(fOp);
40 }
41
42 size_t approximateBytesUsed() const override { return sizeof(*this); }
43 int approximateOpCount() const override { return 1; }
44 SkRect cullRect() const override { return fCull; }
45 bool hasText() const override { return SkTextHunter()(fOp); }
46 bool willPlayBackBitmaps() const override { return SkBitmapHunter()(fOp); }
47 int numSlowPaths() const override {
48 SkPathCounter counter;
49 counter(fOp);
50 return counter.fNumSlowPathsAndDashEffects;
51 }
52
53private:
54 SkRect fCull;
55 T fOp;
56};
57
58
59SkMiniRecorder::SkMiniRecorder() : fState(State::kEmpty) {}
60SkMiniRecorder::~SkMiniRecorder() {
61 if (fState != State::kEmpty) {
62 // We have internal state pending.
63 // Detaching then deleting a picture is an easy way to clean up.
64 SkDELETE(this->detachAsPicture(SkRect::MakeEmpty()));
65 }
66 SkASSERT(fState == State::kEmpty);
67}
68
69#define TRY_TO_STORE(Type, ...) \
70 if (fState != State::kEmpty) { return false; } \
71 fState = State::k##Type; \
72 new (fBuffer.get()) Type(__VA_ARGS__); \
73 return true
74
reeda5517e22015-07-14 10:54:12 -070075bool SkMiniRecorder::drawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst,
76 const SkPaint* p, SkCanvas::SrcRectConstraint constraint) {
mtklein64b4c782015-07-01 13:56:53 -070077 SkRect bounds;
78 if (!src) {
79 bm.getBounds(&bounds);
80 src = &bounds;
81 }
82 SkTLazy<SkPaint> defaultPaint;
83 if (!p) {
84 p = defaultPaint.init();
85 }
reeda5517e22015-07-14 10:54:12 -070086 TRY_TO_STORE(DrawBitmapRectFixedSize, *p, bm, *src, dst, constraint);
mtklein64b4c782015-07-01 13:56:53 -070087}
88
mtklein9db912c2015-05-19 11:11:26 -070089bool SkMiniRecorder::drawRect(const SkRect& rect, const SkPaint& paint) {
90 TRY_TO_STORE(DrawRect, paint, rect);
91}
92
93bool SkMiniRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
94 TRY_TO_STORE(DrawPath, paint, path);
95}
96
97bool SkMiniRecorder::drawTextBlob(const SkTextBlob* b, SkScalar x, SkScalar y, const SkPaint& p) {
98 TRY_TO_STORE(DrawTextBlob, p, b, x, y);
99}
100#undef TRY_TO_STORE
101
mtkleind41ea1d2015-05-20 10:16:49 -0700102
103SkPicture* SkMiniRecorder::detachAsPicture(const SkRect& cull) {
mtklein9db912c2015-05-19 11:11:26 -0700104#define CASE(Type) \
105 case State::k##Type: \
106 fState = State::kEmpty; \
107 return SkNEW_ARGS(SkMiniPicture<Type>, (cull, reinterpret_cast<Type*>(fBuffer.get())))
108
mtklein9db912c2015-05-19 11:11:26 -0700109 switch (fState) {
mtklein2e172ec2015-05-20 10:32:22 -0700110 case State::kEmpty: return SkRef(gEmptyPicture.get());
reeda5517e22015-07-14 10:54:12 -0700111 CASE(DrawBitmapRectFixedSize);
mtklein9db912c2015-05-19 11:11:26 -0700112 CASE(DrawPath);
113 CASE(DrawRect);
114 CASE(DrawTextBlob);
115 }
116 SkASSERT(false);
mtkleind41ea1d2015-05-20 10:16:49 -0700117 return nullptr;
mtklein9db912c2015-05-19 11:11:26 -0700118#undef CASE
mtkleind41ea1d2015-05-20 10:16:49 -0700119}
120
121void SkMiniRecorder::flushAndReset(SkCanvas* canvas) {
122#define CASE(Type) \
123 case State::k##Type: { \
124 fState = State::kEmpty; \
125 Type* op = reinterpret_cast<Type*>(fBuffer.get()); \
126 SkRecords::Draw(canvas, nullptr, nullptr, 0, nullptr)(*op); \
127 op->~Type(); \
128 } return
129
130 switch (fState) {
131 case State::kEmpty: return;
reeda5517e22015-07-14 10:54:12 -0700132 CASE(DrawBitmapRectFixedSize);
mtkleind41ea1d2015-05-20 10:16:49 -0700133 CASE(DrawPath);
134 CASE(DrawRect);
135 CASE(DrawTextBlob);
136 }
137 SkASSERT(false);
138#undef CASE
139}