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