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

changeset 0
6474c204b198
     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

mercurial