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 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 115 static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) { 116 return (SkRegion::Op)(packed & 0xF); 117 } 118 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 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 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: 148 SkFactoryPlayback(int count) : fCount(count) { fArray = new SkFlattenable::Factory[count]; } 149 150 ~SkFactoryPlayback() { delete[] fArray; } 151 152 SkFlattenable::Factory* base() const { return fArray; } 153 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 */ 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 */ 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 */ 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 */ 235 SkNamedFactorySet* getNamedFactorySet() { return fFactorySet; } 236 237 /** 238 * Flags to use during creation of SkFlatData objects. Defaults to zero. 239 */ 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> 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 332 int index() const { return fIndex; } 333 const uint8_t* data() const { return (const uint8_t*)this + sizeof(*this); } 334 size_t flatSize() const { return fFlatSize; } 335 uint32_t checksum() const { return fChecksum; } 336 337 // Returns true if fTopBot[] has been recorded. 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. 344 SkScalar* writableTopBot() const { 345 SkASSERT(!this->isTopBotWritten()); 346 return fTopBot; 347 } 348 349 // Return the topbot[] after it has been recorded. 350 const SkScalar* topBot() const { 351 SkASSERT(this->isTopBotWritten()); 352 return fTopBot; 353 } 354 355 private: 356 struct HashTraits { 357 static const SkFlatData& GetKey(const SkFlatData& flat) { return flat; } 358 static uint32_t Hash(const SkFlatData& flat) { return flat.checksum(); } 359 }; 360 361 void setIndex(int index) { fIndex = index; } 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. 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: 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 */ 396 void reset() { 397 fIndexedData.rewind(); 398 } 399 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 */ 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 */ 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 */ 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 */ 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. 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. 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(). 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). 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 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