blob: fab6253430459b6a9b6a167d8ed6881af33560e0 [file] [log] [blame]
mtkleinc92c1292015-05-07 13:41:07 -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"
9#include "SkLazyPtr.h"
10#include "SkMiniRecorder.h"
11#include "SkPicture.h"
12#include "SkPictureCommon.h"
13#include "SkRecordDraw.h"
14#include "SkTextBlob.h"
15
16using namespace SkRecords;
17
18class 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 bool suitableForGpuRasterization(GrContext*, const char**) const override { return true; }
29};
30SK_DECLARE_STATIC_LAZY_PTR(SkEmptyPicture, gEmptyPicture);
31
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
49 // TODO: These trivial implementations are not all correct for all types.
50 // But I suspect these will never be called on SkMiniPictures, so assert for now.
51 int numSlowPaths() const override { SkASSERT(false); return 0; }
52 bool suitableForGpuRasterization(GrContext*, const char**) const override {
53 SkASSERT(false);
54 return true;
55 }
56
57private:
58 SkRect fCull;
59 T fOp;
60};
61
62
63SkMiniRecorder::SkMiniRecorder() : fState(State::kEmpty) {}
64SkMiniRecorder::~SkMiniRecorder() {
65 // We've done something wrong if no one's called detachAsPicture().
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
75bool SkMiniRecorder::drawRect(const SkRect& rect, const SkPaint& paint) {
76 TRY_TO_STORE(DrawRect, paint, rect);
77}
78
79bool SkMiniRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
80 TRY_TO_STORE(DrawPath, paint, path);
81}
82
83bool SkMiniRecorder::drawTextBlob(const SkTextBlob* b, SkScalar x, SkScalar y, const SkPaint& p) {
84 TRY_TO_STORE(DrawTextBlob, p, b, x, y);
85}
86#undef TRY_TO_STORE
87
88#define CASE(Type) \
89 case State::k##Type: \
90 fState = State::kEmpty; \
91 return SkNEW_ARGS(SkMiniPicture<Type>, (cull, reinterpret_cast<Type*>(fBuffer.get())))
92
93SkPicture* SkMiniRecorder::detachAsPicture(const SkRect& cull) {
94 switch (fState) {
95 case State::kEmpty: return SkRef(gEmptyPicture.get());
96 CASE(DrawPath);
97 CASE(DrawRect);
98 CASE(DrawTextBlob);
99 }
100 SkASSERT(false);
101 return NULL;
102}
103#undef CASE