• 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 "SkCanvas.h"
15 #include "SkChunkAlloc.h"
16 #include "SkDevice.h"
17 #include "SkPicture.h"
18 #include "SkRegion.h"
19 #include "SkStream.h"
20 #include "SkTDArray.h"
21 #include "SkTSearch.h"
22 #include "SkTime.h"
23 
24 #include "SkReader32.h"
25 #include "SkWriter32.h"
26 #include "SkRTree.h"
27 #include "SkBBoxHierarchyRecord.h"
28 
SK_DEFINE_INST_COUNT(SkPicture) const29 SK_DEFINE_INST_COUNT(SkPicture)
30 
31 #define DUMP_BUFFER_SIZE 65536
32 
33 //#define ENABLE_TIME_DRAW    // dumps milliseconds for each draw
34 
35 
36 #ifdef SK_DEBUG
37 // enable SK_DEBUG_TRACE to trace DrawType elements when
38 //     recorded and played back
39 // #define SK_DEBUG_TRACE
40 // enable SK_DEBUG_SIZE to see the size of picture components
41 // #define SK_DEBUG_SIZE
42 // enable SK_DEBUG_DUMP to see the contents of recorded elements
43 // #define SK_DEBUG_DUMP
44 // enable SK_DEBUG_VALIDATE to check internal structures for consistency
45 // #define SK_DEBUG_VALIDATE
46 #endif
47 
48 #if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP
49 const char* DrawTypeToString(DrawType drawType) {
50     switch (drawType) {
51         case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break;
52         case CLIP_PATH: return "CLIP_PATH";
53         case CLIP_REGION: return "CLIP_REGION";
54         case CLIP_RECT: return "CLIP_RECT";
55         case CONCAT: return "CONCAT";
56         case DRAW_BITMAP: return "DRAW_BITMAP";
57         case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
58         case DRAW_BITMAP_RECT: return "DRAW_BITMAP_RECT";
59         case DRAW_PAINT: return "DRAW_PAINT";
60         case DRAW_PATH: return "DRAW_PATH";
61         case DRAW_PICTURE: return "DRAW_PICTURE";
62         case DRAW_POINTS: return "DRAW_POINTS";
63         case DRAW_POS_TEXT: return "DRAW_POS_TEXT";
64         case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
65         case DRAW_RECT_GENERAL: return "DRAW_RECT_GENERAL";
66         case DRAW_RECT_SIMPLE: return "DRAW_RECT_SIMPLE";
67         case DRAW_SPRITE: return "DRAW_SPRITE";
68         case DRAW_TEXT: return "DRAW_TEXT";
69         case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
70         case RESTORE: return "RESTORE";
71         case ROTATE: return "ROTATE";
72         case SAVE: return "SAVE";
73         case SAVE_LAYER: return "SAVE_LAYER";
74         case SCALE: return "SCALE";
75         case SKEW: return "SKEW";
76         case TRANSLATE: return "TRANSLATE";
77         default:
78             SkDebugf("DrawType error 0x%08x\n", drawType);
79             SkASSERT(0);
80             break;
81     }
82     SkASSERT(0);
83     return NULL;
84 }
85 #endif
86 
87 #ifdef SK_DEBUG_VALIDATE
validateMatrix(const SkMatrix * matrix)88 static void validateMatrix(const SkMatrix* matrix) {
89     SkScalar scaleX = matrix->getScaleX();
90     SkScalar scaleY = matrix->getScaleY();
91     SkScalar skewX = matrix->getSkewX();
92     SkScalar skewY = matrix->getSkewY();
93     SkScalar perspX = matrix->getPerspX();
94     SkScalar perspY = matrix->getPerspY();
95     if (scaleX != 0 && skewX != 0)
96         SkDebugf("scaleX != 0 && skewX != 0\n");
97     SkASSERT(scaleX == 0 || skewX == 0);
98     SkASSERT(scaleY == 0 || skewY == 0);
99     SkASSERT(perspX == 0);
100     SkASSERT(perspY == 0);
101 }
102 #endif
103 
104 
105 ///////////////////////////////////////////////////////////////////////////////
106 
SkPicture()107 SkPicture::SkPicture() {
108     fRecord = NULL;
109     fPlayback = NULL;
110     fWidth = fHeight = 0;
111 }
112 
SkPicture(const SkPicture & src)113 SkPicture::SkPicture(const SkPicture& src) : SkRefCnt() {
114     fWidth = src.fWidth;
115     fHeight = src.fHeight;
116     fRecord = NULL;
117 
118     /*  We want to copy the src's playback. However, if that hasn't been built
119         yet, we need to fake a call to endRecording() without actually calling
120         it (since it is destructive, and we don't want to change src).
121      */
122     if (src.fPlayback) {
123         fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback));
124     } else if (src.fRecord) {
125         // here we do a fake src.endRecording()
126         fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord));
127     } else {
128         fPlayback = NULL;
129     }
130 }
131 
~SkPicture()132 SkPicture::~SkPicture() {
133     SkSafeUnref(fRecord);
134     SkDELETE(fPlayback);
135 }
136 
swap(SkPicture & other)137 void SkPicture::swap(SkPicture& other) {
138     SkTSwap(fRecord, other.fRecord);
139     SkTSwap(fPlayback, other.fPlayback);
140     SkTSwap(fWidth, other.fWidth);
141     SkTSwap(fHeight, other.fHeight);
142 }
143 
clone() const144 SkPicture* SkPicture::clone() const {
145     SkPicture* clonedPicture = SkNEW(SkPicture);
146     clone(clonedPicture, 1);
147     return clonedPicture;
148 }
149 
clone(SkPicture * pictures,int count) const150 void SkPicture::clone(SkPicture* pictures, int count) const {
151     SkPictCopyInfo copyInfo;
152 
153     for (int i = 0; i < count; i++) {
154         SkPicture* clone = &pictures[i];
155 
156         clone->fWidth = fWidth;
157         clone->fHeight = fHeight;
158         clone->fRecord = NULL;
159 
160         if (NULL != clone->fRecord) {
161             clone->fRecord->unref();
162             clone->fRecord = NULL;
163         }
164         SkDELETE(clone->fPlayback);
165 
166         /*  We want to copy the src's playback. However, if that hasn't been built
167             yet, we need to fake a call to endRecording() without actually calling
168             it (since it is destructive, and we don't want to change src).
169          */
170         if (fPlayback) {
171             clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fPlayback, &copyInfo));
172         } else if (fRecord) {
173             // here we do a fake src.endRecording()
174             clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, true));
175         } else {
176             clone->fPlayback = NULL;
177         }
178     }
179 }
180 
181 ///////////////////////////////////////////////////////////////////////////////
182 
beginRecording(int width,int height,uint32_t recordingFlags)183 SkCanvas* SkPicture::beginRecording(int width, int height,
184                                     uint32_t recordingFlags) {
185     if (fPlayback) {
186         SkDELETE(fPlayback);
187         fPlayback = NULL;
188     }
189 
190     if (NULL != fRecord) {
191         fRecord->unref();
192         fRecord = NULL;
193     }
194 
195     SkBitmap bm;
196     bm.setConfig(SkBitmap::kNo_Config, width, height);
197     SkAutoTUnref<SkDevice> dev(SkNEW_ARGS(SkDevice, (bm)));
198 
199     // Must be set before calling createBBoxHierarchy
200     fWidth = width;
201     fHeight = height;
202 
203     if (recordingFlags & kOptimizeForClippedPlayback_RecordingFlag) {
204         SkBBoxHierarchy* tree = this->createBBoxHierarchy();
205         SkASSERT(NULL != tree);
206         fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (recordingFlags, tree, dev));
207         tree->unref();
208     } else {
209         fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags, dev));
210     }
211     fRecord->beginRecording();
212 
213     return fRecord;
214 }
215 
createBBoxHierarchy() const216 SkBBoxHierarchy* SkPicture::createBBoxHierarchy() const {
217     // These values were empirically determined to produce reasonable
218     // performance in most cases.
219     static const int kRTreeMinChildren = 6;
220     static const int kRTreeMaxChildren = 11;
221 
222     SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth),
223                                        SkIntToScalar(fHeight));
224     return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren,
225                            aspectRatio);
226 }
227 
getRecordingCanvas() const228 SkCanvas* SkPicture::getRecordingCanvas() const {
229     // will be null if we are not recording
230     return fRecord;
231 }
232 
endRecording()233 void SkPicture::endRecording() {
234     if (NULL == fPlayback) {
235         if (NULL != fRecord) {
236             fRecord->endRecording();
237             fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
238             fRecord->unref();
239             fRecord = NULL;
240         }
241     }
242     SkASSERT(NULL == fRecord);
243 }
244 
draw(SkCanvas * surface)245 void SkPicture::draw(SkCanvas* surface) {
246     this->endRecording();
247     if (fPlayback) {
248         fPlayback->draw(*surface);
249     }
250 }
251 
252 ///////////////////////////////////////////////////////////////////////////////
253 
254 #include "SkStream.h"
255 
SkPicture(SkStream * stream,bool * success,SkSerializationHelpers::DecodeBitmap decoder)256 SkPicture::SkPicture(SkStream* stream, bool* success, SkSerializationHelpers::DecodeBitmap decoder) : SkRefCnt() {
257     if (success) {
258         *success = false;
259     }
260     fRecord = NULL;
261     fPlayback = NULL;
262     fWidth = fHeight = 0;
263 
264     SkPictInfo info;
265 
266     if (!stream->read(&info, sizeof(info))) {
267         return;
268     }
269     if (PICTURE_VERSION != info.fVersion) {
270         return;
271     }
272 
273     if (stream->readBool()) {
274         bool isValid = false;
275         fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream, info, &isValid, decoder));
276         if (!isValid) {
277             SkDELETE(fPlayback);
278             fPlayback = NULL;
279             return;
280         }
281     }
282 
283     // do this at the end, so that they will be zero if we hit an error.
284     fWidth = info.fWidth;
285     fHeight = info.fHeight;
286     if (success) {
287         *success = true;
288     }
289 }
290 
serialize(SkWStream * stream,SkSerializationHelpers::EncodeBitmap encoder) const291 void SkPicture::serialize(SkWStream* stream, SkSerializationHelpers::EncodeBitmap encoder) const {
292     SkPicturePlayback* playback = fPlayback;
293 
294     if (NULL == playback && fRecord) {
295         playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
296     }
297 
298     SkPictInfo info;
299 
300     info.fVersion = PICTURE_VERSION;
301     info.fWidth = fWidth;
302     info.fHeight = fHeight;
303     info.fFlags = SkPictInfo::kCrossProcess_Flag;
304 #ifdef SK_SCALAR_IS_FLOAT
305     info.fFlags |= SkPictInfo::kScalarIsFloat_Flag;
306 #endif
307     if (8 == sizeof(void*)) {
308         info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
309     }
310 
311     stream->write(&info, sizeof(info));
312     if (playback) {
313         stream->writeBool(true);
314         playback->serialize(stream, encoder);
315         // delete playback if it is a local version (i.e. cons'd up just now)
316         if (playback != fPlayback) {
317             SkDELETE(playback);
318         }
319     } else {
320         stream->writeBool(false);
321     }
322 }
323 
324 #ifdef SK_BUILD_FOR_ANDROID
abortPlayback()325 void SkPicture::abortPlayback() {
326     if (NULL == fPlayback) {
327         return;
328     }
329     fPlayback->abort();
330 }
331 #endif
332