|
1 /* |
|
2 * Copyright 2011 Google Inc. |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 |
|
8 #include "SkPictureRecord.h" |
|
9 #include "SkTSearch.h" |
|
10 #include "SkPixelRef.h" |
|
11 #include "SkRRect.h" |
|
12 #include "SkBBoxHierarchy.h" |
|
13 #include "SkDevice.h" |
|
14 #include "SkOffsetTable.h" |
|
15 #include "SkPictureStateTree.h" |
|
16 #include "SkSurface.h" |
|
17 |
|
18 #define HEAP_BLOCK_SIZE 4096 |
|
19 |
|
20 enum { |
|
21 // just need a value that save or getSaveCount would never return |
|
22 kNoInitialSave = -1, |
|
23 }; |
|
24 |
|
25 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc. |
|
26 static int const kUInt32Size = 4; |
|
27 |
|
28 static const uint32_t kSaveSize = 2 * kUInt32Size; |
|
29 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size; |
|
30 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect); |
|
31 |
|
32 SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags) |
|
33 : INHERITED(dimensions.width(), dimensions.height()) |
|
34 , fBoundingHierarchy(NULL) |
|
35 , fStateTree(NULL) |
|
36 , fFlattenableHeap(HEAP_BLOCK_SIZE) |
|
37 , fPaints(&fFlattenableHeap) |
|
38 , fRecordFlags(flags) |
|
39 , fOptsEnabled(true) { |
|
40 #ifdef SK_DEBUG_SIZE |
|
41 fPointBytes = fRectBytes = fTextBytes = 0; |
|
42 fPointWrites = fRectWrites = fTextWrites = 0; |
|
43 #endif |
|
44 |
|
45 fBitmapHeap = SkNEW(SkBitmapHeap); |
|
46 fFlattenableHeap.setBitmapStorage(fBitmapHeap); |
|
47 fPathHeap = NULL; // lazy allocate |
|
48 |
|
49 #ifndef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
50 fFirstSavedLayerIndex = kNoSavedLayerIndex; |
|
51 #endif |
|
52 |
|
53 fInitialSaveCount = kNoInitialSave; |
|
54 |
|
55 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
56 fMCMgr.init(this); |
|
57 #endif |
|
58 } |
|
59 |
|
60 SkPictureRecord::~SkPictureRecord() { |
|
61 SkSafeUnref(fBitmapHeap); |
|
62 SkSafeUnref(fPathHeap); |
|
63 SkSafeUnref(fBoundingHierarchy); |
|
64 SkSafeUnref(fStateTree); |
|
65 fFlattenableHeap.setBitmapStorage(NULL); |
|
66 fPictureRefs.unrefAll(); |
|
67 } |
|
68 |
|
69 /////////////////////////////////////////////////////////////////////////////// |
|
70 |
|
71 // Return the offset of the paint inside a given op's byte stream. A zero |
|
72 // return value means there is no paint (and you really shouldn't be calling |
|
73 // this method) |
|
74 static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) { |
|
75 // These offsets are where the paint would be if the op size doesn't overflow |
|
76 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = { |
|
77 0, // UNUSED - no paint |
|
78 0, // CLIP_PATH - no paint |
|
79 0, // CLIP_REGION - no paint |
|
80 0, // CLIP_RECT - no paint |
|
81 0, // CLIP_RRECT - no paint |
|
82 0, // CONCAT - no paint |
|
83 1, // DRAW_BITMAP - right after op code |
|
84 1, // DRAW_BITMAP_MATRIX - right after op code |
|
85 1, // DRAW_BITMAP_NINE - right after op code |
|
86 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code |
|
87 0, // DRAW_CLEAR - no paint |
|
88 0, // DRAW_DATA - no paint |
|
89 1, // DRAW_OVAL - right after op code |
|
90 1, // DRAW_PAINT - right after op code |
|
91 1, // DRAW_PATH - right after op code |
|
92 0, // DRAW_PICTURE - no paint |
|
93 1, // DRAW_POINTS - right after op code |
|
94 1, // DRAW_POS_TEXT - right after op code |
|
95 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code |
|
96 1, // DRAW_POS_TEXT_H - right after op code |
|
97 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code |
|
98 1, // DRAW_RECT - right after op code |
|
99 1, // DRAW_RRECT - right after op code |
|
100 1, // DRAW_SPRITE - right after op code |
|
101 1, // DRAW_TEXT - right after op code |
|
102 1, // DRAW_TEXT_ON_PATH - right after op code |
|
103 1, // DRAW_TEXT_TOP_BOTTOM - right after op code |
|
104 1, // DRAW_VERTICES - right after op code |
|
105 0, // RESTORE - no paint |
|
106 0, // ROTATE - no paint |
|
107 0, // SAVE - no paint |
|
108 0, // SAVE_LAYER - see below - this paint's location varies |
|
109 0, // SCALE - no paint |
|
110 0, // SET_MATRIX - no paint |
|
111 0, // SKEW - no paint |
|
112 0, // TRANSLATE - no paint |
|
113 0, // NOOP - no paint |
|
114 0, // BEGIN_GROUP - no paint |
|
115 0, // COMMENT - no paint |
|
116 0, // END_GROUP - no paint |
|
117 1, // DRAWDRRECT - right after op code |
|
118 0, // PUSH_CULL - no paint |
|
119 0, // POP_CULL - no paint |
|
120 }; |
|
121 |
|
122 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1, |
|
123 need_to_be_in_sync); |
|
124 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM); |
|
125 |
|
126 int overflow = 0; |
|
127 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) { |
|
128 // This op's size overflows so an extra uint32_t will be written |
|
129 // after the op code |
|
130 overflow = sizeof(uint32_t); |
|
131 } |
|
132 |
|
133 if (SAVE_LAYER == op) { |
|
134 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size; |
|
135 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect); |
|
136 |
|
137 if (kSaveLayerNoBoundsSize == opSize) { |
|
138 return kSaveLayerNoBoundsPaintOffset + overflow; |
|
139 } else { |
|
140 SkASSERT(kSaveLayerWithBoundsSize == opSize); |
|
141 return kSaveLayerWithBoundsPaintOffset + overflow; |
|
142 } |
|
143 } |
|
144 |
|
145 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method |
|
146 return gPaintOffsets[op] * sizeof(uint32_t) + overflow; |
|
147 } |
|
148 |
|
149 void SkPictureRecord::willSave(SaveFlags flags) { |
|
150 |
|
151 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
152 fMCMgr.save(flags); |
|
153 #else |
|
154 // record the offset to us, making it non-positive to distinguish a save |
|
155 // from a clip entry. |
|
156 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten()); |
|
157 this->recordSave(flags); |
|
158 #endif |
|
159 |
|
160 this->INHERITED::willSave(flags); |
|
161 } |
|
162 |
|
163 void SkPictureRecord::recordSave(SaveFlags flags) { |
|
164 // op + flags |
|
165 uint32_t size = kSaveSize; |
|
166 size_t initialOffset = this->addDraw(SAVE, &size); |
|
167 this->addInt(flags); |
|
168 |
|
169 this->validate(initialOffset, size); |
|
170 } |
|
171 |
|
172 SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds, |
|
173 const SkPaint* paint, SaveFlags flags) { |
|
174 |
|
175 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
176 fMCMgr.saveLayer(bounds, paint, flags); |
|
177 #else |
|
178 // record the offset to us, making it non-positive to distinguish a save |
|
179 // from a clip entry. |
|
180 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten()); |
|
181 this->recordSaveLayer(bounds, paint, flags); |
|
182 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) { |
|
183 fFirstSavedLayerIndex = fRestoreOffsetStack.count(); |
|
184 } |
|
185 #endif |
|
186 |
|
187 this->INHERITED::willSaveLayer(bounds, paint, flags); |
|
188 /* No need for a (potentially very big) layer which we don't actually need |
|
189 at this time (and may not be able to afford since during record our |
|
190 clip starts out the size of the picture, which is often much larger |
|
191 than the size of the actual device we'll use during playback). |
|
192 */ |
|
193 return kNoLayer_SaveLayerStrategy; |
|
194 } |
|
195 |
|
196 void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint, |
|
197 SaveFlags flags) { |
|
198 // op + bool for 'bounds' |
|
199 uint32_t size = 2 * kUInt32Size; |
|
200 if (NULL != bounds) { |
|
201 size += sizeof(*bounds); // + rect |
|
202 } |
|
203 // + paint index + flags |
|
204 size += 2 * kUInt32Size; |
|
205 |
|
206 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size); |
|
207 |
|
208 size_t initialOffset = this->addDraw(SAVE_LAYER, &size); |
|
209 this->addRectPtr(bounds); |
|
210 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten()); |
|
211 this->addPaintPtr(paint); |
|
212 this->addInt(flags); |
|
213 |
|
214 this->validate(initialOffset, size); |
|
215 } |
|
216 |
|
217 bool SkPictureRecord::isDrawingToLayer() const { |
|
218 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
219 return fMCMgr.isDrawingToLayer(); |
|
220 #else |
|
221 return fFirstSavedLayerIndex != kNoSavedLayerIndex; |
|
222 #endif |
|
223 } |
|
224 |
|
225 /* |
|
226 * Read the op code from 'offset' in 'writer'. |
|
227 */ |
|
228 #ifdef SK_DEBUG |
|
229 static DrawType peek_op(SkWriter32* writer, int32_t offset) { |
|
230 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24); |
|
231 } |
|
232 #endif |
|
233 |
|
234 /* |
|
235 * Read the op code from 'offset' in 'writer' and extract the size too. |
|
236 */ |
|
237 static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) { |
|
238 uint32_t peek = writer->readTAt<uint32_t>(offset); |
|
239 |
|
240 uint32_t op; |
|
241 UNPACK_8_24(peek, op, *size); |
|
242 if (MASK_24 == *size) { |
|
243 // size required its own slot right after the op code |
|
244 *size = writer->readTAt<uint32_t>(offset + kUInt32Size); |
|
245 } |
|
246 return (DrawType) op; |
|
247 } |
|
248 |
|
249 #ifdef TRACK_COLLAPSE_STATS |
|
250 static int gCollapseCount, gCollapseCalls; |
|
251 #endif |
|
252 |
|
253 // Is the supplied paint simply a color? |
|
254 static bool is_simple(const SkPaint& p) { |
|
255 intptr_t orAccum = (intptr_t)p.getPathEffect() | |
|
256 (intptr_t)p.getShader() | |
|
257 (intptr_t)p.getXfermode() | |
|
258 (intptr_t)p.getMaskFilter() | |
|
259 (intptr_t)p.getColorFilter() | |
|
260 (intptr_t)p.getRasterizer() | |
|
261 (intptr_t)p.getLooper() | |
|
262 (intptr_t)p.getImageFilter(); |
|
263 return 0 == orAccum; |
|
264 } |
|
265 |
|
266 // CommandInfos are fed to the 'match' method and filled in with command |
|
267 // information. |
|
268 struct CommandInfo { |
|
269 DrawType fActualOp; |
|
270 uint32_t fOffset; |
|
271 uint32_t fSize; |
|
272 }; |
|
273 |
|
274 /* |
|
275 * Attempt to match the provided pattern of commands starting at 'offset' |
|
276 * in the byte stream and stopping at the end of the stream. Upon success, |
|
277 * return true with all the pattern information filled out in the result |
|
278 * array (i.e., actual ops, offsets and sizes). |
|
279 * Note this method skips any NOOPs seen in the stream |
|
280 */ |
|
281 static bool match(SkWriter32* writer, uint32_t offset, |
|
282 int* pattern, CommandInfo* result, int numCommands) { |
|
283 SkASSERT(offset < writer->bytesWritten()); |
|
284 |
|
285 uint32_t curOffset = offset; |
|
286 uint32_t curSize = 0; |
|
287 int numMatched; |
|
288 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) { |
|
289 DrawType op = peek_op_and_size(writer, curOffset, &curSize); |
|
290 while (NOOP == op && curOffset < writer->bytesWritten()) { |
|
291 curOffset += curSize; |
|
292 op = peek_op_and_size(writer, curOffset, &curSize); |
|
293 } |
|
294 |
|
295 if (curOffset >= writer->bytesWritten()) { |
|
296 return false; // ran out of byte stream |
|
297 } |
|
298 |
|
299 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) { |
|
300 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op && |
|
301 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) { |
|
302 return false; |
|
303 } |
|
304 } else if (op != pattern[numMatched]) { |
|
305 return false; |
|
306 } |
|
307 |
|
308 result[numMatched].fActualOp = op; |
|
309 result[numMatched].fOffset = curOffset; |
|
310 result[numMatched].fSize = curSize; |
|
311 |
|
312 curOffset += curSize; |
|
313 } |
|
314 |
|
315 if (numMatched != numCommands) { |
|
316 return false; |
|
317 } |
|
318 |
|
319 curOffset += curSize; |
|
320 if (curOffset < writer->bytesWritten()) { |
|
321 // Something else between the last command and the end of the stream |
|
322 return false; |
|
323 } |
|
324 |
|
325 return true; |
|
326 } |
|
327 |
|
328 // temporarily here to make code review easier |
|
329 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer, |
|
330 SkPaintDictionary* paintDict, |
|
331 const CommandInfo& saveLayerInfo, |
|
332 const CommandInfo& dbmInfo); |
|
333 |
|
334 /* |
|
335 * Restore has just been called (but not recorded), look back at the |
|
336 * matching save* and see if we are in the configuration: |
|
337 * SAVE_LAYER |
|
338 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT |
|
339 * RESTORE |
|
340 * where the saveLayer's color can be moved into the drawBitmap*'s paint |
|
341 */ |
|
342 static bool remove_save_layer1(SkWriter32* writer, int32_t offset, |
|
343 SkPaintDictionary* paintDict) { |
|
344 // back up to the save block |
|
345 // TODO: add a stack to track save*/restore offsets rather than searching backwards |
|
346 while (offset > 0) { |
|
347 offset = writer->readTAt<uint32_t>(offset); |
|
348 } |
|
349 |
|
350 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ }; |
|
351 CommandInfo result[SK_ARRAY_COUNT(pattern)]; |
|
352 |
|
353 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) { |
|
354 return false; |
|
355 } |
|
356 |
|
357 if (kSaveLayerWithBoundsSize == result[0].fSize) { |
|
358 // The saveLayer's bound can offset where the dbm is drawn |
|
359 return false; |
|
360 } |
|
361 |
|
362 return merge_savelayer_paint_into_drawbitmp(writer, paintDict, |
|
363 result[0], result[1]); |
|
364 } |
|
365 |
|
366 /* |
|
367 * Convert the command code located at 'offset' to a NOOP. Leave the size |
|
368 * field alone so the NOOP can be skipped later. |
|
369 */ |
|
370 static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) { |
|
371 uint32_t command = writer->readTAt<uint32_t>(offset); |
|
372 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24)); |
|
373 } |
|
374 |
|
375 /* |
|
376 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint. |
|
377 * Return true on success; false otherwise. |
|
378 */ |
|
379 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer, |
|
380 SkPaintDictionary* paintDict, |
|
381 const CommandInfo& saveLayerInfo, |
|
382 const CommandInfo& dbmInfo) { |
|
383 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp); |
|
384 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp || |
|
385 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp || |
|
386 DRAW_BITMAP_NINE == dbmInfo.fActualOp || |
|
387 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp); |
|
388 |
|
389 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize); |
|
390 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize); |
|
391 |
|
392 // we have a match, now we need to get the paints involved |
|
393 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset); |
|
394 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset); |
|
395 |
|
396 if (0 == saveLayerPaintId) { |
|
397 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer |
|
398 // and signal the caller (by returning true) to not add the RESTORE op |
|
399 convert_command_to_noop(writer, saveLayerInfo.fOffset); |
|
400 return true; |
|
401 } |
|
402 |
|
403 if (0 == dbmPaintId) { |
|
404 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer |
|
405 // and signal the caller (by returning true) to not add the RESTORE op |
|
406 convert_command_to_noop(writer, saveLayerInfo.fOffset); |
|
407 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId); |
|
408 return true; |
|
409 } |
|
410 |
|
411 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId)); |
|
412 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) { |
|
413 return false; |
|
414 } |
|
415 |
|
416 // For this optimization we only fold the saveLayer and drawBitmapRect |
|
417 // together if the saveLayer's draw is simple (i.e., no fancy effects) and |
|
418 // and the only difference in the colors is that the saveLayer's can have |
|
419 // an alpha while the drawBitmapRect's is opaque. |
|
420 // TODO: it should be possible to fold them together even if they both |
|
421 // have different non-255 alphas |
|
422 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque |
|
423 |
|
424 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId)); |
|
425 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) { |
|
426 return false; |
|
427 } |
|
428 |
|
429 SkColor newColor = SkColorSetA(dbmPaint->getColor(), |
|
430 SkColorGetA(saveLayerPaint->getColor())); |
|
431 dbmPaint->setColor(newColor); |
|
432 |
|
433 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint); |
|
434 if (NULL == data) { |
|
435 return false; |
|
436 } |
|
437 |
|
438 // kill the saveLayer and alter the DBMR2R's paint to be the modified one |
|
439 convert_command_to_noop(writer, saveLayerInfo.fOffset); |
|
440 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index()); |
|
441 return true; |
|
442 } |
|
443 |
|
444 /* |
|
445 * Restore has just been called (but not recorded), look back at the |
|
446 * matching save* and see if we are in the configuration: |
|
447 * SAVE_LAYER (with NULL == bounds) |
|
448 * SAVE |
|
449 * CLIP_RECT |
|
450 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT |
|
451 * RESTORE |
|
452 * RESTORE |
|
453 * where the saveLayer's color can be moved into the drawBitmap*'s paint |
|
454 */ |
|
455 static bool remove_save_layer2(SkWriter32* writer, int32_t offset, |
|
456 SkPaintDictionary* paintDict) { |
|
457 |
|
458 // back up to the save block |
|
459 // TODO: add a stack to track save*/restore offsets rather than searching backwards |
|
460 while (offset > 0) { |
|
461 offset = writer->readTAt<uint32_t>(offset); |
|
462 } |
|
463 |
|
464 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ }; |
|
465 CommandInfo result[SK_ARRAY_COUNT(pattern)]; |
|
466 |
|
467 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) { |
|
468 return false; |
|
469 } |
|
470 |
|
471 if (kSaveLayerWithBoundsSize == result[0].fSize) { |
|
472 // The saveLayer's bound can offset where the dbm is drawn |
|
473 return false; |
|
474 } |
|
475 |
|
476 return merge_savelayer_paint_into_drawbitmp(writer, paintDict, |
|
477 result[0], result[3]); |
|
478 } |
|
479 |
|
480 static bool is_drawing_op(DrawType op) { |
|
481 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op; |
|
482 } |
|
483 |
|
484 /* |
|
485 * Restore has just been called (but not recorded), so look back at the |
|
486 * matching save(), and see if we can eliminate the pair of them, due to no |
|
487 * intervening matrix/clip calls. |
|
488 * |
|
489 * If so, update the writer and return true, in which case we won't even record |
|
490 * the restore() call. If we still need the restore(), return false. |
|
491 */ |
|
492 static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset, |
|
493 SkPaintDictionary* paintDict) { |
|
494 #ifdef TRACK_COLLAPSE_STATS |
|
495 gCollapseCalls += 1; |
|
496 #endif |
|
497 |
|
498 int32_t restoreOffset = (int32_t)writer->bytesWritten(); |
|
499 |
|
500 // back up to the save block |
|
501 while (offset > 0) { |
|
502 offset = writer->readTAt<uint32_t>(offset); |
|
503 } |
|
504 |
|
505 // now offset points to a save |
|
506 offset = -offset; |
|
507 uint32_t opSize; |
|
508 DrawType op = peek_op_and_size(writer, offset, &opSize); |
|
509 if (SAVE_LAYER == op) { |
|
510 // not ready to cull these out yet (mrr) |
|
511 return false; |
|
512 } |
|
513 SkASSERT(SAVE == op); |
|
514 SkASSERT(kSaveSize == opSize); |
|
515 |
|
516 // get the save flag (last 4-bytes of the space allocated for the opSize) |
|
517 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4); |
|
518 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) { |
|
519 // This function's optimization is only correct for kMatrixClip style saves. |
|
520 // TODO: set checkMatrix & checkClip booleans here and then check for the |
|
521 // offending operations in the following loop. |
|
522 return false; |
|
523 } |
|
524 |
|
525 // Walk forward until we get back to either a draw-verb (abort) or we hit |
|
526 // our restore (success). |
|
527 int32_t saveOffset = offset; |
|
528 |
|
529 offset += opSize; |
|
530 while (offset < restoreOffset) { |
|
531 op = peek_op_and_size(writer, offset, &opSize); |
|
532 if (is_drawing_op(op) || (SAVE_LAYER == op)) { |
|
533 // drawing verb, abort |
|
534 return false; |
|
535 } |
|
536 offset += opSize; |
|
537 } |
|
538 |
|
539 #ifdef TRACK_COLLAPSE_STATS |
|
540 gCollapseCount += 1; |
|
541 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls, |
|
542 (double)gCollapseCount / gCollapseCalls, "%"); |
|
543 #endif |
|
544 |
|
545 writer->rewindToOffset(saveOffset); |
|
546 return true; |
|
547 } |
|
548 |
|
549 typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset, |
|
550 SkPaintDictionary* paintDict); |
|
551 enum PictureRecordOptType { |
|
552 kRewind_OptType, // Optimization rewinds the command stream |
|
553 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair |
|
554 }; |
|
555 |
|
556 enum PictureRecordOptFlags { |
|
557 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the |
|
558 // SkPicture has a bounding box hierarchy. |
|
559 }; |
|
560 |
|
561 struct PictureRecordOpt { |
|
562 PictureRecordOptProc fProc; |
|
563 PictureRecordOptType fType; |
|
564 unsigned fFlags; |
|
565 }; |
|
566 /* |
|
567 * A list of the optimizations that are tried upon seeing a restore |
|
568 * TODO: add a real API for such optimizations |
|
569 * Add the ability to fire optimizations on any op (not just RESTORE) |
|
570 */ |
|
571 static const PictureRecordOpt gPictureRecordOpts[] = { |
|
572 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy |
|
573 // because it is redundant with the state traversal optimization in |
|
574 // SkPictureStateTree, and applying the optimization introduces significant |
|
575 // record time overhead because it requires rewinding contents that were |
|
576 // recorded into the BBoxHierarchy. |
|
577 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag }, |
|
578 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 }, |
|
579 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 } |
|
580 }; |
|
581 |
|
582 // This is called after an optimization has been applied to the command stream |
|
583 // in order to adjust the contents and state of the bounding box hierarchy and |
|
584 // state tree to reflect the optimization. |
|
585 static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree, |
|
586 SkBBoxHierarchy* boundingHierarchy) { |
|
587 switch (opt) { |
|
588 case kCollapseSaveLayer_OptType: |
|
589 if (NULL != stateTree) { |
|
590 stateTree->saveCollapsed(); |
|
591 } |
|
592 break; |
|
593 case kRewind_OptType: |
|
594 if (NULL != boundingHierarchy) { |
|
595 boundingHierarchy->rewindInserts(); |
|
596 } |
|
597 // Note: No need to touch the state tree for this to work correctly. |
|
598 // Unused branches do not burden the playback, and pruning the tree |
|
599 // would be O(N^2), so it is best to leave it alone. |
|
600 break; |
|
601 default: |
|
602 SkASSERT(0); |
|
603 } |
|
604 } |
|
605 |
|
606 void SkPictureRecord::willRestore() { |
|
607 // FIXME: SkDeferredCanvas needs to be refactored to respect |
|
608 // save/restore balancing so that the following test can be |
|
609 // turned on permanently. |
|
610 #if 0 |
|
611 SkASSERT(fRestoreOffsetStack.count() > 1); |
|
612 #endif |
|
613 |
|
614 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
615 if (fMCMgr.getSaveCount() == 1) { |
|
616 return; |
|
617 } |
|
618 |
|
619 fMCMgr.restore(); |
|
620 #else |
|
621 // check for underflow |
|
622 if (fRestoreOffsetStack.count() == 0) { |
|
623 return; |
|
624 } |
|
625 |
|
626 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) { |
|
627 fFirstSavedLayerIndex = kNoSavedLayerIndex; |
|
628 } |
|
629 |
|
630 size_t opt = 0; |
|
631 if (fOptsEnabled) { |
|
632 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) { |
|
633 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag) |
|
634 && NULL != fBoundingHierarchy) { |
|
635 continue; |
|
636 } |
|
637 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) { |
|
638 // Some optimization fired so don't add the RESTORE |
|
639 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType, |
|
640 fStateTree, fBoundingHierarchy); |
|
641 break; |
|
642 } |
|
643 } |
|
644 } |
|
645 |
|
646 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) { |
|
647 // No optimization fired so add the RESTORE |
|
648 this->recordRestore(); |
|
649 } |
|
650 |
|
651 fRestoreOffsetStack.pop(); |
|
652 #endif |
|
653 |
|
654 this->INHERITED::willRestore(); |
|
655 } |
|
656 |
|
657 void SkPictureRecord::recordRestore(bool fillInSkips) { |
|
658 uint32_t initialOffset, size; |
|
659 if (fillInSkips) { |
|
660 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten()); |
|
661 } |
|
662 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code |
|
663 initialOffset = this->addDraw(RESTORE, &size); |
|
664 this->validate(initialOffset, size); |
|
665 } |
|
666 |
|
667 void SkPictureRecord::didTranslate(SkScalar dx, SkScalar dy) { |
|
668 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
669 fMCMgr.translate(dx, dy); |
|
670 #else |
|
671 // op + dx + dy |
|
672 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); |
|
673 size_t initialOffset = this->addDraw(TRANSLATE, &size); |
|
674 this->addScalar(dx); |
|
675 this->addScalar(dy); |
|
676 this->validate(initialOffset, size); |
|
677 #endif |
|
678 this->INHERITED::didTranslate(dx, dy); |
|
679 } |
|
680 |
|
681 void SkPictureRecord::didScale(SkScalar sx, SkScalar sy) { |
|
682 |
|
683 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
684 fMCMgr.scale(sx, sy); |
|
685 #else |
|
686 // op + sx + sy |
|
687 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); |
|
688 size_t initialOffset = this->addDraw(SCALE, &size); |
|
689 this->addScalar(sx); |
|
690 this->addScalar(sy); |
|
691 this->validate(initialOffset, size); |
|
692 #endif |
|
693 this->INHERITED::didScale(sx, sy); |
|
694 } |
|
695 |
|
696 void SkPictureRecord::didRotate(SkScalar degrees) { |
|
697 |
|
698 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
699 fMCMgr.rotate(degrees); |
|
700 #else |
|
701 // op + degrees |
|
702 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar); |
|
703 size_t initialOffset = this->addDraw(ROTATE, &size); |
|
704 this->addScalar(degrees); |
|
705 this->validate(initialOffset, size); |
|
706 #endif |
|
707 this->INHERITED::didRotate(degrees); |
|
708 } |
|
709 |
|
710 void SkPictureRecord::didSkew(SkScalar sx, SkScalar sy) { |
|
711 |
|
712 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
713 fMCMgr.skew(sx, sy); |
|
714 #else |
|
715 // op + sx + sy |
|
716 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); |
|
717 size_t initialOffset = this->addDraw(SKEW, &size); |
|
718 this->addScalar(sx); |
|
719 this->addScalar(sy); |
|
720 this->validate(initialOffset, size); |
|
721 #endif |
|
722 this->INHERITED::didSkew(sx, sy); |
|
723 } |
|
724 |
|
725 void SkPictureRecord::didConcat(const SkMatrix& matrix) { |
|
726 |
|
727 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
728 fMCMgr.concat(matrix); |
|
729 #else |
|
730 this->recordConcat(matrix); |
|
731 #endif |
|
732 this->INHERITED::didConcat(matrix); |
|
733 } |
|
734 |
|
735 void SkPictureRecord::recordConcat(const SkMatrix& matrix) { |
|
736 this->validate(fWriter.bytesWritten(), 0); |
|
737 // op + matrix |
|
738 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL); |
|
739 size_t initialOffset = this->addDraw(CONCAT, &size); |
|
740 this->addMatrix(matrix); |
|
741 this->validate(initialOffset, size); |
|
742 } |
|
743 |
|
744 void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) { |
|
745 |
|
746 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
747 fMCMgr.setMatrix(matrix); |
|
748 #else |
|
749 this->validate(fWriter.bytesWritten(), 0); |
|
750 // op + matrix |
|
751 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL); |
|
752 size_t initialOffset = this->addDraw(SET_MATRIX, &size); |
|
753 this->addMatrix(matrix); |
|
754 this->validate(initialOffset, size); |
|
755 #endif |
|
756 this->INHERITED::didSetMatrix(matrix); |
|
757 } |
|
758 |
|
759 static bool regionOpExpands(SkRegion::Op op) { |
|
760 switch (op) { |
|
761 case SkRegion::kUnion_Op: |
|
762 case SkRegion::kXOR_Op: |
|
763 case SkRegion::kReverseDifference_Op: |
|
764 case SkRegion::kReplace_Op: |
|
765 return true; |
|
766 case SkRegion::kIntersect_Op: |
|
767 case SkRegion::kDifference_Op: |
|
768 return false; |
|
769 default: |
|
770 SkDEBUGFAIL("unknown region op"); |
|
771 return false; |
|
772 } |
|
773 } |
|
774 |
|
775 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
776 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) { |
|
777 fMCMgr.fillInSkips(&fWriter, restoreOffset); |
|
778 } |
|
779 #else |
|
780 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) { |
|
781 int32_t offset = fRestoreOffsetStack.top(); |
|
782 while (offset > 0) { |
|
783 uint32_t peek = fWriter.readTAt<uint32_t>(offset); |
|
784 fWriter.overwriteTAt(offset, restoreOffset); |
|
785 offset = peek; |
|
786 } |
|
787 |
|
788 #ifdef SK_DEBUG |
|
789 // assert that the final offset value points to a save verb |
|
790 uint32_t opSize; |
|
791 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize); |
|
792 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp); |
|
793 #endif |
|
794 } |
|
795 #endif |
|
796 |
|
797 void SkPictureRecord::beginRecording() { |
|
798 // we have to call this *after* our constructor, to ensure that it gets |
|
799 // recorded. This is balanced by restoreToCount() call from endRecording, |
|
800 // which in-turn calls our overridden restore(), so those get recorded too. |
|
801 fInitialSaveCount = this->save(kMatrixClip_SaveFlag); |
|
802 } |
|
803 |
|
804 void SkPictureRecord::endRecording() { |
|
805 SkASSERT(kNoInitialSave != fInitialSaveCount); |
|
806 this->restoreToCount(fInitialSaveCount); |
|
807 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
808 fMCMgr.finish(); |
|
809 #endif |
|
810 } |
|
811 |
|
812 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
813 int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) { |
|
814 size_t offset = fWriter.bytesWritten(); |
|
815 this->addInt(-1); |
|
816 return offset; |
|
817 } |
|
818 #else |
|
819 int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) { |
|
820 if (fRestoreOffsetStack.isEmpty()) { |
|
821 return -1; |
|
822 } |
|
823 |
|
824 // The RestoreOffset field is initially filled with a placeholder |
|
825 // value that points to the offset of the previous RestoreOffset |
|
826 // in the current stack level, thus forming a linked list so that |
|
827 // the restore offsets can be filled in when the corresponding |
|
828 // restore command is recorded. |
|
829 int32_t prevOffset = fRestoreOffsetStack.top(); |
|
830 |
|
831 if (regionOpExpands(op)) { |
|
832 // Run back through any previous clip ops, and mark their offset to |
|
833 // be 0, disabling their ability to trigger a jump-to-restore, otherwise |
|
834 // they could hide this clips ability to expand the clip (i.e. go from |
|
835 // empty to non-empty). |
|
836 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0); |
|
837 |
|
838 // Reset the pointer back to the previous clip so that subsequent |
|
839 // restores don't overwrite the offsets we just cleared. |
|
840 prevOffset = 0; |
|
841 } |
|
842 |
|
843 size_t offset = fWriter.bytesWritten(); |
|
844 this->addInt(prevOffset); |
|
845 fRestoreOffsetStack.top() = offset; |
|
846 return offset; |
|
847 } |
|
848 #endif |
|
849 |
|
850 void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { |
|
851 |
|
852 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
853 fMCMgr.clipRect(rect, op, doAA); |
|
854 #else |
|
855 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle); |
|
856 #endif |
|
857 this->INHERITED::onClipRect(rect, op, edgeStyle); |
|
858 } |
|
859 |
|
860 int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
|
861 // id + rect + clip params |
|
862 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size; |
|
863 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
864 size += kUInt32Size; // + restore offset |
|
865 #else |
|
866 // recordRestoreOffsetPlaceholder doesn't always write an offset |
|
867 if (!fRestoreOffsetStack.isEmpty()) { |
|
868 // + restore offset |
|
869 size += kUInt32Size; |
|
870 } |
|
871 #endif |
|
872 size_t initialOffset = this->addDraw(CLIP_RECT, &size); |
|
873 this->addRect(rect); |
|
874 this->addInt(ClipParams_pack(op, doAA)); |
|
875 int offset = this->recordRestoreOffsetPlaceholder(op); |
|
876 |
|
877 this->validate(initialOffset, size); |
|
878 return offset; |
|
879 } |
|
880 |
|
881 void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { |
|
882 |
|
883 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
884 fMCMgr.clipRRect(rrect, op, doAA); |
|
885 #else |
|
886 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle); |
|
887 #endif |
|
888 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { |
|
889 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false); |
|
890 } else { |
|
891 this->INHERITED::onClipRRect(rrect, op, edgeStyle); |
|
892 } |
|
893 } |
|
894 |
|
895 int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { |
|
896 // op + rrect + clip params |
|
897 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size; |
|
898 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
899 size += kUInt32Size; // + restore offset |
|
900 #else |
|
901 // recordRestoreOffsetPlaceholder doesn't always write an offset |
|
902 if (!fRestoreOffsetStack.isEmpty()) { |
|
903 // + restore offset |
|
904 size += kUInt32Size; |
|
905 } |
|
906 #endif |
|
907 size_t initialOffset = this->addDraw(CLIP_RRECT, &size); |
|
908 this->addRRect(rrect); |
|
909 this->addInt(ClipParams_pack(op, doAA)); |
|
910 int offset = recordRestoreOffsetPlaceholder(op); |
|
911 this->validate(initialOffset, size); |
|
912 return offset; |
|
913 } |
|
914 |
|
915 void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { |
|
916 |
|
917 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
918 fMCMgr.clipPath(path, op, doAA); |
|
919 #else |
|
920 int pathID = this->addPathToHeap(path); |
|
921 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle); |
|
922 #endif |
|
923 |
|
924 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { |
|
925 this->updateClipConservativelyUsingBounds(path.getBounds(), op, |
|
926 path.isInverseFillType()); |
|
927 } else { |
|
928 this->INHERITED::onClipPath(path, op, edgeStyle); |
|
929 } |
|
930 } |
|
931 |
|
932 int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) { |
|
933 // op + path index + clip params |
|
934 uint32_t size = 3 * kUInt32Size; |
|
935 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
936 size += kUInt32Size; // + restore offset |
|
937 #else |
|
938 // recordRestoreOffsetPlaceholder doesn't always write an offset |
|
939 if (!fRestoreOffsetStack.isEmpty()) { |
|
940 // + restore offset |
|
941 size += kUInt32Size; |
|
942 } |
|
943 #endif |
|
944 size_t initialOffset = this->addDraw(CLIP_PATH, &size); |
|
945 this->addInt(pathID); |
|
946 this->addInt(ClipParams_pack(op, doAA)); |
|
947 int offset = recordRestoreOffsetPlaceholder(op); |
|
948 this->validate(initialOffset, size); |
|
949 return offset; |
|
950 } |
|
951 |
|
952 void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) { |
|
953 |
|
954 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
955 fMCMgr.clipRegion(region, op); |
|
956 #else |
|
957 this->recordClipRegion(region, op); |
|
958 #endif |
|
959 this->INHERITED::onClipRegion(region, op); |
|
960 } |
|
961 |
|
962 int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) { |
|
963 // op + clip params + region |
|
964 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL); |
|
965 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
966 size += kUInt32Size; // + restore offset |
|
967 #else |
|
968 // recordRestoreOffsetPlaceholder doesn't always write an offset |
|
969 if (!fRestoreOffsetStack.isEmpty()) { |
|
970 // + restore offset |
|
971 size += kUInt32Size; |
|
972 } |
|
973 #endif |
|
974 size_t initialOffset = this->addDraw(CLIP_REGION, &size); |
|
975 this->addRegion(region); |
|
976 this->addInt(ClipParams_pack(op, false)); |
|
977 int offset = this->recordRestoreOffsetPlaceholder(op); |
|
978 |
|
979 this->validate(initialOffset, size); |
|
980 return offset; |
|
981 } |
|
982 |
|
983 void SkPictureRecord::clear(SkColor color) { |
|
984 |
|
985 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
986 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
987 #endif |
|
988 |
|
989 // op + color |
|
990 uint32_t size = 2 * kUInt32Size; |
|
991 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size); |
|
992 this->addInt(color); |
|
993 this->validate(initialOffset, size); |
|
994 } |
|
995 |
|
996 void SkPictureRecord::drawPaint(const SkPaint& paint) { |
|
997 |
|
998 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
999 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1000 #endif |
|
1001 |
|
1002 // op + paint index |
|
1003 uint32_t size = 2 * kUInt32Size; |
|
1004 size_t initialOffset = this->addDraw(DRAW_PAINT, &size); |
|
1005 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten()); |
|
1006 this->addPaint(paint); |
|
1007 this->validate(initialOffset, size); |
|
1008 } |
|
1009 |
|
1010 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[], |
|
1011 const SkPaint& paint) { |
|
1012 |
|
1013 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1014 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1015 #endif |
|
1016 |
|
1017 // op + paint index + mode + count + point data |
|
1018 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint); |
|
1019 size_t initialOffset = this->addDraw(DRAW_POINTS, &size); |
|
1020 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten()); |
|
1021 this->addPaint(paint); |
|
1022 this->addInt(mode); |
|
1023 this->addInt(count); |
|
1024 fWriter.writeMul4(pts, count * sizeof(SkPoint)); |
|
1025 this->validate(initialOffset, size); |
|
1026 } |
|
1027 |
|
1028 void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) { |
|
1029 |
|
1030 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1031 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1032 #endif |
|
1033 |
|
1034 // op + paint index + rect |
|
1035 uint32_t size = 2 * kUInt32Size + sizeof(oval); |
|
1036 size_t initialOffset = this->addDraw(DRAW_OVAL, &size); |
|
1037 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten()); |
|
1038 this->addPaint(paint); |
|
1039 this->addRect(oval); |
|
1040 this->validate(initialOffset, size); |
|
1041 } |
|
1042 |
|
1043 void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) { |
|
1044 |
|
1045 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1046 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1047 #endif |
|
1048 |
|
1049 // op + paint index + rect |
|
1050 uint32_t size = 2 * kUInt32Size + sizeof(rect); |
|
1051 size_t initialOffset = this->addDraw(DRAW_RECT, &size); |
|
1052 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten()); |
|
1053 this->addPaint(paint); |
|
1054 this->addRect(rect); |
|
1055 this->validate(initialOffset, size); |
|
1056 } |
|
1057 |
|
1058 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { |
|
1059 |
|
1060 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1061 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1062 #endif |
|
1063 |
|
1064 if (rrect.isRect()) { |
|
1065 this->SkPictureRecord::drawRect(rrect.getBounds(), paint); |
|
1066 } else if (rrect.isOval()) { |
|
1067 this->SkPictureRecord::drawOval(rrect.getBounds(), paint); |
|
1068 } else { |
|
1069 // op + paint index + rrect |
|
1070 uint32_t initialOffset, size; |
|
1071 size = 2 * kUInt32Size + SkRRect::kSizeInMemory; |
|
1072 initialOffset = this->addDraw(DRAW_RRECT, &size); |
|
1073 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten()); |
|
1074 this->addPaint(paint); |
|
1075 this->addRRect(rrect); |
|
1076 this->validate(initialOffset, size); |
|
1077 } |
|
1078 } |
|
1079 |
|
1080 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, |
|
1081 const SkPaint& paint) { |
|
1082 |
|
1083 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1084 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1085 #endif |
|
1086 |
|
1087 // op + paint index + rrects |
|
1088 uint32_t initialOffset, size; |
|
1089 size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2; |
|
1090 initialOffset = this->addDraw(DRAW_DRRECT, &size); |
|
1091 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten()); |
|
1092 this->addPaint(paint); |
|
1093 this->addRRect(outer); |
|
1094 this->addRRect(inner); |
|
1095 this->validate(initialOffset, size); |
|
1096 } |
|
1097 |
|
1098 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { |
|
1099 |
|
1100 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1101 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1102 #endif |
|
1103 |
|
1104 // op + paint index + path index |
|
1105 uint32_t size = 3 * kUInt32Size; |
|
1106 size_t initialOffset = this->addDraw(DRAW_PATH, &size); |
|
1107 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten()); |
|
1108 this->addPaint(paint); |
|
1109 this->addPath(path); |
|
1110 this->validate(initialOffset, size); |
|
1111 } |
|
1112 |
|
1113 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, |
|
1114 const SkPaint* paint = NULL) { |
|
1115 if (bitmap.drawsNothing()) { |
|
1116 return; |
|
1117 } |
|
1118 |
|
1119 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1120 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1121 #endif |
|
1122 |
|
1123 // op + paint index + bitmap index + left + top |
|
1124 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); |
|
1125 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size); |
|
1126 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten()); |
|
1127 this->addPaintPtr(paint); |
|
1128 int bitmapID = this->addBitmap(bitmap); |
|
1129 this->addScalar(left); |
|
1130 this->addScalar(top); |
|
1131 this->validate(initialOffset, size); |
|
1132 this->trackBitmapUse(bitmapID, initialOffset); |
|
1133 } |
|
1134 |
|
1135 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, |
|
1136 const SkRect& dst, const SkPaint* paint, |
|
1137 DrawBitmapRectFlags flags) { |
|
1138 if (bitmap.drawsNothing()) { |
|
1139 return; |
|
1140 } |
|
1141 |
|
1142 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1143 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1144 #endif |
|
1145 // id + paint index + bitmap index + bool for 'src' + flags |
|
1146 uint32_t size = 5 * kUInt32Size; |
|
1147 if (NULL != src) { |
|
1148 size += sizeof(*src); // + rect |
|
1149 } |
|
1150 size += sizeof(dst); // + rect |
|
1151 |
|
1152 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size); |
|
1153 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) |
|
1154 == fWriter.bytesWritten()); |
|
1155 this->addPaintPtr(paint); |
|
1156 int bitmapID = this->addBitmap(bitmap); |
|
1157 this->addRectPtr(src); // may be null |
|
1158 this->addRect(dst); |
|
1159 this->addInt(flags); |
|
1160 this->validate(initialOffset, size); |
|
1161 this->trackBitmapUse(bitmapID, initialOffset); |
|
1162 } |
|
1163 |
|
1164 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, |
|
1165 const SkPaint* paint) { |
|
1166 if (bitmap.drawsNothing()) { |
|
1167 return; |
|
1168 } |
|
1169 |
|
1170 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1171 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1172 #endif |
|
1173 |
|
1174 // id + paint index + bitmap index + matrix |
|
1175 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL); |
|
1176 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size); |
|
1177 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten()); |
|
1178 this->addPaintPtr(paint); |
|
1179 int bitmapID = this->addBitmap(bitmap); |
|
1180 this->addMatrix(matrix); |
|
1181 this->validate(initialOffset, size); |
|
1182 this->trackBitmapUse(bitmapID, initialOffset); |
|
1183 } |
|
1184 |
|
1185 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, |
|
1186 const SkRect& dst, const SkPaint* paint) { |
|
1187 if (bitmap.drawsNothing()) { |
|
1188 return; |
|
1189 } |
|
1190 |
|
1191 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1192 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1193 #endif |
|
1194 |
|
1195 // op + paint index + bitmap id + center + dst rect |
|
1196 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); |
|
1197 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); |
|
1198 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten()); |
|
1199 this->addPaintPtr(paint); |
|
1200 int bitmapID = this->addBitmap(bitmap); |
|
1201 this->addIRect(center); |
|
1202 this->addRect(dst); |
|
1203 this->validate(initialOffset, size); |
|
1204 this->trackBitmapUse(bitmapID, initialOffset); |
|
1205 } |
|
1206 |
|
1207 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top, |
|
1208 const SkPaint* paint = NULL) { |
|
1209 if (bitmap.drawsNothing()) { |
|
1210 return; |
|
1211 } |
|
1212 |
|
1213 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1214 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1215 #endif |
|
1216 |
|
1217 // op + paint index + bitmap index + left + top |
|
1218 uint32_t size = 5 * kUInt32Size; |
|
1219 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size); |
|
1220 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten()); |
|
1221 this->addPaintPtr(paint); |
|
1222 int bitmapID = this->addBitmap(bitmap); |
|
1223 this->addInt(left); |
|
1224 this->addInt(top); |
|
1225 this->validate(initialOffset, size); |
|
1226 this->trackBitmapUse(bitmapID, initialOffset); |
|
1227 } |
|
1228 |
|
1229 void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) { |
|
1230 SkPaint::FontMetrics metrics; |
|
1231 paint.getFontMetrics(&metrics); |
|
1232 SkRect bounds; |
|
1233 // construct a rect so we can see any adjustments from the paint. |
|
1234 // we use 0,1 for left,right, just so the rect isn't empty |
|
1235 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom); |
|
1236 (void)paint.computeFastBounds(bounds, &bounds); |
|
1237 topbot[0] = bounds.fTop; |
|
1238 topbot[1] = bounds.fBottom; |
|
1239 } |
|
1240 |
|
1241 void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat, |
|
1242 SkScalar minY, SkScalar maxY) { |
|
1243 WriteTopBot(paint, flat); |
|
1244 this->addScalar(flat.topBot()[0] + minY); |
|
1245 this->addScalar(flat.topBot()[1] + maxY); |
|
1246 } |
|
1247 |
|
1248 void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x, |
|
1249 SkScalar y, const SkPaint& paint) { |
|
1250 |
|
1251 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1252 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1253 #endif |
|
1254 |
|
1255 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); |
|
1256 |
|
1257 // op + paint index + length + 'length' worth of chars + x + y |
|
1258 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar); |
|
1259 if (fast) { |
|
1260 size += 2 * sizeof(SkScalar); // + top & bottom |
|
1261 } |
|
1262 |
|
1263 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT; |
|
1264 size_t initialOffset = this->addDraw(op, &size); |
|
1265 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten()); |
|
1266 const SkFlatData* flatPaintData = addPaint(paint); |
|
1267 SkASSERT(flatPaintData); |
|
1268 this->addText(text, byteLength); |
|
1269 this->addScalar(x); |
|
1270 this->addScalar(y); |
|
1271 if (fast) { |
|
1272 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y); |
|
1273 } |
|
1274 this->validate(initialOffset, size); |
|
1275 } |
|
1276 |
|
1277 void SkPictureRecord::drawPosText(const void* text, size_t byteLength, |
|
1278 const SkPoint pos[], const SkPaint& paint) { |
|
1279 |
|
1280 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1281 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1282 #endif |
|
1283 |
|
1284 size_t points = paint.countText(text, byteLength); |
|
1285 if (0 == points) |
|
1286 return; |
|
1287 |
|
1288 bool canUseDrawH = true; |
|
1289 SkScalar minY = pos[0].fY; |
|
1290 SkScalar maxY = pos[0].fY; |
|
1291 // check if the caller really should have used drawPosTextH() |
|
1292 { |
|
1293 const SkScalar firstY = pos[0].fY; |
|
1294 for (size_t index = 1; index < points; index++) { |
|
1295 if (pos[index].fY != firstY) { |
|
1296 canUseDrawH = false; |
|
1297 if (pos[index].fY < minY) { |
|
1298 minY = pos[index].fY; |
|
1299 } else if (pos[index].fY > maxY) { |
|
1300 maxY = pos[index].fY; |
|
1301 } |
|
1302 } |
|
1303 } |
|
1304 } |
|
1305 |
|
1306 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds(); |
|
1307 bool fast = canUseDrawH && fastBounds; |
|
1308 |
|
1309 // op + paint index + length + 'length' worth of data + num points |
|
1310 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; |
|
1311 if (canUseDrawH) { |
|
1312 if (fast) { |
|
1313 size += 2 * sizeof(SkScalar); // + top & bottom |
|
1314 } |
|
1315 // + y-pos + actual x-point data |
|
1316 size += sizeof(SkScalar) + points * sizeof(SkScalar); |
|
1317 } else { |
|
1318 // + x&y point data |
|
1319 size += points * sizeof(SkPoint); |
|
1320 if (fastBounds) { |
|
1321 size += 2 * sizeof(SkScalar); // + top & bottom |
|
1322 } |
|
1323 } |
|
1324 |
|
1325 DrawType op; |
|
1326 if (fast) { |
|
1327 op = DRAW_POS_TEXT_H_TOP_BOTTOM; |
|
1328 } else if (canUseDrawH) { |
|
1329 op = DRAW_POS_TEXT_H; |
|
1330 } else if (fastBounds) { |
|
1331 op = DRAW_POS_TEXT_TOP_BOTTOM; |
|
1332 } else { |
|
1333 op = DRAW_POS_TEXT; |
|
1334 } |
|
1335 size_t initialOffset = this->addDraw(op, &size); |
|
1336 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten()); |
|
1337 const SkFlatData* flatPaintData = this->addPaint(paint); |
|
1338 SkASSERT(flatPaintData); |
|
1339 this->addText(text, byteLength); |
|
1340 this->addInt(points); |
|
1341 |
|
1342 #ifdef SK_DEBUG_SIZE |
|
1343 size_t start = fWriter.bytesWritten(); |
|
1344 #endif |
|
1345 if (canUseDrawH) { |
|
1346 if (fast) { |
|
1347 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY); |
|
1348 } |
|
1349 this->addScalar(pos[0].fY); |
|
1350 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar)); |
|
1351 for (size_t index = 0; index < points; index++) |
|
1352 *xptr++ = pos[index].fX; |
|
1353 } else { |
|
1354 fWriter.writeMul4(pos, points * sizeof(SkPoint)); |
|
1355 if (fastBounds) { |
|
1356 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY); |
|
1357 } |
|
1358 } |
|
1359 #ifdef SK_DEBUG_SIZE |
|
1360 fPointBytes += fWriter.bytesWritten() - start; |
|
1361 fPointWrites += points; |
|
1362 #endif |
|
1363 this->validate(initialOffset, size); |
|
1364 } |
|
1365 |
|
1366 void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength, |
|
1367 const SkScalar xpos[], SkScalar constY, |
|
1368 const SkPaint& paint) { |
|
1369 |
|
1370 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1371 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1372 #endif |
|
1373 |
|
1374 const SkFlatData* flatPaintData = this->getFlatPaintData(paint); |
|
1375 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData); |
|
1376 } |
|
1377 |
|
1378 void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength, |
|
1379 const SkScalar xpos[], SkScalar constY, |
|
1380 const SkPaint& paint, const SkFlatData* flatPaintData) { |
|
1381 size_t points = paint.countText(text, byteLength); |
|
1382 if (0 == points) |
|
1383 return; |
|
1384 |
|
1385 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); |
|
1386 |
|
1387 // op + paint index + length + 'length' worth of data + num points |
|
1388 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; |
|
1389 if (fast) { |
|
1390 size += 2 * sizeof(SkScalar); // + top & bottom |
|
1391 } |
|
1392 // + y + the actual points |
|
1393 size += 1 * kUInt32Size + points * sizeof(SkScalar); |
|
1394 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H, |
|
1395 &size); |
|
1396 SkASSERT(flatPaintData); |
|
1397 this->addFlatPaint(flatPaintData); |
|
1398 |
|
1399 this->addText(text, byteLength); |
|
1400 this->addInt(points); |
|
1401 |
|
1402 #ifdef SK_DEBUG_SIZE |
|
1403 size_t start = fWriter.bytesWritten(); |
|
1404 #endif |
|
1405 if (fast) { |
|
1406 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY); |
|
1407 } |
|
1408 this->addScalar(constY); |
|
1409 fWriter.writeMul4(xpos, points * sizeof(SkScalar)); |
|
1410 #ifdef SK_DEBUG_SIZE |
|
1411 fPointBytes += fWriter.bytesWritten() - start; |
|
1412 fPointWrites += points; |
|
1413 #endif |
|
1414 this->validate(initialOffset, size); |
|
1415 } |
|
1416 |
|
1417 void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength, |
|
1418 const SkPath& path, const SkMatrix* matrix, |
|
1419 const SkPaint& paint) { |
|
1420 |
|
1421 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1422 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1423 #endif |
|
1424 |
|
1425 // op + paint index + length + 'length' worth of data + path index + matrix |
|
1426 const SkMatrix& m = matrix ? *matrix : SkMatrix::I(); |
|
1427 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL); |
|
1428 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size); |
|
1429 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten()); |
|
1430 this->addPaint(paint); |
|
1431 this->addText(text, byteLength); |
|
1432 this->addPath(path); |
|
1433 this->addMatrix(m); |
|
1434 this->validate(initialOffset, size); |
|
1435 } |
|
1436 |
|
1437 void SkPictureRecord::drawPicture(SkPicture& picture) { |
|
1438 |
|
1439 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1440 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1441 #endif |
|
1442 |
|
1443 // op + picture index |
|
1444 uint32_t size = 2 * kUInt32Size; |
|
1445 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size); |
|
1446 this->addPicture(picture); |
|
1447 this->validate(initialOffset, size); |
|
1448 } |
|
1449 |
|
1450 void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount, |
|
1451 const SkPoint vertices[], const SkPoint texs[], |
|
1452 const SkColor colors[], SkXfermode* xfer, |
|
1453 const uint16_t indices[], int indexCount, |
|
1454 const SkPaint& paint) { |
|
1455 |
|
1456 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1457 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1458 #endif |
|
1459 |
|
1460 uint32_t flags = 0; |
|
1461 if (texs) { |
|
1462 flags |= DRAW_VERTICES_HAS_TEXS; |
|
1463 } |
|
1464 if (colors) { |
|
1465 flags |= DRAW_VERTICES_HAS_COLORS; |
|
1466 } |
|
1467 if (indexCount > 0) { |
|
1468 flags |= DRAW_VERTICES_HAS_INDICES; |
|
1469 } |
|
1470 if (NULL != xfer) { |
|
1471 SkXfermode::Mode mode; |
|
1472 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) { |
|
1473 flags |= DRAW_VERTICES_HAS_XFER; |
|
1474 } |
|
1475 } |
|
1476 |
|
1477 // op + paint index + flags + vmode + vCount + vertices |
|
1478 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint); |
|
1479 if (flags & DRAW_VERTICES_HAS_TEXS) { |
|
1480 size += vertexCount * sizeof(SkPoint); // + uvs |
|
1481 } |
|
1482 if (flags & DRAW_VERTICES_HAS_COLORS) { |
|
1483 size += vertexCount * sizeof(SkColor); // + vert colors |
|
1484 } |
|
1485 if (flags & DRAW_VERTICES_HAS_INDICES) { |
|
1486 // + num indices + indices |
|
1487 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t)); |
|
1488 } |
|
1489 if (flags & DRAW_VERTICES_HAS_XFER) { |
|
1490 size += kUInt32Size; // mode enum |
|
1491 } |
|
1492 |
|
1493 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size); |
|
1494 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten()); |
|
1495 this->addPaint(paint); |
|
1496 this->addInt(flags); |
|
1497 this->addInt(vmode); |
|
1498 this->addInt(vertexCount); |
|
1499 this->addPoints(vertices, vertexCount); |
|
1500 if (flags & DRAW_VERTICES_HAS_TEXS) { |
|
1501 this->addPoints(texs, vertexCount); |
|
1502 } |
|
1503 if (flags & DRAW_VERTICES_HAS_COLORS) { |
|
1504 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor)); |
|
1505 } |
|
1506 if (flags & DRAW_VERTICES_HAS_INDICES) { |
|
1507 this->addInt(indexCount); |
|
1508 fWriter.writePad(indices, indexCount * sizeof(uint16_t)); |
|
1509 } |
|
1510 if (flags & DRAW_VERTICES_HAS_XFER) { |
|
1511 SkXfermode::Mode mode = SkXfermode::kModulate_Mode; |
|
1512 (void)xfer->asMode(&mode); |
|
1513 this->addInt(mode); |
|
1514 } |
|
1515 this->validate(initialOffset, size); |
|
1516 } |
|
1517 |
|
1518 void SkPictureRecord::drawData(const void* data, size_t length) { |
|
1519 |
|
1520 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE |
|
1521 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); |
|
1522 #endif |
|
1523 |
|
1524 // op + length + 'length' worth of data |
|
1525 uint32_t size = 2 * kUInt32Size + SkAlign4(length); |
|
1526 size_t initialOffset = this->addDraw(DRAW_DATA, &size); |
|
1527 this->addInt(length); |
|
1528 fWriter.writePad(data, length); |
|
1529 this->validate(initialOffset, size); |
|
1530 } |
|
1531 |
|
1532 void SkPictureRecord::beginCommentGroup(const char* description) { |
|
1533 // op/size + length of string + \0 terminated chars |
|
1534 int length = strlen(description); |
|
1535 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1); |
|
1536 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size); |
|
1537 fWriter.writeString(description, length); |
|
1538 this->validate(initialOffset, size); |
|
1539 } |
|
1540 |
|
1541 void SkPictureRecord::addComment(const char* kywd, const char* value) { |
|
1542 // op/size + 2x length of string + 2x \0 terminated chars |
|
1543 int kywdLen = strlen(kywd); |
|
1544 int valueLen = strlen(value); |
|
1545 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1); |
|
1546 size_t initialOffset = this->addDraw(COMMENT, &size); |
|
1547 fWriter.writeString(kywd, kywdLen); |
|
1548 fWriter.writeString(value, valueLen); |
|
1549 this->validate(initialOffset, size); |
|
1550 } |
|
1551 |
|
1552 void SkPictureRecord::endCommentGroup() { |
|
1553 // op/size |
|
1554 uint32_t size = 1 * kUInt32Size; |
|
1555 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size); |
|
1556 this->validate(initialOffset, size); |
|
1557 } |
|
1558 |
|
1559 // [op/size] [rect] [skip offset] |
|
1560 static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect); |
|
1561 void SkPictureRecord::onPushCull(const SkRect& cullRect) { |
|
1562 // Skip identical cull rects. |
|
1563 if (!fCullOffsetStack.isEmpty()) { |
|
1564 const SkRect& prevCull = fWriter.readTAt<SkRect>(fCullOffsetStack.top() - sizeof(SkRect)); |
|
1565 if (prevCull == cullRect) { |
|
1566 // Skipped culls are tracked on the stack, but they point to the previous offset. |
|
1567 fCullOffsetStack.push(fCullOffsetStack.top()); |
|
1568 return; |
|
1569 } |
|
1570 |
|
1571 SkASSERT(prevCull.contains(cullRect)); |
|
1572 } |
|
1573 |
|
1574 uint32_t size = kPushCullOpSize; |
|
1575 size_t initialOffset = this->addDraw(PUSH_CULL, &size); |
|
1576 // PUSH_CULL's size should stay constant (used to rewind). |
|
1577 SkASSERT(size == kPushCullOpSize); |
|
1578 |
|
1579 this->addRect(cullRect); |
|
1580 fCullOffsetStack.push(fWriter.bytesWritten()); |
|
1581 this->addInt(0); |
|
1582 this->validate(initialOffset, size); |
|
1583 } |
|
1584 |
|
1585 void SkPictureRecord::onPopCull() { |
|
1586 SkASSERT(!fCullOffsetStack.isEmpty()); |
|
1587 |
|
1588 uint32_t cullSkipOffset = fCullOffsetStack.top(); |
|
1589 fCullOffsetStack.pop(); |
|
1590 |
|
1591 // Skipped push, do the same for pop. |
|
1592 if (!fCullOffsetStack.isEmpty() && cullSkipOffset == fCullOffsetStack.top()) { |
|
1593 return; |
|
1594 } |
|
1595 |
|
1596 // Collapse empty push/pop pairs. |
|
1597 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) { |
|
1598 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize); |
|
1599 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize)); |
|
1600 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize); |
|
1601 return; |
|
1602 } |
|
1603 |
|
1604 // op only |
|
1605 uint32_t size = kUInt32Size; |
|
1606 size_t initialOffset = this->addDraw(POP_CULL, &size); |
|
1607 |
|
1608 // update the cull skip offset to point past this op. |
|
1609 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, fWriter.bytesWritten()); |
|
1610 |
|
1611 this->validate(initialOffset, size); |
|
1612 } |
|
1613 |
|
1614 /////////////////////////////////////////////////////////////////////////////// |
|
1615 |
|
1616 SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) { |
|
1617 return SkSurface::NewPicture(info.fWidth, info.fHeight); |
|
1618 } |
|
1619 |
|
1620 void SkPictureRecord::trackBitmapUse(int bitmapID, size_t offset) { |
|
1621 #ifndef SK_ALLOW_BITMAP_TRACKING |
|
1622 return; |
|
1623 #endif |
|
1624 |
|
1625 if (!(fRecordFlags & SkPicture::kOptimizeForClippedPlayback_RecordingFlag)) { |
|
1626 return; |
|
1627 } |
|
1628 |
|
1629 if (SkBitmapHeap::INVALID_SLOT == bitmapID) { |
|
1630 return; |
|
1631 } |
|
1632 |
|
1633 if (NULL == fBitmapUseOffsets) { |
|
1634 fBitmapUseOffsets.reset(SkNEW(SkOffsetTable)); |
|
1635 } |
|
1636 |
|
1637 fBitmapUseOffsets->add(bitmapID, offset); |
|
1638 } |
|
1639 |
|
1640 int SkPictureRecord::addBitmap(const SkBitmap& bitmap) { |
|
1641 const int index = fBitmapHeap->insert(bitmap); |
|
1642 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In |
|
1643 // release builds, the invalid value will be recorded so that the reader will know that there |
|
1644 // was a problem. |
|
1645 SkASSERT(index != SkBitmapHeap::INVALID_SLOT); |
|
1646 this->addInt(index); |
|
1647 return index; |
|
1648 } |
|
1649 |
|
1650 void SkPictureRecord::addMatrix(const SkMatrix& matrix) { |
|
1651 fWriter.writeMatrix(matrix); |
|
1652 } |
|
1653 |
|
1654 const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) { |
|
1655 return fPaints.findAndReturnFlat(paint); |
|
1656 } |
|
1657 |
|
1658 const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) { |
|
1659 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL; |
|
1660 this->addFlatPaint(data); |
|
1661 return data; |
|
1662 } |
|
1663 |
|
1664 void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) { |
|
1665 int index = flatPaint ? flatPaint->index() : 0; |
|
1666 this->addInt(index); |
|
1667 } |
|
1668 |
|
1669 int SkPictureRecord::addPathToHeap(const SkPath& path) { |
|
1670 if (NULL == fPathHeap) { |
|
1671 fPathHeap = SkNEW(SkPathHeap); |
|
1672 } |
|
1673 #ifdef SK_DEDUP_PICTURE_PATHS |
|
1674 return fPathHeap->insert(path); |
|
1675 #else |
|
1676 return fPathHeap->append(path); |
|
1677 #endif |
|
1678 } |
|
1679 |
|
1680 void SkPictureRecord::addPath(const SkPath& path) { |
|
1681 this->addInt(this->addPathToHeap(path)); |
|
1682 } |
|
1683 |
|
1684 void SkPictureRecord::addPicture(SkPicture& picture) { |
|
1685 int index = fPictureRefs.find(&picture); |
|
1686 if (index < 0) { // not found |
|
1687 index = fPictureRefs.count(); |
|
1688 *fPictureRefs.append() = &picture; |
|
1689 picture.ref(); |
|
1690 } |
|
1691 // follow the convention of recording a 1-based index |
|
1692 this->addInt(index + 1); |
|
1693 } |
|
1694 |
|
1695 void SkPictureRecord::addPoint(const SkPoint& point) { |
|
1696 #ifdef SK_DEBUG_SIZE |
|
1697 size_t start = fWriter.bytesWritten(); |
|
1698 #endif |
|
1699 fWriter.writePoint(point); |
|
1700 #ifdef SK_DEBUG_SIZE |
|
1701 fPointBytes += fWriter.bytesWritten() - start; |
|
1702 fPointWrites++; |
|
1703 #endif |
|
1704 } |
|
1705 |
|
1706 void SkPictureRecord::addPoints(const SkPoint pts[], int count) { |
|
1707 fWriter.writeMul4(pts, count * sizeof(SkPoint)); |
|
1708 #ifdef SK_DEBUG_SIZE |
|
1709 fPointBytes += count * sizeof(SkPoint); |
|
1710 fPointWrites++; |
|
1711 #endif |
|
1712 } |
|
1713 |
|
1714 void SkPictureRecord::addRect(const SkRect& rect) { |
|
1715 #ifdef SK_DEBUG_SIZE |
|
1716 size_t start = fWriter.bytesWritten(); |
|
1717 #endif |
|
1718 fWriter.writeRect(rect); |
|
1719 #ifdef SK_DEBUG_SIZE |
|
1720 fRectBytes += fWriter.bytesWritten() - start; |
|
1721 fRectWrites++; |
|
1722 #endif |
|
1723 } |
|
1724 |
|
1725 void SkPictureRecord::addRectPtr(const SkRect* rect) { |
|
1726 if (fWriter.writeBool(rect != NULL)) { |
|
1727 fWriter.writeRect(*rect); |
|
1728 } |
|
1729 } |
|
1730 |
|
1731 void SkPictureRecord::addIRect(const SkIRect& rect) { |
|
1732 fWriter.write(&rect, sizeof(rect)); |
|
1733 } |
|
1734 |
|
1735 void SkPictureRecord::addIRectPtr(const SkIRect* rect) { |
|
1736 if (fWriter.writeBool(rect != NULL)) { |
|
1737 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect; |
|
1738 } |
|
1739 } |
|
1740 |
|
1741 void SkPictureRecord::addRRect(const SkRRect& rrect) { |
|
1742 fWriter.writeRRect(rrect); |
|
1743 } |
|
1744 |
|
1745 void SkPictureRecord::addRegion(const SkRegion& region) { |
|
1746 fWriter.writeRegion(region); |
|
1747 } |
|
1748 |
|
1749 void SkPictureRecord::addText(const void* text, size_t byteLength) { |
|
1750 #ifdef SK_DEBUG_SIZE |
|
1751 size_t start = fWriter.bytesWritten(); |
|
1752 #endif |
|
1753 addInt(byteLength); |
|
1754 fWriter.writePad(text, byteLength); |
|
1755 #ifdef SK_DEBUG_SIZE |
|
1756 fTextBytes += fWriter.bytesWritten() - start; |
|
1757 fTextWrites++; |
|
1758 #endif |
|
1759 } |
|
1760 |
|
1761 /////////////////////////////////////////////////////////////////////////////// |
|
1762 |
|
1763 #ifdef SK_DEBUG_SIZE |
|
1764 size_t SkPictureRecord::size() const { |
|
1765 size_t result = 0; |
|
1766 size_t sizeData; |
|
1767 bitmaps(&sizeData); |
|
1768 result += sizeData; |
|
1769 matrices(&sizeData); |
|
1770 result += sizeData; |
|
1771 paints(&sizeData); |
|
1772 result += sizeData; |
|
1773 paths(&sizeData); |
|
1774 result += sizeData; |
|
1775 pictures(&sizeData); |
|
1776 result += sizeData; |
|
1777 regions(&sizeData); |
|
1778 result += sizeData; |
|
1779 result += streamlen(); |
|
1780 return result; |
|
1781 } |
|
1782 |
|
1783 int SkPictureRecord::bitmaps(size_t* size) const { |
|
1784 size_t result = 0; |
|
1785 int count = fBitmaps.count(); |
|
1786 for (int index = 0; index < count; index++) |
|
1787 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size(); |
|
1788 *size = result; |
|
1789 return count; |
|
1790 } |
|
1791 |
|
1792 int SkPictureRecord::matrices(size_t* size) const { |
|
1793 int count = fMatrices.count(); |
|
1794 *size = sizeof(fMatrices[0]) * count; |
|
1795 return count; |
|
1796 } |
|
1797 |
|
1798 int SkPictureRecord::paints(size_t* size) const { |
|
1799 size_t result = 0; |
|
1800 int count = fPaints.count(); |
|
1801 for (int index = 0; index < count; index++) |
|
1802 result += sizeof(fPaints[index]) + fPaints[index]->size(); |
|
1803 *size = result; |
|
1804 return count; |
|
1805 } |
|
1806 |
|
1807 int SkPictureRecord::paths(size_t* size) const { |
|
1808 size_t result = 0; |
|
1809 int count = fPaths.count(); |
|
1810 for (int index = 0; index < count; index++) |
|
1811 result += sizeof(fPaths[index]) + fPaths[index]->size(); |
|
1812 *size = result; |
|
1813 return count; |
|
1814 } |
|
1815 |
|
1816 int SkPictureRecord::regions(size_t* size) const { |
|
1817 size_t result = 0; |
|
1818 int count = fRegions.count(); |
|
1819 for (int index = 0; index < count; index++) |
|
1820 result += sizeof(fRegions[index]) + fRegions[index]->size(); |
|
1821 *size = result; |
|
1822 return count; |
|
1823 } |
|
1824 |
|
1825 size_t SkPictureRecord::streamlen() const { |
|
1826 return fWriter.size(); |
|
1827 } |
|
1828 #endif |
|
1829 |
|
1830 #ifdef SK_DEBUG_VALIDATE |
|
1831 void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const { |
|
1832 SkASSERT(fWriter.size() == initialOffset + size); |
|
1833 |
|
1834 validateBitmaps(); |
|
1835 validateMatrices(); |
|
1836 validatePaints(); |
|
1837 validatePaths(); |
|
1838 validateRegions(); |
|
1839 } |
|
1840 |
|
1841 void SkPictureRecord::validateBitmaps() const { |
|
1842 int count = fBitmapHeap->count(); |
|
1843 SkASSERT((unsigned) count < 0x1000); |
|
1844 for (int index = 0; index < count; index++) { |
|
1845 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index); |
|
1846 SkASSERT(bitPtr); |
|
1847 bitPtr->validate(); |
|
1848 } |
|
1849 } |
|
1850 |
|
1851 void SkPictureRecord::validateMatrices() const { |
|
1852 int count = fMatrices.count(); |
|
1853 SkASSERT((unsigned) count < 0x1000); |
|
1854 for (int index = 0; index < count; index++) { |
|
1855 const SkFlatData* matrix = fMatrices[index]; |
|
1856 SkASSERT(matrix); |
|
1857 // matrix->validate(); |
|
1858 } |
|
1859 } |
|
1860 |
|
1861 void SkPictureRecord::validatePaints() const { |
|
1862 int count = fPaints.count(); |
|
1863 SkASSERT((unsigned) count < 0x1000); |
|
1864 for (int index = 0; index < count; index++) { |
|
1865 const SkFlatData* paint = fPaints[index]; |
|
1866 SkASSERT(paint); |
|
1867 // paint->validate(); |
|
1868 } |
|
1869 } |
|
1870 |
|
1871 void SkPictureRecord::validatePaths() const { |
|
1872 if (NULL == fPathHeap) { |
|
1873 return; |
|
1874 } |
|
1875 |
|
1876 int count = fPathHeap->count(); |
|
1877 SkASSERT((unsigned) count < 0x1000); |
|
1878 for (int index = 0; index < count; index++) { |
|
1879 const SkPath& path = (*fPathHeap)[index]; |
|
1880 path.validate(); |
|
1881 } |
|
1882 } |
|
1883 |
|
1884 void SkPictureRecord::validateRegions() const { |
|
1885 int count = fRegions.count(); |
|
1886 SkASSERT((unsigned) count < 0x1000); |
|
1887 for (int index = 0; index < count; index++) { |
|
1888 const SkFlatData* region = fRegions[index]; |
|
1889 SkASSERT(region); |
|
1890 // region->validate(); |
|
1891 } |
|
1892 } |
|
1893 #endif |