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