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