1 /*
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
DrawTypeToString(DrawType drawType)52 const 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
validateMatrix(const SkMatrix * matrix)91 static 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
SkPicture()110 SkPicture::SkPicture() {
111 fRecord = NULL;
112 fPlayback = NULL;
113 fWidth = fHeight = 0;
114 }
115
SkPicture(const SkPicture & src)116 SkPicture::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
~SkPicture()135 SkPicture::~SkPicture() {
136 fRecord->safeUnref();
137 SkDELETE(fPlayback);
138 }
139
swap(SkPicture & other)140 void 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
beginRecording(int width,int height,uint32_t recordingFlags)149 SkCanvas* SkPicture::beginRecording(int width, int height,
150 uint32_t recordingFlags) {
151 if (fPlayback) {
152 SkDELETE(fPlayback);
153 fPlayback = NULL;
154 }
155
156 if (NULL != fRecord) {
157 fRecord->unref();
158 fRecord = NULL;
159 }
160
161 fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags));
162
163 fWidth = width;
164 fHeight = height;
165
166 SkBitmap bm;
167 bm.setConfig(SkBitmap::kNo_Config, width, height);
168 fRecord->setBitmapDevice(bm);
169
170 return fRecord;
171 }
172
getRecordingCanvas() const173 SkCanvas* SkPicture::getRecordingCanvas() const {
174 // will be null if we are not recording
175 return fRecord;
176 }
177
endRecording()178 void SkPicture::endRecording() {
179 if (NULL == fPlayback) {
180 if (NULL != fRecord) {
181 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
182 fRecord->unref();
183 fRecord = NULL;
184 }
185 }
186 SkASSERT(NULL == fRecord);
187 }
188
draw(SkCanvas * surface)189 void SkPicture::draw(SkCanvas* surface) {
190 this->endRecording();
191 if (fPlayback) {
192 fPlayback->draw(*surface);
193 }
194 }
195
196 ///////////////////////////////////////////////////////////////////////////////
197
198 #include "SkStream.h"
199
200 #define PICTURE_VERSION 1
201
SkPicture(SkStream * stream)202 SkPicture::SkPicture(SkStream* stream) : SkRefCnt() {
203 if (stream->readU32() != PICTURE_VERSION) {
204 sk_throw();
205 }
206
207 fWidth = stream->readU32();
208 fHeight = stream->readU32();
209
210 fRecord = NULL;
211 fPlayback = NULL;
212
213 if (stream->readBool()) {
214 fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream));
215 }
216 }
217
serialize(SkWStream * stream) const218 void SkPicture::serialize(SkWStream* stream) const {
219 SkPicturePlayback* playback = fPlayback;
220
221 if (NULL == playback && fRecord) {
222 playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
223 }
224
225 stream->write32(PICTURE_VERSION);
226 stream->write32(fWidth);
227 stream->write32(fHeight);
228 if (playback) {
229 stream->writeBool(true);
230 playback->serialize(stream);
231 // delete playback if it is a local version (i.e. cons'd up just now)
232 if (playback != fPlayback) {
233 SkDELETE(playback);
234 }
235 } else {
236 stream->writeBool(false);
237 }
238 }
239
abortPlayback()240 void SkPicture::abortPlayback() {
241 if (NULL == fPlayback) {
242 return;
243 }
244 fPlayback->abort();
245 }
246
247
248