1
2 /*
3 * 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
9
10 #include "SkPictureFlat.h"
11 #include "SkPicturePlayback.h"
12 #include "SkPictureRecord.h"
13
14 #include "SkBBHFactory.h"
15 #include "SkBitmapDevice.h"
16 #include "SkCanvas.h"
17 #include "SkChunkAlloc.h"
18 #include "SkPaintPriv.h"
19 #include "SkPicture.h"
20 #include "SkRegion.h"
21 #include "SkStream.h"
22 #include "SkTDArray.h"
23 #include "SkTSearch.h"
24 #include "SkTime.h"
25
26 #include "SkReader32.h"
27 #include "SkWriter32.h"
28 #include "SkRTree.h"
29 #include "SkBBoxHierarchyRecord.h"
30
31 #if SK_SUPPORT_GPU
32 #include "GrContext.h"
33 #endif
34
SafeCount(const T * obj)35 template <typename T> int SafeCount(const T* obj) {
36 return obj ? obj->count() : 0;
37 }
38
39 #define DUMP_BUFFER_SIZE 65536
40
41 //#define ENABLE_TIME_DRAW // dumps milliseconds for each draw
42
43
44 #ifdef SK_DEBUG
45 // enable SK_DEBUG_TRACE to trace DrawType elements when
46 // recorded and played back
47 // #define SK_DEBUG_TRACE
48 // enable SK_DEBUG_SIZE to see the size of picture components
49 // #define SK_DEBUG_SIZE
50 // enable SK_DEBUG_DUMP to see the contents of recorded elements
51 // #define SK_DEBUG_DUMP
52 // enable SK_DEBUG_VALIDATE to check internal structures for consistency
53 // #define SK_DEBUG_VALIDATE
54 #endif
55
56 #if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP
DrawTypeToString(DrawType drawType)57 const char* DrawTypeToString(DrawType drawType) {
58 switch (drawType) {
59 case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break;
60 case CLIP_PATH: return "CLIP_PATH";
61 case CLIP_REGION: return "CLIP_REGION";
62 case CLIP_RECT: return "CLIP_RECT";
63 case CLIP_RRECT: return "CLIP_RRECT";
64 case CONCAT: return "CONCAT";
65 case DRAW_BITMAP: return "DRAW_BITMAP";
66 case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
67 case DRAW_BITMAP_NINE: return "DRAW_BITMAP_NINE";
68 case DRAW_BITMAP_RECT_TO_RECT: return "DRAW_BITMAP_RECT_TO_RECT";
69 case DRAW_CLEAR: return "DRAW_CLEAR";
70 case DRAW_DATA: return "DRAW_DATA";
71 case DRAW_OVAL: return "DRAW_OVAL";
72 case DRAW_PAINT: return "DRAW_PAINT";
73 case DRAW_PATH: return "DRAW_PATH";
74 case DRAW_PICTURE: return "DRAW_PICTURE";
75 case DRAW_POINTS: return "DRAW_POINTS";
76 case DRAW_POS_TEXT: return "DRAW_POS_TEXT";
77 case DRAW_POS_TEXT_TOP_BOTTOM: return "DRAW_POS_TEXT_TOP_BOTTOM";
78 case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
79 case DRAW_POS_TEXT_H_TOP_BOTTOM: return "DRAW_POS_TEXT_H_TOP_BOTTOM";
80 case DRAW_RECT: return "DRAW_RECT";
81 case DRAW_RRECT: return "DRAW_RRECT";
82 case DRAW_SPRITE: return "DRAW_SPRITE";
83 case DRAW_TEXT: return "DRAW_TEXT";
84 case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
85 case DRAW_TEXT_TOP_BOTTOM: return "DRAW_TEXT_TOP_BOTTOM";
86 case DRAW_VERTICES: return "DRAW_VERTICES";
87 case RESTORE: return "RESTORE";
88 case ROTATE: return "ROTATE";
89 case SAVE: return "SAVE";
90 case SAVE_LAYER: return "SAVE_LAYER";
91 case SCALE: return "SCALE";
92 case SET_MATRIX: return "SET_MATRIX";
93 case SKEW: return "SKEW";
94 case TRANSLATE: return "TRANSLATE";
95 case NOOP: return "NOOP";
96 default:
97 SkDebugf("DrawType error 0x%08x\n", drawType);
98 SkASSERT(0);
99 break;
100 }
101 SkASSERT(0);
102 return NULL;
103 }
104 #endif
105
106 #ifdef SK_DEBUG_VALIDATE
validateMatrix(const SkMatrix * matrix)107 static void validateMatrix(const SkMatrix* matrix) {
108 SkScalar scaleX = matrix->getScaleX();
109 SkScalar scaleY = matrix->getScaleY();
110 SkScalar skewX = matrix->getSkewX();
111 SkScalar skewY = matrix->getSkewY();
112 SkScalar perspX = matrix->getPerspX();
113 SkScalar perspY = matrix->getPerspY();
114 if (scaleX != 0 && skewX != 0)
115 SkDebugf("scaleX != 0 && skewX != 0\n");
116 SkASSERT(scaleX == 0 || skewX == 0);
117 SkASSERT(scaleY == 0 || skewY == 0);
118 SkASSERT(perspX == 0);
119 SkASSERT(perspY == 0);
120 }
121 #endif
122
123
124 ///////////////////////////////////////////////////////////////////////////////
125
SkPicture()126 SkPicture::SkPicture()
127 : fAccelData(NULL) {
128 this->needsNewGenID();
129 fPlayback = NULL;
130 fWidth = fHeight = 0;
131 }
132
SkPicture(int width,int height,const SkPictureRecord & record,bool deepCopyOps)133 SkPicture::SkPicture(int width, int height,
134 const SkPictureRecord& record,
135 bool deepCopyOps)
136 : fWidth(width)
137 , fHeight(height)
138 , fAccelData(NULL) {
139 this->needsNewGenID();
140
141 SkPictInfo info;
142 this->createHeader(&info);
143 fPlayback = SkNEW_ARGS(SkPicturePlayback, (record, info, deepCopyOps));
144 }
145
SkPicture(const SkPicture & src)146 SkPicture::SkPicture(const SkPicture& src)
147 : INHERITED()
148 , fAccelData(NULL) {
149 this->needsNewGenID();
150 fWidth = src.fWidth;
151 fHeight = src.fHeight;
152
153 if (src.fPlayback) {
154 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback));
155 fUniqueID = src.uniqueID(); // need to call method to ensure != 0
156 } else {
157 fPlayback = NULL;
158 }
159 }
160
~SkPicture()161 SkPicture::~SkPicture() {
162 SkDELETE(fPlayback);
163 SkSafeUnref(fAccelData);
164 }
165
swap(SkPicture & other)166 void SkPicture::swap(SkPicture& other) {
167 SkTSwap(fUniqueID, other.fUniqueID);
168 SkTSwap(fPlayback, other.fPlayback);
169 SkTSwap(fAccelData, other.fAccelData);
170 SkTSwap(fWidth, other.fWidth);
171 SkTSwap(fHeight, other.fHeight);
172 }
173
clone() const174 SkPicture* SkPicture::clone() const {
175 SkPicture* clonedPicture = SkNEW(SkPicture);
176 this->clone(clonedPicture, 1);
177 return clonedPicture;
178 }
179
clone(SkPicture * pictures,int count) const180 void SkPicture::clone(SkPicture* pictures, int count) const {
181 SkPictCopyInfo copyInfo;
182
183 for (int i = 0; i < count; i++) {
184 SkPicture* clone = &pictures[i];
185
186 clone->needsNewGenID();
187 clone->fWidth = fWidth;
188 clone->fHeight = fHeight;
189 SkDELETE(clone->fPlayback);
190
191 /* We want to copy the src's playback. However, if that hasn't been built
192 yet, we need to fake a call to endRecording() without actually calling
193 it (since it is destructive, and we don't want to change src).
194 */
195 if (fPlayback) {
196 if (!copyInfo.initialized) {
197 int paintCount = SafeCount(fPlayback->fPaints);
198
199 /* The alternative to doing this is to have a clone method on the paint and have it
200 * make the deep copy of its internal structures as needed. The holdup to doing
201 * that is at this point we would need to pass the SkBitmapHeap so that we don't
202 * unnecessarily flatten the pixels in a bitmap shader.
203 */
204 copyInfo.paintData.setCount(paintCount);
205
206 /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is
207 * one, use it. If this SkPicturePlayback was created from a stream, fBitmapHeap
208 * will be NULL, so create a new one.
209 */
210 if (fPlayback->fBitmapHeap.get() == NULL) {
211 // FIXME: Put this on the stack inside SkPicture::clone.
212 SkBitmapHeap* heap = SkNEW(SkBitmapHeap);
213 copyInfo.controller.setBitmapStorage(heap);
214 heap->unref();
215 } else {
216 copyInfo.controller.setBitmapStorage(fPlayback->fBitmapHeap);
217 }
218
219 SkDEBUGCODE(int heapSize = SafeCount(fPlayback->fBitmapHeap.get());)
220 for (int i = 0; i < paintCount; i++) {
221 if (NeedsDeepCopy(fPlayback->fPaints->at(i))) {
222 copyInfo.paintData[i] =
223 SkFlatData::Create<SkPaint::FlatteningTraits>(©Info.controller,
224 fPlayback->fPaints->at(i), 0);
225
226 } else {
227 // this is our sentinel, which we use in the unflatten loop
228 copyInfo.paintData[i] = NULL;
229 }
230 }
231 SkASSERT(SafeCount(fPlayback->fBitmapHeap.get()) == heapSize);
232
233 // needed to create typeface playback
234 copyInfo.controller.setupPlaybacks();
235 copyInfo.initialized = true;
236 }
237
238 clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fPlayback, ©Info));
239 clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0
240 } else {
241 clone->fPlayback = NULL;
242 }
243 }
244 }
245
GenerateDomain()246 SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
247 static int32_t gNextID = 0;
248
249 int32_t id = sk_atomic_inc(&gNextID);
250 if (id >= 1 << (8 * sizeof(Domain))) {
251 SK_CRASH();
252 }
253
254 return static_cast<Domain>(id);
255 }
256
257 ///////////////////////////////////////////////////////////////////////////////
258
InvalidList()259 const SkPicture::OperationList& SkPicture::OperationList::InvalidList() {
260 static OperationList gInvalid;
261 return gInvalid;
262 }
263
EXPERIMENTAL_getActiveOps(const SkIRect & queryRect) const264 const SkPicture::OperationList& SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const {
265 SkASSERT(NULL != fPlayback);
266 if (NULL != fPlayback) {
267 return fPlayback->getActiveOps(queryRect);
268 }
269 return OperationList::InvalidList();
270 }
271
EXPERIMENTAL_curOpID() const272 size_t SkPicture::EXPERIMENTAL_curOpID() const {
273 if (NULL != fPlayback) {
274 return fPlayback->curOpID();
275 }
276 return 0;
277 }
278
draw(SkCanvas * surface,SkDrawPictureCallback * callback) const279 void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) const {
280 SkASSERT(NULL != fPlayback);
281 if (NULL != fPlayback) {
282 fPlayback->draw(*surface, callback);
283 }
284 }
285
286 ///////////////////////////////////////////////////////////////////////////////
287
288 #include "SkStream.h"
289
290 static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
291
IsValidPictInfo(const SkPictInfo & info)292 bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
293 if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
294 return false;
295 }
296
297 if (info.fVersion < MIN_PICTURE_VERSION ||
298 info.fVersion > CURRENT_PICTURE_VERSION) {
299 return false;
300 }
301
302 return true;
303 }
304
InternalOnly_StreamIsSKP(SkStream * stream,SkPictInfo * pInfo)305 bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
306 if (NULL == stream) {
307 return false;
308 }
309
310 // Check magic bytes.
311 SkPictInfo info;
312 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
313 if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) {
314 return false;
315 }
316
317 if (pInfo != NULL) {
318 *pInfo = info;
319 }
320 return true;
321 }
322
InternalOnly_BufferIsSKP(SkReadBuffer & buffer,SkPictInfo * pInfo)323 bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) {
324 // Check magic bytes.
325 SkPictInfo info;
326 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
327 if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) {
328 return false;
329 }
330
331 if (pInfo != NULL) {
332 *pInfo = info;
333 }
334 return true;
335 }
336
SkPicture(SkPicturePlayback * playback,int width,int height)337 SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height)
338 : fPlayback(playback)
339 , fWidth(width)
340 , fHeight(height)
341 , fAccelData(NULL) {
342 this->needsNewGenID();
343 }
344
CreateFromStream(SkStream * stream,InstallPixelRefProc proc)345 SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
346 SkPictInfo info;
347
348 if (!InternalOnly_StreamIsSKP(stream, &info)) {
349 return NULL;
350 }
351
352 // Check to see if there is a playback to recreate.
353 if (stream->readBool()) {
354 SkPicturePlayback* playback = SkPicturePlayback::CreateFromStream(stream, info, proc);
355 if (NULL == playback) {
356 return NULL;
357 }
358
359 return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight));
360 }
361
362 return NULL;
363 }
364
CreateFromBuffer(SkReadBuffer & buffer)365 SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
366 SkPictInfo info;
367
368 if (!InternalOnly_BufferIsSKP(buffer, &info)) {
369 return NULL;
370 }
371
372 // Check to see if there is a playback to recreate.
373 if (buffer.readBool()) {
374 SkPicturePlayback* playback = SkPicturePlayback::CreateFromBuffer(buffer, info);
375 if (NULL == playback) {
376 return NULL;
377 }
378
379 return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight));
380 }
381
382 return NULL;
383 }
384
createHeader(SkPictInfo * info) const385 void SkPicture::createHeader(SkPictInfo* info) const {
386 // Copy magic bytes at the beginning of the header
387 SkASSERT(sizeof(kMagic) == 8);
388 SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
389 memcpy(info->fMagic, kMagic, sizeof(kMagic));
390
391 // Set picture info after magic bytes in the header
392 info->fVersion = CURRENT_PICTURE_VERSION;
393 info->fWidth = fWidth;
394 info->fHeight = fHeight;
395 info->fFlags = SkPictInfo::kCrossProcess_Flag;
396 // TODO: remove this flag, since we're always float (now)
397 info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
398
399 if (8 == sizeof(void*)) {
400 info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
401 }
402 }
403
serialize(SkWStream * stream,EncodeBitmap encoder) const404 void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
405 SkPicturePlayback* playback = fPlayback;
406
407 SkPictInfo info;
408 this->createHeader(&info);
409 stream->write(&info, sizeof(info));
410 if (playback) {
411 stream->writeBool(true);
412 playback->serialize(stream, encoder);
413 // delete playback if it is a local version (i.e. cons'd up just now)
414 if (playback != fPlayback) {
415 SkDELETE(playback);
416 }
417 } else {
418 stream->writeBool(false);
419 }
420 }
421
WriteTagSize(SkWriteBuffer & buffer,uint32_t tag,size_t size)422 void SkPicture::WriteTagSize(SkWriteBuffer& buffer, uint32_t tag, size_t size) {
423 buffer.writeUInt(tag);
424 buffer.writeUInt(SkToU32(size));
425 }
426
WriteTagSize(SkWStream * stream,uint32_t tag,size_t size)427 void SkPicture::WriteTagSize(SkWStream* stream, uint32_t tag, size_t size) {
428 stream->write32(tag);
429 stream->write32(SkToU32(size));
430 }
431
flatten(SkWriteBuffer & buffer) const432 void SkPicture::flatten(SkWriteBuffer& buffer) const {
433 SkPicturePlayback* playback = fPlayback;
434
435 SkPictInfo info;
436 this->createHeader(&info);
437 buffer.writeByteArray(&info, sizeof(info));
438 if (playback) {
439 buffer.writeBool(true);
440 playback->flatten(buffer);
441 // delete playback if it is a local version (i.e. cons'd up just now)
442 if (playback != fPlayback) {
443 SkDELETE(playback);
444 }
445 } else {
446 buffer.writeBool(false);
447 }
448 }
449
450 #if SK_SUPPORT_GPU
suitableForGpuRasterization(GrContext * context,const char ** reason) const451 bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const {
452 if (NULL == fPlayback) {
453 if (NULL != reason) {
454 *reason = "Missing playback object.";
455 }
456 return false;
457 }
458
459 return fPlayback->suitableForGpuRasterization(context, reason);
460 }
461 #endif
462
willPlayBackBitmaps() const463 bool SkPicture::willPlayBackBitmaps() const {
464 if (!fPlayback) {
465 return false;
466 }
467 return fPlayback->containsBitmaps();
468 }
469
470 #ifdef SK_BUILD_FOR_ANDROID
abortPlayback()471 void SkPicture::abortPlayback() {
472 if (NULL == fPlayback) {
473 return;
474 }
475 fPlayback->abort();
476 }
477 #endif
478
next_picture_generation_id()479 static int32_t next_picture_generation_id() {
480 static int32_t gPictureGenerationID = 0;
481 // do a loop in case our global wraps around, as we never want to
482 // return a 0
483 int32_t genID;
484 do {
485 genID = sk_atomic_inc(&gPictureGenerationID) + 1;
486 } while (SK_InvalidGenID == genID);
487 return genID;
488 }
489
uniqueID() const490 uint32_t SkPicture::uniqueID() const {
491 if (SK_InvalidGenID == fUniqueID) {
492 fUniqueID = next_picture_generation_id();
493 }
494 return fUniqueID;
495 }
496