1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifndef SkPictureFlat_DEFINED
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkPictureFlat_DEFINED
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11e2589aeebf321f6d3b5005c19740beacee964be7reed@google.com
1221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com#include "SkBitmapHeap.h"
139e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com#include "SkChecksum.h"
149e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com#include "SkChunkAlloc.h"
158b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
168b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPaint.h"
189e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com#include "SkPicture.h"
199e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com#include "SkPtrRecorder.h"
209e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com#include "SkTDynamicHash.h"
21f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com#include "SkTRefArray.h"
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comenum DrawType {
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    UNUSED,
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    CLIP_PATH,
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    CLIP_REGION,
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    CLIP_RECT,
284ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    CLIP_RRECT,
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    CONCAT,
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_BITMAP,
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_BITMAP_MATRIX,
32f0b5e1190af9807a027c0adba2f1380663c8e910reed@google.com    DRAW_BITMAP_NINE,
337112173c3c4cd1b1e7da8cdf971d71f01dd91299reed@google.com    DRAW_BITMAP_RECT_TO_RECT,
342a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com    DRAW_CLEAR,
35cb60844b34766aad4151df5e87c144d4a57e9abereed@android.com    DRAW_DATA,
364ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    DRAW_OVAL,
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_PAINT,
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_PATH,
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_PICTURE,
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_POINTS,
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_POS_TEXT,
429efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com    DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_POS_TEXT_H,
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_RECT,
464ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    DRAW_RRECT,
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_SPRITE,
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_TEXT,
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_TEXT_ON_PATH,
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_TEXT_TOP_BOTTOM,   // fast variant of DRAW_TEXT
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_VERTICES,
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    RESTORE,
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ROTATE,
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SAVE,
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SAVE_LAYER,
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SCALE,
576e073b9e2b70d6bbf8a06050fff1364827204f08reed@android.com    SET_MATRIX,
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SKEW,
59ffacd3c56d73c03d3fe53b47a49ea6be2ca4748freed@google.com    TRANSLATE,
60e4ce5b82627d7ef7cab34b808ff88dc208aef7bcrobertphillips@google.com    NOOP,
610a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com    BEGIN_COMMENT_GROUP,
620a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com    COMMENT,
630a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com    END_COMMENT_GROUP,
64ffacd3c56d73c03d3fe53b47a49ea6be2ca4748freed@google.com
65ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org    // new ops -- feel free to re-alphabetize on next version bump
66ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org    DRAW_DRRECT,
67210ae2a42613b9048e8e8c4096c5bf4fe2ddf838commit-bot@chromium.org    PUSH_CULL,
68210ae2a42613b9048e8e8c4096c5bf4fe2ddf838commit-bot@chromium.org    POP_CULL,
69963137b75c0a1fe91f35e9826742f36309f5e65ddandov
70963137b75c0a1fe91f35e9826742f36309f5e65ddandov    DRAW_PATCH, // could not add in aphabetical order
71d5fa1a455aad61f3e99081fe7a9b065cb3b115c6reed    DRAW_PICTURE_MATRIX_PAINT,
72b7425173f96e93b090787e2386ba5f022b6c2869fmalita    DRAW_TEXT_BLOB,
73ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org
74b7425173f96e93b090787e2386ba5f022b6c2869fmalita    LAST_DRAWTYPE_ENUM = DRAW_TEXT_BLOB
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
77b8f9610ac6efb5426cb799ab9b1ab5d985b7b05arobertphillips@google.com// In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
78b8f9610ac6efb5426cb799ab9b1ab5d985b7b05arobertphillips@google.comstatic const int kDRAW_BITMAP_FLAVOR = LAST_DRAWTYPE_ENUM+1;
79b8f9610ac6efb5426cb799ab9b1ab5d985b7b05arobertphillips@google.com
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comenum DrawVertexFlags {
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_VERTICES_HAS_TEXS    = 0x01,
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_VERTICES_HAS_COLORS  = 0x02,
8385e143c33c214e54187aa28146aa7666961a0d17reed@google.com    DRAW_VERTICES_HAS_INDICES = 0x04,
8485e143c33c214e54187aa28146aa7666961a0d17reed@google.com    DRAW_VERTICES_HAS_XFER    = 0x08,
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8783ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com///////////////////////////////////////////////////////////////////////////////
8883ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com// clipparams are packed in 5 bits
8983ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com//  doAA:1 | regionOp:4
9083ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com
9183ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.comstatic inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) {
9283ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com    unsigned doAABit = doAA ? 1 : 0;
9383ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com    return (doAABit << 4) | op;
9483ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com}
9583ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com
9683ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.comstatic inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) {
9783ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com    return (SkRegion::Op)(packed & 0xF);
9883ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com}
9983ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com
10083ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.comstatic inline bool ClipParams_unpackDoAA(uint32_t packed) {
10183ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com    return SkToBool((packed >> 4) & 1);
10283ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com}
10383ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com
10483ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com///////////////////////////////////////////////////////////////////////////////
10583ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com
10621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.comclass SkTypefacePlayback {
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
10821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    SkTypefacePlayback();
10921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    virtual ~SkTypefacePlayback();
110fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count() const { return fCount; }
112fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
113e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org    void reset(const SkRefCntSet*);
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setCount(int count);
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt* set(int index, SkRefCnt*);
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1188b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org    void setupBuffer(SkReadBuffer& buffer) const {
11921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com        buffer.setTypefaceArray((SkTypeface**)fArray, fCount);
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
121fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprotected:
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int fCount;
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt** fArray;
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkFactoryPlayback {
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFactoryPlayback(int count) : fCount(count) {
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fArray = SkNEW_ARRAY(SkFlattenable::Factory, count);
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ~SkFactoryPlayback() {
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDELETE_ARRAY(fArray);
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
136fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFlattenable::Factory* base() const { return fArray; }
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1398b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org    void setupBuffer(SkReadBuffer& buffer) const {
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        buffer.setFactoryPlayback(fArray, fCount);
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
142fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int fCount;
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFlattenable::Factory* fArray;
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
148d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com///////////////////////////////////////////////////////////////////////////////
149d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//
150d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//
151d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com// The following templated classes provide an efficient way to store and compare
152d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com// objects that have been flattened (i.e. serialized in an ordered binary
153d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com// format).
154d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//
155d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com// SkFlatData:       is a simple indexable container for the flattened data
156d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//                   which is agnostic to the type of data is is indexing. It is
157d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//                   also responsible for flattening/unflattening objects but
158fed2ab648341ec153ad2af746a31d368963171e4commit-bot@chromium.org//                   details of that operation are hidden in the provided traits
1594dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com// SkFlatDictionary: is an abstract templated dictionary that maintains a
160ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org//                   searchable set of SkFlatData objects of type T.
1614dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com// SkFlatController: is an interface provided to SkFlatDictionary which handles
162ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org//                   allocation (and unallocation in some cases). It also holds
1631554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com//                   ref count recorders and the like.
164d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//
165fed2ab648341ec153ad2af746a31d368963171e4commit-bot@chromium.org// NOTE: any class that wishes to be used in conjunction with SkFlatDictionary must subclass the
166fed2ab648341ec153ad2af746a31d368963171e4commit-bot@chromium.org// dictionary and provide the necessary flattening traits.  SkFlatController must also be
167fed2ab648341ec153ad2af746a31d368963171e4commit-bot@chromium.org// implemented, or SkChunkFlatController can be used to use an SkChunkAllocator and never do
168fed2ab648341ec153ad2af746a31d368963171e4commit-bot@chromium.org// replacements.
169d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//
170d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//
171d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com///////////////////////////////////////////////////////////////////////////////
172d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com
1734dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.comclass SkFlatData;
1744dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
1754dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.comclass SkFlatController : public SkRefCnt {
1764dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.compublic:
177a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com    SK_DECLARE_INST_COUNT(SkFlatController)
178a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com
179a2bd2d12ad9504583e9311404fcd82b40df49d30commit-bot@chromium.org    SkFlatController(uint32_t writeBufferFlags = 0);
1801554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    virtual ~SkFlatController();
1814dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    /**
182ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org     * Return a new block of memory for the SkFlatDictionary to use.
183ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org     * This memory is owned by the controller and has the same lifetime unless you
184ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org     * call unalloc(), in which case it may be freed early.
1854dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     */
1864dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    virtual void* allocThrow(size_t bytes) = 0;
1874dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
1884dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    /**
189ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org     * Hint that this block, which was allocated with allocThrow, is no longer needed.
190ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org     * The implementation may choose to free this memory any time beteween now and destruction.
1914dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     */
1924dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    virtual void unalloc(void* ptr) = 0;
1930c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com
1941554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
19521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com     * Used during creation and unflattening of SkFlatData objects. If the
19621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com     * objects being flattened contain bitmaps they are stored in this heap
19721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com     * and the flattenable stores the index to the bitmap on the heap.
19821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com     * This should be set by the protected setBitmapHeap.
1991554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
20021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; }
2011554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2021554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
2031554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * Used during creation of SkFlatData objects. If a typeface recorder is
2041554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * required to flatten the objects being flattened (i.e. for SkPaints), this
2051554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * should be set by the protected setTypefaceSet.
2061554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
2071554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkRefCntSet* getTypefaceSet() { return fTypefaceSet; }
2081554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2091554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
2101554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * Used during unflattening of the SkFlatData objects in the
2111554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * SkFlatDictionary. Needs to be set by the protected setTypefacePlayback
2121554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * and needs to be reset to the SkRefCntSet passed to setTypefaceSet.
2131554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
2141554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkTypefacePlayback* getTypefacePlayback() { return fTypefacePlayback; }
2151554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2161554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
2171554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * Optional factory recorder used during creation of SkFlatData objects. Set
2181554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * using the protected method setNamedFactorySet.
2191554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
2201554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkNamedFactorySet* getNamedFactorySet() { return fFactorySet; }
2211554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
222664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com    /**
223664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com     * Flags to use during creation of SkFlatData objects. Defaults to zero.
224664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com     */
225664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com    uint32_t getWriteBufferFlags() { return fWriteBufferFlags; }
226664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com
2271554360a9511d996e1618d19c163c810ef3f128cscroggo@google.comprotected:
2281554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
22921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com     * Set an SkBitmapHeap to be used to store/read SkBitmaps. Ref counted.
2301554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
23121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    void setBitmapHeap(SkBitmapHeap*);
2321554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2331554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
2341554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * Set an SkRefCntSet to be used to store SkTypefaces during flattening. Ref
2351554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * counted.
2361554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
2371554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    void setTypefaceSet(SkRefCntSet*);
2381554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2391554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
2401554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * Set an SkTypefacePlayback to be used to find references to SkTypefaces
2411554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * during unflattening. Should be reset to the set provided to
2421554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * setTypefaceSet.
2431554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
2441554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    void setTypefacePlayback(SkTypefacePlayback*);
2451554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2461554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
2471554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * Set an SkNamedFactorySet to be used to store Factorys and their
2481554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * corresponding names during flattening. Ref counted. Returns the same
2491554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * set as a convenience.
2501554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
2511554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkNamedFactorySet* setNamedFactorySet(SkNamedFactorySet*);
2521554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2531554360a9511d996e1618d19c163c810ef3f128cscroggo@google.comprivate:
25421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    SkBitmapHeap*       fBitmapHeap;
2551554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkRefCntSet*        fTypefaceSet;
2561554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkTypefacePlayback* fTypefacePlayback;
2571554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkNamedFactorySet*  fFactorySet;
258a2bd2d12ad9504583e9311404fcd82b40df49d30commit-bot@chromium.org    const uint32_t      fWriteBufferFlags;
259a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com
260a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com    typedef SkRefCnt INHERITED;
2614dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com};
2624dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkFlatData {
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
2659e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // Flatten obj into an SkFlatData with this index.  controller owns the SkFlatData*.
26607adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    template <typename Traits, typename T>
26707adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    static SkFlatData* Create(SkFlatController* controller, const T& obj, int index) {
26807adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        // A buffer of 256 bytes should fit most paints, regions, and matrices.
26907adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        uint32_t storage[64];
270a2bd2d12ad9504583e9311404fcd82b40df49d30commit-bot@chromium.org        SkWriteBuffer buffer(storage, sizeof(storage), controller->getWriteBufferFlags());
27107adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
27207adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        buffer.setBitmapHeap(controller->getBitmapHeap());
27307adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        buffer.setTypefaceRecorder(controller->getTypefaceSet());
27407adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        buffer.setNamedFactoryRecorder(controller->getNamedFactorySet());
27507adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
276186c0ccac25229534ec6fb84726043083304d4d1commit-bot@chromium.org        Traits::Flatten(buffer, obj);
2778b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org        size_t size = buffer.bytesWritten();
27807adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        SkASSERT(SkIsAlign4(size));
27907adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
28007adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        // Allocate enough memory to hold SkFlatData struct and the flat data itself.
28107adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        size_t allocSize = sizeof(SkFlatData) + size;
28207adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        SkFlatData* result = (SkFlatData*) controller->allocThrow(allocSize);
28307adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
28407adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        // Put the serialized contents into the data section of the new allocation.
28507adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        buffer.writeToMemory(result->data());
28607adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        // Stamp the index, size and checksum in the header.
2877fa2a65c0cfc714364490cb715171461143024e0reed@google.com        result->stampHeader(index, SkToS32(size));
28807adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        return result;
28907adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    }
29007adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
29107adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    // Unflatten this into result, using bitmapHeap and facePlayback for bitmaps and fonts if given
29207adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    template <typename Traits, typename T>
29307adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    void unflatten(T* result,
29421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com                   SkBitmapHeap* bitmapHeap = NULL,
29507adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org                   SkTypefacePlayback* facePlayback = NULL) const {
2968b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org        SkReadBuffer buffer(this->data(), fFlatSize);
29707adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
29807adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        if (bitmapHeap) {
29907adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org            buffer.setBitmapStorage(bitmapHeap);
30007adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        }
30107adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        if (facePlayback) {
30207adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org            facePlayback->setupBuffer(buffer);
30307adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        }
30407adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
305186c0ccac25229534ec6fb84726043083304d4d1commit-bot@chromium.org        Traits::Unflatten(buffer, result);
30607adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        SkASSERT(fFlatSize == (int32_t)buffer.offset());
30707adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    }
308d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com
3099e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // Do these contain the same data?  Ignores index() and topBot().
3109e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    bool operator==(const SkFlatData& that) const {
3119e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        if (this->checksum() != that.checksum() || this->flatSize() != that.flatSize()) {
3129e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com            return false;
3139e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        }
3149e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        return memcmp(this->data(), that.data(), this->flatSize()) == 0;
315e2589aeebf321f6d3b5005c19740beacee964be7reed@google.com    }
316e2589aeebf321f6d3b5005c19740beacee964be7reed@google.com
3179e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    int index() const { return fIndex; }
3189e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    const uint8_t* data() const { return (const uint8_t*)this + sizeof(*this); }
3199e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    size_t flatSize() const { return fFlatSize; }
3209e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    uint32_t checksum() const { return fChecksum; }
3219e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
3229e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // Returns true if fTopBot[] has been recorded.
323148a3961b1c82a891012f2feb2a875cea2593170bungeman@google.com    bool isTopBotWritten() const {
324148a3961b1c82a891012f2feb2a875cea2593170bungeman@google.com        return !SkScalarIsNaN(fTopBot[0]);
3254595426b553c0c721f41aa14d598caa5d9940207reed@google.com    }
3264595426b553c0c721f41aa14d598caa5d9940207reed@google.com
3274595426b553c0c721f41aa14d598caa5d9940207reed@google.com    // Returns fTopBot array, so it can be passed to a routine to compute them.
3284595426b553c0c721f41aa14d598caa5d9940207reed@google.com    // For efficiency, we assert that fTopBot have not been recorded yet.
329f3b1223e6d52b161dbc59a4119ba6a4161b10a54junov@chromium.org    SkScalar* writableTopBot() const {
330148a3961b1c82a891012f2feb2a875cea2593170bungeman@google.com        SkASSERT(!this->isTopBotWritten());
3314595426b553c0c721f41aa14d598caa5d9940207reed@google.com        return fTopBot;
3324595426b553c0c721f41aa14d598caa5d9940207reed@google.com    }
3334595426b553c0c721f41aa14d598caa5d9940207reed@google.com
3349e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // Return the topbot[] after it has been recorded.
3354595426b553c0c721f41aa14d598caa5d9940207reed@google.com    const SkScalar* topBot() const {
336148a3961b1c82a891012f2feb2a875cea2593170bungeman@google.com        SkASSERT(this->isTopBotWritten());
3374595426b553c0c721f41aa14d598caa5d9940207reed@google.com        return fTopBot;
3384595426b553c0c721f41aa14d598caa5d9940207reed@google.com    }
3394595426b553c0c721f41aa14d598caa5d9940207reed@google.com
340d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.comprivate:
34155bd940446506f8409f38271f2e4969e9b4f3991commit-bot@chromium.org    struct HashTraits {
34255bd940446506f8409f38271f2e4969e9b4f3991commit-bot@chromium.org        static const SkFlatData& GetKey(const SkFlatData& flat) { return flat; }
34355bd940446506f8409f38271f2e4969e9b4f3991commit-bot@chromium.org        static uint32_t Hash(const SkFlatData& flat) { return flat.checksum(); }
34455bd940446506f8409f38271f2e4969e9b4f3991commit-bot@chromium.org    };
345b4ed0178d0f86da920b101a661cbe8fd4fda3ab3reed@google.com
3469e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    void setIndex(int index) { fIndex = index; }
3479e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    uint8_t* data() { return (uint8_t*)this + sizeof(*this); }
3484595426b553c0c721f41aa14d598caa5d9940207reed@google.com
3499e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // This assumes the payload flat data has already been written and does not modify it.
3509e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    void stampHeader(int index, int32_t size) {
3519e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        SkASSERT(SkIsAlign4(size));
3529e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fIndex     = index;
3539e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fFlatSize  = size;
3549e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fTopBot[0] = SK_ScalarNaN;  // Mark as unwritten.
3559e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fChecksum  = SkChecksum::Compute((uint32_t*)this->data(), size);
356148a3961b1c82a891012f2feb2a875cea2593170bungeman@google.com    }
357148a3961b1c82a891012f2feb2a875cea2593170bungeman@google.com
3589e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    int fIndex;
3599e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    int32_t fFlatSize;
360ef76060cbf36032a5bef9cd8d18138704349c3aejunov@chromium.org    uint32_t fChecksum;
3619e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    mutable SkScalar fTopBot[2];  // Cache of FontMetrics fTop, fBottom.  Starts as [NaN,?].
3629e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // uint32_t flattenedData[] implicitly hangs off the end.
363ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
36419382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org    template <typename T, typename Traits> friend class SkFlatDictionary;
3658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
36719382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.orgtemplate <typename T, typename Traits>
368d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.comclass SkFlatDictionary {
3698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
37007adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    explicit SkFlatDictionary(SkFlatController* controller)
37107adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    : fController(SkRef(controller))
372a2bd2d12ad9504583e9311404fcd82b40df49d30commit-bot@chromium.org    , fScratch(controller->getWriteBufferFlags())
373ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org    , fReady(false) {
3749e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        this->reset();
3759e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    }
3769e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
3779e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    /**
3789e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * Clears the dictionary of all entries. However, it does NOT free the
3799e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * memory that was allocated for each entry (that's owned by controller).
3809e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     */
3819e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    void reset() {
3829e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fIndexedData.rewind();
383d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com    }
3848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3850f12e1fe42245a30c5dae856b600803aabbf137bskia.committer@gmail.com    int count() const {
3866e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        SkASSERT(fHash.count() == fIndexedData.count());
387f85251c74d214ffc7dafa6d9fe23c1be0a2f3aa6commit-bot@chromium.org        return fHash.count();
3887d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com    }
389d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com
3909e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // For testing only.  Index is zero-based.
3919e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    const SkFlatData* operator[](int index) {
3926e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        return fIndexedData[index];
393d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com    }
394d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com
395d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com    /**
3969e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * Given an element of type T return its 1-based index in the dictionary. If
3979e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * the element wasn't previously in the dictionary it is automatically
3989e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * added.
3999e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     *
400d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com     */
4019e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    int find(const T& element) {
4029e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        return this->findAndReturnFlat(element)->index();
40383ca337348c74dede813b2022943c25a337f32ebreed@google.com    }
4044dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
405d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com    /**
4064dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * Similar to find. Allows the caller to specify an SkFlatData to replace in
4074dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * the case of an add. Also tells the caller whether a new SkFlatData was
4084dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * added and whether the old one was replaced. The parameters added and
4094dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * replaced are required to be non-NULL. Rather than returning the index of
4104dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * the entry in the dictionary, it returns the actual SkFlatData.
411d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com     */
4124dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    const SkFlatData* findAndReplace(const T& element,
4139e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com                                     const SkFlatData* toReplace,
4149e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com                                     bool* added,
4154dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                                     bool* replaced) {
4164dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        SkASSERT(added != NULL && replaced != NULL);
4179e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
4189e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        const int oldCount = this->count();
4199e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        SkFlatData* flat = this->findAndReturnMutableFlat(element);
4209e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        *added = this->count() > oldCount;
4219e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
4229e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        // If we don't want to replace anything, we're done.
4239e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        if (!*added || toReplace == NULL) {
4249e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com            *replaced = false;
4259e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com            return flat;
4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
427e2589aeebf321f6d3b5005c19740beacee964be7reed@google.com
4289e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        // If we don't have the thing to replace, we're done.
4299e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        const SkFlatData* found = fHash.find(*toReplace);
4309e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        if (found == NULL) {
4319e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com            *replaced = false;
4329e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com            return flat;
4339e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        }
4349e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
435f85251c74d214ffc7dafa6d9fe23c1be0a2f3aa6commit-bot@chromium.org        // findAndReturnMutableFlat put flat at the back.  Swap it into found->index() instead.
4366e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        // indices in SkFlatData are 1-based, while fIndexedData is 0-based.  Watch out!
437f85251c74d214ffc7dafa6d9fe23c1be0a2f3aa6commit-bot@chromium.org        SkASSERT(flat->index() == this->count());
4389e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        flat->setIndex(found->index());
4396e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        fIndexedData.removeShuffle(found->index()-1);
4406e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        SkASSERT(flat == fIndexedData[found->index()-1]);
4419e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
4429e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        // findAndReturnMutableFlat already called fHash.add(), so we just clean up the old entry.
4439e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fHash.remove(*found);
4449e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fController->unalloc((void*)found);
4459e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        SkASSERT(this->count() == oldCount);
4469e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
4479e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        *replaced = true;
4489e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        return flat;
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
450d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com
451f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com    /**
452f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com     *  Unflatten the objects and return them in SkTRefArray, or return NULL
4539e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     *  if there no objects.  Caller takes ownership of result.
454f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com     */
4551554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkTRefArray<T>* unflattenToArray() const {
4569e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        const int count = this->count();
4579e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        if (count == 0) {
4589e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com            return NULL;
4599e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        }
4609e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        SkTRefArray<T>* array = SkTRefArray<T>::Create(count);
4619e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        for (int i = 0; i < count; i++) {
4626e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org            this->unflatten(&array->writableAt(i), fIndexedData[i]);
463f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com        }
464f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com        return array;
465f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com    }
466f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com
467e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com    /**
4689e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * Unflatten the specific object at the given index.
4699e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * Caller takes ownership of the result.
470e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com     */
471e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com    T* unflatten(int index) const {
4726e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        // index is 1-based, while fIndexedData is 0-based.
4736e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        const SkFlatData* element = fIndexedData[index-1];
4747d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com        SkASSERT(index == element->index());
475e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com
4767d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com        T* dst = new T;
4777d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com        this->unflatten(dst, element);
4787d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com        return dst;
479e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com    }
480e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com
4819e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    /**
4829e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * Find or insert a flattened version of element into the dictionary.
4839e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * Caller does not take ownership of the result.  This will not return NULL.
4849e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     */
485664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com    const SkFlatData* findAndReturnFlat(const T& element) {
4869e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        return this->findAndReturnMutableFlat(element);
4874dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    }
488fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
489f3b1223e6d52b161dbc59a4119ba6a4161b10a54junov@chromium.orgprivate:
49019382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org    // We have to delay fScratch's initialization until its first use; fController might not
49119382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org    // be fully set up by the time we get it in the constructor.
492ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org    void lazyInit() {
493ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org        if (fReady) {
494ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org            return;
495ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        }
496ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org
497ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // Without a bitmap heap, we'll flatten bitmaps into paints.  That's never what you want.
498ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        SkASSERT(fController->getBitmapHeap() != NULL);
49919382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        fScratch.setBitmapHeap(fController->getBitmapHeap());
50019382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        fScratch.setTypefaceRecorder(fController->getTypefaceSet());
50119382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        fScratch.setNamedFactoryRecorder(fController->getNamedFactorySet());
502ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org        fReady = true;
503ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    }
504ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
5059e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // As findAndReturnFlat, but returns a mutable pointer for internal use.
5069e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    SkFlatData* findAndReturnMutableFlat(const T& element) {
5079e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        // Only valid until the next call to resetScratch().
508f85251c74d214ffc7dafa6d9fe23c1be0a2f3aa6commit-bot@chromium.org        const SkFlatData& scratch = this->resetScratch(element, this->count()+1);
5099e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
5109e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        SkFlatData* candidate = fHash.find(scratch);
511d7e0fbef5d6c7c63b312a5ea1955a9802ad4302fcommit-bot@chromium.org        if (candidate != NULL) {
512d7e0fbef5d6c7c63b312a5ea1955a9802ad4302fcommit-bot@chromium.org            return candidate;
513d7e0fbef5d6c7c63b312a5ea1955a9802ad4302fcommit-bot@chromium.org        }
5149e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
5159e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        SkFlatData* detached = this->detachScratch();
5169e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fHash.add(detached);
517f85251c74d214ffc7dafa6d9fe23c1be0a2f3aa6commit-bot@chromium.org        *fIndexedData.append() = detached;
518f85251c74d214ffc7dafa6d9fe23c1be0a2f3aa6commit-bot@chromium.org        SkASSERT(fIndexedData.top()->index() == this->count());
5199e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        return detached;
5209e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    }
5219e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
522ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    // This reference is valid only until the next call to resetScratch() or detachScratch().
523ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    const SkFlatData& resetScratch(const T& element, int index) {
524ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org        this->lazyInit();
525ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
52619382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        // Layout of fScratch: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ]
52719382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        fScratch.reset();
52819382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        fScratch.reserve(sizeof(SkFlatData));
529186c0ccac25229534ec6fb84726043083304d4d1commit-bot@chromium.org        Traits::Flatten(fScratch, element);
53019382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        const size_t dataSize = fScratch.bytesWritten() - sizeof(SkFlatData);
531ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
53219382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        // Reinterpret data in fScratch as an SkFlatData.
53319382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
53419382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        SkASSERT(scratch != NULL);
535dcecb168968ca136c7fb9e8b444bec56f19af70ccommit-bot@chromium.org        scratch->stampHeader(index, SkToS32(dataSize));
53619382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        return *scratch;
537ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    }
538ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
539ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    // This result is owned by fController and lives as long as it does (unless unalloc'd).
540ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    SkFlatData* detachScratch() {
541ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // Allocate a new SkFlatData exactly big enough to hold our current scratch.
542ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // We use the controller for this allocation to extend the allocation's lifetime and allow
543ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // the controller to do whatever memory management it wants.
54419382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        SkFlatData* detached = (SkFlatData*)fController->allocThrow(fScratch.bytesWritten());
545ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
5469e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        // Copy scratch into the new SkFlatData.
54719382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
54819382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        SkASSERT(scratch != NULL);
54919382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        memcpy(detached, scratch, fScratch.bytesWritten());
550ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
551ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // We can now reuse fScratch, and detached will live until fController dies.
552ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        return detached;
553ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    }
554ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
555e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com    void unflatten(T* dst, const SkFlatData* element) const {
55607adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        element->unflatten<Traits>(dst,
55707adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org                                   fController->getBitmapHeap(),
55807adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org                                   fController->getTypefacePlayback());
559e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com    }
560e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com
5619e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // All SkFlatData* stored in fIndexedData and fHash are owned by the controller.
562ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    SkAutoTUnref<SkFlatController> fController;
5638b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org    SkWriteBuffer fScratch;
564ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org    bool fReady;
5657d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com
5666e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org    // For index -> SkFlatData.  0-based, while all indices in the API are 1-based.  Careful!
5677d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com    SkTDArray<const SkFlatData*> fIndexedData;
5689e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
5699e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // For SkFlatData -> cached SkFlatData, which has index().
57055bd940446506f8409f38271f2e4969e9b4f3991commit-bot@chromium.org    SkTDynamicHash<SkFlatData, SkFlatData, SkFlatData::HashTraits> fHash;
5718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
5728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
573aca1c01f3b39a8159a0ca10ba740d9995027317bcommit-bot@chromium.orgtypedef SkFlatDictionary<SkPaint, SkPaint::FlatteningTraits> SkPaintDictionary;
574d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com
5754dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.comclass SkChunkFlatController : public SkFlatController {
5764dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.compublic:
5774dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    SkChunkFlatController(size_t minSize)
5781554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    : fHeap(minSize)
57946724e457e9df0dd4fbafca4746621a42bd37ac3commit-bot@chromium.org    , fTypefaceSet(SkNEW(SkRefCntSet))
58046724e457e9df0dd4fbafca4746621a42bd37ac3commit-bot@chromium.org    , fLastAllocated(NULL) {
5811554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com        this->setTypefaceSet(fTypefaceSet);
5821554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com        this->setTypefacePlayback(&fTypefacePlayback);
5831554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    }
5844dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
5851554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    virtual void* allocThrow(size_t bytes) SK_OVERRIDE {
586ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        fLastAllocated = fHeap.allocThrow(bytes);
587ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        return fLastAllocated;
5884dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    }
5894dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
5901554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    virtual void unalloc(void* ptr) SK_OVERRIDE {
591ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // fHeap can only free a pointer if it was the last one allocated.  Otherwise, we'll just
592ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // have to wait until fHeap is destroyed.
593ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        if (ptr == fLastAllocated) (void)fHeap.unalloc(ptr);
5944dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    }
5951554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
5961554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    void setupPlaybacks() const {
597ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        fTypefacePlayback.reset(fTypefaceSet.get());
5981554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    }
5991554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
60021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    void setBitmapStorage(SkBitmapHeap* heap) {
60121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com        this->setBitmapHeap(heap);
60221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    }
60321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com
6044dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.comprivate:
6051554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkChunkAlloc               fHeap;
606ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    SkAutoTUnref<SkRefCntSet>  fTypefaceSet;
607ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    void*                      fLastAllocated;
6081554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    mutable SkTypefacePlayback fTypefacePlayback;
6094dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com};
6104dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
6118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
612