1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkPictureFlat.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,609 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 +#ifndef SkPictureFlat_DEFINED 1.12 +#define SkPictureFlat_DEFINED 1.13 + 1.14 +//#define SK_DEBUG_SIZE 1.15 + 1.16 +#include "SkBitmapHeap.h" 1.17 +#include "SkChecksum.h" 1.18 +#include "SkChunkAlloc.h" 1.19 +#include "SkReadBuffer.h" 1.20 +#include "SkWriteBuffer.h" 1.21 +#include "SkPaint.h" 1.22 +#include "SkPicture.h" 1.23 +#include "SkPtrRecorder.h" 1.24 +#include "SkTDynamicHash.h" 1.25 +#include "SkTRefArray.h" 1.26 + 1.27 +enum DrawType { 1.28 + UNUSED, 1.29 + CLIP_PATH, 1.30 + CLIP_REGION, 1.31 + CLIP_RECT, 1.32 + CLIP_RRECT, 1.33 + CONCAT, 1.34 + DRAW_BITMAP, 1.35 + DRAW_BITMAP_MATRIX, 1.36 + DRAW_BITMAP_NINE, 1.37 + DRAW_BITMAP_RECT_TO_RECT, 1.38 + DRAW_CLEAR, 1.39 + DRAW_DATA, 1.40 + DRAW_OVAL, 1.41 + DRAW_PAINT, 1.42 + DRAW_PATH, 1.43 + DRAW_PICTURE, 1.44 + DRAW_POINTS, 1.45 + DRAW_POS_TEXT, 1.46 + DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT 1.47 + DRAW_POS_TEXT_H, 1.48 + DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H 1.49 + DRAW_RECT, 1.50 + DRAW_RRECT, 1.51 + DRAW_SPRITE, 1.52 + DRAW_TEXT, 1.53 + DRAW_TEXT_ON_PATH, 1.54 + DRAW_TEXT_TOP_BOTTOM, // fast variant of DRAW_TEXT 1.55 + DRAW_VERTICES, 1.56 + RESTORE, 1.57 + ROTATE, 1.58 + SAVE, 1.59 + SAVE_LAYER, 1.60 + SCALE, 1.61 + SET_MATRIX, 1.62 + SKEW, 1.63 + TRANSLATE, 1.64 + NOOP, 1.65 + BEGIN_COMMENT_GROUP, 1.66 + COMMENT, 1.67 + END_COMMENT_GROUP, 1.68 + 1.69 + // new ops -- feel free to re-alphabetize on next version bump 1.70 + DRAW_DRRECT, 1.71 + PUSH_CULL, 1.72 + POP_CULL, 1.73 + 1.74 + LAST_DRAWTYPE_ENUM = POP_CULL 1.75 +}; 1.76 + 1.77 +// In the 'match' method, this constant will match any flavor of DRAW_BITMAP* 1.78 +static const int kDRAW_BITMAP_FLAVOR = LAST_DRAWTYPE_ENUM+1; 1.79 + 1.80 +enum DrawVertexFlags { 1.81 + DRAW_VERTICES_HAS_TEXS = 0x01, 1.82 + DRAW_VERTICES_HAS_COLORS = 0x02, 1.83 + DRAW_VERTICES_HAS_INDICES = 0x04, 1.84 + DRAW_VERTICES_HAS_XFER = 0x08, 1.85 +}; 1.86 + 1.87 +/////////////////////////////////////////////////////////////////////////////// 1.88 +// clipparams are packed in 5 bits 1.89 +// doAA:1 | regionOp:4 1.90 + 1.91 +static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) { 1.92 + unsigned doAABit = doAA ? 1 : 0; 1.93 + return (doAABit << 4) | op; 1.94 +} 1.95 + 1.96 +static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) { 1.97 + return (SkRegion::Op)(packed & 0xF); 1.98 +} 1.99 + 1.100 +static inline bool ClipParams_unpackDoAA(uint32_t packed) { 1.101 + return SkToBool((packed >> 4) & 1); 1.102 +} 1.103 + 1.104 +/////////////////////////////////////////////////////////////////////////////// 1.105 + 1.106 +class SkTypefacePlayback { 1.107 +public: 1.108 + SkTypefacePlayback(); 1.109 + virtual ~SkTypefacePlayback(); 1.110 + 1.111 + int count() const { return fCount; } 1.112 + 1.113 + void reset(const SkRefCntSet*); 1.114 + 1.115 + void setCount(int count); 1.116 + SkRefCnt* set(int index, SkRefCnt*); 1.117 + 1.118 + void setupBuffer(SkReadBuffer& buffer) const { 1.119 + buffer.setTypefaceArray((SkTypeface**)fArray, fCount); 1.120 + } 1.121 + 1.122 +protected: 1.123 + int fCount; 1.124 + SkRefCnt** fArray; 1.125 +}; 1.126 + 1.127 +class SkFactoryPlayback { 1.128 +public: 1.129 + SkFactoryPlayback(int count) : fCount(count) { 1.130 + fArray = SkNEW_ARRAY(SkFlattenable::Factory, count); 1.131 + } 1.132 + 1.133 + ~SkFactoryPlayback() { 1.134 + SkDELETE_ARRAY(fArray); 1.135 + } 1.136 + 1.137 + SkFlattenable::Factory* base() const { return fArray; } 1.138 + 1.139 + void setupBuffer(SkReadBuffer& buffer) const { 1.140 + buffer.setFactoryPlayback(fArray, fCount); 1.141 + } 1.142 + 1.143 +private: 1.144 + int fCount; 1.145 + SkFlattenable::Factory* fArray; 1.146 +}; 1.147 + 1.148 +/////////////////////////////////////////////////////////////////////////////// 1.149 +// 1.150 +// 1.151 +// The following templated classes provide an efficient way to store and compare 1.152 +// objects that have been flattened (i.e. serialized in an ordered binary 1.153 +// format). 1.154 +// 1.155 +// SkFlatData: is a simple indexable container for the flattened data 1.156 +// which is agnostic to the type of data is is indexing. It is 1.157 +// also responsible for flattening/unflattening objects but 1.158 +// details of that operation are hidden in the provided traits 1.159 +// SkFlatDictionary: is an abstract templated dictionary that maintains a 1.160 +// searchable set of SkFlatData objects of type T. 1.161 +// SkFlatController: is an interface provided to SkFlatDictionary which handles 1.162 +// allocation (and unallocation in some cases). It also holds 1.163 +// ref count recorders and the like. 1.164 +// 1.165 +// NOTE: any class that wishes to be used in conjunction with SkFlatDictionary must subclass the 1.166 +// dictionary and provide the necessary flattening traits. SkFlatController must also be 1.167 +// implemented, or SkChunkFlatController can be used to use an SkChunkAllocator and never do 1.168 +// replacements. 1.169 +// 1.170 +// 1.171 +/////////////////////////////////////////////////////////////////////////////// 1.172 + 1.173 +class SkFlatData; 1.174 + 1.175 +class SkFlatController : public SkRefCnt { 1.176 +public: 1.177 + SK_DECLARE_INST_COUNT(SkFlatController) 1.178 + 1.179 + SkFlatController(uint32_t writeBufferFlags = 0); 1.180 + virtual ~SkFlatController(); 1.181 + /** 1.182 + * Return a new block of memory for the SkFlatDictionary to use. 1.183 + * This memory is owned by the controller and has the same lifetime unless you 1.184 + * call unalloc(), in which case it may be freed early. 1.185 + */ 1.186 + virtual void* allocThrow(size_t bytes) = 0; 1.187 + 1.188 + /** 1.189 + * Hint that this block, which was allocated with allocThrow, is no longer needed. 1.190 + * The implementation may choose to free this memory any time beteween now and destruction. 1.191 + */ 1.192 + virtual void unalloc(void* ptr) = 0; 1.193 + 1.194 + /** 1.195 + * Used during creation and unflattening of SkFlatData objects. If the 1.196 + * objects being flattened contain bitmaps they are stored in this heap 1.197 + * and the flattenable stores the index to the bitmap on the heap. 1.198 + * This should be set by the protected setBitmapHeap. 1.199 + */ 1.200 + SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; } 1.201 + 1.202 + /** 1.203 + * Used during creation of SkFlatData objects. If a typeface recorder is 1.204 + * required to flatten the objects being flattened (i.e. for SkPaints), this 1.205 + * should be set by the protected setTypefaceSet. 1.206 + */ 1.207 + SkRefCntSet* getTypefaceSet() { return fTypefaceSet; } 1.208 + 1.209 + /** 1.210 + * Used during unflattening of the SkFlatData objects in the 1.211 + * SkFlatDictionary. Needs to be set by the protected setTypefacePlayback 1.212 + * and needs to be reset to the SkRefCntSet passed to setTypefaceSet. 1.213 + */ 1.214 + SkTypefacePlayback* getTypefacePlayback() { return fTypefacePlayback; } 1.215 + 1.216 + /** 1.217 + * Optional factory recorder used during creation of SkFlatData objects. Set 1.218 + * using the protected method setNamedFactorySet. 1.219 + */ 1.220 + SkNamedFactorySet* getNamedFactorySet() { return fFactorySet; } 1.221 + 1.222 + /** 1.223 + * Flags to use during creation of SkFlatData objects. Defaults to zero. 1.224 + */ 1.225 + uint32_t getWriteBufferFlags() { return fWriteBufferFlags; } 1.226 + 1.227 +protected: 1.228 + /** 1.229 + * Set an SkBitmapHeap to be used to store/read SkBitmaps. Ref counted. 1.230 + */ 1.231 + void setBitmapHeap(SkBitmapHeap*); 1.232 + 1.233 + /** 1.234 + * Set an SkRefCntSet to be used to store SkTypefaces during flattening. Ref 1.235 + * counted. 1.236 + */ 1.237 + void setTypefaceSet(SkRefCntSet*); 1.238 + 1.239 + /** 1.240 + * Set an SkTypefacePlayback to be used to find references to SkTypefaces 1.241 + * during unflattening. Should be reset to the set provided to 1.242 + * setTypefaceSet. 1.243 + */ 1.244 + void setTypefacePlayback(SkTypefacePlayback*); 1.245 + 1.246 + /** 1.247 + * Set an SkNamedFactorySet to be used to store Factorys and their 1.248 + * corresponding names during flattening. Ref counted. Returns the same 1.249 + * set as a convenience. 1.250 + */ 1.251 + SkNamedFactorySet* setNamedFactorySet(SkNamedFactorySet*); 1.252 + 1.253 +private: 1.254 + SkBitmapHeap* fBitmapHeap; 1.255 + SkRefCntSet* fTypefaceSet; 1.256 + SkTypefacePlayback* fTypefacePlayback; 1.257 + SkNamedFactorySet* fFactorySet; 1.258 + const uint32_t fWriteBufferFlags; 1.259 + 1.260 + typedef SkRefCnt INHERITED; 1.261 +}; 1.262 + 1.263 +class SkFlatData { 1.264 +public: 1.265 + // Flatten obj into an SkFlatData with this index. controller owns the SkFlatData*. 1.266 + template <typename Traits, typename T> 1.267 + static SkFlatData* Create(SkFlatController* controller, const T& obj, int index) { 1.268 + // A buffer of 256 bytes should fit most paints, regions, and matrices. 1.269 + uint32_t storage[64]; 1.270 + SkWriteBuffer buffer(storage, sizeof(storage), controller->getWriteBufferFlags()); 1.271 + 1.272 + buffer.setBitmapHeap(controller->getBitmapHeap()); 1.273 + buffer.setTypefaceRecorder(controller->getTypefaceSet()); 1.274 + buffer.setNamedFactoryRecorder(controller->getNamedFactorySet()); 1.275 + 1.276 + Traits::Flatten(buffer, obj); 1.277 + size_t size = buffer.bytesWritten(); 1.278 + SkASSERT(SkIsAlign4(size)); 1.279 + 1.280 + // Allocate enough memory to hold SkFlatData struct and the flat data itself. 1.281 + size_t allocSize = sizeof(SkFlatData) + size; 1.282 + SkFlatData* result = (SkFlatData*) controller->allocThrow(allocSize); 1.283 + 1.284 + // Put the serialized contents into the data section of the new allocation. 1.285 + buffer.writeToMemory(result->data()); 1.286 + // Stamp the index, size and checksum in the header. 1.287 + result->stampHeader(index, SkToS32(size)); 1.288 + return result; 1.289 + } 1.290 + 1.291 + // Unflatten this into result, using bitmapHeap and facePlayback for bitmaps and fonts if given 1.292 + template <typename Traits, typename T> 1.293 + void unflatten(T* result, 1.294 + SkBitmapHeap* bitmapHeap = NULL, 1.295 + SkTypefacePlayback* facePlayback = NULL) const { 1.296 + SkReadBuffer buffer(this->data(), fFlatSize); 1.297 + 1.298 + if (bitmapHeap) { 1.299 + buffer.setBitmapStorage(bitmapHeap); 1.300 + } 1.301 + if (facePlayback) { 1.302 + facePlayback->setupBuffer(buffer); 1.303 + } 1.304 + 1.305 + Traits::Unflatten(buffer, result); 1.306 + SkASSERT(fFlatSize == (int32_t)buffer.offset()); 1.307 + } 1.308 + 1.309 + // Do these contain the same data? Ignores index() and topBot(). 1.310 + bool operator==(const SkFlatData& that) const { 1.311 + if (this->checksum() != that.checksum() || this->flatSize() != that.flatSize()) { 1.312 + return false; 1.313 + } 1.314 + return memcmp(this->data(), that.data(), this->flatSize()) == 0; 1.315 + } 1.316 + 1.317 + int index() const { return fIndex; } 1.318 + const uint8_t* data() const { return (const uint8_t*)this + sizeof(*this); } 1.319 + size_t flatSize() const { return fFlatSize; } 1.320 + uint32_t checksum() const { return fChecksum; } 1.321 + 1.322 + // Returns true if fTopBot[] has been recorded. 1.323 + bool isTopBotWritten() const { 1.324 + return !SkScalarIsNaN(fTopBot[0]); 1.325 + } 1.326 + 1.327 + // Returns fTopBot array, so it can be passed to a routine to compute them. 1.328 + // For efficiency, we assert that fTopBot have not been recorded yet. 1.329 + SkScalar* writableTopBot() const { 1.330 + SkASSERT(!this->isTopBotWritten()); 1.331 + return fTopBot; 1.332 + } 1.333 + 1.334 + // Return the topbot[] after it has been recorded. 1.335 + const SkScalar* topBot() const { 1.336 + SkASSERT(this->isTopBotWritten()); 1.337 + return fTopBot; 1.338 + } 1.339 + 1.340 +private: 1.341 + // For SkTDynamicHash. 1.342 + static const SkFlatData& Identity(const SkFlatData& flat) { return flat; } 1.343 + static uint32_t Hash(const SkFlatData& flat) { return flat.checksum(); } 1.344 + static bool Equal(const SkFlatData& a, const SkFlatData& b) { return a == b; } 1.345 + 1.346 + void setIndex(int index) { fIndex = index; } 1.347 + uint8_t* data() { return (uint8_t*)this + sizeof(*this); } 1.348 + 1.349 + // This assumes the payload flat data has already been written and does not modify it. 1.350 + void stampHeader(int index, int32_t size) { 1.351 + SkASSERT(SkIsAlign4(size)); 1.352 + fIndex = index; 1.353 + fFlatSize = size; 1.354 + fTopBot[0] = SK_ScalarNaN; // Mark as unwritten. 1.355 + fChecksum = SkChecksum::Compute((uint32_t*)this->data(), size); 1.356 + } 1.357 + 1.358 + int fIndex; 1.359 + int32_t fFlatSize; 1.360 + uint32_t fChecksum; 1.361 + mutable SkScalar fTopBot[2]; // Cache of FontMetrics fTop, fBottom. Starts as [NaN,?]. 1.362 + // uint32_t flattenedData[] implicitly hangs off the end. 1.363 + 1.364 + template <typename T, typename Traits> friend class SkFlatDictionary; 1.365 +}; 1.366 + 1.367 +template <typename T, typename Traits> 1.368 +class SkFlatDictionary { 1.369 +public: 1.370 + explicit SkFlatDictionary(SkFlatController* controller) 1.371 + : fController(SkRef(controller)) 1.372 + , fScratch(controller->getWriteBufferFlags()) 1.373 + , fReady(false) { 1.374 + this->reset(); 1.375 + } 1.376 + 1.377 + /** 1.378 + * Clears the dictionary of all entries. However, it does NOT free the 1.379 + * memory that was allocated for each entry (that's owned by controller). 1.380 + */ 1.381 + void reset() { 1.382 + fIndexedData.rewind(); 1.383 + } 1.384 + 1.385 + int count() const { 1.386 + SkASSERT(fHash.count() == fIndexedData.count()); 1.387 + return fHash.count(); 1.388 + } 1.389 + 1.390 + // For testing only. Index is zero-based. 1.391 + const SkFlatData* operator[](int index) { 1.392 + return fIndexedData[index]; 1.393 + } 1.394 + 1.395 + /** 1.396 + * Given an element of type T return its 1-based index in the dictionary. If 1.397 + * the element wasn't previously in the dictionary it is automatically 1.398 + * added. 1.399 + * 1.400 + */ 1.401 + int find(const T& element) { 1.402 + return this->findAndReturnFlat(element)->index(); 1.403 + } 1.404 + 1.405 + /** 1.406 + * Similar to find. Allows the caller to specify an SkFlatData to replace in 1.407 + * the case of an add. Also tells the caller whether a new SkFlatData was 1.408 + * added and whether the old one was replaced. The parameters added and 1.409 + * replaced are required to be non-NULL. Rather than returning the index of 1.410 + * the entry in the dictionary, it returns the actual SkFlatData. 1.411 + */ 1.412 + const SkFlatData* findAndReplace(const T& element, 1.413 + const SkFlatData* toReplace, 1.414 + bool* added, 1.415 + bool* replaced) { 1.416 + SkASSERT(added != NULL && replaced != NULL); 1.417 + 1.418 + const int oldCount = this->count(); 1.419 + SkFlatData* flat = this->findAndReturnMutableFlat(element); 1.420 + *added = this->count() > oldCount; 1.421 + 1.422 + // If we don't want to replace anything, we're done. 1.423 + if (!*added || toReplace == NULL) { 1.424 + *replaced = false; 1.425 + return flat; 1.426 + } 1.427 + 1.428 + // If we don't have the thing to replace, we're done. 1.429 + const SkFlatData* found = fHash.find(*toReplace); 1.430 + if (found == NULL) { 1.431 + *replaced = false; 1.432 + return flat; 1.433 + } 1.434 + 1.435 + // findAndReturnMutableFlat put flat at the back. Swap it into found->index() instead. 1.436 + // indices in SkFlatData are 1-based, while fIndexedData is 0-based. Watch out! 1.437 + SkASSERT(flat->index() == this->count()); 1.438 + flat->setIndex(found->index()); 1.439 + fIndexedData.removeShuffle(found->index()-1); 1.440 + SkASSERT(flat == fIndexedData[found->index()-1]); 1.441 + 1.442 + // findAndReturnMutableFlat already called fHash.add(), so we just clean up the old entry. 1.443 + fHash.remove(*found); 1.444 + fController->unalloc((void*)found); 1.445 + SkASSERT(this->count() == oldCount); 1.446 + 1.447 + *replaced = true; 1.448 + return flat; 1.449 + } 1.450 + 1.451 + /** 1.452 + * Unflatten the objects and return them in SkTRefArray, or return NULL 1.453 + * if there no objects. Caller takes ownership of result. 1.454 + */ 1.455 + SkTRefArray<T>* unflattenToArray() const { 1.456 + const int count = this->count(); 1.457 + if (count == 0) { 1.458 + return NULL; 1.459 + } 1.460 + SkTRefArray<T>* array = SkTRefArray<T>::Create(count); 1.461 + for (int i = 0; i < count; i++) { 1.462 + this->unflatten(&array->writableAt(i), fIndexedData[i]); 1.463 + } 1.464 + return array; 1.465 + } 1.466 + 1.467 + /** 1.468 + * Unflatten the specific object at the given index. 1.469 + * Caller takes ownership of the result. 1.470 + */ 1.471 + T* unflatten(int index) const { 1.472 + // index is 1-based, while fIndexedData is 0-based. 1.473 + const SkFlatData* element = fIndexedData[index-1]; 1.474 + SkASSERT(index == element->index()); 1.475 + 1.476 + T* dst = new T; 1.477 + this->unflatten(dst, element); 1.478 + return dst; 1.479 + } 1.480 + 1.481 + /** 1.482 + * Find or insert a flattened version of element into the dictionary. 1.483 + * Caller does not take ownership of the result. This will not return NULL. 1.484 + */ 1.485 + const SkFlatData* findAndReturnFlat(const T& element) { 1.486 + return this->findAndReturnMutableFlat(element); 1.487 + } 1.488 + 1.489 +private: 1.490 + // We have to delay fScratch's initialization until its first use; fController might not 1.491 + // be fully set up by the time we get it in the constructor. 1.492 + void lazyInit() { 1.493 + if (fReady) { 1.494 + return; 1.495 + } 1.496 + 1.497 + // Without a bitmap heap, we'll flatten bitmaps into paints. That's never what you want. 1.498 + SkASSERT(fController->getBitmapHeap() != NULL); 1.499 + fScratch.setBitmapHeap(fController->getBitmapHeap()); 1.500 + fScratch.setTypefaceRecorder(fController->getTypefaceSet()); 1.501 + fScratch.setNamedFactoryRecorder(fController->getNamedFactorySet()); 1.502 + fReady = true; 1.503 + } 1.504 + 1.505 + // As findAndReturnFlat, but returns a mutable pointer for internal use. 1.506 + SkFlatData* findAndReturnMutableFlat(const T& element) { 1.507 + // Only valid until the next call to resetScratch(). 1.508 + const SkFlatData& scratch = this->resetScratch(element, this->count()+1); 1.509 + 1.510 + SkFlatData* candidate = fHash.find(scratch); 1.511 + if (candidate != NULL) { 1.512 + return candidate; 1.513 + } 1.514 + 1.515 + SkFlatData* detached = this->detachScratch(); 1.516 + fHash.add(detached); 1.517 + *fIndexedData.append() = detached; 1.518 + SkASSERT(fIndexedData.top()->index() == this->count()); 1.519 + return detached; 1.520 + } 1.521 + 1.522 + // This reference is valid only until the next call to resetScratch() or detachScratch(). 1.523 + const SkFlatData& resetScratch(const T& element, int index) { 1.524 + this->lazyInit(); 1.525 + 1.526 + // Layout of fScratch: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ] 1.527 + fScratch.reset(); 1.528 + fScratch.reserve(sizeof(SkFlatData)); 1.529 + Traits::Flatten(fScratch, element); 1.530 + const size_t dataSize = fScratch.bytesWritten() - sizeof(SkFlatData); 1.531 + 1.532 + // Reinterpret data in fScratch as an SkFlatData. 1.533 + SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray(); 1.534 + SkASSERT(scratch != NULL); 1.535 + scratch->stampHeader(index, dataSize); 1.536 + return *scratch; 1.537 + } 1.538 + 1.539 + // This result is owned by fController and lives as long as it does (unless unalloc'd). 1.540 + SkFlatData* detachScratch() { 1.541 + // Allocate a new SkFlatData exactly big enough to hold our current scratch. 1.542 + // We use the controller for this allocation to extend the allocation's lifetime and allow 1.543 + // the controller to do whatever memory management it wants. 1.544 + SkFlatData* detached = (SkFlatData*)fController->allocThrow(fScratch.bytesWritten()); 1.545 + 1.546 + // Copy scratch into the new SkFlatData. 1.547 + SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray(); 1.548 + SkASSERT(scratch != NULL); 1.549 + memcpy(detached, scratch, fScratch.bytesWritten()); 1.550 + 1.551 + // We can now reuse fScratch, and detached will live until fController dies. 1.552 + return detached; 1.553 + } 1.554 + 1.555 + void unflatten(T* dst, const SkFlatData* element) const { 1.556 + element->unflatten<Traits>(dst, 1.557 + fController->getBitmapHeap(), 1.558 + fController->getTypefacePlayback()); 1.559 + } 1.560 + 1.561 + // All SkFlatData* stored in fIndexedData and fHash are owned by the controller. 1.562 + SkAutoTUnref<SkFlatController> fController; 1.563 + SkWriteBuffer fScratch; 1.564 + bool fReady; 1.565 + 1.566 + // For index -> SkFlatData. 0-based, while all indices in the API are 1-based. Careful! 1.567 + SkTDArray<const SkFlatData*> fIndexedData; 1.568 + 1.569 + // For SkFlatData -> cached SkFlatData, which has index(). 1.570 + SkTDynamicHash<SkFlatData, SkFlatData, 1.571 + SkFlatData::Identity, SkFlatData::Hash, SkFlatData::Equal> fHash; 1.572 +}; 1.573 + 1.574 +typedef SkFlatDictionary<SkPaint, SkPaint::FlatteningTraits> SkPaintDictionary; 1.575 + 1.576 +class SkChunkFlatController : public SkFlatController { 1.577 +public: 1.578 + SkChunkFlatController(size_t minSize) 1.579 + : fHeap(minSize) 1.580 + , fTypefaceSet(SkNEW(SkRefCntSet)) 1.581 + , fLastAllocated(NULL) { 1.582 + this->setTypefaceSet(fTypefaceSet); 1.583 + this->setTypefacePlayback(&fTypefacePlayback); 1.584 + } 1.585 + 1.586 + virtual void* allocThrow(size_t bytes) SK_OVERRIDE { 1.587 + fLastAllocated = fHeap.allocThrow(bytes); 1.588 + return fLastAllocated; 1.589 + } 1.590 + 1.591 + virtual void unalloc(void* ptr) SK_OVERRIDE { 1.592 + // fHeap can only free a pointer if it was the last one allocated. Otherwise, we'll just 1.593 + // have to wait until fHeap is destroyed. 1.594 + if (ptr == fLastAllocated) (void)fHeap.unalloc(ptr); 1.595 + } 1.596 + 1.597 + void setupPlaybacks() const { 1.598 + fTypefacePlayback.reset(fTypefaceSet.get()); 1.599 + } 1.600 + 1.601 + void setBitmapStorage(SkBitmapHeap* heap) { 1.602 + this->setBitmapHeap(heap); 1.603 + } 1.604 + 1.605 +private: 1.606 + SkChunkAlloc fHeap; 1.607 + SkAutoTUnref<SkRefCntSet> fTypefaceSet; 1.608 + void* fLastAllocated; 1.609 + mutable SkTypefacePlayback fTypefacePlayback; 1.610 +}; 1.611 + 1.612 +#endif