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