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