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//#define SK_DEBUG_SIZE
12e2589aeebf321f6d3b5005c19740beacee964be7reed@google.com
1321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com#include "SkBitmapHeap.h"
149e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com#include "SkChecksum.h"
159e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com#include "SkChunkAlloc.h"
168b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
178b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPaint.h"
199e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com#include "SkPicture.h"
209e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com#include "SkPtrRecorder.h"
219e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com#include "SkTDynamicHash.h"
22f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com#include "SkTRefArray.h"
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comenum DrawType {
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    UNUSED,
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    CLIP_PATH,
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    CLIP_REGION,
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    CLIP_RECT,
294ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    CLIP_RRECT,
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    CONCAT,
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_BITMAP,
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_BITMAP_MATRIX,
33f0b5e1190af9807a027c0adba2f1380663c8e910reed@google.com    DRAW_BITMAP_NINE,
347112173c3c4cd1b1e7da8cdf971d71f01dd91299reed@google.com    DRAW_BITMAP_RECT_TO_RECT,
352a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com    DRAW_CLEAR,
36cb60844b34766aad4151df5e87c144d4a57e9abereed@android.com    DRAW_DATA,
374ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    DRAW_OVAL,
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_PAINT,
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_PATH,
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_PICTURE,
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_POINTS,
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_POS_TEXT,
439efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com    DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_POS_TEXT_H,
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_RECT,
474ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    DRAW_RRECT,
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_SPRITE,
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_TEXT,
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_TEXT_ON_PATH,
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_TEXT_TOP_BOTTOM,   // fast variant of DRAW_TEXT
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_VERTICES,
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    RESTORE,
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ROTATE,
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SAVE,
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SAVE_LAYER,
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SCALE,
586e073b9e2b70d6bbf8a06050fff1364827204f08reed@android.com    SET_MATRIX,
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SKEW,
60ffacd3c56d73c03d3fe53b47a49ea6be2ca4748freed@google.com    TRANSLATE,
61e4ce5b82627d7ef7cab34b808ff88dc208aef7bcrobertphillips@google.com    NOOP,
620a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com    BEGIN_COMMENT_GROUP,
630a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com    COMMENT,
640a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com    END_COMMENT_GROUP,
65ffacd3c56d73c03d3fe53b47a49ea6be2ca4748freed@google.com
66ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org    // new ops -- feel free to re-alphabetize on next version bump
67ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org    DRAW_DRRECT,
68210ae2a42613b9048e8e8c4096c5bf4fe2ddf838commit-bot@chromium.org    PUSH_CULL,
69210ae2a42613b9048e8e8c4096c5bf4fe2ddf838commit-bot@chromium.org    POP_CULL,
70ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org
71210ae2a42613b9048e8e8c4096c5bf4fe2ddf838commit-bot@chromium.org    LAST_DRAWTYPE_ENUM = POP_CULL
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
74b8f9610ac6efb5426cb799ab9b1ab5d985b7b05arobertphillips@google.com// In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
75b8f9610ac6efb5426cb799ab9b1ab5d985b7b05arobertphillips@google.comstatic const int kDRAW_BITMAP_FLAVOR = LAST_DRAWTYPE_ENUM+1;
76b8f9610ac6efb5426cb799ab9b1ab5d985b7b05arobertphillips@google.com
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comenum DrawVertexFlags {
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_VERTICES_HAS_TEXS    = 0x01,
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DRAW_VERTICES_HAS_COLORS  = 0x02,
8085e143c33c214e54187aa28146aa7666961a0d17reed@google.com    DRAW_VERTICES_HAS_INDICES = 0x04,
8185e143c33c214e54187aa28146aa7666961a0d17reed@google.com    DRAW_VERTICES_HAS_XFER    = 0x08,
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8483ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com///////////////////////////////////////////////////////////////////////////////
8583ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com// clipparams are packed in 5 bits
8683ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com//  doAA:1 | regionOp:4
8783ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com
8883ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.comstatic inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) {
8983ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com    unsigned doAABit = doAA ? 1 : 0;
9083ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com    return (doAABit << 4) | op;
9183ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com}
9283ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com
9383ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.comstatic inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) {
9483ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com    return (SkRegion::Op)(packed & 0xF);
9583ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com}
9683ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com
9783ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.comstatic inline bool ClipParams_unpackDoAA(uint32_t packed) {
9883ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com    return SkToBool((packed >> 4) & 1);
9983ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com}
10083ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com
10183ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com///////////////////////////////////////////////////////////////////////////////
10283ab49556ffc83fd3b2c1142db264362d21e6b19reed@google.com
10321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.comclass SkTypefacePlayback {
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
10521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    SkTypefacePlayback();
10621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    virtual ~SkTypefacePlayback();
107fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count() const { return fCount; }
109fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
110e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org    void reset(const SkRefCntSet*);
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setCount(int count);
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt* set(int index, SkRefCnt*);
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1158b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org    void setupBuffer(SkReadBuffer& buffer) const {
11621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com        buffer.setTypefaceArray((SkTypeface**)fArray, fCount);
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
118fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprotected:
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int fCount;
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt** fArray;
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkFactoryPlayback {
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFactoryPlayback(int count) : fCount(count) {
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fArray = SkNEW_ARRAY(SkFlattenable::Factory, count);
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ~SkFactoryPlayback() {
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDELETE_ARRAY(fArray);
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
133fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFlattenable::Factory* base() const { return fArray; }
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1368b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org    void setupBuffer(SkReadBuffer& buffer) const {
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        buffer.setFactoryPlayback(fArray, fCount);
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
139fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int fCount;
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFlattenable::Factory* fArray;
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
145d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com///////////////////////////////////////////////////////////////////////////////
146d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//
147d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//
148d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com// The following templated classes provide an efficient way to store and compare
149d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com// objects that have been flattened (i.e. serialized in an ordered binary
150d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com// format).
151d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//
152d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com// SkFlatData:       is a simple indexable container for the flattened data
153d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//                   which is agnostic to the type of data is is indexing. It is
154d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//                   also responsible for flattening/unflattening objects but
155fed2ab648341ec153ad2af746a31d368963171e4commit-bot@chromium.org//                   details of that operation are hidden in the provided traits
1564dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com// SkFlatDictionary: is an abstract templated dictionary that maintains a
157ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org//                   searchable set of SkFlatData objects of type T.
1584dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com// SkFlatController: is an interface provided to SkFlatDictionary which handles
159ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org//                   allocation (and unallocation in some cases). It also holds
1601554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com//                   ref count recorders and the like.
161d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//
162fed2ab648341ec153ad2af746a31d368963171e4commit-bot@chromium.org// NOTE: any class that wishes to be used in conjunction with SkFlatDictionary must subclass the
163fed2ab648341ec153ad2af746a31d368963171e4commit-bot@chromium.org// dictionary and provide the necessary flattening traits.  SkFlatController must also be
164fed2ab648341ec153ad2af746a31d368963171e4commit-bot@chromium.org// implemented, or SkChunkFlatController can be used to use an SkChunkAllocator and never do
165fed2ab648341ec153ad2af746a31d368963171e4commit-bot@chromium.org// replacements.
166d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//
167d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com//
168d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com///////////////////////////////////////////////////////////////////////////////
169d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com
1704dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.comclass SkFlatData;
1714dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
1724dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.comclass SkFlatController : public SkRefCnt {
1734dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.compublic:
174a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com    SK_DECLARE_INST_COUNT(SkFlatController)
175a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com
176a2bd2d12ad9504583e9311404fcd82b40df49d30commit-bot@chromium.org    SkFlatController(uint32_t writeBufferFlags = 0);
1771554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    virtual ~SkFlatController();
1784dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    /**
179ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org     * Return a new block of memory for the SkFlatDictionary to use.
180ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org     * This memory is owned by the controller and has the same lifetime unless you
181ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org     * call unalloc(), in which case it may be freed early.
1824dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     */
1834dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    virtual void* allocThrow(size_t bytes) = 0;
1844dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
1854dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    /**
186ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org     * Hint that this block, which was allocated with allocThrow, is no longer needed.
187ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org     * The implementation may choose to free this memory any time beteween now and destruction.
1884dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     */
1894dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    virtual void unalloc(void* ptr) = 0;
1900c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com
1911554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
19221830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com     * Used during creation and unflattening of SkFlatData objects. If the
19321830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com     * objects being flattened contain bitmaps they are stored in this heap
19421830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com     * and the flattenable stores the index to the bitmap on the heap.
19521830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com     * This should be set by the protected setBitmapHeap.
1961554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
19721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; }
1981554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
1991554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
2001554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * Used during creation of SkFlatData objects. If a typeface recorder is
2011554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * required to flatten the objects being flattened (i.e. for SkPaints), this
2021554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * should be set by the protected setTypefaceSet.
2031554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
2041554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkRefCntSet* getTypefaceSet() { return fTypefaceSet; }
2051554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2061554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
2071554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * Used during unflattening of the SkFlatData objects in the
2081554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * SkFlatDictionary. Needs to be set by the protected setTypefacePlayback
2091554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * and needs to be reset to the SkRefCntSet passed to setTypefaceSet.
2101554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
2111554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkTypefacePlayback* getTypefacePlayback() { return fTypefacePlayback; }
2121554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2131554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
2141554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * Optional factory recorder used during creation of SkFlatData objects. Set
2151554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * using the protected method setNamedFactorySet.
2161554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
2171554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkNamedFactorySet* getNamedFactorySet() { return fFactorySet; }
2181554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
219664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com    /**
220664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com     * Flags to use during creation of SkFlatData objects. Defaults to zero.
221664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com     */
222664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com    uint32_t getWriteBufferFlags() { return fWriteBufferFlags; }
223664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com
2241554360a9511d996e1618d19c163c810ef3f128cscroggo@google.comprotected:
2251554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
22621830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com     * Set an SkBitmapHeap to be used to store/read SkBitmaps. Ref counted.
2271554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
22821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    void setBitmapHeap(SkBitmapHeap*);
2291554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2301554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
2311554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * Set an SkRefCntSet to be used to store SkTypefaces during flattening. Ref
2321554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * counted.
2331554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
2341554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    void setTypefaceSet(SkRefCntSet*);
2351554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2361554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
2371554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * Set an SkTypefacePlayback to be used to find references to SkTypefaces
2381554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * during unflattening. Should be reset to the set provided to
2391554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * setTypefaceSet.
2401554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
2411554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    void setTypefacePlayback(SkTypefacePlayback*);
2421554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2431554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    /**
2441554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * Set an SkNamedFactorySet to be used to store Factorys and their
2451554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * corresponding names during flattening. Ref counted. Returns the same
2461554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     * set as a convenience.
2471554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com     */
2481554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkNamedFactorySet* setNamedFactorySet(SkNamedFactorySet*);
2491554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
2501554360a9511d996e1618d19c163c810ef3f128cscroggo@google.comprivate:
25121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    SkBitmapHeap*       fBitmapHeap;
2521554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkRefCntSet*        fTypefaceSet;
2531554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkTypefacePlayback* fTypefacePlayback;
2541554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkNamedFactorySet*  fFactorySet;
255a2bd2d12ad9504583e9311404fcd82b40df49d30commit-bot@chromium.org    const uint32_t      fWriteBufferFlags;
256a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com
257a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com    typedef SkRefCnt INHERITED;
2584dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com};
2594dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkFlatData {
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
2629e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // Flatten obj into an SkFlatData with this index.  controller owns the SkFlatData*.
26307adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    template <typename Traits, typename T>
26407adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    static SkFlatData* Create(SkFlatController* controller, const T& obj, int index) {
26507adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        // A buffer of 256 bytes should fit most paints, regions, and matrices.
26607adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        uint32_t storage[64];
267a2bd2d12ad9504583e9311404fcd82b40df49d30commit-bot@chromium.org        SkWriteBuffer buffer(storage, sizeof(storage), controller->getWriteBufferFlags());
26807adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
26907adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        buffer.setBitmapHeap(controller->getBitmapHeap());
27007adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        buffer.setTypefaceRecorder(controller->getTypefaceSet());
27107adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        buffer.setNamedFactoryRecorder(controller->getNamedFactorySet());
27207adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
273186c0ccac25229534ec6fb84726043083304d4d1commit-bot@chromium.org        Traits::Flatten(buffer, obj);
2748b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org        size_t size = buffer.bytesWritten();
27507adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        SkASSERT(SkIsAlign4(size));
27607adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
27707adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        // Allocate enough memory to hold SkFlatData struct and the flat data itself.
27807adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        size_t allocSize = sizeof(SkFlatData) + size;
27907adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        SkFlatData* result = (SkFlatData*) controller->allocThrow(allocSize);
28007adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
28107adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        // Put the serialized contents into the data section of the new allocation.
28207adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        buffer.writeToMemory(result->data());
28307adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        // Stamp the index, size and checksum in the header.
2847fa2a65c0cfc714364490cb715171461143024e0reed@google.com        result->stampHeader(index, SkToS32(size));
28507adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        return result;
28607adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    }
28707adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
28807adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    // Unflatten this into result, using bitmapHeap and facePlayback for bitmaps and fonts if given
28907adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    template <typename Traits, typename T>
29007adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    void unflatten(T* result,
29121830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com                   SkBitmapHeap* bitmapHeap = NULL,
29207adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org                   SkTypefacePlayback* facePlayback = NULL) const {
2938b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org        SkReadBuffer buffer(this->data(), fFlatSize);
29407adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
29507adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        if (bitmapHeap) {
29607adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org            buffer.setBitmapStorage(bitmapHeap);
29707adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        }
29807adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        if (facePlayback) {
29907adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org            facePlayback->setupBuffer(buffer);
30007adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        }
30107adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org
302186c0ccac25229534ec6fb84726043083304d4d1commit-bot@chromium.org        Traits::Unflatten(buffer, result);
30307adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        SkASSERT(fFlatSize == (int32_t)buffer.offset());
30407adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    }
305d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com
3069e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // Do these contain the same data?  Ignores index() and topBot().
3079e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    bool operator==(const SkFlatData& that) const {
3089e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        if (this->checksum() != that.checksum() || this->flatSize() != that.flatSize()) {
3099e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com            return false;
3109e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        }
3119e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        return memcmp(this->data(), that.data(), this->flatSize()) == 0;
312e2589aeebf321f6d3b5005c19740beacee964be7reed@google.com    }
313e2589aeebf321f6d3b5005c19740beacee964be7reed@google.com
3149e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    int index() const { return fIndex; }
3159e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    const uint8_t* data() const { return (const uint8_t*)this + sizeof(*this); }
3169e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    size_t flatSize() const { return fFlatSize; }
3179e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    uint32_t checksum() const { return fChecksum; }
3189e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
3199e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // Returns true if fTopBot[] has been recorded.
320148a3961b1c82a891012f2feb2a875cea2593170bungeman@google.com    bool isTopBotWritten() const {
321148a3961b1c82a891012f2feb2a875cea2593170bungeman@google.com        return !SkScalarIsNaN(fTopBot[0]);
3224595426b553c0c721f41aa14d598caa5d9940207reed@google.com    }
3234595426b553c0c721f41aa14d598caa5d9940207reed@google.com
3244595426b553c0c721f41aa14d598caa5d9940207reed@google.com    // Returns fTopBot array, so it can be passed to a routine to compute them.
3254595426b553c0c721f41aa14d598caa5d9940207reed@google.com    // For efficiency, we assert that fTopBot have not been recorded yet.
326f3b1223e6d52b161dbc59a4119ba6a4161b10a54junov@chromium.org    SkScalar* writableTopBot() const {
327148a3961b1c82a891012f2feb2a875cea2593170bungeman@google.com        SkASSERT(!this->isTopBotWritten());
3284595426b553c0c721f41aa14d598caa5d9940207reed@google.com        return fTopBot;
3294595426b553c0c721f41aa14d598caa5d9940207reed@google.com    }
3304595426b553c0c721f41aa14d598caa5d9940207reed@google.com
3319e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // Return the topbot[] after it has been recorded.
3324595426b553c0c721f41aa14d598caa5d9940207reed@google.com    const SkScalar* topBot() const {
333148a3961b1c82a891012f2feb2a875cea2593170bungeman@google.com        SkASSERT(this->isTopBotWritten());
3344595426b553c0c721f41aa14d598caa5d9940207reed@google.com        return fTopBot;
3354595426b553c0c721f41aa14d598caa5d9940207reed@google.com    }
3364595426b553c0c721f41aa14d598caa5d9940207reed@google.com
337d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.comprivate:
33855bd940446506f8409f38271f2e4969e9b4f3991commit-bot@chromium.org    struct HashTraits {
33955bd940446506f8409f38271f2e4969e9b4f3991commit-bot@chromium.org        static const SkFlatData& GetKey(const SkFlatData& flat) { return flat; }
34055bd940446506f8409f38271f2e4969e9b4f3991commit-bot@chromium.org        static uint32_t Hash(const SkFlatData& flat) { return flat.checksum(); }
34155bd940446506f8409f38271f2e4969e9b4f3991commit-bot@chromium.org    };
342b4ed0178d0f86da920b101a661cbe8fd4fda3ab3reed@google.com
3439e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    void setIndex(int index) { fIndex = index; }
3449e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    uint8_t* data() { return (uint8_t*)this + sizeof(*this); }
3454595426b553c0c721f41aa14d598caa5d9940207reed@google.com
3469e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // This assumes the payload flat data has already been written and does not modify it.
3479e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    void stampHeader(int index, int32_t size) {
3489e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        SkASSERT(SkIsAlign4(size));
3499e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fIndex     = index;
3509e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fFlatSize  = size;
3519e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fTopBot[0] = SK_ScalarNaN;  // Mark as unwritten.
3529e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fChecksum  = SkChecksum::Compute((uint32_t*)this->data(), size);
353148a3961b1c82a891012f2feb2a875cea2593170bungeman@google.com    }
354148a3961b1c82a891012f2feb2a875cea2593170bungeman@google.com
3559e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    int fIndex;
3569e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    int32_t fFlatSize;
357ef76060cbf36032a5bef9cd8d18138704349c3aejunov@chromium.org    uint32_t fChecksum;
3589e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    mutable SkScalar fTopBot[2];  // Cache of FontMetrics fTop, fBottom.  Starts as [NaN,?].
3599e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // uint32_t flattenedData[] implicitly hangs off the end.
360ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
36119382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org    template <typename T, typename Traits> friend class SkFlatDictionary;
3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
36419382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.orgtemplate <typename T, typename Traits>
365d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.comclass SkFlatDictionary {
3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
36707adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    explicit SkFlatDictionary(SkFlatController* controller)
36807adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org    : fController(SkRef(controller))
369a2bd2d12ad9504583e9311404fcd82b40df49d30commit-bot@chromium.org    , fScratch(controller->getWriteBufferFlags())
370ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org    , fReady(false) {
3719e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        this->reset();
3729e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    }
3739e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
3749e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    /**
3759e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * Clears the dictionary of all entries. However, it does NOT free the
3769e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * memory that was allocated for each entry (that's owned by controller).
3779e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     */
3789e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    void reset() {
3799e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fIndexedData.rewind();
380d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com    }
3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3820f12e1fe42245a30c5dae856b600803aabbf137bskia.committer@gmail.com    int count() const {
3836e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        SkASSERT(fHash.count() == fIndexedData.count());
384f85251c74d214ffc7dafa6d9fe23c1be0a2f3aa6commit-bot@chromium.org        return fHash.count();
3857d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com    }
386d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com
3879e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // For testing only.  Index is zero-based.
3889e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    const SkFlatData* operator[](int index) {
3896e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        return fIndexedData[index];
390d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com    }
391d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com
392d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com    /**
3939e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * Given an element of type T return its 1-based index in the dictionary. If
3949e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * the element wasn't previously in the dictionary it is automatically
3959e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * added.
3969e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     *
397d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com     */
3989e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    int find(const T& element) {
3999e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        return this->findAndReturnFlat(element)->index();
40083ca337348c74dede813b2022943c25a337f32ebreed@google.com    }
4014dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
402d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com    /**
4034dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * Similar to find. Allows the caller to specify an SkFlatData to replace in
4044dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * the case of an add. Also tells the caller whether a new SkFlatData was
4054dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * added and whether the old one was replaced. The parameters added and
4064dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * replaced are required to be non-NULL. Rather than returning the index of
4074dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * the entry in the dictionary, it returns the actual SkFlatData.
408d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com     */
4094dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    const SkFlatData* findAndReplace(const T& element,
4109e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com                                     const SkFlatData* toReplace,
4119e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com                                     bool* added,
4124dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                                     bool* replaced) {
4134dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        SkASSERT(added != NULL && replaced != NULL);
4149e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
4159e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        const int oldCount = this->count();
4169e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        SkFlatData* flat = this->findAndReturnMutableFlat(element);
4179e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        *added = this->count() > oldCount;
4189e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
4199e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        // If we don't want to replace anything, we're done.
4209e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        if (!*added || toReplace == NULL) {
4219e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com            *replaced = false;
4229e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com            return flat;
4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
424e2589aeebf321f6d3b5005c19740beacee964be7reed@google.com
4259e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        // If we don't have the thing to replace, we're done.
4269e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        const SkFlatData* found = fHash.find(*toReplace);
4279e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        if (found == NULL) {
4289e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com            *replaced = false;
4299e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com            return flat;
4309e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        }
4319e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
432f85251c74d214ffc7dafa6d9fe23c1be0a2f3aa6commit-bot@chromium.org        // findAndReturnMutableFlat put flat at the back.  Swap it into found->index() instead.
4336e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        // indices in SkFlatData are 1-based, while fIndexedData is 0-based.  Watch out!
434f85251c74d214ffc7dafa6d9fe23c1be0a2f3aa6commit-bot@chromium.org        SkASSERT(flat->index() == this->count());
4359e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        flat->setIndex(found->index());
4366e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        fIndexedData.removeShuffle(found->index()-1);
4376e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        SkASSERT(flat == fIndexedData[found->index()-1]);
4389e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
4399e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        // findAndReturnMutableFlat already called fHash.add(), so we just clean up the old entry.
4409e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fHash.remove(*found);
4419e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fController->unalloc((void*)found);
4429e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        SkASSERT(this->count() == oldCount);
4439e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
4449e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        *replaced = true;
4459e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        return flat;
4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
447d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com
448f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com    /**
449f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com     *  Unflatten the objects and return them in SkTRefArray, or return NULL
4509e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     *  if there no objects.  Caller takes ownership of result.
451f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com     */
4521554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkTRefArray<T>* unflattenToArray() const {
4539e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        const int count = this->count();
4549e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        if (count == 0) {
4559e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com            return NULL;
4569e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        }
4579e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        SkTRefArray<T>* array = SkTRefArray<T>::Create(count);
4589e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        for (int i = 0; i < count; i++) {
4596e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org            this->unflatten(&array->writableAt(i), fIndexedData[i]);
460f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com        }
461f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com        return array;
462f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com    }
463f4cc18726b52a76ba18c07a6490851c4a5e38835reed@google.com
464e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com    /**
4659e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * Unflatten the specific object at the given index.
4669e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * Caller takes ownership of the result.
467e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com     */
468e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com    T* unflatten(int index) const {
4696e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        // index is 1-based, while fIndexedData is 0-based.
4706e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org        const SkFlatData* element = fIndexedData[index-1];
4717d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com        SkASSERT(index == element->index());
472e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com
4737d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com        T* dst = new T;
4747d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com        this->unflatten(dst, element);
4757d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com        return dst;
476e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com    }
477e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com
4789e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    /**
4799e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * Find or insert a flattened version of element into the dictionary.
4809e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     * Caller does not take ownership of the result.  This will not return NULL.
4819e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com     */
482664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com    const SkFlatData* findAndReturnFlat(const T& element) {
4839e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        return this->findAndReturnMutableFlat(element);
4844dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    }
485fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
486f3b1223e6d52b161dbc59a4119ba6a4161b10a54junov@chromium.orgprivate:
48719382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org    // We have to delay fScratch's initialization until its first use; fController might not
48819382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org    // be fully set up by the time we get it in the constructor.
489ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org    void lazyInit() {
490ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org        if (fReady) {
491ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org            return;
492ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        }
493ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org
494ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // Without a bitmap heap, we'll flatten bitmaps into paints.  That's never what you want.
495ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        SkASSERT(fController->getBitmapHeap() != NULL);
49619382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        fScratch.setBitmapHeap(fController->getBitmapHeap());
49719382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        fScratch.setTypefaceRecorder(fController->getTypefaceSet());
49819382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        fScratch.setNamedFactoryRecorder(fController->getNamedFactorySet());
499ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org        fReady = true;
500ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    }
501ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
5029e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // As findAndReturnFlat, but returns a mutable pointer for internal use.
5039e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    SkFlatData* findAndReturnMutableFlat(const T& element) {
5049e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        // Only valid until the next call to resetScratch().
505f85251c74d214ffc7dafa6d9fe23c1be0a2f3aa6commit-bot@chromium.org        const SkFlatData& scratch = this->resetScratch(element, this->count()+1);
5069e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
5079e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        SkFlatData* candidate = fHash.find(scratch);
508d7e0fbef5d6c7c63b312a5ea1955a9802ad4302fcommit-bot@chromium.org        if (candidate != NULL) {
509d7e0fbef5d6c7c63b312a5ea1955a9802ad4302fcommit-bot@chromium.org            return candidate;
510d7e0fbef5d6c7c63b312a5ea1955a9802ad4302fcommit-bot@chromium.org        }
5119e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
5129e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        SkFlatData* detached = this->detachScratch();
5139e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        fHash.add(detached);
514f85251c74d214ffc7dafa6d9fe23c1be0a2f3aa6commit-bot@chromium.org        *fIndexedData.append() = detached;
515f85251c74d214ffc7dafa6d9fe23c1be0a2f3aa6commit-bot@chromium.org        SkASSERT(fIndexedData.top()->index() == this->count());
5169e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        return detached;
5179e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    }
5189e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
519ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    // This reference is valid only until the next call to resetScratch() or detachScratch().
520ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    const SkFlatData& resetScratch(const T& element, int index) {
521ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org        this->lazyInit();
522ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
52319382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        // Layout of fScratch: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ]
52419382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        fScratch.reset();
52519382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        fScratch.reserve(sizeof(SkFlatData));
526186c0ccac25229534ec6fb84726043083304d4d1commit-bot@chromium.org        Traits::Flatten(fScratch, element);
52719382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        const size_t dataSize = fScratch.bytesWritten() - sizeof(SkFlatData);
528ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
52919382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        // Reinterpret data in fScratch as an SkFlatData.
53019382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
53119382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        SkASSERT(scratch != NULL);
532dcecb168968ca136c7fb9e8b444bec56f19af70ccommit-bot@chromium.org        scratch->stampHeader(index, SkToS32(dataSize));
53319382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        return *scratch;
534ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    }
535ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
536ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    // This result is owned by fController and lives as long as it does (unless unalloc'd).
537ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    SkFlatData* detachScratch() {
538ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // Allocate a new SkFlatData exactly big enough to hold our current scratch.
539ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // We use the controller for this allocation to extend the allocation's lifetime and allow
540ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // the controller to do whatever memory management it wants.
54119382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        SkFlatData* detached = (SkFlatData*)fController->allocThrow(fScratch.bytesWritten());
542ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
5439e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com        // Copy scratch into the new SkFlatData.
54419382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
54519382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        SkASSERT(scratch != NULL);
54619382421b916aab00be7265815ba4e2690adf2c9commit-bot@chromium.org        memcpy(detached, scratch, fScratch.bytesWritten());
547ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
548ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // We can now reuse fScratch, and detached will live until fController dies.
549ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        return detached;
550ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    }
551ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org
552e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com    void unflatten(T* dst, const SkFlatData* element) const {
55307adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        element->unflatten<Traits>(dst,
55407adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org                                   fController->getBitmapHeap(),
55507adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org                                   fController->getTypefacePlayback());
556e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com    }
557e37ad358b7219e45323a79c484ea67a5c59f34c2robertphillips@google.com
5589e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // All SkFlatData* stored in fIndexedData and fHash are owned by the controller.
559ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    SkAutoTUnref<SkFlatController> fController;
5608b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org    SkWriteBuffer fScratch;
561ff007e8ff358d9253de22291ebfd5fe7980512edcommit-bot@chromium.org    bool fReady;
5627d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com
5636e83423f1653b97915b80e3adab477e68d2b2933commit-bot@chromium.org    // For index -> SkFlatData.  0-based, while all indices in the API are 1-based.  Careful!
5647d3451b1844d8f93892f032bc060212f17173214robertphillips@google.com    SkTDArray<const SkFlatData*> fIndexedData;
5659e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com
5669e3074e968f52eb02fdc329bb9fbe7be5e674268mtklein@google.com    // For SkFlatData -> cached SkFlatData, which has index().
56755bd940446506f8409f38271f2e4969e9b4f3991commit-bot@chromium.org    SkTDynamicHash<SkFlatData, SkFlatData, SkFlatData::HashTraits> fHash;
5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
570aca1c01f3b39a8159a0ca10ba740d9995027317bcommit-bot@chromium.orgtypedef SkFlatDictionary<SkPaint, SkPaint::FlatteningTraits> SkPaintDictionary;
571d2700eec7eb2e26beb206b88a0f0b6f3c5f49118djsollen@google.com
5724dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.comclass SkChunkFlatController : public SkFlatController {
5734dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.compublic:
5744dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    SkChunkFlatController(size_t minSize)
5751554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    : fHeap(minSize)
57646724e457e9df0dd4fbafca4746621a42bd37ac3commit-bot@chromium.org    , fTypefaceSet(SkNEW(SkRefCntSet))
57746724e457e9df0dd4fbafca4746621a42bd37ac3commit-bot@chromium.org    , fLastAllocated(NULL) {
5781554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com        this->setTypefaceSet(fTypefaceSet);
5791554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com        this->setTypefacePlayback(&fTypefacePlayback);
5801554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    }
5814dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
5821554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    virtual void* allocThrow(size_t bytes) SK_OVERRIDE {
583ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        fLastAllocated = fHeap.allocThrow(bytes);
584ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        return fLastAllocated;
5854dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    }
5864dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
5871554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    virtual void unalloc(void* ptr) SK_OVERRIDE {
588ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // fHeap can only free a pointer if it was the last one allocated.  Otherwise, we'll just
589ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        // have to wait until fHeap is destroyed.
590ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        if (ptr == fLastAllocated) (void)fHeap.unalloc(ptr);
5914dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    }
5921554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
5931554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    void setupPlaybacks() const {
594ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org        fTypefacePlayback.reset(fTypefaceSet.get());
5951554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    }
5961554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com
59721830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    void setBitmapStorage(SkBitmapHeap* heap) {
59821830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com        this->setBitmapHeap(heap);
59921830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com    }
60021830d90096d2dccc4168d99a427e78035ce942adjsollen@google.com
6014dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.comprivate:
6021554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    SkChunkAlloc               fHeap;
603ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    SkAutoTUnref<SkRefCntSet>  fTypefaceSet;
604ff36a1d07f23f2b7feddaba110d448073a96f83ccommit-bot@chromium.org    void*                      fLastAllocated;
6051554360a9511d996e1618d19c163c810ef3f128cscroggo@google.com    mutable SkTypefacePlayback fTypefacePlayback;
6064dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com};
6074dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
6088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
609