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 "SkChunkAlloc.h" 14 #include "SkBitmap.h" 15 #include "SkBitmapHeap.h" 16 #include "SkOrderedReadBuffer.h" 17 #include "SkOrderedWriteBuffer.h" 18 #include "SkPicture.h" 19 #include "SkPtrRecorder.h" 20 #include "SkMatrix.h" 21 #include "SkPaint.h" 22 #include "SkPath.h" 23 #include "SkRegion.h" 24 #include "SkTRefArray.h" 25 #include "SkTSearch.h" 26 27 enum DrawType { 28 UNUSED, 29 CLIP_PATH, 30 CLIP_REGION, 31 CLIP_RECT, 32 CLIP_RRECT, 33 CONCAT, 34 DRAW_BITMAP, 35 DRAW_BITMAP_MATRIX, 36 DRAW_BITMAP_NINE, 37 DRAW_BITMAP_RECT_TO_RECT, 38 DRAW_CLEAR, 39 DRAW_DATA, 40 DRAW_OVAL, 41 DRAW_PAINT, 42 DRAW_PATH, 43 DRAW_PICTURE, 44 DRAW_POINTS, 45 DRAW_POS_TEXT, 46 DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT 47 DRAW_POS_TEXT_H, 48 DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H 49 DRAW_RECT, 50 DRAW_RRECT, 51 DRAW_SPRITE, 52 DRAW_TEXT, 53 DRAW_TEXT_ON_PATH, 54 DRAW_TEXT_TOP_BOTTOM, // fast variant of DRAW_TEXT 55 DRAW_VERTICES, 56 RESTORE, 57 ROTATE, 58 SAVE, 59 SAVE_LAYER, 60 SCALE, 61 SET_MATRIX, 62 SKEW, 63 TRANSLATE, 64 65 LAST_DRAWTYPE_ENUM = TRANSLATE 66 }; 67 68 enum DrawVertexFlags { 69 DRAW_VERTICES_HAS_TEXS = 0x01, 70 DRAW_VERTICES_HAS_COLORS = 0x02, 71 DRAW_VERTICES_HAS_INDICES = 0x04 72 }; 73 74 /////////////////////////////////////////////////////////////////////////////// 75 // clipparams are packed in 5 bits 76 // doAA:1 | regionOp:4 77 78 static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) { 79 unsigned doAABit = doAA ? 1 : 0; 80 return (doAABit << 4) | op; 81 } 82 83 static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) { 84 return (SkRegion::Op)(packed & 0xF); 85 } 86 87 static inline bool ClipParams_unpackDoAA(uint32_t packed) { 88 return SkToBool((packed >> 4) & 1); 89 } 90 91 /////////////////////////////////////////////////////////////////////////////// 92 93 class SkTypefacePlayback { 94 public: 95 SkTypefacePlayback(); 96 virtual ~SkTypefacePlayback(); 97 98 int count() const { return fCount; } 99 100 void reset(const SkRefCntSet*); 101 102 void setCount(int count); 103 SkRefCnt* set(int index, SkRefCnt*); 104 105 void setupBuffer(SkOrderedReadBuffer& buffer) const { 106 buffer.setTypefaceArray((SkTypeface**)fArray, fCount); 107 } 108 109 protected: 110 int fCount; 111 SkRefCnt** fArray; 112 }; 113 114 class SkFactoryPlayback { 115 public: 116 SkFactoryPlayback(int count) : fCount(count) { 117 fArray = SkNEW_ARRAY(SkFlattenable::Factory, count); 118 } 119 120 ~SkFactoryPlayback() { 121 SkDELETE_ARRAY(fArray); 122 } 123 124 SkFlattenable::Factory* base() const { return fArray; } 125 126 void setupBuffer(SkOrderedReadBuffer& buffer) const { 127 buffer.setFactoryPlayback(fArray, fCount); 128 } 129 130 private: 131 int fCount; 132 SkFlattenable::Factory* fArray; 133 }; 134 135 /////////////////////////////////////////////////////////////////////////////// 136 // 137 // 138 // The following templated classes provide an efficient way to store and compare 139 // objects that have been flattened (i.e. serialized in an ordered binary 140 // format). 141 // 142 // SkFlatData: is a simple indexable container for the flattened data 143 // which is agnostic to the type of data is is indexing. It is 144 // also responsible for flattening/unflattening objects but 145 // details of that operation are hidden in the provided procs 146 // SkFlatDictionary: is an abstract templated dictionary that maintains a 147 // searchable set of SkFlataData objects of type T. 148 // SkFlatController: is an interface provided to SkFlatDictionary which handles 149 // allocation and unallocation in some cases. It also holds 150 // ref count recorders and the like. 151 // 152 // NOTE: any class that wishes to be used in conjunction with SkFlatDictionary 153 // must subclass the dictionary and provide the necessary flattening procs. 154 // The end of this header contains dictionary subclasses for some common classes 155 // like SkBitmap, SkMatrix, SkPaint, and SkRegion. SkFlatController must also 156 // be implemented, or SkChunkFlatController can be used to use an 157 // SkChunkAllocator and never do replacements. 158 // 159 // 160 /////////////////////////////////////////////////////////////////////////////// 161 162 class SkFlatData; 163 164 class SkFlatController : public SkRefCnt { 165 public: 166 SK_DECLARE_INST_COUNT(SkFlatController) 167 168 SkFlatController(); 169 virtual ~SkFlatController(); 170 /** 171 * Provide a new block of memory for the SkFlatDictionary to use. 172 */ 173 virtual void* allocThrow(size_t bytes) = 0; 174 175 /** 176 * Unallocate a previously allocated block, returned by allocThrow. 177 * Implementation should at least perform an unallocation if passed the last 178 * pointer returned by allocThrow. If findAndReplace() is intended to be 179 * used, unalloc should also be able to unallocate the SkFlatData that is 180 * provided. 181 */ 182 virtual void unalloc(void* ptr) = 0; 183 184 /** 185 * Used during creation and unflattening of SkFlatData objects. If the 186 * objects being flattened contain bitmaps they are stored in this heap 187 * and the flattenable stores the index to the bitmap on the heap. 188 * This should be set by the protected setBitmapHeap. 189 */ 190 SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; } 191 192 /** 193 * Used during creation of SkFlatData objects. If a typeface recorder is 194 * required to flatten the objects being flattened (i.e. for SkPaints), this 195 * should be set by the protected setTypefaceSet. 196 */ 197 SkRefCntSet* getTypefaceSet() { return fTypefaceSet; } 198 199 /** 200 * Used during unflattening of the SkFlatData objects in the 201 * SkFlatDictionary. Needs to be set by the protected setTypefacePlayback 202 * and needs to be reset to the SkRefCntSet passed to setTypefaceSet. 203 */ 204 SkTypefacePlayback* getTypefacePlayback() { return fTypefacePlayback; } 205 206 /** 207 * Optional factory recorder used during creation of SkFlatData objects. Set 208 * using the protected method setNamedFactorySet. 209 */ 210 SkNamedFactorySet* getNamedFactorySet() { return fFactorySet; } 211 212 /** 213 * Flags to use during creation of SkFlatData objects. Defaults to zero. 214 */ 215 uint32_t getWriteBufferFlags() { return fWriteBufferFlags; } 216 217 protected: 218 /** 219 * Set an SkBitmapHeap to be used to store/read SkBitmaps. Ref counted. 220 */ 221 void setBitmapHeap(SkBitmapHeap*); 222 223 /** 224 * Set an SkRefCntSet to be used to store SkTypefaces during flattening. Ref 225 * counted. 226 */ 227 void setTypefaceSet(SkRefCntSet*); 228 229 /** 230 * Set an SkTypefacePlayback to be used to find references to SkTypefaces 231 * during unflattening. Should be reset to the set provided to 232 * setTypefaceSet. 233 */ 234 void setTypefacePlayback(SkTypefacePlayback*); 235 236 /** 237 * Set an SkNamedFactorySet to be used to store Factorys and their 238 * corresponding names during flattening. Ref counted. Returns the same 239 * set as a convenience. 240 */ 241 SkNamedFactorySet* setNamedFactorySet(SkNamedFactorySet*); 242 243 /** 244 * Set the flags to be used during flattening. 245 */ 246 void setWriteBufferFlags(uint32_t flags) { fWriteBufferFlags = flags; } 247 248 private: 249 SkBitmapHeap* fBitmapHeap; 250 SkRefCntSet* fTypefaceSet; 251 SkTypefacePlayback* fTypefacePlayback; 252 SkNamedFactorySet* fFactorySet; 253 uint32_t fWriteBufferFlags; 254 255 typedef SkRefCnt INHERITED; 256 }; 257 258 class SkFlatData { 259 public: 260 /** 261 * Compare two SkFlatData ptrs, returning -1, 0, 1 to allow them to be 262 * sorted. 263 * 264 * Note: this assumes that a and b have different sentinel values, either 265 * InCache or AsCandidate, otherwise the loop will go beyond the end of 266 * the buffers. 267 * 268 * dataToCompare() returns 2 fields before the flattened data: 269 * - checksum 270 * - size 271 * This ensures that if we see two blocks of different length, we will 272 * notice that right away, and not read any further. It also ensures that 273 * we see the checksum right away, so that most of the time it is enough 274 * to short-circuit our comparison. 275 */ 276 static int Compare(const SkFlatData* a, const SkFlatData* b) { 277 const uint32_t* stop = a->dataStop(); 278 const uint32_t* a_ptr = a->dataToCompare() - 1; 279 const uint32_t* b_ptr = b->dataToCompare() - 1; 280 // We use -1 above, so we can pre-increment our pointers in the loop 281 while (*++a_ptr == *++b_ptr) {} 282 283 if (a_ptr == stop) { // sentinel 284 SkASSERT(b->dataStop() == b_ptr); 285 return 0; 286 } 287 SkASSERT(a_ptr < a->dataStop()); 288 SkASSERT(b_ptr < b->dataStop()); 289 return (*a_ptr < *b_ptr) ? -1 : 1; 290 } 291 292 int index() const { return fIndex; } 293 const void* data() const { return (const char*)this + sizeof(*this); } 294 void* data() { return (char*)this + sizeof(*this); } 295 // Our data is always 32bit aligned, so we can offer this accessor 296 uint32_t* data32() { return (uint32_t*)this->data(); } 297 // Returns the size of the flattened data. 298 size_t flatSize() const { return fFlatSize; } 299 300 void setSentinelInCache() { 301 this->setSentinel(kInCache_Sentinel); 302 } 303 void setSentinelAsCandidate() { 304 this->setSentinel(kCandidate_Sentinel); 305 } 306 307 uint32_t checksum() const { return fChecksum; } 308 309 #ifdef SK_DEBUG_SIZE 310 // returns the logical size of our data. Does not return any sentinel or 311 // padding we might have. 312 size_t size() const { 313 return sizeof(SkFlatData) + fFlatSize; 314 } 315 #endif 316 317 static SkFlatData* Create(SkFlatController* controller, const void* obj, int index, 318 void (*flattenProc)(SkOrderedWriteBuffer&, const void*)); 319 320 void unflatten(void* result, 321 void (*unflattenProc)(SkOrderedReadBuffer&, void*), 322 SkBitmapHeap* bitmapHeap = NULL, 323 SkTypefacePlayback* facePlayback = NULL) const; 324 325 // When we purge an entry, we want to reuse an old index for the new entry, 326 // so we expose this setter. 327 void setIndex(int index) { fIndex = index; } 328 329 // for unittesting 330 friend bool operator==(const SkFlatData& a, const SkFlatData& b) { 331 size_t N = (const char*)a.dataStop() - (const char*)a.dataToCompare(); 332 return !memcmp(a.dataToCompare(), b.dataToCompare(), N); 333 } 334 335 // returns true if fTopBot[] has been recorded 336 bool isTopBotWritten() const { 337 return !SkScalarIsNaN(fTopBot[0]); 338 } 339 340 // Returns fTopBot array, so it can be passed to a routine to compute them. 341 // For efficiency, we assert that fTopBot have not been recorded yet. 342 SkScalar* writableTopBot() const { 343 SkASSERT(!this->isTopBotWritten()); 344 return fTopBot; 345 } 346 347 // return the topbot[] after it has been recorded 348 const SkScalar* topBot() const { 349 SkASSERT(this->isTopBotWritten()); 350 return fTopBot; 351 } 352 353 private: 354 // This is *not* part of the key for search/sort 355 int fIndex; 356 357 // Cache of paint's FontMetrics fTop,fBottom 358 // initialied to [NaN,NaN] as a sentinel that they have not been recorded yet 359 // 360 // This is *not* part of the key for search/sort 361 mutable SkScalar fTopBot[2]; 362 363 // marks fTopBot[] as unrecorded 364 void setTopBotUnwritten() { 365 this->fTopBot[0] = this->fTopBot[1] = SK_ScalarNaN; // initial to sentinel values 366 } 367 368 // From here down is the data we look at in the search/sort. We always begin 369 // with the checksum and then length. 370 uint32_t fChecksum; 371 int32_t fFlatSize; // size of flattened data 372 // uint32_t flattenedData[] 373 // uint32_t sentinelValue 374 375 const uint32_t* dataToCompare() const { 376 return (const uint32_t*)&fChecksum; 377 } 378 const uint32_t* dataStop() const { 379 SkASSERT(SkIsAlign4(fFlatSize)); 380 return (const uint32_t*)((const char*)this->data() + fFlatSize); 381 } 382 383 enum { 384 kInCache_Sentinel = 0, 385 kCandidate_Sentinel = ~0U, 386 }; 387 void setSentinel(uint32_t value) { 388 SkASSERT(SkIsAlign4(fFlatSize)); 389 this->data32()[fFlatSize >> 2] = value; 390 } 391 }; 392 393 template <class T> 394 class SkFlatDictionary { 395 public: 396 SkFlatDictionary(SkFlatController* controller) 397 : fController(controller) { 398 fFlattenProc = NULL; 399 fUnflattenProc = NULL; 400 SkASSERT(controller); 401 fController->ref(); 402 // set to 1 since returning a zero from find() indicates failure 403 fNextIndex = 1; 404 sk_bzero(fHash, sizeof(fHash)); 405 } 406 407 virtual ~SkFlatDictionary() { 408 fController->unref(); 409 } 410 411 int count() const { return fData.count(); } 412 413 const SkFlatData* operator[](int index) const { 414 SkASSERT(index >= 0 && index < fData.count()); 415 return fData[index]; 416 } 417 418 /** 419 * Clears the dictionary of all entries. However, it does NOT free the 420 * memory that was allocated for each entry. 421 */ 422 void reset() { 423 fData.reset(); 424 fNextIndex = 1; 425 sk_bzero(fHash, sizeof(fHash)); 426 } 427 428 /** 429 * Similar to find. Allows the caller to specify an SkFlatData to replace in 430 * the case of an add. Also tells the caller whether a new SkFlatData was 431 * added and whether the old one was replaced. The parameters added and 432 * replaced are required to be non-NULL. Rather than returning the index of 433 * the entry in the dictionary, it returns the actual SkFlatData. 434 */ 435 const SkFlatData* findAndReplace(const T& element, 436 const SkFlatData* toReplace, bool* added, 437 bool* replaced) { 438 SkASSERT(added != NULL && replaced != NULL); 439 int oldCount = fData.count(); 440 const SkFlatData* flat = this->findAndReturnFlat(element); 441 *added = fData.count() == oldCount + 1; 442 *replaced = false; 443 if (*added && toReplace != NULL) { 444 // First, find the index of the one to replace 445 int indexToReplace = fData.find(toReplace); 446 if (indexToReplace >= 0) { 447 // findAndReturnFlat set the index to fNextIndex and increased 448 // fNextIndex by one. Reuse the index from the one being 449 // replaced and reset fNextIndex to the proper value. 450 const_cast<SkFlatData*>(flat)->setIndex(toReplace->index()); 451 fNextIndex--; 452 // Remove from the array. 453 fData.remove(indexToReplace); 454 // Remove from the hash table. 455 int oldHash = ChecksumToHashIndex(toReplace->checksum()); 456 if (fHash[oldHash] == toReplace) { 457 fHash[oldHash] = NULL; 458 } 459 // Delete the actual object. 460 fController->unalloc((void*)toReplace); 461 *replaced = true; 462 } 463 } 464 return flat; 465 } 466 467 /** 468 * Given an element of type T return its 1-based index in the dictionary. If 469 * the element wasn't previously in the dictionary it is automatically 470 * added. 471 * 472 * To make the Compare function fast, we write a sentinel value at the end 473 * of each block. The blocks in our fData[] all have a 0 sentinel. The 474 * newly created block we're comparing against has a -1 in the sentinel. 475 * 476 * This trick allows Compare to always loop until failure. If it fails on 477 * the sentinal value, we know the blocks are equal. 478 */ 479 int find(const T& element) { 480 return this->findAndReturnFlat(element)->index(); 481 } 482 483 /** 484 * Unflatten the objects and return them in SkTRefArray, or return NULL 485 * if there no objects (instead of an empty array). 486 */ 487 SkTRefArray<T>* unflattenToArray() const { 488 int count = fData.count(); 489 SkTRefArray<T>* array = NULL; 490 if (count > 0) { 491 array = SkTRefArray<T>::Create(count); 492 this->unflattenIntoArray(&array->writableAt(0)); 493 } 494 return array; 495 } 496 497 const SkFlatData* findAndReturnFlat(const T& element) { 498 SkFlatData* flat = SkFlatData::Create(fController, &element, fNextIndex, fFlattenProc); 499 500 int hashIndex = ChecksumToHashIndex(flat->checksum()); 501 const SkFlatData* candidate = fHash[hashIndex]; 502 if (candidate && !SkFlatData::Compare(flat, candidate)) { 503 fController->unalloc(flat); 504 return candidate; 505 } 506 507 int index = SkTSearch<SkFlatData>((const SkFlatData**) fData.begin(), 508 fData.count(), flat, sizeof(flat), 509 &SkFlatData::Compare); 510 if (index >= 0) { 511 fController->unalloc(flat); 512 fHash[hashIndex] = fData[index]; 513 return fData[index]; 514 } 515 516 index = ~index; 517 *fData.insert(index) = flat; 518 SkASSERT(fData.count() == fNextIndex); 519 fNextIndex++; 520 flat->setSentinelInCache(); 521 fHash[hashIndex] = flat; 522 return flat; 523 } 524 525 protected: 526 void (*fFlattenProc)(SkOrderedWriteBuffer&, const void*); 527 void (*fUnflattenProc)(SkOrderedReadBuffer&, void*); 528 529 private: 530 void unflattenIntoArray(T* array) const { 531 const int count = fData.count(); 532 const SkFlatData** iter = fData.begin(); 533 for (int i = 0; i < count; ++i) { 534 const SkFlatData* element = iter[i]; 535 int index = element->index() - 1; 536 SkASSERT((unsigned)index < (unsigned)count); 537 element->unflatten(&array[index], fUnflattenProc, 538 fController->getBitmapHeap(), 539 fController->getTypefacePlayback()); 540 } 541 } 542 543 SkFlatController * const fController; 544 int fNextIndex; 545 SkTDArray<const SkFlatData*> fData; 546 547 enum { 548 // Determined by trying diff values on picture-recording benchmarks 549 // (e.g. PictureRecordBench.cpp), choosing the smallest value that 550 // showed a big improvement. Even better would be to benchmark diff 551 // values on recording representative web-pages or other "real" content. 552 HASH_BITS = 7, 553 HASH_MASK = (1 << HASH_BITS) - 1, 554 HASH_COUNT = 1 << HASH_BITS 555 }; 556 const SkFlatData* fHash[HASH_COUNT]; 557 558 static int ChecksumToHashIndex(uint32_t checksum) { 559 int n = checksum; 560 if (HASH_BITS < 32) { 561 n ^= n >> 16; 562 } 563 if (HASH_BITS < 16) { 564 n ^= n >> 8; 565 } 566 if (HASH_BITS < 8) { 567 n ^= n >> 4; 568 } 569 return n & HASH_MASK; 570 } 571 }; 572 573 /////////////////////////////////////////////////////////////////////////////// 574 // Some common dictionaries are defined here for both reference and convenience 575 /////////////////////////////////////////////////////////////////////////////// 576 577 template <class T> 578 static void SkFlattenObjectProc(SkOrderedWriteBuffer& buffer, const void* obj) { 579 ((T*)obj)->flatten(buffer); 580 } 581 582 template <class T> 583 static void SkUnflattenObjectProc(SkOrderedReadBuffer& buffer, void* obj) { 584 ((T*)obj)->unflatten(buffer); 585 } 586 587 class SkChunkFlatController : public SkFlatController { 588 public: 589 SkChunkFlatController(size_t minSize) 590 : fHeap(minSize) 591 , fTypefaceSet(SkNEW(SkRefCntSet)) { 592 this->setTypefaceSet(fTypefaceSet); 593 this->setTypefacePlayback(&fTypefacePlayback); 594 } 595 596 ~SkChunkFlatController() { 597 fTypefaceSet->unref(); 598 } 599 600 virtual void* allocThrow(size_t bytes) SK_OVERRIDE { 601 return fHeap.allocThrow(bytes); 602 } 603 604 virtual void unalloc(void* ptr) SK_OVERRIDE { 605 (void) fHeap.unalloc(ptr); 606 } 607 608 void setupPlaybacks() const { 609 fTypefacePlayback.reset(fTypefaceSet); 610 } 611 612 void setBitmapStorage(SkBitmapHeap* heap) { 613 this->setBitmapHeap(heap); 614 } 615 616 private: 617 SkChunkAlloc fHeap; 618 SkRefCntSet* fTypefaceSet; 619 mutable SkTypefacePlayback fTypefacePlayback; 620 }; 621 622 class SkBitmapDictionary : public SkFlatDictionary<SkBitmap> { 623 public: 624 SkBitmapDictionary(SkFlatController* controller) 625 : SkFlatDictionary<SkBitmap>(controller) { 626 fFlattenProc = &SkFlattenObjectProc<SkBitmap>; 627 fUnflattenProc = &SkUnflattenObjectProc<SkBitmap>; 628 } 629 }; 630 631 class SkMatrixDictionary : public SkFlatDictionary<SkMatrix> { 632 public: 633 SkMatrixDictionary(SkFlatController* controller) 634 : SkFlatDictionary<SkMatrix>(controller) { 635 fFlattenProc = &flattenMatrix; 636 fUnflattenProc = &unflattenMatrix; 637 } 638 639 static void flattenMatrix(SkOrderedWriteBuffer& buffer, const void* obj) { 640 buffer.getWriter32()->writeMatrix(*(SkMatrix*)obj); 641 } 642 643 static void unflattenMatrix(SkOrderedReadBuffer& buffer, void* obj) { 644 buffer.getReader32()->readMatrix((SkMatrix*)obj); 645 } 646 }; 647 648 class SkPaintDictionary : public SkFlatDictionary<SkPaint> { 649 public: 650 SkPaintDictionary(SkFlatController* controller) 651 : SkFlatDictionary<SkPaint>(controller) { 652 fFlattenProc = &SkFlattenObjectProc<SkPaint>; 653 fUnflattenProc = &SkUnflattenObjectProc<SkPaint>; 654 } 655 }; 656 657 class SkRegionDictionary : public SkFlatDictionary<SkRegion> { 658 public: 659 SkRegionDictionary(SkFlatController* controller) 660 : SkFlatDictionary<SkRegion>(controller) { 661 fFlattenProc = &flattenRegion; 662 fUnflattenProc = &unflattenRegion; 663 } 664 665 static void flattenRegion(SkOrderedWriteBuffer& buffer, const void* obj) { 666 buffer.getWriter32()->writeRegion(*(SkRegion*)obj); 667 } 668 669 static void unflattenRegion(SkOrderedReadBuffer& buffer, void* obj) { 670 buffer.getReader32()->readRegion((SkRegion*)obj); 671 } 672 }; 673 674 #endif 675