[go: nahoru, domu]

blob: af1cd60cbfcb273be86a71c369e5e2a849cbd3ce [file] [log] [blame]
epoger@google.com685cfc02011-07-28 14:26:00 +00001
reed@android.combcd4d5a2008-12-17 15:59:43 +00002/*
epoger@google.com685cfc02011-07-28 14:26:00 +00003 * Copyright 2007 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
reed@android.combcd4d5a2008-12-17 15:59:43 +00009
10#include "SkPictureFlat.h"
11#include "SkPicturePlayback.h"
12#include "SkPictureRecord.h"
13
14#include "SkCanvas.h"
15#include "SkChunkAlloc.h"
16#include "SkPicture.h"
17#include "SkRegion.h"
18#include "SkStream.h"
19#include "SkTDArray.h"
20#include "SkTSearch.h"
21#include "SkTime.h"
22
23#include "SkReader32.h"
24#include "SkWriter32.h"
rileya@google.com7fb3d2f2012-09-13 21:41:51 +000025#include "SkRTree.h"
26#include "SkBBoxHierarchyRecord.h"
reed@android.combcd4d5a2008-12-17 15:59:43 +000027
robertphillips@google.com86dbfc42012-06-21 20:25:03 +000028SK_DEFINE_INST_COUNT(SkPicture)
29
reed@android.combcd4d5a2008-12-17 15:59:43 +000030#define DUMP_BUFFER_SIZE 65536
31
32//#define ENABLE_TIME_DRAW // dumps milliseconds for each draw
33
34
35#ifdef SK_DEBUG
reed@google.com91911482011-02-07 15:30:46 +000036// enable SK_DEBUG_TRACE to trace DrawType elements when
reed@android.combcd4d5a2008-12-17 15:59:43 +000037// recorded and played back
38// #define SK_DEBUG_TRACE
39// enable SK_DEBUG_SIZE to see the size of picture components
40// #define SK_DEBUG_SIZE
41// enable SK_DEBUG_DUMP to see the contents of recorded elements
42// #define SK_DEBUG_DUMP
43// enable SK_DEBUG_VALIDATE to check internal structures for consistency
44// #define SK_DEBUG_VALIDATE
45#endif
46
47#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP
48const char* DrawTypeToString(DrawType drawType) {
49 switch (drawType) {
50 case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break;
51 case CLIP_PATH: return "CLIP_PATH";
52 case CLIP_REGION: return "CLIP_REGION";
53 case CLIP_RECT: return "CLIP_RECT";
54 case CONCAT: return "CONCAT";
55 case DRAW_BITMAP: return "DRAW_BITMAP";
56 case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
57 case DRAW_BITMAP_RECT: return "DRAW_BITMAP_RECT";
58 case DRAW_PAINT: return "DRAW_PAINT";
59 case DRAW_PATH: return "DRAW_PATH";
60 case DRAW_PICTURE: return "DRAW_PICTURE";
61 case DRAW_POINTS: return "DRAW_POINTS";
62 case DRAW_POS_TEXT: return "DRAW_POS_TEXT";
63 case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
64 case DRAW_RECT_GENERAL: return "DRAW_RECT_GENERAL";
65 case DRAW_RECT_SIMPLE: return "DRAW_RECT_SIMPLE";
66 case DRAW_SPRITE: return "DRAW_SPRITE";
67 case DRAW_TEXT: return "DRAW_TEXT";
68 case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
69 case RESTORE: return "RESTORE";
70 case ROTATE: return "ROTATE";
71 case SAVE: return "SAVE";
72 case SAVE_LAYER: return "SAVE_LAYER";
73 case SCALE: return "SCALE";
74 case SKEW: return "SKEW";
75 case TRANSLATE: return "TRANSLATE";
reed@google.com91911482011-02-07 15:30:46 +000076 default:
77 SkDebugf("DrawType error 0x%08x\n", drawType);
78 SkASSERT(0);
reed@android.combcd4d5a2008-12-17 15:59:43 +000079 break;
80 }
reed@google.com91911482011-02-07 15:30:46 +000081 SkASSERT(0);
reed@android.combcd4d5a2008-12-17 15:59:43 +000082 return NULL;
83}
84#endif
85
86#ifdef SK_DEBUG_VALIDATE
87static void validateMatrix(const SkMatrix* matrix) {
88 SkScalar scaleX = matrix->getScaleX();
89 SkScalar scaleY = matrix->getScaleY();
90 SkScalar skewX = matrix->getSkewX();
91 SkScalar skewY = matrix->getSkewY();
92 SkScalar perspX = matrix->getPerspX();
93 SkScalar perspY = matrix->getPerspY();
94 if (scaleX != 0 && skewX != 0)
95 SkDebugf("scaleX != 0 && skewX != 0\n");
96 SkASSERT(scaleX == 0 || skewX == 0);
97 SkASSERT(scaleY == 0 || skewY == 0);
98 SkASSERT(perspX == 0);
99 SkASSERT(perspY == 0);
100}
101#endif
102
103
104///////////////////////////////////////////////////////////////////////////////
105
106SkPicture::SkPicture() {
107 fRecord = NULL;
108 fPlayback = NULL;
109 fWidth = fHeight = 0;
110}
111
112SkPicture::SkPicture(const SkPicture& src) : SkRefCnt() {
113 fWidth = src.fWidth;
114 fHeight = src.fHeight;
115 fRecord = NULL;
116
117 /* We want to copy the src's playback. However, if that hasn't been built
118 yet, we need to fake a call to endRecording() without actually calling
119 it (since it is destructive, and we don't want to change src).
120 */
121 if (src.fPlayback) {
122 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback));
123 } else if (src.fRecord) {
124 // here we do a fake src.endRecording()
125 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord));
126 } else {
127 fPlayback = NULL;
128 }
129}
130
131SkPicture::~SkPicture() {
reed@google.com91911482011-02-07 15:30:46 +0000132 SkSafeUnref(fRecord);
reed@android.combcd4d5a2008-12-17 15:59:43 +0000133 SkDELETE(fPlayback);
134}
135
136void SkPicture::swap(SkPicture& other) {
137 SkTSwap(fRecord, other.fRecord);
138 SkTSwap(fPlayback, other.fPlayback);
139 SkTSwap(fWidth, other.fWidth);
140 SkTSwap(fHeight, other.fHeight);
141}
142
djsollen@google.com3855f872012-08-29 18:52:07 +0000143SkPicture* SkPicture::clone() const {
144 SkPicture* clonedPicture = SkNEW(SkPicture);
145 clone(clonedPicture, 1);
146 return clonedPicture;
147}
148
149void SkPicture::clone(SkPicture* pictures, int count) const {
150 SkPictCopyInfo copyInfo;
151
152 for (int i = 0; i < count; i++) {
153 SkPicture* clone = &pictures[i];
154
155 clone->fWidth = fWidth;
156 clone->fHeight = fHeight;
157 clone->fRecord = NULL;
158
159 /* We want to copy the src's playback. However, if that hasn't been built
160 yet, we need to fake a call to endRecording() without actually calling
161 it (since it is destructive, and we don't want to change src).
162 */
163 if (fPlayback) {
164 clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fPlayback, &copyInfo));
165 } else if (fRecord) {
166 // here we do a fake src.endRecording()
167 clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, true));
168 } else {
169 clone->fPlayback = NULL;
170 }
171 }
172}
173
reed@android.combcd4d5a2008-12-17 15:59:43 +0000174///////////////////////////////////////////////////////////////////////////////
175
reed@android.comc4a55d72009-02-13 14:56:09 +0000176SkCanvas* SkPicture::beginRecording(int width, int height,
177 uint32_t recordingFlags) {
reed@android.combcd4d5a2008-12-17 15:59:43 +0000178 if (fPlayback) {
179 SkDELETE(fPlayback);
180 fPlayback = NULL;
181 }
182
183 if (NULL != fRecord) {
184 fRecord->unref();
185 fRecord = NULL;
186 }
187
rileya@google.com7fb3d2f2012-09-13 21:41:51 +0000188 if (recordingFlags & kOptimizeForClippedPlayback_RecordingFlag) {
189 SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(width),
190 SkIntToScalar(height));
191 SkRTree* tree = SkRTree::Create(6, 11, aspectRatio);
192 SkASSERT(NULL != tree);
193 fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (recordingFlags, tree));
194 tree->unref();
195 } else {
196 fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags));
197 }
reed@android.combcd4d5a2008-12-17 15:59:43 +0000198
199 fWidth = width;
200 fHeight = height;
201
202 SkBitmap bm;
203 bm.setConfig(SkBitmap::kNo_Config, width, height);
204 fRecord->setBitmapDevice(bm);
reed@google.com91911482011-02-07 15:30:46 +0000205
reed@android.combcd4d5a2008-12-17 15:59:43 +0000206 return fRecord;
207}
208
junov@chromium.orgdc8630f2012-06-01 21:23:07 +0000209bool SkPicture::hasRecorded() const {
210 return NULL != fRecord && fRecord->writeStream().size() > 0;
211}
212
reed@android.combcd4d5a2008-12-17 15:59:43 +0000213SkCanvas* SkPicture::getRecordingCanvas() const {
214 // will be null if we are not recording
215 return fRecord;
216}
217
218void SkPicture::endRecording() {
219 if (NULL == fPlayback) {
220 if (NULL != fRecord) {
junov@chromium.org9aa18db2012-07-12 17:47:34 +0000221 fRecord->endRecording();
reed@android.combcd4d5a2008-12-17 15:59:43 +0000222 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
223 fRecord->unref();
224 fRecord = NULL;
225 }
226 }
227 SkASSERT(NULL == fRecord);
228}
229
230void SkPicture::draw(SkCanvas* surface) {
231 this->endRecording();
232 if (fPlayback) {
233 fPlayback->draw(*surface);
234 }
235}
236
237///////////////////////////////////////////////////////////////////////////////
238
239#include "SkStream.h"
240
reed@google.comc162a862012-06-22 13:12:17 +0000241// V2 : adds SkPixelRef's generation ID.
242// V3 : PictInfo tag at beginning, and EOF tag at the end
reed@google.com4bca7f62012-06-22 15:38:39 +0000243// V4 : move SkPictInfo to be the header
reed@google.com481fc1f2012-06-25 14:36:28 +0000244// V5 : don't read/write FunctionPtr on cross-process (we can detect that)
robertphillips@google.com18163cc2012-08-17 10:58:49 +0000245// V6 : added serialization of SkPath's bounds (and packed its flags tighter)
246#define PICTURE_VERSION 6
reed@android.combcd4d5a2008-12-17 15:59:43 +0000247
248SkPicture::SkPicture(SkStream* stream) : SkRefCnt() {
reed@android.combcd4d5a2008-12-17 15:59:43 +0000249 fRecord = NULL;
250 fPlayback = NULL;
reed@google.com4bca7f62012-06-22 15:38:39 +0000251 fWidth = fHeight = 0;
252
253 SkPictInfo info;
254
255 if (!stream->read(&info, sizeof(info))) {
256 return;
257 }
258 if (PICTURE_VERSION != info.fVersion) {
259 return;
260 }
reed@android.combcd4d5a2008-12-17 15:59:43 +0000261
262 if (stream->readBool()) {
reed@google.com4bca7f62012-06-22 15:38:39 +0000263 bool isValid = false;
264 fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream, info, &isValid));
265 if (!isValid) {
266 SkDELETE(fPlayback);
267 fPlayback = NULL;
268 return;
269 }
reed@android.combcd4d5a2008-12-17 15:59:43 +0000270 }
reed@google.com4bca7f62012-06-22 15:38:39 +0000271
272 // do this at the end, so that they will be zero if we hit an error.
273 fWidth = info.fWidth;
274 fHeight = info.fHeight;
reed@android.combcd4d5a2008-12-17 15:59:43 +0000275}
276
277void SkPicture::serialize(SkWStream* stream) const {
278 SkPicturePlayback* playback = fPlayback;
reed@google.com91911482011-02-07 15:30:46 +0000279
reed@android.combcd4d5a2008-12-17 15:59:43 +0000280 if (NULL == playback && fRecord) {
281 playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
282 }
283
reed@google.com4bca7f62012-06-22 15:38:39 +0000284 SkPictInfo info;
285
286 info.fVersion = PICTURE_VERSION;
287 info.fWidth = fWidth;
288 info.fHeight = fHeight;
289 info.fFlags = SkPictInfo::kCrossProcess_Flag;
290#ifdef SK_SCALAR_IS_FLOAT
291 info.fFlags |= SkPictInfo::kScalarIsFloat_Flag;
292#endif
293 if (8 == sizeof(void*)) {
294 info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
295 }
296
297 stream->write(&info, sizeof(info));
reed@android.combcd4d5a2008-12-17 15:59:43 +0000298 if (playback) {
299 stream->writeBool(true);
300 playback->serialize(stream);
301 // delete playback if it is a local version (i.e. cons'd up just now)
302 if (playback != fPlayback) {
303 SkDELETE(playback);
304 }
305 } else {
306 stream->writeBool(false);
307 }
308}
309
310void SkPicture::abortPlayback() {
311 if (NULL == fPlayback) {
312 return;
313 }
314 fPlayback->abort();
315}
316
317