OLD | NEW |
| (Empty) |
1 | |
2 /* | |
3 * Copyright 2011 Google Inc. | |
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 #ifndef SkPicturePlayback_DEFINED | |
10 #define SkPicturePlayback_DEFINED | |
11 | |
12 #include "SkBitmap.h" | |
13 #include "SkPathHeap.h" | |
14 #include "SkPicture.h" | |
15 #include "SkPictureFlat.h" | |
16 | |
17 #ifdef SK_BUILD_FOR_ANDROID | |
18 #include "SkThread.h" | |
19 #endif | |
20 | |
21 class SkData; | |
22 class SkPictureRecord; | |
23 class SkReader32; | |
24 class SkStream; | |
25 class SkWStream; | |
26 class SkBBoxHierarchy; | |
27 class SkMatrix; | |
28 class SkPaint; | |
29 class SkPath; | |
30 class SkPictureStateTree; | |
31 class SkReadBuffer; | |
32 class SkRegion; | |
33 | |
34 struct SkPictInfo { | |
35 enum Flags { | |
36 kCrossProcess_Flag = 1 << 0, | |
37 kScalarIsFloat_Flag = 1 << 1, | |
38 kPtrIs64Bit_Flag = 1 << 2, | |
39 }; | |
40 | |
41 char fMagic[8]; | |
42 uint32_t fVersion; | |
43 uint32_t fWidth; | |
44 uint32_t fHeight; | |
45 uint32_t fFlags; | |
46 }; | |
47 | |
48 #define SK_PICT_READER_TAG SkSetFourByteTag('r', 'e', 'a', 'd') | |
49 #define SK_PICT_FACTORY_TAG SkSetFourByteTag('f', 'a', 'c', 't') | |
50 #define SK_PICT_TYPEFACE_TAG SkSetFourByteTag('t', 'p', 'f', 'c') | |
51 #define SK_PICT_PICTURE_TAG SkSetFourByteTag('p', 'c', 't', 'r') | |
52 | |
53 // This tag specifies the size of the ReadBuffer, needed for the following tags | |
54 #define SK_PICT_BUFFER_SIZE_TAG SkSetFourByteTag('a', 'r', 'a', 'y') | |
55 // these are all inside the ARRAYS tag | |
56 #define SK_PICT_BITMAP_BUFFER_TAG SkSetFourByteTag('b', 't', 'm', 'p') | |
57 #define SK_PICT_PAINT_BUFFER_TAG SkSetFourByteTag('p', 'n', 't', ' ') | |
58 #define SK_PICT_PATH_BUFFER_TAG SkSetFourByteTag('p', 't', 'h', ' ') | |
59 | |
60 // Always write this guy last (with no length field afterwards) | |
61 #define SK_PICT_EOF_TAG SkSetFourByteTag('e', 'o', 'f', ' ') | |
62 | |
63 // SkPictureContentInfo is not serialized! It is intended solely for use | |
64 // with suitableForGpuRasterization. | |
65 class SkPictureContentInfo { | |
66 public: | |
67 SkPictureContentInfo() { this->reset(); } | |
68 | |
69 SkPictureContentInfo(const SkPictureContentInfo& src) { this->set(src); } | |
70 | |
71 void set(const SkPictureContentInfo& src) { | |
72 fNumPaintWithPathEffectUses = src.fNumPaintWithPathEffectUses; | |
73 fNumFastPathDashEffects = src.fNumFastPathDashEffects; | |
74 fNumAAConcavePaths = src.fNumAAConcavePaths; | |
75 fNumAAHairlineConcavePaths = src.fNumAAHairlineConcavePaths; | |
76 } | |
77 | |
78 void reset() { | |
79 fNumPaintWithPathEffectUses = 0; | |
80 fNumFastPathDashEffects = 0; | |
81 fNumAAConcavePaths = 0; | |
82 fNumAAHairlineConcavePaths = 0; | |
83 } | |
84 | |
85 void swap(SkPictureContentInfo* other) { | |
86 SkTSwap(fNumPaintWithPathEffectUses, other->fNumPaintWithPathEffectUses)
; | |
87 SkTSwap(fNumFastPathDashEffects, other->fNumFastPathDashEffects); | |
88 SkTSwap(fNumAAConcavePaths, other->fNumAAConcavePaths); | |
89 SkTSwap(fNumAAHairlineConcavePaths, other->fNumAAHairlineConcavePaths); | |
90 } | |
91 | |
92 void incPaintWithPathEffectUses() { ++fNumPaintWithPathEffectUses; } | |
93 int numPaintWithPathEffectUses() const { return fNumPaintWithPathEffectUses;
} | |
94 | |
95 void incFastPathDashEffects() { ++fNumFastPathDashEffects; } | |
96 int numFastPathDashEffects() const { return fNumFastPathDashEffects; } | |
97 | |
98 void incAAConcavePaths() { ++fNumAAConcavePaths; } | |
99 int numAAConcavePaths() const { return fNumAAConcavePaths; } | |
100 | |
101 void incAAHairlineConcavePaths() { | |
102 ++fNumAAHairlineConcavePaths; | |
103 SkASSERT(fNumAAHairlineConcavePaths <= fNumAAConcavePaths); | |
104 } | |
105 int numAAHairlineConcavePaths() const { return fNumAAHairlineConcavePaths; } | |
106 | |
107 private: | |
108 // This field is incremented every time a paint with a path effect is | |
109 // used (i.e., it is not a de-duplicated count) | |
110 int fNumPaintWithPathEffectUses; | |
111 // This field is incremented every time a paint with a path effect that is | |
112 // dashed, we are drawing a line, and we can use the gpu fast path | |
113 int fNumFastPathDashEffects; | |
114 // This field is incremented every time an anti-aliased drawPath call is | |
115 // issued with a concave path | |
116 int fNumAAConcavePaths; | |
117 // This field is incremented every time a drawPath call is | |
118 // issued for a hairline stroked concave path. | |
119 int fNumAAHairlineConcavePaths; | |
120 }; | |
121 | |
122 #ifdef SK_SUPPORT_LEGACY_PICTURE_CLONE | |
123 /** | |
124 * Container for data that is needed to deep copy a SkPicture. The container | |
125 * enables the data to be generated once and reused for subsequent copies. | |
126 */ | |
127 struct SkPictCopyInfo { | |
128 SkPictCopyInfo() : initialized(false), controller(1024) {} | |
129 | |
130 bool initialized; | |
131 SkChunkFlatController controller; | |
132 SkTDArray<SkFlatData*> paintData; | |
133 }; | |
134 #endif | |
135 | |
136 class SkPicturePlayback { | |
137 public: | |
138 #ifdef SK_SUPPORT_LEGACY_PICTURE_CLONE | |
139 SkPicturePlayback(const SkPicturePlayback& src, | |
140 SkPictCopyInfo* deepCopyInfo = NULL); | |
141 #else | |
142 SkPicturePlayback(const SkPicturePlayback& src); | |
143 #endif | |
144 SkPicturePlayback(const SkPictureRecord& record, const SkPictInfo&, bool dee
pCopyOps); | |
145 static SkPicturePlayback* CreateFromStream(SkStream*, | |
146 const SkPictInfo&, | |
147 SkPicture::InstallPixelRefProc); | |
148 static SkPicturePlayback* CreateFromBuffer(SkReadBuffer&, | |
149 const SkPictInfo&); | |
150 | |
151 virtual ~SkPicturePlayback(); | |
152 | |
153 const SkPicture::OperationList& getActiveOps(const SkIRect& queryRect); | |
154 | |
155 void setUseBBH(bool useBBH) { fUseBBH = useBBH; } | |
156 | |
157 void draw(SkCanvas& canvas, SkDrawPictureCallback*); | |
158 | |
159 void serialize(SkWStream*, SkPicture::EncodeBitmap) const; | |
160 void flatten(SkWriteBuffer&) const; | |
161 | |
162 void dumpSize() const; | |
163 | |
164 bool containsBitmaps() const; | |
165 | |
166 #ifdef SK_BUILD_FOR_ANDROID | |
167 // Can be called in the middle of playback (the draw() call). WIll abort the | |
168 // drawing and return from draw() after the "current" op code is done | |
169 void abort() { fAbortCurrentPlayback = true; } | |
170 #endif | |
171 | |
172 size_t curOpID() const { return fCurOffset; } | |
173 void resetOpID() { fCurOffset = 0; } | |
174 | |
175 protected: | |
176 explicit SkPicturePlayback(const SkPictInfo& info); | |
177 | |
178 bool parseStream(SkStream*, SkPicture::InstallPixelRefProc); | |
179 bool parseBuffer(SkReadBuffer& buffer); | |
180 #ifdef SK_DEVELOPER | |
181 virtual bool preDraw(int opIndex, int type); | |
182 virtual void postDraw(int opIndex); | |
183 #endif | |
184 | |
185 private: | |
186 class TextContainer { | |
187 public: | |
188 size_t length() { return fByteLength; } | |
189 const void* text() { return (const void*) fText; } | |
190 size_t fByteLength; | |
191 const char* fText; | |
192 }; | |
193 | |
194 const SkBitmap& getBitmap(SkReader32& reader) { | |
195 const int index = reader.readInt(); | |
196 if (SkBitmapHeap::INVALID_SLOT == index) { | |
197 #ifdef SK_DEBUG | |
198 SkDebugf("An invalid bitmap was recorded!\n"); | |
199 #endif | |
200 return fBadBitmap; | |
201 } | |
202 return (*fBitmaps)[index]; | |
203 } | |
204 | |
205 void getMatrix(SkReader32& reader, SkMatrix* matrix) { | |
206 reader.readMatrix(matrix); | |
207 } | |
208 | |
209 const SkPath& getPath(SkReader32& reader) { | |
210 int index = reader.readInt() - 1; | |
211 return (*fPathHeap.get())[index]; | |
212 } | |
213 | |
214 const SkPicture* getPicture(SkReader32& reader) { | |
215 int index = reader.readInt(); | |
216 SkASSERT(index > 0 && index <= fPictureCount); | |
217 return fPictureRefs[index - 1]; | |
218 } | |
219 | |
220 const SkPaint* getPaint(SkReader32& reader) { | |
221 int index = reader.readInt(); | |
222 if (index == 0) { | |
223 return NULL; | |
224 } | |
225 return &(*fPaints)[index - 1]; | |
226 } | |
227 | |
228 const SkRect* getRectPtr(SkReader32& reader) { | |
229 if (reader.readBool()) { | |
230 return &reader.skipT<SkRect>(); | |
231 } else { | |
232 return NULL; | |
233 } | |
234 } | |
235 | |
236 const SkIRect* getIRectPtr(SkReader32& reader) { | |
237 if (reader.readBool()) { | |
238 return &reader.skipT<SkIRect>(); | |
239 } else { | |
240 return NULL; | |
241 } | |
242 } | |
243 | |
244 void getRegion(SkReader32& reader, SkRegion* region) { | |
245 reader.readRegion(region); | |
246 } | |
247 | |
248 void getText(SkReader32& reader, TextContainer* text) { | |
249 size_t length = text->fByteLength = reader.readInt(); | |
250 text->fText = (const char*)reader.skip(length); | |
251 } | |
252 | |
253 void init(); | |
254 | |
255 #ifdef SK_DEBUG_SIZE | |
256 public: | |
257 int size(size_t* sizePtr); | |
258 int bitmaps(size_t* size); | |
259 int paints(size_t* size); | |
260 int paths(size_t* size); | |
261 #endif | |
262 | |
263 #ifdef SK_DEBUG_DUMP | |
264 private: | |
265 void dumpBitmap(const SkBitmap& bitmap) const; | |
266 void dumpMatrix(const SkMatrix& matrix) const; | |
267 void dumpPaint(const SkPaint& paint) const; | |
268 void dumpPath(const SkPath& path) const; | |
269 void dumpPicture(const SkPicture& picture) const; | |
270 void dumpRegion(const SkRegion& region) const; | |
271 int dumpDrawType(char* bufferPtr, char* buffer, DrawType drawType); | |
272 int dumpInt(char* bufferPtr, char* buffer, char* name); | |
273 int dumpRect(char* bufferPtr, char* buffer, char* name); | |
274 int dumpPoint(char* bufferPtr, char* buffer, char* name); | |
275 void dumpPointArray(char** bufferPtrPtr, char* buffer, int count); | |
276 int dumpPtr(char* bufferPtr, char* buffer, char* name, void* ptr); | |
277 int dumpRectPtr(char* bufferPtr, char* buffer, char* name); | |
278 int dumpScalar(char* bufferPtr, char* buffer, char* name); | |
279 void dumpText(char** bufferPtrPtr, char* buffer); | |
280 void dumpStream(); | |
281 | |
282 public: | |
283 void dump() const; | |
284 #endif | |
285 | |
286 #if SK_SUPPORT_GPU | |
287 /** | |
288 * sampleCount is the number of samples-per-pixel or zero if non-MSAA. | |
289 * It is defaulted to be zero. | |
290 */ | |
291 bool suitableForGpuRasterization(GrContext* context, const char **reason, | |
292 int sampleCount = 0) const; | |
293 | |
294 /** | |
295 * Calls getRecommendedSampleCount with GrPixelConfig and dpi to calculate s
ampleCount | |
296 * and then calls the above version of suitableForGpuRasterization | |
297 */ | |
298 bool suitableForGpuRasterization(GrContext* context, const char **reason, | |
299 GrPixelConfig config, SkScalar dpi) const; | |
300 #endif | |
301 | |
302 private: // these help us with reading/writing | |
303 bool parseStreamTag(SkStream*, uint32_t tag, uint32_t size, SkPicture::Insta
llPixelRefProc); | |
304 bool parseBufferTag(SkReadBuffer&, uint32_t tag, uint32_t size); | |
305 void flattenToBuffer(SkWriteBuffer&) const; | |
306 | |
307 private: | |
308 friend class SkPicture; | |
309 friend class SkGpuDevice; // for access to setDrawLimits & setReplacements | |
310 | |
311 // Only used by getBitmap() if the passed in index is SkBitmapHeap::INVALID_
SLOT. This empty | |
312 // bitmap allows playback to draw nothing and move on. | |
313 SkBitmap fBadBitmap; | |
314 | |
315 SkAutoTUnref<SkBitmapHeap> fBitmapHeap; | |
316 | |
317 SkTRefArray<SkBitmap>* fBitmaps; | |
318 SkTRefArray<SkPaint>* fPaints; | |
319 | |
320 SkData* fOpData; // opcodes and parameters | |
321 | |
322 SkAutoTUnref<const SkPathHeap> fPathHeap; // reference counted | |
323 | |
324 const SkPicture** fPictureRefs; | |
325 int fPictureCount; | |
326 | |
327 SkBBoxHierarchy* fBoundingHierarchy; | |
328 SkPictureStateTree* fStateTree; | |
329 | |
330 SkPictureContentInfo fContentInfo; | |
331 | |
332 // Limit the opcode playback to be between the offsets 'start' and 'stop'. | |
333 // The opcode at 'start' should be a saveLayer while the opcode at | |
334 // 'stop' should be a restore. Neither of those commands will be issued. | |
335 // Set both start & stop to 0 to disable draw limiting | |
336 // Draw limiting cannot be enabled at the same time as draw replacing | |
337 void setDrawLimits(size_t start, size_t stop) { | |
338 SkASSERT(NULL == fReplacements); | |
339 fStart = start; | |
340 fStop = stop; | |
341 } | |
342 | |
343 // PlaybackReplacements collects op ranges that can be replaced with | |
344 // a single drawBitmap call (using a precomputed bitmap). | |
345 class PlaybackReplacements { | |
346 public: | |
347 // All the operations between fStart and fStop (inclusive) will be repla
ced with | |
348 // a single drawBitmap call using fPos, fBM and fPaint. | |
349 // fPaint will be NULL if the picture's paint wasn't copyable | |
350 struct ReplacementInfo { | |
351 size_t fStart; | |
352 size_t fStop; | |
353 SkIPoint fPos; | |
354 SkBitmap* fBM; // fBM is allocated so ReplacementInfo can
remain POD | |
355 const SkPaint* fPaint; // Note: this object doesn't own the paint | |
356 | |
357 SkIRect fSrcRect; | |
358 }; | |
359 | |
360 ~PlaybackReplacements() { this->freeAll(); } | |
361 | |
362 // Add a new replacement range. The replacement ranges should be | |
363 // sorted in increasing order and non-overlapping (esp. no nested | |
364 // saveLayers). | |
365 ReplacementInfo* push(); | |
366 | |
367 private: | |
368 friend class SkPicturePlayback; // for access to lookupByStart | |
369 | |
370 // look up a replacement range by its start offset | |
371 ReplacementInfo* lookupByStart(size_t start); | |
372 | |
373 void freeAll(); | |
374 | |
375 #ifdef SK_DEBUG | |
376 void validate() const; | |
377 #endif | |
378 | |
379 SkTDArray<ReplacementInfo> fReplacements; | |
380 }; | |
381 | |
382 // Replace all the draw ops in the replacement ranges in 'replacements' with | |
383 // the associated drawBitmap call | |
384 // Draw replacing cannot be enabled at the same time as draw limiting | |
385 void setReplacements(PlaybackReplacements* replacements) { | |
386 SkASSERT(fStart == 0 && fStop == 0); | |
387 fReplacements = replacements; | |
388 } | |
389 | |
390 bool fUseBBH; | |
391 size_t fStart; | |
392 size_t fStop; | |
393 PlaybackReplacements* fReplacements; | |
394 | |
395 class CachedOperationList : public SkPicture::OperationList { | |
396 public: | |
397 CachedOperationList() { | |
398 fCacheQueryRect.setEmpty(); | |
399 } | |
400 | |
401 virtual bool valid() const { return true; } | |
402 virtual int numOps() const SK_OVERRIDE { return fOps.count(); } | |
403 virtual uint32_t offset(int index) const SK_OVERRIDE; | |
404 virtual const SkMatrix& matrix(int index) const SK_OVERRIDE; | |
405 | |
406 // The query rect for which the cached active ops are valid | |
407 SkIRect fCacheQueryRect; | |
408 | |
409 // The operations which are active within 'fCachedQueryRect' | |
410 SkTDArray<void*> fOps; | |
411 | |
412 private: | |
413 typedef SkPicture::OperationList INHERITED; | |
414 }; | |
415 | |
416 CachedOperationList* fCachedActiveOps; | |
417 | |
418 SkTypefacePlayback fTFPlayback; | |
419 SkFactoryPlayback* fFactoryPlayback; | |
420 | |
421 // The offset of the current operation when within the draw method | |
422 size_t fCurOffset; | |
423 | |
424 const SkPictInfo fInfo; | |
425 | |
426 static void WriteFactories(SkWStream* stream, const SkFactorySet& rec); | |
427 static void WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec); | |
428 | |
429 void initForPlayback() const; | |
430 | |
431 #ifdef SK_BUILD_FOR_ANDROID | |
432 SkMutex fDrawMutex; | |
433 bool fAbortCurrentPlayback; | |
434 #endif | |
435 }; | |
436 | |
437 #endif | |
OLD | NEW |