blob: 66e538c0d699ed4b62b65344fd213b0fcaad661a [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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.com8a1c16f2008-12-17 15:59:43 +00008#ifndef SkPictureFlat_DEFINED
9#define SkPictureFlat_DEFINED
10
11#include "SkChunkAlloc.h"
12#include "SkBitmap.h"
djsollen@google.com2b2ede32012-04-12 13:24:04 +000013#include "SkOrderedReadBuffer.h"
djsollen@google.comd2700ee2012-05-30 16:54:13 +000014#include "SkOrderedWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkPicture.h"
16#include "SkMatrix.h"
17#include "SkPaint.h"
18#include "SkPath.h"
19#include "SkRegion.h"
djsollen@google.comd2700ee2012-05-30 16:54:13 +000020#include "SkTSearch.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000021
22enum DrawType {
23 UNUSED,
24 CLIP_PATH,
25 CLIP_REGION,
26 CLIP_RECT,
27 CONCAT,
28 DRAW_BITMAP,
29 DRAW_BITMAP_MATRIX,
reed@google.comf0b5e112011-09-07 11:57:34 +000030 DRAW_BITMAP_NINE,
reed@android.com8a1c16f2008-12-17 15:59:43 +000031 DRAW_BITMAP_RECT,
reed@google.com2a981812011-04-14 18:59:28 +000032 DRAW_CLEAR,
reed@android.comcb608442009-12-04 21:32:27 +000033 DRAW_DATA,
reed@android.com8a1c16f2008-12-17 15:59:43 +000034 DRAW_PAINT,
35 DRAW_PATH,
36 DRAW_PICTURE,
37 DRAW_POINTS,
38 DRAW_POS_TEXT,
reed@google.com9efd9a02012-01-30 15:41:43 +000039 DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
reed@android.com8a1c16f2008-12-17 15:59:43 +000040 DRAW_POS_TEXT_H,
41 DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
42 DRAW_RECT,
43 DRAW_SPRITE,
44 DRAW_TEXT,
45 DRAW_TEXT_ON_PATH,
46 DRAW_TEXT_TOP_BOTTOM, // fast variant of DRAW_TEXT
47 DRAW_VERTICES,
48 RESTORE,
49 ROTATE,
50 SAVE,
51 SAVE_LAYER,
52 SCALE,
reed@android.com6e073b92009-01-06 15:03:30 +000053 SET_MATRIX,
reed@android.com8a1c16f2008-12-17 15:59:43 +000054 SKEW,
55 TRANSLATE
56};
57
58enum DrawVertexFlags {
59 DRAW_VERTICES_HAS_TEXS = 0x01,
60 DRAW_VERTICES_HAS_COLORS = 0x02,
61 DRAW_VERTICES_HAS_INDICES = 0x04
62};
63
reed@google.com83ab4952011-11-11 21:34:54 +000064///////////////////////////////////////////////////////////////////////////////
65// clipparams are packed in 5 bits
66// doAA:1 | regionOp:4
67
68static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) {
69 unsigned doAABit = doAA ? 1 : 0;
70 return (doAABit << 4) | op;
71}
72
73static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) {
74 return (SkRegion::Op)(packed & 0xF);
75}
76
77static inline bool ClipParams_unpackDoAA(uint32_t packed) {
78 return SkToBool((packed >> 4) & 1);
79}
80
81///////////////////////////////////////////////////////////////////////////////
82
reed@android.com8a1c16f2008-12-17 15:59:43 +000083class SkRefCntPlayback {
84public:
85 SkRefCntPlayback();
reed@android.com04225dc2009-03-20 04:59:37 +000086 virtual ~SkRefCntPlayback();
reed@android.com8a1c16f2008-12-17 15:59:43 +000087
88 int count() const { return fCount; }
89
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +000090 void reset(const SkRefCntSet*);
reed@android.com8a1c16f2008-12-17 15:59:43 +000091
92 void setCount(int count);
93 SkRefCnt* set(int index, SkRefCnt*);
94
95 virtual void setupBuffer(SkFlattenableReadBuffer& buffer) const {
96 buffer.setRefCntArray(fArray, fCount);
97 }
98
99protected:
100 int fCount;
101 SkRefCnt** fArray;
102};
103
104class SkTypefacePlayback : public SkRefCntPlayback {
105public:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106 virtual void setupBuffer(SkFlattenableReadBuffer& buffer) const {
107 buffer.setTypefaceArray((SkTypeface**)fArray, fCount);
108 }
109};
110
111class SkFactoryPlayback {
112public:
113 SkFactoryPlayback(int count) : fCount(count) {
114 fArray = SkNEW_ARRAY(SkFlattenable::Factory, count);
115 }
116
117 ~SkFactoryPlayback() {
118 SkDELETE_ARRAY(fArray);
119 }
120
121 SkFlattenable::Factory* base() const { return fArray; }
122
123 void setupBuffer(SkFlattenableReadBuffer& buffer) const {
124 buffer.setFactoryPlayback(fArray, fCount);
125 }
126
127private:
128 int fCount;
129 SkFlattenable::Factory* fArray;
130};
131
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000132///////////////////////////////////////////////////////////////////////////////
133//
134//
135// The following templated classes provide an efficient way to store and compare
136// objects that have been flattened (i.e. serialized in an ordered binary
137// format).
138//
139// SkFlatData: is a simple indexable container for the flattened data
140// which is agnostic to the type of data is is indexing. It is
141// also responsible for flattening/unflattening objects but
142// details of that operation are hidden in the provided procs
143// SkFlatDictionary: is a abstract templated dictionary that maintains a
144// searchable set of SkFlataData objects of type T.
145//
146// NOTE: any class that wishes to be used in conjunction with SkFlatDictionary
147// must subclass the dictionary and provide the necessary flattening procs.
148// The end of this header contains dictionary subclasses for some common classes
149// like SkBitmap, SkMatrix, SkPaint, and SkRegion.
150//
151//
152///////////////////////////////////////////////////////////////////////////////
153
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154class SkFlatData {
155public:
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000156
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 static int Compare(const SkFlatData* a, const SkFlatData* b) {
reed@google.comb4ed0172012-07-10 13:29:52 +0000158 size_t bytes = a->bytesToCompare();
159 SkASSERT(SkIsAlign4(bytes));
reed@google.com142e1fe2012-07-09 17:44:44 +0000160
reed@google.comb4ed0172012-07-10 13:29:52 +0000161 const uint32_t* a_ptr = a->dataToCompare();
162 const uint32_t* b_ptr = b->dataToCompare();
163 const uint32_t* stop = a_ptr + bytes / sizeof(uint32_t);
junov@chromium.orgef760602012-06-27 20:03:16 +0000164 while(a_ptr < stop) {
165 if (*a_ptr != *b_ptr) {
166 return (*a_ptr < *b_ptr) ? -1 : 1;
167 }
168 a_ptr++;
169 b_ptr++;
170 }
171 return 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 }
173
174 int index() const { return fIndex; }
reed@google.comb4ed0172012-07-10 13:29:52 +0000175 const void* data() const { return (const char*)this + sizeof(*this); }
176 void* data() { return (char*)this + sizeof(*this); }
177 // Our data is always 32bit aligned, so we can offer this accessor
178 uint32_t* data32() { return (uint32_t*)this->data(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179
180#ifdef SK_DEBUG_SIZE
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000181 size_t size() const { return sizeof(SkFlatData) + fAllocSize; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182#endif
183
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000184 static SkFlatData* Create(SkChunkAlloc* heap, const void* obj, int index,
185 void (*flattenProc)(SkOrderedWriteBuffer&, const void*),
186 SkRefCntSet* refCntRecorder = NULL,
junov@chromium.org4866cc02012-06-01 21:23:07 +0000187 SkRefCntSet* faceRecorder = NULL,
188 uint32_t writeBufferflags = 0);
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000189 void unflatten(void* result,
190 void (*unflattenProc)(SkOrderedReadBuffer&, void*),
191 SkRefCntPlayback* refCntPlayback = NULL,
192 SkTypefacePlayback* facePlayback = NULL) const;
193
194private:
junov@chromium.orgef760602012-06-27 20:03:16 +0000195 // Data members add-up to 128 bits of storage, so data() is 128-bit
196 // aligned, which helps performance of memcpy in SkWriter32::flatten
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 int fIndex;
reed@google.comb4ed0172012-07-10 13:29:52 +0000198
199 // From here down is the data we look at in the search/sort. We always begin
200 // with the checksum and then length.
junov@chromium.orgef760602012-06-27 20:03:16 +0000201 uint32_t fChecksum;
reed@google.comb4ed0172012-07-10 13:29:52 +0000202 int32_t fAllocSize;
203 // uint32_t data[]
204
205 const uint32_t* dataToCompare() const { return &fChecksum; }
206 size_t bytesToCompare() const {
207 return sizeof(fChecksum) + sizeof(fAllocSize) + fAllocSize;
208 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209};
210
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000211template <class T>
212class SkFlatDictionary {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213public:
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000214 SkFlatDictionary(SkChunkAlloc* heap) {
215 fFlattenProc = NULL;
216 fUnflattenProc = NULL;
217 fHeap = heap;
218 // set to 1 since returning a zero from find() indicates failure
219 fNextIndex = 1;
220 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000222 int count() const { return fData.count(); }
223
224 const SkFlatData* operator[](int index) const {
225 SkASSERT(index >= 0 && index < fData.count());
226 return fData[index];
227 }
228
229 /**
230 * Clears the dictionary of all entries. However, it does NOT free the
231 * memory that was allocated for each entry.
232 */
233 void reset() { fData.reset(); fNextIndex = 1; }
234
235 /**
236 * Given an element of type T it returns its index in the dictionary. If
237 * the element wasn't previously in the dictionary it is automatically added
238 */
239 int find(const T* element, SkRefCntSet* refCntRecorder = NULL,
junov@chromium.org4866cc02012-06-01 21:23:07 +0000240 SkRefCntSet* faceRecorder = NULL, uint32_t writeBufferflags = 0) {
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000241 if (element == NULL)
242 return 0;
243 SkFlatData* flat = SkFlatData::Create(fHeap, element, fNextIndex,
junov@chromium.org4866cc02012-06-01 21:23:07 +0000244 fFlattenProc, refCntRecorder, faceRecorder, writeBufferflags);
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000245 int index = SkTSearch<SkFlatData>((const SkFlatData**) fData.begin(),
246 fData.count(), flat, sizeof(flat), &SkFlatData::Compare);
247 if (index >= 0) {
248 (void)fHeap->unalloc(flat);
249 return fData[index]->index();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250 }
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000251 index = ~index;
252 *fData.insert(index) = flat;
253 SkASSERT(fData.count() == fNextIndex);
254 return fNextIndex++;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 }
256
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000257 /**
258 * Given a pointer to a array of type T we allocate the array and fill it
259 * with the unflattened dictionary contents. The return value is the size of
260 * the allocated array.
261 */
262 int unflattenDictionary(T*& array, SkRefCntPlayback* refCntPlayback = NULL,
263 SkTypefacePlayback* facePlayback = NULL) const {
264 int elementCount = fData.count();
265 if (elementCount > 0) {
266 array = SkNEW_ARRAY(T, elementCount);
267 for (const SkFlatData** elementPtr = fData.begin();
268 elementPtr != fData.end(); elementPtr++) {
269 const SkFlatData* element = *elementPtr;
270 int index = element->index() - 1;
271 element->unflatten(&array[index], fUnflattenProc,
272 refCntPlayback, facePlayback);
273 }
274 }
275 return elementCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 }
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000277
278protected:
279 void (*fFlattenProc)(SkOrderedWriteBuffer&, const void*);
280 void (*fUnflattenProc)(SkOrderedReadBuffer&, void*);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281
282private:
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000283 SkChunkAlloc* fHeap;
284 int fNextIndex;
285 SkTDArray<const SkFlatData*> fData;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000286};
287
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000288///////////////////////////////////////////////////////////////////////////////
289// Some common dictionaries are defined here for both reference and convenience
290///////////////////////////////////////////////////////////////////////////////
291
292template <class T>
293static void SkFlattenObjectProc(SkOrderedWriteBuffer& buffer, const void* obj) {
294 ((T*)obj)->flatten(buffer);
295}
296
297template <class T>
298static void SkUnflattenObjectProc(SkOrderedReadBuffer& buffer, void* obj) {
299 ((T*)obj)->unflatten(buffer);
300}
301
302class SkBitmapDictionary : public SkFlatDictionary<SkBitmap> {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303public:
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000304 SkBitmapDictionary(SkChunkAlloc* heap) : SkFlatDictionary<SkBitmap>(heap) {
305 fFlattenProc = &SkFlattenObjectProc<SkBitmap>;
306 fUnflattenProc = &SkUnflattenObjectProc<SkBitmap>;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000307 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000308};
309
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000310class SkMatrixDictionary : public SkFlatDictionary<SkMatrix> {
311 public:
312 SkMatrixDictionary(SkChunkAlloc* heap) : SkFlatDictionary<SkMatrix>(heap) {
313 fFlattenProc = &flattenMatrix;
314 fUnflattenProc = &unflattenMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000317 static void flattenMatrix(SkOrderedWriteBuffer& buffer, const void* obj) {
318 buffer.getWriter32()->writeMatrix(*(SkMatrix*)obj);
319 }
320
321 static void unflattenMatrix(SkOrderedReadBuffer& buffer, void* obj) {
322 buffer.getReader32()->readMatrix((SkMatrix*)obj);
323 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324};
325
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000326class SkPaintDictionary : public SkFlatDictionary<SkPaint> {
327 public:
328 SkPaintDictionary(SkChunkAlloc* heap) : SkFlatDictionary<SkPaint>(heap) {
329 fFlattenProc = &SkFlattenObjectProc<SkPaint>;
330 fUnflattenProc = &SkUnflattenObjectProc<SkPaint>;
331 }
332};
333
334class SkRegionDictionary : public SkFlatDictionary<SkRegion> {
335 public:
336 SkRegionDictionary(SkChunkAlloc* heap) : SkFlatDictionary<SkRegion>(heap) {
337 fFlattenProc = &flattenRegion;
338 fUnflattenProc = &unflattenRegion;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 }
340
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000341 static void flattenRegion(SkOrderedWriteBuffer& buffer, const void* obj) {
342 buffer.getWriter32()->writeRegion(*(SkRegion*)obj);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000345 static void unflattenRegion(SkOrderedReadBuffer& buffer, void* obj) {
346 buffer.getReader32()->readRegion((SkRegion*)obj);
347 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348};
349
350#endif