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 #ifndef SkPictureFlat_DEFINED
9 #define SkPictureFlat_DEFINED
10
11
12 #include "SkBitmapHeap.h"
13 #include "SkChecksum.h"
14 #include "SkChunkAlloc.h"
15 #include "SkReadBuffer.h"
16 #include "SkWriteBuffer.h"
17 #include "SkPaint.h"
18 #include "SkPicture.h"
19 #include "SkPtrRecorder.h"
20 #include "SkTDynamicHash.h"
21
22 enum DrawType {
23 UNUSED,
24 CLIP_PATH,
25 CLIP_REGION,
26 CLIP_RECT,
27 CLIP_RRECT,
28 CONCAT,
29 DRAW_BITMAP,
30 DRAW_BITMAP_MATRIX, // deprecated, M41 was last Chromium version to write this to an .skp
31 DRAW_BITMAP_NINE,
32 DRAW_BITMAP_RECT_TO_RECT,
33 DRAW_CLEAR,
34 DRAW_DATA,
35 DRAW_OVAL,
36 DRAW_PAINT,
37 DRAW_PATH,
38 DRAW_PICTURE,
39 DRAW_POINTS,
40 DRAW_POS_TEXT,
41 DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
42 DRAW_POS_TEXT_H,
43 DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
44 DRAW_RECT,
45 DRAW_RRECT,
46 DRAW_SPRITE,
47 DRAW_TEXT,
48 DRAW_TEXT_ON_PATH,
49 DRAW_TEXT_TOP_BOTTOM, // fast variant of DRAW_TEXT
50 DRAW_VERTICES,
51 RESTORE,
52 ROTATE,
53 SAVE,
54 SAVE_LAYER,
55 SCALE,
56 SET_MATRIX,
57 SKEW,
58 TRANSLATE,
59 NOOP,
60 BEGIN_COMMENT_GROUP,
61 COMMENT,
62 END_COMMENT_GROUP,
63
64 // new ops -- feel free to re-alphabetize on next version bump
65 DRAW_DRRECT,
66 PUSH_CULL, // deprecated, M41 was last Chromium version to write this to an .skp
67 POP_CULL, // deprecated, M41 was last Chromium version to write this to an .skp
68
69 DRAW_PATCH, // could not add in aphabetical order
70 DRAW_PICTURE_MATRIX_PAINT,
71 DRAW_TEXT_BLOB,
72
73 LAST_DRAWTYPE_ENUM = DRAW_TEXT_BLOB
74 };
75
76 // In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
77 static const int kDRAW_BITMAP_FLAVOR = LAST_DRAWTYPE_ENUM+1;
78
79 enum DrawVertexFlags {
80 DRAW_VERTICES_HAS_TEXS = 0x01,
81 DRAW_VERTICES_HAS_COLORS = 0x02,
82 DRAW_VERTICES_HAS_INDICES = 0x04,
83 DRAW_VERTICES_HAS_XFER = 0x08,
84 };
85
86 ///////////////////////////////////////////////////////////////////////////////
87 // clipparams are packed in 5 bits
88 // doAA:1 | regionOp:4
89
ClipParams_pack(SkRegion::Op op,bool doAA)90 static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) {
91 unsigned doAABit = doAA ? 1 : 0;
92 return (doAABit << 4) | op;
93 }
94
ClipParams_unpackRegionOp(uint32_t packed)95 static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) {
96 return (SkRegion::Op)(packed & 0xF);
97 }
98
ClipParams_unpackDoAA(uint32_t packed)99 static inline bool ClipParams_unpackDoAA(uint32_t packed) {
100 return SkToBool((packed >> 4) & 1);
101 }
102
103 ///////////////////////////////////////////////////////////////////////////////
104
105 class SkTypefacePlayback {
106 public:
107 SkTypefacePlayback();
108 virtual ~SkTypefacePlayback();
109
count()110 int count() const { return fCount; }
111
112 void reset(const SkRefCntSet*);
113
114 void setCount(int count);
115 SkRefCnt* set(int index, SkRefCnt*);
116
setupBuffer(SkReadBuffer & buffer)117 void setupBuffer(SkReadBuffer& buffer) const {
118 buffer.setTypefaceArray((SkTypeface**)fArray, fCount);
119 }
120
121 protected:
122 int fCount;
123 SkRefCnt** fArray;
124 };
125
126 class SkFactoryPlayback {
127 public:
SkFactoryPlayback(int count)128 SkFactoryPlayback(int count) : fCount(count) {
129 fArray = SkNEW_ARRAY(SkFlattenable::Factory, count);
130 }
131
~SkFactoryPlayback()132 ~SkFactoryPlayback() {
133 SkDELETE_ARRAY(fArray);
134 }
135
base()136 SkFlattenable::Factory* base() const { return fArray; }
137
setupBuffer(SkReadBuffer & buffer)138 void setupBuffer(SkReadBuffer& buffer) const {
139 buffer.setFactoryPlayback(fArray, fCount);
140 }
141
142 private:
143 int fCount;
144 SkFlattenable::Factory* fArray;
145 };
146
147 ///////////////////////////////////////////////////////////////////////////////
148 //
149 //
150 // The following templated classes provide an efficient way to store and compare
151 // objects that have been flattened (i.e. serialized in an ordered binary
152 // format).
153 //
154 // SkFlatData: is a simple indexable container for the flattened data
155 // which is agnostic to the type of data is is indexing. It is
156 // also responsible for flattening/unflattening objects but
157 // details of that operation are hidden in the provided traits
158 // SkFlatDictionary: is an abstract templated dictionary that maintains a
159 // searchable set of SkFlatData objects of type T.
160 // SkFlatController: is an interface provided to SkFlatDictionary which handles
161 // allocation (and unallocation in some cases). It also holds
162 // ref count recorders and the like.
163 //
164 // NOTE: any class that wishes to be used in conjunction with SkFlatDictionary must subclass the
165 // dictionary and provide the necessary flattening traits. SkFlatController must also be
166 // implemented, or SkChunkFlatController can be used to use an SkChunkAllocator and never do
167 // replacements.
168 //
169 //
170 ///////////////////////////////////////////////////////////////////////////////
171
172 class SkFlatData;
173
174 class SkFlatController : public SkRefCnt {
175 public:
176 SK_DECLARE_INST_COUNT(SkFlatController)
177
178 SkFlatController(uint32_t writeBufferFlags = 0);
179 virtual ~SkFlatController();
180 /**
181 * Return a new block of memory for the SkFlatDictionary to use.
182 * This memory is owned by the controller and has the same lifetime unless you
183 * call unalloc(), in which case it may be freed early.
184 */
185 virtual void* allocThrow(size_t bytes) = 0;
186
187 /**
188 * Hint that this block, which was allocated with allocThrow, is no longer needed.
189 * The implementation may choose to free this memory any time beteween now and destruction.
190 */
191 virtual void unalloc(void* ptr) = 0;
192
193 /**
194 * Used during creation and unflattening of SkFlatData objects. If the
195 * objects being flattened contain bitmaps they are stored in this heap
196 * and the flattenable stores the index to the bitmap on the heap.
197 * This should be set by the protected setBitmapHeap.
198 */
getBitmapHeap()199 SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; }
200
201 /**
202 * Used during creation of SkFlatData objects. If a typeface recorder is
203 * required to flatten the objects being flattened (i.e. for SkPaints), this
204 * should be set by the protected setTypefaceSet.
205 */
getTypefaceSet()206 SkRefCntSet* getTypefaceSet() { return fTypefaceSet; }
207
208 /**
209 * Used during unflattening of the SkFlatData objects in the
210 * SkFlatDictionary. Needs to be set by the protected setTypefacePlayback
211 * and needs to be reset to the SkRefCntSet passed to setTypefaceSet.
212 */
getTypefacePlayback()213 SkTypefacePlayback* getTypefacePlayback() { return fTypefacePlayback; }
214
215 /**
216 * Optional factory recorder used during creation of SkFlatData objects. Set
217 * using the protected method setNamedFactorySet.
218 */
getNamedFactorySet()219 SkNamedFactorySet* getNamedFactorySet() { return fFactorySet; }
220
221 /**
222 * Flags to use during creation of SkFlatData objects. Defaults to zero.
223 */
getWriteBufferFlags()224 uint32_t getWriteBufferFlags() { return fWriteBufferFlags; }
225
226 protected:
227 /**
228 * Set an SkBitmapHeap to be used to store/read SkBitmaps. Ref counted.
229 */
230 void setBitmapHeap(SkBitmapHeap*);
231
232 /**
233 * Set an SkRefCntSet to be used to store SkTypefaces during flattening. Ref
234 * counted.
235 */
236 void setTypefaceSet(SkRefCntSet*);
237
238 /**
239 * Set an SkTypefacePlayback to be used to find references to SkTypefaces
240 * during unflattening. Should be reset to the set provided to
241 * setTypefaceSet.
242 */
243 void setTypefacePlayback(SkTypefacePlayback*);
244
245 /**
246 * Set an SkNamedFactorySet to be used to store Factorys and their
247 * corresponding names during flattening. Ref counted. Returns the same
248 * set as a convenience.
249 */
250 SkNamedFactorySet* setNamedFactorySet(SkNamedFactorySet*);
251
252 private:
253 SkBitmapHeap* fBitmapHeap;
254 SkRefCntSet* fTypefaceSet;
255 SkTypefacePlayback* fTypefacePlayback;
256 SkNamedFactorySet* fFactorySet;
257 const uint32_t fWriteBufferFlags;
258
259 typedef SkRefCnt INHERITED;
260 };
261
262 class SkFlatData {
263 public:
264 // Flatten obj into an SkFlatData with this index. controller owns the SkFlatData*.
265 template <typename Traits, typename T>
Create(SkFlatController * controller,const T & obj,int index)266 static SkFlatData* Create(SkFlatController* controller, const T& obj, int index) {
267 // A buffer of 256 bytes should fit most paints, regions, and matrices.
268 uint32_t storage[64];
269 SkWriteBuffer buffer(storage, sizeof(storage), controller->getWriteBufferFlags());
270
271 buffer.setBitmapHeap(controller->getBitmapHeap());
272 buffer.setTypefaceRecorder(controller->getTypefaceSet());
273 buffer.setNamedFactoryRecorder(controller->getNamedFactorySet());
274
275 Traits::Flatten(buffer, obj);
276 size_t size = buffer.bytesWritten();
277 SkASSERT(SkIsAlign4(size));
278
279 // Allocate enough memory to hold SkFlatData struct and the flat data itself.
280 size_t allocSize = sizeof(SkFlatData) + size;
281 SkFlatData* result = (SkFlatData*) controller->allocThrow(allocSize);
282
283 // Put the serialized contents into the data section of the new allocation.
284 buffer.writeToMemory(result->data());
285 // Stamp the index, size and checksum in the header.
286 result->stampHeader(index, SkToS32(size));
287 return result;
288 }
289
290 // Unflatten this into result, using bitmapHeap and facePlayback for bitmaps and fonts if given
291 template <typename Traits, typename T>
292 void unflatten(T* result,
293 SkBitmapHeap* bitmapHeap = NULL,
294 SkTypefacePlayback* facePlayback = NULL) const {
295 SkReadBuffer buffer(this->data(), fFlatSize);
296
297 if (bitmapHeap) {
298 buffer.setBitmapStorage(bitmapHeap);
299 }
300 if (facePlayback) {
301 facePlayback->setupBuffer(buffer);
302 }
303
304 Traits::Unflatten(buffer, result);
305 SkASSERT(fFlatSize == (int32_t)buffer.offset());
306 }
307
308 // Do these contain the same data? Ignores index() and topBot().
309 bool operator==(const SkFlatData& that) const {
310 if (this->checksum() != that.checksum() || this->flatSize() != that.flatSize()) {
311 return false;
312 }
313 return memcmp(this->data(), that.data(), this->flatSize()) == 0;
314 }
315
index()316 int index() const { return fIndex; }
data()317 const uint8_t* data() const { return (const uint8_t*)this + sizeof(*this); }
flatSize()318 size_t flatSize() const { return fFlatSize; }
checksum()319 uint32_t checksum() const { return fChecksum; }
320
321 // Returns true if fTopBot[] has been recorded.
isTopBotWritten()322 bool isTopBotWritten() const {
323 return !SkScalarIsNaN(fTopBot[0]);
324 }
325
326 // Returns fTopBot array, so it can be passed to a routine to compute them.
327 // For efficiency, we assert that fTopBot have not been recorded yet.
writableTopBot()328 SkScalar* writableTopBot() const {
329 SkASSERT(!this->isTopBotWritten());
330 return fTopBot;
331 }
332
333 // Return the topbot[] after it has been recorded.
topBot()334 const SkScalar* topBot() const {
335 SkASSERT(this->isTopBotWritten());
336 return fTopBot;
337 }
338
339 private:
340 struct HashTraits {
GetKeyHashTraits341 static const SkFlatData& GetKey(const SkFlatData& flat) { return flat; }
HashHashTraits342 static uint32_t Hash(const SkFlatData& flat) { return flat.checksum(); }
343 };
344
setIndex(int index)345 void setIndex(int index) { fIndex = index; }
data()346 uint8_t* data() { return (uint8_t*)this + sizeof(*this); }
347
348 // This assumes the payload flat data has already been written and does not modify it.
stampHeader(int index,int32_t size)349 void stampHeader(int index, int32_t size) {
350 SkASSERT(SkIsAlign4(size));
351 fIndex = index;
352 fFlatSize = size;
353 fTopBot[0] = SK_ScalarNaN; // Mark as unwritten.
354 fChecksum = SkChecksum::Compute((uint32_t*)this->data(), size);
355 }
356
357 int fIndex;
358 int32_t fFlatSize;
359 uint32_t fChecksum;
360 mutable SkScalar fTopBot[2]; // Cache of FontMetrics fTop, fBottom. Starts as [NaN,?].
361 // uint32_t flattenedData[] implicitly hangs off the end.
362
363 template <typename T, typename Traits> friend class SkFlatDictionary;
364 };
365
366 template <typename T, typename Traits>
367 class SkFlatDictionary {
368 public:
SkFlatDictionary(SkFlatController * controller)369 explicit SkFlatDictionary(SkFlatController* controller)
370 : fController(SkRef(controller))
371 , fScratch(controller->getWriteBufferFlags())
372 , fReady(false) {
373 this->reset();
374 }
375
376 /**
377 * Clears the dictionary of all entries. However, it does NOT free the
378 * memory that was allocated for each entry (that's owned by controller).
379 */
reset()380 void reset() {
381 fIndexedData.rewind();
382 }
383
count()384 int count() const {
385 SkASSERT(fHash.count() == fIndexedData.count());
386 return fHash.count();
387 }
388
389 // For testing only. Index is zero-based.
390 const SkFlatData* operator[](int index) {
391 return fIndexedData[index];
392 }
393
394 /**
395 * Given an element of type T return its 1-based index in the dictionary. If
396 * the element wasn't previously in the dictionary it is automatically
397 * added.
398 *
399 */
find(const T & element)400 int find(const T& element) {
401 return this->findAndReturnFlat(element)->index();
402 }
403
404 /**
405 * Similar to find. Allows the caller to specify an SkFlatData to replace in
406 * the case of an add. Also tells the caller whether a new SkFlatData was
407 * added and whether the old one was replaced. The parameters added and
408 * replaced are required to be non-NULL. Rather than returning the index of
409 * the entry in the dictionary, it returns the actual SkFlatData.
410 */
findAndReplace(const T & element,const SkFlatData * toReplace,bool * added,bool * replaced)411 const SkFlatData* findAndReplace(const T& element,
412 const SkFlatData* toReplace,
413 bool* added,
414 bool* replaced) {
415 SkASSERT(added != NULL && replaced != NULL);
416
417 const int oldCount = this->count();
418 SkFlatData* flat = this->findAndReturnMutableFlat(element);
419 *added = this->count() > oldCount;
420
421 // If we don't want to replace anything, we're done.
422 if (!*added || toReplace == NULL) {
423 *replaced = false;
424 return flat;
425 }
426
427 // If we don't have the thing to replace, we're done.
428 const SkFlatData* found = fHash.find(*toReplace);
429 if (found == NULL) {
430 *replaced = false;
431 return flat;
432 }
433
434 // findAndReturnMutableFlat put flat at the back. Swap it into found->index() instead.
435 // indices in SkFlatData are 1-based, while fIndexedData is 0-based. Watch out!
436 SkASSERT(flat->index() == this->count());
437 flat->setIndex(found->index());
438 fIndexedData.removeShuffle(found->index()-1);
439 SkASSERT(flat == fIndexedData[found->index()-1]);
440
441 // findAndReturnMutableFlat already called fHash.add(), so we just clean up the old entry.
442 fHash.remove(*found);
443 fController->unalloc((void*)found);
444 SkASSERT(this->count() == oldCount);
445
446 *replaced = true;
447 return flat;
448 }
449
450 /**
451 * Unflatten the specific object at the given index.
452 * Caller takes ownership of the result.
453 */
unflatten(int index)454 T* unflatten(int index) const {
455 // index is 1-based, while fIndexedData is 0-based.
456 const SkFlatData* element = fIndexedData[index-1];
457 SkASSERT(index == element->index());
458
459 T* dst = new T;
460 this->unflatten(dst, element);
461 return dst;
462 }
463
464 /**
465 * Find or insert a flattened version of element into the dictionary.
466 * Caller does not take ownership of the result. This will not return NULL.
467 */
findAndReturnFlat(const T & element)468 const SkFlatData* findAndReturnFlat(const T& element) {
469 return this->findAndReturnMutableFlat(element);
470 }
471
472 private:
473 // We have to delay fScratch's initialization until its first use; fController might not
474 // be fully set up by the time we get it in the constructor.
lazyInit()475 void lazyInit() {
476 if (fReady) {
477 return;
478 }
479
480 // Without a bitmap heap, we'll flatten bitmaps into paints. That's never what you want.
481 SkASSERT(fController->getBitmapHeap() != NULL);
482 fScratch.setBitmapHeap(fController->getBitmapHeap());
483 fScratch.setTypefaceRecorder(fController->getTypefaceSet());
484 fScratch.setNamedFactoryRecorder(fController->getNamedFactorySet());
485 fReady = true;
486 }
487
488 // As findAndReturnFlat, but returns a mutable pointer for internal use.
findAndReturnMutableFlat(const T & element)489 SkFlatData* findAndReturnMutableFlat(const T& element) {
490 // Only valid until the next call to resetScratch().
491 const SkFlatData& scratch = this->resetScratch(element, this->count()+1);
492
493 SkFlatData* candidate = fHash.find(scratch);
494 if (candidate != NULL) {
495 return candidate;
496 }
497
498 SkFlatData* detached = this->detachScratch();
499 fHash.add(detached);
500 *fIndexedData.append() = detached;
501 SkASSERT(fIndexedData.top()->index() == this->count());
502 return detached;
503 }
504
505 // This reference is valid only until the next call to resetScratch() or detachScratch().
resetScratch(const T & element,int index)506 const SkFlatData& resetScratch(const T& element, int index) {
507 this->lazyInit();
508
509 // Layout of fScratch: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ]
510 fScratch.reset();
511 fScratch.reserve(sizeof(SkFlatData));
512 Traits::Flatten(fScratch, element);
513 const size_t dataSize = fScratch.bytesWritten() - sizeof(SkFlatData);
514
515 // Reinterpret data in fScratch as an SkFlatData.
516 SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
517 SkASSERT(scratch != NULL);
518 scratch->stampHeader(index, SkToS32(dataSize));
519 return *scratch;
520 }
521
522 // This result is owned by fController and lives as long as it does (unless unalloc'd).
detachScratch()523 SkFlatData* detachScratch() {
524 // Allocate a new SkFlatData exactly big enough to hold our current scratch.
525 // We use the controller for this allocation to extend the allocation's lifetime and allow
526 // the controller to do whatever memory management it wants.
527 SkFlatData* detached = (SkFlatData*)fController->allocThrow(fScratch.bytesWritten());
528
529 // Copy scratch into the new SkFlatData.
530 SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
531 SkASSERT(scratch != NULL);
532 memcpy(detached, scratch, fScratch.bytesWritten());
533
534 // We can now reuse fScratch, and detached will live until fController dies.
535 return detached;
536 }
537
unflatten(T * dst,const SkFlatData * element)538 void unflatten(T* dst, const SkFlatData* element) const {
539 element->unflatten<Traits>(dst,
540 fController->getBitmapHeap(),
541 fController->getTypefacePlayback());
542 }
543
544 // All SkFlatData* stored in fIndexedData and fHash are owned by the controller.
545 SkAutoTUnref<SkFlatController> fController;
546 SkWriteBuffer fScratch;
547 bool fReady;
548
549 // For index -> SkFlatData. 0-based, while all indices in the API are 1-based. Careful!
550 SkTDArray<const SkFlatData*> fIndexedData;
551
552 // For SkFlatData -> cached SkFlatData, which has index().
553 SkTDynamicHash<SkFlatData, SkFlatData, SkFlatData::HashTraits> fHash;
554 };
555
556 #endif
557