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