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 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 96 static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) { 97 return (SkRegion::Op)(packed & 0xF); 98 } 99 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 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 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: 129 SkFactoryPlayback(int count) : fCount(count) { 130 fArray = SkNEW_ARRAY(SkFlattenable::Factory, count); 131 } 132 133 ~SkFactoryPlayback() { 134 SkDELETE_ARRAY(fArray); 135 } 136 137 SkFlattenable::Factory* base() const { return fArray; } 138 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 */ 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 */ 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 */ 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 */ 220 SkNamedFactorySet* getNamedFactorySet() { return fFactorySet; } 221 222 /** 223 * Flags to use during creation of SkFlatData objects. Defaults to zero. 224 */ 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> 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 317 int index() const { return fIndex; } 318 const uint8_t* data() const { return (const uint8_t*)this + sizeof(*this); } 319 size_t flatSize() const { return fFlatSize; } 320 uint32_t checksum() const { return fChecksum; } 321 322 // Returns true if fTopBot[] has been recorded. 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. 329 SkScalar* writableTopBot() const { 330 SkASSERT(!this->isTopBotWritten()); 331 return fTopBot; 332 } 333 334 // Return the topbot[] after it has been recorded. 335 const SkScalar* topBot() const { 336 SkASSERT(this->isTopBotWritten()); 337 return fTopBot; 338 } 339 340 private: 341 struct HashTraits { 342 static const SkFlatData& GetKey(const SkFlatData& flat) { return flat; } 343 static uint32_t Hash(const SkFlatData& flat) { return flat.checksum(); } 344 }; 345 346 void setIndex(int index) { fIndex = index; } 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. 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: 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 */ 381 void reset() { 382 fIndexedData.rewind(); 383 } 384 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 */ 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 */ 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 */ 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 */ 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 */ 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. 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. 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(). 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). 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 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: 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 585 virtual void* allocThrow(size_t bytes) SK_OVERRIDE { 586 fLastAllocated = fHeap.allocThrow(bytes); 587 return fLastAllocated; 588 } 589 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 596 void setupPlaybacks() const { 597 fTypefacePlayback.reset(fTypefaceSet.get()); 598 } 599 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