blob: 07cb0a6795cc31f320ef8fdcdf4706a9ac27a0aa [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
2**
3** Copyright 2007, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkPictureFlat.h"
19#include "SkPicturePlayback.h"
20#include "SkPictureRecord.h"
21
22#include "SkCanvas.h"
23#include "SkChunkAlloc.h"
24#include "SkPicture.h"
25#include "SkRegion.h"
26#include "SkStream.h"
27#include "SkTDArray.h"
28#include "SkTSearch.h"
29#include "SkTime.h"
30
31#include "SkReader32.h"
32#include "SkWriter32.h"
33
34#define DUMP_BUFFER_SIZE 65536
35
36//#define ENABLE_TIME_DRAW // dumps milliseconds for each draw
37
38
39#ifdef SK_DEBUG
40// enable SK_DEBUG_TRACE to trace DrawType elements when
41// recorded and played back
42// #define SK_DEBUG_TRACE
43// enable SK_DEBUG_SIZE to see the size of picture components
44// #define SK_DEBUG_SIZE
45// enable SK_DEBUG_DUMP to see the contents of recorded elements
46// #define SK_DEBUG_DUMP
47// enable SK_DEBUG_VALIDATE to check internal structures for consistency
48// #define SK_DEBUG_VALIDATE
49#endif
50
51#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP
52const char* DrawTypeToString(DrawType drawType) {
53 switch (drawType) {
54 case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break;
55 case CLIP_PATH: return "CLIP_PATH";
56 case CLIP_REGION: return "CLIP_REGION";
57 case CLIP_RECT: return "CLIP_RECT";
58 case CONCAT: return "CONCAT";
59 case DRAW_BITMAP: return "DRAW_BITMAP";
60 case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
61 case DRAW_BITMAP_RECT: return "DRAW_BITMAP_RECT";
62 case DRAW_PAINT: return "DRAW_PAINT";
63 case DRAW_PATH: return "DRAW_PATH";
64 case DRAW_PICTURE: return "DRAW_PICTURE";
65 case DRAW_POINTS: return "DRAW_POINTS";
66 case DRAW_POS_TEXT: return "DRAW_POS_TEXT";
67 case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
68 case DRAW_RECT_GENERAL: return "DRAW_RECT_GENERAL";
69 case DRAW_RECT_SIMPLE: return "DRAW_RECT_SIMPLE";
70 case DRAW_SPRITE: return "DRAW_SPRITE";
71 case DRAW_TEXT: return "DRAW_TEXT";
72 case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
73 case RESTORE: return "RESTORE";
74 case ROTATE: return "ROTATE";
75 case SAVE: return "SAVE";
76 case SAVE_LAYER: return "SAVE_LAYER";
77 case SCALE: return "SCALE";
78 case SKEW: return "SKEW";
79 case TRANSLATE: return "TRANSLATE";
80 default:
81 SkDebugf("DrawType error 0x%08x\n", drawType);
82 SkASSERT(0);
83 break;
84 }
85 SkASSERT(0);
86 return NULL;
87}
88#endif
89
90#ifdef SK_DEBUG_VALIDATE
91static void validateMatrix(const SkMatrix* matrix) {
92 SkScalar scaleX = matrix->getScaleX();
93 SkScalar scaleY = matrix->getScaleY();
94 SkScalar skewX = matrix->getSkewX();
95 SkScalar skewY = matrix->getSkewY();
96 SkScalar perspX = matrix->getPerspX();
97 SkScalar perspY = matrix->getPerspY();
98 if (scaleX != 0 && skewX != 0)
99 SkDebugf("scaleX != 0 && skewX != 0\n");
100 SkASSERT(scaleX == 0 || skewX == 0);
101 SkASSERT(scaleY == 0 || skewY == 0);
102 SkASSERT(perspX == 0);
103 SkASSERT(perspY == 0);
104}
105#endif
106
107
108///////////////////////////////////////////////////////////////////////////////
109
110SkPicture::SkPicture() {
111 fRecord = NULL;
112 fPlayback = NULL;
113 fWidth = fHeight = 0;
114}
115
116SkPicture::SkPicture(const SkPicture& src) : SkRefCnt() {
117 fWidth = src.fWidth;
118 fHeight = src.fHeight;
119 fRecord = NULL;
120
121 /* We want to copy the src's playback. However, if that hasn't been built
122 yet, we need to fake a call to endRecording() without actually calling
123 it (since it is destructive, and we don't want to change src).
124 */
125 if (src.fPlayback) {
126 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback));
127 } else if (src.fRecord) {
128 // here we do a fake src.endRecording()
129 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord));
130 } else {
131 fPlayback = NULL;
132 }
133}
134
135SkPicture::~SkPicture() {
136 fRecord->safeUnref();
137 SkDELETE(fPlayback);
138}
139
140void SkPicture::swap(SkPicture& other) {
141 SkTSwap(fRecord, other.fRecord);
142 SkTSwap(fPlayback, other.fPlayback);
143 SkTSwap(fWidth, other.fWidth);
144 SkTSwap(fHeight, other.fHeight);
145}
146
147///////////////////////////////////////////////////////////////////////////////
148
149SkCanvas* SkPicture::beginRecording(int width, int height) {
150 if (fPlayback) {
151 SkDELETE(fPlayback);
152 fPlayback = NULL;
153 }
154
155 if (NULL != fRecord) {
156 fRecord->unref();
157 fRecord = NULL;
158 }
159
160 fRecord = SkNEW(SkPictureRecord);
161
162 fWidth = width;
163 fHeight = height;
164
165 SkBitmap bm;
166 bm.setConfig(SkBitmap::kNo_Config, width, height);
167 fRecord->setBitmapDevice(bm);
168
169 return fRecord;
170}
171
172SkCanvas* SkPicture::getRecordingCanvas() const {
173 // will be null if we are not recording
174 return fRecord;
175}
176
177void SkPicture::endRecording() {
178 if (NULL == fPlayback) {
179 if (NULL != fRecord) {
180 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
181 fRecord->unref();
182 fRecord = NULL;
183 }
184 }
185 SkASSERT(NULL == fRecord);
186}
187
188void SkPicture::draw(SkCanvas* surface) {
189 this->endRecording();
190 if (fPlayback) {
191 fPlayback->draw(*surface);
192 }
193}
194
195///////////////////////////////////////////////////////////////////////////////
196
197#include "SkStream.h"
198
199#define PICTURE_VERSION 1
200
201SkPicture::SkPicture(SkStream* stream) : SkRefCnt() {
202 if (stream->readU32() != PICTURE_VERSION) {
203 sk_throw();
204 }
205
206 fWidth = stream->readU32();
207 fHeight = stream->readU32();
208
209 fRecord = NULL;
210 fPlayback = NULL;
211
212 if (stream->readBool()) {
213 fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream));
214 }
215}
216
217void SkPicture::serialize(SkWStream* stream) const {
218 SkPicturePlayback* playback = fPlayback;
219
220 if (NULL == playback && fRecord) {
221 playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
222 }
223
224 stream->write32(PICTURE_VERSION);
225 stream->write32(fWidth);
226 stream->write32(fHeight);
227 if (playback) {
228 stream->writeBool(true);
229 playback->serialize(stream);
230 // delete playback if it is a local version (i.e. cons'd up just now)
231 if (playback != fPlayback) {
232 SkDELETE(playback);
233 }
234 } else {
235 stream->writeBool(false);
236 }
237}
238
239void SkPicture::abortPlayback() {
240 if (NULL == fPlayback) {
241 return;
242 }
243 fPlayback->abort();
244}
245
246