• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>(&copyInfo.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, &copyInfo));
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