gfx/skia/trunk/src/core/SkPictureFlat.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial