3 * Copyright 2011 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
8 #include "SkPictureRecord.h"
10 #include "SkPixelRef.h"
12 #include "SkBBoxHierarchy.h"
14 #include "SkPictureStateTree.h"
16 #define HEAP_BLOCK_SIZE 4096
19 // just need a value that save or getSaveCount would never return
23 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
24 static int const kUInt32Size = 4;
26 static const uint32_t kSaveSize = 2 * kUInt32Size;
27 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
28 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
30 SkPictureRecord::SkPictureRecord(uint32_t flags, SkBaseDevice* device) :
32 fBoundingHierarchy(NULL),
34 fFlattenableHeap(HEAP_BLOCK_SIZE),
35 fPaints(&fFlattenableHeap),
38 fPointBytes = fRectBytes = fTextBytes = 0;
39 fPointWrites = fRectWrites = fTextWrites = 0;
42 fBitmapHeap = SkNEW(SkBitmapHeap);
43 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
44 fPathHeap = NULL; // lazy allocate
45 fFirstSavedLayerIndex = kNoSavedLayerIndex;
47 fInitialSaveCount = kNoInitialSave;
50 SkPictureRecord::~SkPictureRecord() {
51 SkSafeUnref(fBitmapHeap);
52 SkSafeUnref(fPathHeap);
53 SkSafeUnref(fBoundingHierarchy);
54 SkSafeUnref(fStateTree);
55 fFlattenableHeap.setBitmapStorage(NULL);
56 fPictureRefs.unrefAll();
59 ///////////////////////////////////////////////////////////////////////////////
61 // Return the offset of the paint inside a given op's byte stream. A zero
62 // return value means there is no paint (and you really shouldn't be calling
64 static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
65 // These offsets are where the paint would be if the op size doesn't overflow
66 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
67 0, // UNUSED - no paint
68 0, // CLIP_PATH - no paint
69 0, // CLIP_REGION - no paint
70 0, // CLIP_RECT - no paint
71 0, // CLIP_RRECT - no paint
72 0, // CONCAT - no paint
73 1, // DRAW_BITMAP - right after op code
74 1, // DRAW_BITMAP_MATRIX - right after op code
75 1, // DRAW_BITMAP_NINE - right after op code
76 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
77 0, // DRAW_CLEAR - no paint
78 0, // DRAW_DATA - no paint
79 1, // DRAW_OVAL - right after op code
80 1, // DRAW_PAINT - right after op code
81 1, // DRAW_PATH - right after op code
82 0, // DRAW_PICTURE - no paint
83 1, // DRAW_POINTS - right after op code
84 1, // DRAW_POS_TEXT - right after op code
85 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
86 1, // DRAW_POS_TEXT_H - right after op code
87 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
88 1, // DRAW_RECT - right after op code
89 1, // DRAW_RRECT - right after op code
90 1, // DRAW_SPRITE - right after op code
91 1, // DRAW_TEXT - right after op code
92 1, // DRAW_TEXT_ON_PATH - right after op code
93 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
94 1, // DRAW_VERTICES - right after op code
95 0, // RESTORE - no paint
96 0, // ROTATE - no paint
98 0, // SAVE_LAYER - see below - this paint's location varies
99 0, // SCALE - no paint
100 0, // SET_MATRIX - no paint
101 0, // SKEW - no paint
102 0, // TRANSLATE - no paint
103 0, // NOOP - no paint
104 0, // BEGIN_GROUP - no paint
105 0, // COMMENT - no paint
106 0, // END_GROUP - no paint
109 SkASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1);
110 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
113 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
114 // This op's size overflows so an extra uint32_t will be written
116 overflow = sizeof(uint32_t);
119 if (SAVE_LAYER == op) {
120 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
121 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
123 if (kSaveLayerNoBoundsSize == opSize) {
124 return kSaveLayerNoBoundsPaintOffset + overflow;
126 SkASSERT(kSaveLayerWithBoundsSize == opSize);
127 return kSaveLayerWithBoundsPaintOffset + overflow;
131 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
132 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
135 SkBaseDevice* SkPictureRecord::setDevice(SkBaseDevice* device) {
136 SkDEBUGFAIL("eeek, don't try to change the device on a recording canvas");
137 return this->INHERITED::setDevice(device);
140 int SkPictureRecord::save(SaveFlags flags) {
141 // record the offset to us, making it non-positive to distinguish a save
142 // from a clip entry.
143 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
146 uint32_t size = kSaveSize;
147 size_t initialOffset = this->addDraw(SAVE, &size);
150 this->validate(initialOffset, size);
151 return this->INHERITED::save(flags);
154 int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
156 // record the offset to us, making it non-positive to distinguish a save
157 // from a clip entry.
158 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
160 // op + bool for 'bounds'
161 uint32_t size = 2 * kUInt32Size;
162 if (NULL != bounds) {
163 size += sizeof(*bounds); // + rect
165 // + paint index + flags
166 size += 2 * kUInt32Size;
168 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
170 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
172 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
176 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
177 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
180 this->validate(initialOffset, size);
181 /* Don't actually call saveLayer, because that will try to allocate an
182 offscreen device (potentially very big) which we don't actually need
183 at this time (and may not be able to afford since during record our
184 clip starts out the size of the picture, which is often much larger
185 than the size of the actual device we'll use during playback).
187 int count = this->INHERITED::save(flags);
188 this->clipRectBounds(bounds, flags, NULL);
192 bool SkPictureRecord::isDrawingToLayer() const {
193 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
197 * Read the op code from 'offset' in 'writer' and extract the size too.
199 static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
200 uint32_t* peek = writer->peek32(offset);
203 UNPACK_8_24(*peek, op, *size);
204 if (MASK_24 == *size) {
205 // size required its own slot right after the op code
206 *size = *writer->peek32(offset+kUInt32Size);
208 return (DrawType) op;
211 #ifdef TRACK_COLLAPSE_STATS
212 static int gCollapseCount, gCollapseCalls;
215 // Is the supplied paint simply a color?
216 static bool is_simple(const SkPaint& p) {
217 intptr_t orAccum = (intptr_t)p.getPathEffect() |
218 (intptr_t)p.getShader() |
219 (intptr_t)p.getXfermode() |
220 (intptr_t)p.getMaskFilter() |
221 (intptr_t)p.getColorFilter() |
222 (intptr_t)p.getRasterizer() |
223 (intptr_t)p.getLooper() |
224 (intptr_t)p.getImageFilter();
228 // CommandInfos are fed to the 'match' method and filled in with command
237 * Attempt to match the provided pattern of commands starting at 'offset'
238 * in the byte stream and stopping at the end of the stream. Upon success,
239 * return true with all the pattern information filled out in the result
240 * array (i.e., actual ops, offsets and sizes).
241 * Note this method skips any NOOPs seen in the stream
243 static bool match(SkWriter32* writer, uint32_t offset,
244 int* pattern, CommandInfo* result, int numCommands) {
245 SkASSERT(offset < writer->bytesWritten());
247 uint32_t curOffset = offset;
248 uint32_t curSize = 0;
250 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
251 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
252 while (NOOP == op && curOffset < writer->bytesWritten()) {
253 curOffset += curSize;
254 op = peek_op_and_size(writer, curOffset, &curSize);
257 if (curOffset >= writer->bytesWritten()) {
258 return false; // ran out of byte stream
261 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
262 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
263 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
266 } else if (op != pattern[numMatched]) {
270 result[numMatched].fActualOp = op;
271 result[numMatched].fOffset = curOffset;
272 result[numMatched].fSize = curSize;
274 curOffset += curSize;
277 if (numMatched != numCommands) {
281 curOffset += curSize;
282 if (curOffset < writer->bytesWritten()) {
283 // Something else between the last command and the end of the stream
290 // temporarily here to make code review easier
291 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
292 SkPaintDictionary* paintDict,
293 const CommandInfo& saveLayerInfo,
294 const CommandInfo& dbmInfo);
297 * Restore has just been called (but not recorded), look back at the
298 * matching save* and see if we are in the configuration:
300 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
302 * where the saveLayer's color can be moved into the drawBitmap*'s paint
304 static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
305 SkPaintDictionary* paintDict) {
306 // back up to the save block
307 // TODO: add a stack to track save*/restore offsets rather than searching backwards
309 offset = *writer->peek32(offset);
312 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
313 CommandInfo result[SK_ARRAY_COUNT(pattern)];
315 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
319 if (kSaveLayerWithBoundsSize == result[0].fSize) {
320 // The saveLayer's bound can offset where the dbm is drawn
325 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
326 result[0], result[1]);
330 * Convert the command code located at 'offset' to a NOOP. Leave the size
331 * field alone so the NOOP can be skipped later.
333 static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
334 uint32_t* ptr = writer->peek32(offset);
335 *ptr = (*ptr & MASK_24) | (NOOP << 24);
339 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
340 * Return true on success; false otherwise.
342 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
343 SkPaintDictionary* paintDict,
344 const CommandInfo& saveLayerInfo,
345 const CommandInfo& dbmInfo) {
346 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
347 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
348 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
349 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
350 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
352 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
353 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
355 // we have a match, now we need to get the paints involved
356 uint32_t dbmPaintId = *writer->peek32(dbmInfo.fOffset+dbmPaintOffset);
357 uint32_t saveLayerPaintId = *writer->peek32(saveLayerInfo.fOffset+slPaintOffset);
359 if (0 == saveLayerPaintId) {
360 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
361 // and signal the caller (by returning true) to not add the RESTORE op
362 convert_command_to_noop(writer, saveLayerInfo.fOffset);
366 if (0 == dbmPaintId) {
367 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
368 // and signal the caller (by returning true) to not add the RESTORE op
369 convert_command_to_noop(writer, saveLayerInfo.fOffset);
370 uint32_t* ptr = writer->peek32(dbmInfo.fOffset+dbmPaintOffset);
372 *ptr = saveLayerPaintId;
376 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
377 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
381 // For this optimization we only fold the saveLayer and drawBitmapRect
382 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
383 // and the only difference in the colors is that the saveLayer's can have
384 // an alpha while the drawBitmapRect's is opaque.
385 // TODO: it should be possible to fold them together even if they both
386 // have different non-255 alphas
387 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
389 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
390 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
394 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
395 SkColorGetA(saveLayerPaint->getColor()));
396 dbmPaint->setColor(newColor);
398 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
403 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
404 convert_command_to_noop(writer, saveLayerInfo.fOffset);
405 uint32_t* ptr = writer->peek32(dbmInfo.fOffset+dbmPaintOffset);
406 SkASSERT(dbmPaintId == *ptr);
407 *ptr = data->index();
412 * Restore has just been called (but not recorded), look back at the
413 * matching save* and see if we are in the configuration:
414 * SAVE_LAYER (with NULL == bounds)
417 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
420 * where the saveLayer's color can be moved into the drawBitmap*'s paint
422 static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
423 SkPaintDictionary* paintDict) {
425 // back up to the save block
426 // TODO: add a stack to track save*/restore offsets rather than searching backwards
428 offset = *writer->peek32(offset);
431 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
432 CommandInfo result[SK_ARRAY_COUNT(pattern)];
434 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
438 if (kSaveLayerWithBoundsSize == result[0].fSize) {
439 // The saveLayer's bound can offset where the dbm is drawn
443 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
444 result[0], result[3]);
448 * Restore has just been called (but not recorded), so look back at the
449 * matching save(), and see if we can eliminate the pair of them, due to no
450 * intervening matrix/clip calls.
452 * If so, update the writer and return true, in which case we won't even record
453 * the restore() call. If we still need the restore(), return false.
455 static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
456 SkPaintDictionary* paintDict) {
457 #ifdef TRACK_COLLAPSE_STATS
461 int32_t restoreOffset = (int32_t)writer->bytesWritten();
463 // back up to the save block
465 offset = *writer->peek32(offset);
468 // now offset points to a save
471 DrawType op = peek_op_and_size(writer, offset, &opSize);
472 if (SAVE_LAYER == op) {
473 // not ready to cull these out yet (mrr)
476 SkASSERT(SAVE == op);
477 SkASSERT(kSaveSize == opSize);
479 // get the save flag (last 4-bytes of the space allocated for the opSize)
480 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) *writer->peek32(offset+4);
481 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
482 // This function's optimization is only correct for kMatrixClip style saves.
483 // TODO: set checkMatrix & checkClip booleans here and then check for the
484 // offending operations in the following loop.
488 // Walk forward until we get back to either a draw-verb (abort) or we hit
489 // our restore (success).
490 int32_t saveOffset = offset;
493 while (offset < restoreOffset) {
494 op = peek_op_and_size(writer, offset, &opSize);
495 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
496 // drawing verb, abort
502 #ifdef TRACK_COLLAPSE_STATS
504 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
505 (double)gCollapseCount / gCollapseCalls, "%");
508 writer->rewindToOffset(saveOffset);
512 typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
513 SkPaintDictionary* paintDict);
514 enum PictureRecordOptType {
515 kRewind_OptType, // Optimization rewinds the command stream
516 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
519 enum PictureRecordOptFlags {
520 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
521 // SkPicture has a bounding box hierarchy.
524 struct PictureRecordOpt {
525 PictureRecordOptProc fProc;
526 PictureRecordOptType fType;
530 * A list of the optimizations that are tried upon seeing a restore
531 * TODO: add a real API for such optimizations
532 * Add the ability to fire optimizations on any op (not just RESTORE)
534 static const PictureRecordOpt gPictureRecordOpts[] = {
535 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
536 // because it is redundant with the state traversal optimization in
537 // SkPictureStateTree, and applying the optimization introduces significant
538 // record time overhead because it requires rewinding contents that were
539 // recorded into the BBoxHierarchy.
540 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
541 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
542 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
545 // This is called after an optimization has been applied to the command stream
546 // in order to adjust the contents and state of the bounding box hierarchy and
547 // state tree to reflect the optimization.
548 static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
549 SkBBoxHierarchy* boundingHierarchy) {
551 case kCollapseSaveLayer_OptType:
552 if (NULL != stateTree) {
553 stateTree->saveCollapsed();
556 case kRewind_OptType:
557 if (NULL != boundingHierarchy) {
558 boundingHierarchy->rewindInserts();
560 // Note: No need to touch the state tree for this to work correctly.
561 // Unused branches do not burden the playback, and pruning the tree
562 // would be O(N^2), so it is best to leave it alone.
569 void SkPictureRecord::restore() {
570 // FIXME: SkDeferredCanvas needs to be refactored to respect
571 // save/restore balancing so that the following test can be
572 // turned on permanently.
574 SkASSERT(fRestoreOffsetStack.count() > 1);
577 // check for underflow
578 if (fRestoreOffsetStack.count() == 0) {
582 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
583 fFirstSavedLayerIndex = kNoSavedLayerIndex;
586 uint32_t initialOffset, size;
588 if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
589 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
590 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
591 && NULL != fBoundingHierarchy) {
594 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
595 // Some optimization fired so don't add the RESTORE
597 initialOffset = fWriter.bytesWritten();
598 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
599 fStateTree, fBoundingHierarchy);
605 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
606 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
607 // No optimization fired so add the RESTORE
608 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
609 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
610 initialOffset = this->addDraw(RESTORE, &size);
613 fRestoreOffsetStack.pop();
615 this->validate(initialOffset, size);
616 return this->INHERITED::restore();
619 bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
621 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
622 size_t initialOffset = this->addDraw(TRANSLATE, &size);
625 this->validate(initialOffset, size);
626 return this->INHERITED::translate(dx, dy);
629 bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
631 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
632 size_t initialOffset = this->addDraw(SCALE, &size);
635 this->validate(initialOffset, size);
636 return this->INHERITED::scale(sx, sy);
639 bool SkPictureRecord::rotate(SkScalar degrees) {
641 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
642 size_t initialOffset = this->addDraw(ROTATE, &size);
644 this->validate(initialOffset, size);
645 return this->INHERITED::rotate(degrees);
648 bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
650 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
651 size_t initialOffset = this->addDraw(SKEW, &size);
654 this->validate(initialOffset, size);
655 return this->INHERITED::skew(sx, sy);
658 bool SkPictureRecord::concat(const SkMatrix& matrix) {
659 this->validate(fWriter.bytesWritten(), 0);
661 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
662 size_t initialOffset = this->addDraw(CONCAT, &size);
664 this->validate(initialOffset, size);
665 return this->INHERITED::concat(matrix);
668 void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
669 this->validate(fWriter.bytesWritten(), 0);
671 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
672 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
674 this->validate(initialOffset, size);
675 this->INHERITED::setMatrix(matrix);
678 static bool regionOpExpands(SkRegion::Op op) {
680 case SkRegion::kUnion_Op:
681 case SkRegion::kXOR_Op:
682 case SkRegion::kReverseDifference_Op:
683 case SkRegion::kReplace_Op:
685 case SkRegion::kIntersect_Op:
686 case SkRegion::kDifference_Op:
689 SkDEBUGFAIL("unknown region op");
694 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
695 int32_t offset = fRestoreOffsetStack.top();
697 uint32_t* peek = fWriter.peek32(offset);
699 *peek = restoreOffset;
703 // assert that the final offset value points to a save verb
705 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
706 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
710 void SkPictureRecord::beginRecording() {
711 // we have to call this *after* our constructor, to ensure that it gets
712 // recorded. This is balanced by restoreToCount() call from endRecording,
713 // which in-turn calls our overridden restore(), so those get recorded too.
714 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
717 void SkPictureRecord::endRecording() {
718 SkASSERT(kNoInitialSave != fInitialSaveCount);
719 this->restoreToCount(fInitialSaveCount);
722 void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
723 if (fRestoreOffsetStack.isEmpty()) {
727 // The RestoreOffset field is initially filled with a placeholder
728 // value that points to the offset of the previous RestoreOffset
729 // in the current stack level, thus forming a linked list so that
730 // the restore offsets can be filled in when the corresponding
731 // restore command is recorded.
732 int32_t prevOffset = fRestoreOffsetStack.top();
734 if (regionOpExpands(op)) {
735 // Run back through any previous clip ops, and mark their offset to
736 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
737 // they could hide this clips ability to expand the clip (i.e. go from
738 // empty to non-empty).
739 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
741 // Reset the pointer back to the previous clip so that subsequent
742 // restores don't overwrite the offsets we just cleared.
746 size_t offset = fWriter.bytesWritten();
748 fRestoreOffsetStack.top() = offset;
751 bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
752 // id + rect + clip params
753 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
754 // recordRestoreOffsetPlaceholder doesn't always write an offset
755 if (!fRestoreOffsetStack.isEmpty()) {
759 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
761 addInt(ClipParams_pack(op, doAA));
762 recordRestoreOffsetPlaceholder(op);
764 this->validate(initialOffset, size);
765 return this->INHERITED::clipRect(rect, op, doAA);
768 bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
769 if (rrect.isRect()) {
770 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
773 // op + rrect + clip params
774 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
775 // recordRestoreOffsetPlaceholder doesn't always write an offset
776 if (!fRestoreOffsetStack.isEmpty()) {
780 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
782 addInt(ClipParams_pack(op, doAA));
783 recordRestoreOffsetPlaceholder(op);
785 this->validate(initialOffset, size);
787 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
788 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
790 return this->INHERITED::clipRRect(rrect, op, doAA);
794 bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
797 if (!path.isInverseFillType() && path.isRect(&r)) {
798 return this->clipRect(r, op, doAA);
801 // op + path index + clip params
802 uint32_t size = 3 * kUInt32Size;
803 // recordRestoreOffsetPlaceholder doesn't always write an offset
804 if (!fRestoreOffsetStack.isEmpty()) {
808 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
810 addInt(ClipParams_pack(op, doAA));
811 recordRestoreOffsetPlaceholder(op);
813 this->validate(initialOffset, size);
815 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
816 return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
817 path.isInverseFillType());
819 return this->INHERITED::clipPath(path, op, doAA);
823 bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
824 // op + clip params + region
825 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
826 // recordRestoreOffsetPlaceholder doesn't always write an offset
827 if (!fRestoreOffsetStack.isEmpty()) {
831 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
833 addInt(ClipParams_pack(op, false));
834 recordRestoreOffsetPlaceholder(op);
836 this->validate(initialOffset, size);
837 return this->INHERITED::clipRegion(region, op);
840 void SkPictureRecord::clear(SkColor color) {
842 uint32_t size = 2 * kUInt32Size;
843 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
845 this->validate(initialOffset, size);
848 void SkPictureRecord::drawPaint(const SkPaint& paint) {
850 uint32_t size = 2 * kUInt32Size;
851 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
852 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
854 this->validate(initialOffset, size);
857 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
858 const SkPaint& paint) {
859 // op + paint index + mode + count + point data
860 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
861 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
862 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
866 fWriter.writeMul4(pts, count * sizeof(SkPoint));
867 this->validate(initialOffset, size);
870 void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
871 // op + paint index + rect
872 uint32_t size = 2 * kUInt32Size + sizeof(oval);
873 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
874 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
877 this->validate(initialOffset, size);
880 void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
881 // op + paint index + rect
882 uint32_t size = 2 * kUInt32Size + sizeof(rect);
883 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
884 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
887 this->validate(initialOffset, size);
890 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
891 if (rrect.isRect()) {
892 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
893 } else if (rrect.isOval()) {
894 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
896 // op + paint index + rrect
897 uint32_t initialOffset, size;
898 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
899 initialOffset = this->addDraw(DRAW_RRECT, &size);
900 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
903 this->validate(initialOffset, size);
907 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
908 // op + paint index + path index
909 uint32_t size = 3 * kUInt32Size;
910 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
911 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
914 this->validate(initialOffset, size);
917 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
918 const SkPaint* paint = NULL) {
919 // op + paint index + bitmap index + left + top
920 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
921 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
922 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
927 this->validate(initialOffset, size);
930 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
931 const SkRect& dst, const SkPaint* paint,
932 DrawBitmapRectFlags flags) {
933 // id + paint index + bitmap index + bool for 'src' + flags
934 uint32_t size = 5 * kUInt32Size;
936 size += sizeof(*src); // + rect
938 size += sizeof(dst); // + rect
940 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
941 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.bytesWritten());
944 addRectPtr(src); // may be null
947 this->validate(initialOffset, size);
950 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
951 const SkPaint* paint) {
952 // id + paint index + bitmap index + matrix
953 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
954 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
955 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
959 this->validate(initialOffset, size);
962 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
963 const SkRect& dst, const SkPaint* paint) {
964 // op + paint index + bitmap id + center + dst rect
965 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
966 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
967 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
972 this->validate(initialOffset, size);
975 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
976 const SkPaint* paint = NULL) {
977 // op + paint index + bitmap index + left + top
978 uint32_t size = 5 * kUInt32Size;
979 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
980 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
985 this->validate(initialOffset, size);
988 void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
989 SkPaint::FontMetrics metrics;
990 paint.getFontMetrics(&metrics);
992 // construct a rect so we can see any adjustments from the paint.
993 // we use 0,1 for left,right, just so the rect isn't empty
994 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
995 (void)paint.computeFastBounds(bounds, &bounds);
996 topbot[0] = bounds.fTop;
997 topbot[1] = bounds.fBottom;
1000 void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
1001 SkScalar minY, SkScalar maxY) {
1002 WriteTopBot(paint, flat);
1003 addScalar(flat.topBot()[0] + minY);
1004 addScalar(flat.topBot()[1] + maxY);
1007 void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
1008 SkScalar y, const SkPaint& paint) {
1009 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
1011 // op + paint index + length + 'length' worth of chars + x + y
1012 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1014 size += 2 * sizeof(SkScalar); // + top & bottom
1017 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
1018 size_t initialOffset = this->addDraw(op, &size);
1019 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
1020 const SkFlatData* flatPaintData = addPaint(paint);
1021 SkASSERT(flatPaintData);
1022 addText(text, byteLength);
1026 addFontMetricsTopBottom(paint, *flatPaintData, y, y);
1028 this->validate(initialOffset, size);
1031 void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
1032 const SkPoint pos[], const SkPaint& paint) {
1033 size_t points = paint.countText(text, byteLength);
1037 bool canUseDrawH = true;
1038 SkScalar minY = pos[0].fY;
1039 SkScalar maxY = pos[0].fY;
1040 // check if the caller really should have used drawPosTextH()
1042 const SkScalar firstY = pos[0].fY;
1043 for (size_t index = 1; index < points; index++) {
1044 if (pos[index].fY != firstY) {
1045 canUseDrawH = false;
1046 if (pos[index].fY < minY) {
1047 minY = pos[index].fY;
1048 } else if (pos[index].fY > maxY) {
1049 maxY = pos[index].fY;
1055 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
1056 bool fast = canUseDrawH && fastBounds;
1058 // op + paint index + length + 'length' worth of data + num points
1059 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1062 size += 2 * sizeof(SkScalar); // + top & bottom
1064 // + y-pos + actual x-point data
1065 size += sizeof(SkScalar) + points * sizeof(SkScalar);
1068 size += points * sizeof(SkPoint);
1070 size += 2 * sizeof(SkScalar); // + top & bottom
1076 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1077 } else if (canUseDrawH) {
1078 op = DRAW_POS_TEXT_H;
1079 } else if (fastBounds) {
1080 op = DRAW_POS_TEXT_TOP_BOTTOM;
1084 size_t initialOffset = this->addDraw(op, &size);
1085 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
1086 const SkFlatData* flatPaintData = addPaint(paint);
1087 SkASSERT(flatPaintData);
1088 addText(text, byteLength);
1091 #ifdef SK_DEBUG_SIZE
1092 size_t start = fWriter.bytesWritten();
1096 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
1098 addScalar(pos[0].fY);
1099 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
1100 for (size_t index = 0; index < points; index++)
1101 *xptr++ = pos[index].fX;
1103 fWriter.writeMul4(pos, points * sizeof(SkPoint));
1105 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
1108 #ifdef SK_DEBUG_SIZE
1109 fPointBytes += fWriter.bytesWritten() - start;
1110 fPointWrites += points;
1112 this->validate(initialOffset, size);
1115 void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1116 const SkScalar xpos[], SkScalar constY,
1117 const SkPaint& paint) {
1119 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
1120 drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
1123 void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1124 const SkScalar xpos[], SkScalar constY,
1125 const SkPaint& paint, const SkFlatData* flatPaintData) {
1126 size_t points = paint.countText(text, byteLength);
1130 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
1132 // op + paint index + length + 'length' worth of data + num points
1133 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1135 size += 2 * sizeof(SkScalar); // + top & bottom
1137 // + y + the actual points
1138 size += 1 * kUInt32Size + points * sizeof(SkScalar);
1139 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
1141 SkASSERT(flatPaintData);
1142 addFlatPaint(flatPaintData);
1144 addText(text, byteLength);
1147 #ifdef SK_DEBUG_SIZE
1148 size_t start = fWriter.bytesWritten();
1151 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
1154 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1155 #ifdef SK_DEBUG_SIZE
1156 fPointBytes += fWriter.bytesWritten() - start;
1157 fPointWrites += points;
1159 this->validate(initialOffset, size);
1162 void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1163 const SkPath& path, const SkMatrix* matrix,
1164 const SkPaint& paint) {
1165 // op + paint index + length + 'length' worth of data + path index + matrix
1166 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1167 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
1168 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
1169 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
1171 addText(text, byteLength);
1174 this->validate(initialOffset, size);
1177 void SkPictureRecord::drawPicture(SkPicture& picture) {
1178 // op + picture index
1179 uint32_t size = 2 * kUInt32Size;
1180 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
1181 addPicture(picture);
1182 this->validate(initialOffset, size);
1185 void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1186 const SkPoint vertices[], const SkPoint texs[],
1187 const SkColor colors[], SkXfermode* xfer,
1188 const uint16_t indices[], int indexCount,
1189 const SkPaint& paint) {
1192 flags |= DRAW_VERTICES_HAS_TEXS;
1195 flags |= DRAW_VERTICES_HAS_COLORS;
1197 if (indexCount > 0) {
1198 flags |= DRAW_VERTICES_HAS_INDICES;
1201 SkXfermode::Mode mode;
1202 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1203 flags |= DRAW_VERTICES_HAS_XFER;
1207 // op + paint index + flags + vmode + vCount + vertices
1208 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1209 if (flags & DRAW_VERTICES_HAS_TEXS) {
1210 size += vertexCount * sizeof(SkPoint); // + uvs
1212 if (flags & DRAW_VERTICES_HAS_COLORS) {
1213 size += vertexCount * sizeof(SkColor); // + vert colors
1215 if (flags & DRAW_VERTICES_HAS_INDICES) {
1216 // + num indices + indices
1217 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1219 if (flags & DRAW_VERTICES_HAS_XFER) {
1220 size += kUInt32Size; // mode enum
1223 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
1224 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
1228 addInt(vertexCount);
1229 addPoints(vertices, vertexCount);
1230 if (flags & DRAW_VERTICES_HAS_TEXS) {
1231 addPoints(texs, vertexCount);
1233 if (flags & DRAW_VERTICES_HAS_COLORS) {
1234 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1236 if (flags & DRAW_VERTICES_HAS_INDICES) {
1238 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1240 if (flags & DRAW_VERTICES_HAS_XFER) {
1241 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1242 (void)xfer->asMode(&mode);
1245 this->validate(initialOffset, size);
1248 void SkPictureRecord::drawData(const void* data, size_t length) {
1249 // op + length + 'length' worth of data
1250 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
1251 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
1253 fWriter.writePad(data, length);
1254 this->validate(initialOffset, size);
1257 void SkPictureRecord::beginCommentGroup(const char* description) {
1258 // op/size + length of string + \0 terminated chars
1259 int length = strlen(description);
1260 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
1261 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
1262 fWriter.writeString(description, length);
1263 this->validate(initialOffset, size);
1266 void SkPictureRecord::addComment(const char* kywd, const char* value) {
1267 // op/size + 2x length of string + 2x \0 terminated chars
1268 int kywdLen = strlen(kywd);
1269 int valueLen = strlen(value);
1270 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
1271 size_t initialOffset = this->addDraw(COMMENT, &size);
1272 fWriter.writeString(kywd, kywdLen);
1273 fWriter.writeString(value, valueLen);
1274 this->validate(initialOffset, size);
1277 void SkPictureRecord::endCommentGroup() {
1279 uint32_t size = 1 * kUInt32Size;
1280 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1281 this->validate(initialOffset, size);
1284 ///////////////////////////////////////////////////////////////////////////////
1286 void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
1287 const int index = fBitmapHeap->insert(bitmap);
1288 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1289 // release builds, the invalid value will be recorded so that the reader will know that there
1291 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
1295 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
1296 fWriter.writeMatrix(matrix);
1299 const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1300 return fPaints.findAndReturnFlat(paint);
1303 const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
1304 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1305 this->addFlatPaint(data);
1309 void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1310 int index = flatPaint ? flatPaint->index() : 0;
1311 this->addInt(index);
1314 void SkPictureRecord::addPath(const SkPath& path) {
1315 if (NULL == fPathHeap) {
1316 fPathHeap = SkNEW(SkPathHeap);
1318 addInt(fPathHeap->append(path));
1321 void SkPictureRecord::addPicture(SkPicture& picture) {
1322 int index = fPictureRefs.find(&picture);
1323 if (index < 0) { // not found
1324 index = fPictureRefs.count();
1325 *fPictureRefs.append() = &picture;
1328 // follow the convention of recording a 1-based index
1332 void SkPictureRecord::addPoint(const SkPoint& point) {
1333 #ifdef SK_DEBUG_SIZE
1334 size_t start = fWriter.bytesWritten();
1336 fWriter.writePoint(point);
1337 #ifdef SK_DEBUG_SIZE
1338 fPointBytes += fWriter.bytesWritten() - start;
1343 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1344 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1345 #ifdef SK_DEBUG_SIZE
1346 fPointBytes += count * sizeof(SkPoint);
1351 void SkPictureRecord::addRect(const SkRect& rect) {
1352 #ifdef SK_DEBUG_SIZE
1353 size_t start = fWriter.bytesWritten();
1355 fWriter.writeRect(rect);
1356 #ifdef SK_DEBUG_SIZE
1357 fRectBytes += fWriter.bytesWritten() - start;
1362 void SkPictureRecord::addRectPtr(const SkRect* rect) {
1363 if (fWriter.writeBool(rect != NULL)) {
1364 fWriter.writeRect(*rect);
1368 void SkPictureRecord::addIRect(const SkIRect& rect) {
1369 fWriter.write(&rect, sizeof(rect));
1372 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1373 if (fWriter.writeBool(rect != NULL)) {
1374 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1378 void SkPictureRecord::addRRect(const SkRRect& rrect) {
1379 fWriter.writeRRect(rrect);
1382 void SkPictureRecord::addRegion(const SkRegion& region) {
1383 fWriter.writeRegion(region);
1386 void SkPictureRecord::addText(const void* text, size_t byteLength) {
1387 #ifdef SK_DEBUG_SIZE
1388 size_t start = fWriter.bytesWritten();
1391 fWriter.writePad(text, byteLength);
1392 #ifdef SK_DEBUG_SIZE
1393 fTextBytes += fWriter.bytesWritten() - start;
1398 ///////////////////////////////////////////////////////////////////////////////
1400 #ifdef SK_DEBUG_SIZE
1401 size_t SkPictureRecord::size() const {
1406 matrices(&sizeData);
1412 pictures(&sizeData);
1416 result += streamlen();
1420 int SkPictureRecord::bitmaps(size_t* size) const {
1422 int count = fBitmaps.count();
1423 for (int index = 0; index < count; index++)
1424 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1429 int SkPictureRecord::matrices(size_t* size) const {
1430 int count = fMatrices.count();
1431 *size = sizeof(fMatrices[0]) * count;
1435 int SkPictureRecord::paints(size_t* size) const {
1437 int count = fPaints.count();
1438 for (int index = 0; index < count; index++)
1439 result += sizeof(fPaints[index]) + fPaints[index]->size();
1444 int SkPictureRecord::paths(size_t* size) const {
1446 int count = fPaths.count();
1447 for (int index = 0; index < count; index++)
1448 result += sizeof(fPaths[index]) + fPaths[index]->size();
1453 int SkPictureRecord::regions(size_t* size) const {
1455 int count = fRegions.count();
1456 for (int index = 0; index < count; index++)
1457 result += sizeof(fRegions[index]) + fRegions[index]->size();
1462 size_t SkPictureRecord::streamlen() const {
1463 return fWriter.size();
1467 #ifdef SK_DEBUG_VALIDATE
1468 void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1469 SkASSERT(fWriter.size() == initialOffset + size);
1478 void SkPictureRecord::validateBitmaps() const {
1479 int count = fBitmapHeap->count();
1480 SkASSERT((unsigned) count < 0x1000);
1481 for (int index = 0; index < count; index++) {
1482 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
1488 void SkPictureRecord::validateMatrices() const {
1489 int count = fMatrices.count();
1490 SkASSERT((unsigned) count < 0x1000);
1491 for (int index = 0; index < count; index++) {
1492 const SkFlatData* matrix = fMatrices[index];
1494 // matrix->validate();
1498 void SkPictureRecord::validatePaints() const {
1499 int count = fPaints.count();
1500 SkASSERT((unsigned) count < 0x1000);
1501 for (int index = 0; index < count; index++) {
1502 const SkFlatData* paint = fPaints[index];
1504 // paint->validate();
1508 void SkPictureRecord::validatePaths() const {
1509 if (NULL == fPathHeap) {
1513 int count = fPathHeap->count();
1514 SkASSERT((unsigned) count < 0x1000);
1515 for (int index = 0; index < count; index++) {
1516 const SkPath& path = (*fPathHeap)[index];
1521 void SkPictureRecord::validateRegions() const {
1522 int count = fRegions.count();
1523 SkASSERT((unsigned) count < 0x1000);
1524 for (int index = 0; index < count; index++) {
1525 const SkFlatData* region = fRegions[index];
1527 // region->validate();