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