2 * Copyright 2011 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * 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
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
28 // just need a value that save or getSaveCount would never return
32 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
33 static int const kUInt32Size = 4;
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);
39 SkPictureRecord::SkPictureRecord(SkPicture* picture, const SkISize& dimensions, uint32_t flags)
40 : INHERITED(dimensions.width(), dimensions.height())
41 , fBoundingHierarchy(NULL)
43 , fFlattenableHeap(HEAP_BLOCK_SIZE)
44 , fPaints(&fFlattenableHeap)
46 , fOptsEnabled(kBeClever) {
48 fPointBytes = fRectBytes = fTextBytes = 0;
49 fPointWrites = fRectWrites = fTextWrites = 0;
53 fBitmapHeap = SkNEW(SkBitmapHeap);
54 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
56 #ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
57 fFirstSavedLayerIndex = kNoSavedLayerIndex;
60 fInitialSaveCount = kNoInitialSave;
62 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
67 SkPictureRecord::~SkPictureRecord() {
68 SkSafeUnref(fBitmapHeap);
69 SkSafeUnref(fBoundingHierarchy);
70 SkSafeUnref(fStateTree);
71 fFlattenableHeap.setBitmapStorage(NULL);
72 fPictureRefs.unrefAll();
75 ///////////////////////////////////////////////////////////////////////////////
77 // Return the offset of the paint inside a given op's byte stream. A zero
78 // return value means there is no paint (and you really shouldn't be calling
80 static inline size_t getPaintOffset(DrawType op, size_t opSize) {
81 // These offsets are where the paint would be if the op size doesn't overflow
82 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
83 0, // UNUSED - no paint
84 0, // CLIP_PATH - no paint
85 0, // CLIP_REGION - no paint
86 0, // CLIP_RECT - no paint
87 0, // CLIP_RRECT - no paint
88 0, // CONCAT - no paint
89 1, // DRAW_BITMAP - right after op code
90 1, // DRAW_BITMAP_MATRIX - right after op code
91 1, // DRAW_BITMAP_NINE - right after op code
92 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
93 0, // DRAW_CLEAR - no paint
94 0, // DRAW_DATA - no paint
95 1, // DRAW_OVAL - right after op code
96 1, // DRAW_PAINT - right after op code
97 1, // DRAW_PATH - right after op code
98 0, // DRAW_PICTURE - no paint
99 1, // DRAW_POINTS - right after op code
100 1, // DRAW_POS_TEXT - right after op code
101 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
102 1, // DRAW_POS_TEXT_H - right after op code
103 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
104 1, // DRAW_RECT - right after op code
105 1, // DRAW_RRECT - right after op code
106 1, // DRAW_SPRITE - right after op code
107 1, // DRAW_TEXT - right after op code
108 1, // DRAW_TEXT_ON_PATH - right after op code
109 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
110 1, // DRAW_VERTICES - right after op code
111 0, // RESTORE - no paint
112 0, // ROTATE - no paint
113 0, // SAVE - no paint
114 0, // SAVE_LAYER - see below - this paint's location varies
115 0, // SCALE - no paint
116 0, // SET_MATRIX - no paint
117 0, // SKEW - no paint
118 0, // TRANSLATE - no paint
119 0, // NOOP - no paint
120 0, // BEGIN_GROUP - no paint
121 0, // COMMENT - no paint
122 0, // END_GROUP - no paint
123 1, // DRAWDRRECT - right after op code
124 0, // PUSH_CULL - no paint
125 0, // POP_CULL - no paint
128 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
130 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
133 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
134 // This op's size overflows so an extra uint32_t will be written
136 overflow = sizeof(uint32_t);
139 if (SAVE_LAYER == op) {
140 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
141 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
143 if (kSaveLayerNoBoundsSize == opSize) {
144 return kSaveLayerNoBoundsPaintOffset + overflow;
146 SkASSERT(kSaveLayerWithBoundsSize == opSize);
147 return kSaveLayerWithBoundsPaintOffset + overflow;
151 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
152 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
155 void SkPictureRecord::willSave(SaveFlags flags) {
157 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
160 // record the offset to us, making it non-positive to distinguish a save
161 // from a clip entry.
162 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
163 this->recordSave(flags);
166 this->INHERITED::willSave(flags);
169 void SkPictureRecord::recordSave(SaveFlags flags) {
171 size_t size = kSaveSize;
172 size_t initialOffset = this->addDraw(SAVE, &size);
175 this->validate(initialOffset, size);
178 SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
179 const SkPaint* paint, SaveFlags flags) {
181 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
182 fMCMgr.saveLayer(bounds, paint, flags);
184 // record the offset to us, making it non-positive to distinguish a save
185 // from a clip entry.
186 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
187 this->recordSaveLayer(bounds, paint, flags);
188 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
189 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
193 this->INHERITED::willSaveLayer(bounds, paint, flags);
194 /* No need for a (potentially very big) layer which we don't actually need
195 at this time (and may not be able to afford since during record our
196 clip starts out the size of the picture, which is often much larger
197 than the size of the actual device we'll use during playback).
199 return kNoLayer_SaveLayerStrategy;
202 void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
204 // op + bool for 'bounds'
205 size_t size = 2 * kUInt32Size;
206 if (NULL != bounds) {
207 size += sizeof(*bounds); // + rect
209 // + paint index + flags
210 size += 2 * kUInt32Size;
212 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
214 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
215 this->addRectPtr(bounds);
216 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
217 this->addPaintPtr(paint);
220 this->validate(initialOffset, size);
223 bool SkPictureRecord::isDrawingToLayer() const {
224 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
225 return fMCMgr.isDrawingToLayer();
227 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
232 * Read the op code from 'offset' in 'writer'.
235 static DrawType peek_op(SkWriter32* writer, size_t offset) {
236 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
241 * Read the op code from 'offset' in 'writer' and extract the size too.
243 static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
244 uint32_t peek = writer->readTAt<uint32_t>(offset);
247 UNPACK_8_24(peek, op, *size);
248 if (MASK_24 == *size) {
249 // size required its own slot right after the op code
250 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
252 return (DrawType) op;
255 #ifdef TRACK_COLLAPSE_STATS
256 static int gCollapseCount, gCollapseCalls;
259 // Is the supplied paint simply a color?
260 static bool is_simple(const SkPaint& p) {
261 intptr_t orAccum = (intptr_t)p.getPathEffect() |
262 (intptr_t)p.getShader() |
263 (intptr_t)p.getXfermode() |
264 (intptr_t)p.getMaskFilter() |
265 (intptr_t)p.getColorFilter() |
266 (intptr_t)p.getRasterizer() |
267 (intptr_t)p.getLooper() |
268 (intptr_t)p.getImageFilter();
272 // CommandInfos are fed to the 'match' method and filled in with command
281 * Attempt to match the provided pattern of commands starting at 'offset'
282 * in the byte stream and stopping at the end of the stream. Upon success,
283 * return true with all the pattern information filled out in the result
284 * array (i.e., actual ops, offsets and sizes).
285 * Note this method skips any NOOPs seen in the stream
287 static bool match(SkWriter32* writer, uint32_t offset,
288 int* pattern, CommandInfo* result, int numCommands) {
289 SkASSERT(offset < writer->bytesWritten());
291 uint32_t curOffset = offset;
292 uint32_t curSize = 0;
294 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
295 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
296 while (NOOP == op && curOffset < writer->bytesWritten()) {
297 curOffset += curSize;
298 op = peek_op_and_size(writer, curOffset, &curSize);
301 if (curOffset >= writer->bytesWritten()) {
302 return false; // ran out of byte stream
305 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
306 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
307 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
310 } else if (op != pattern[numMatched]) {
314 result[numMatched].fActualOp = op;
315 result[numMatched].fOffset = curOffset;
316 result[numMatched].fSize = curSize;
318 curOffset += curSize;
321 if (numMatched != numCommands) {
325 curOffset += curSize;
326 if (curOffset < writer->bytesWritten()) {
327 // Something else between the last command and the end of the stream
334 // temporarily here to make code review easier
335 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
336 SkPaintDictionary* paintDict,
337 const CommandInfo& saveLayerInfo,
338 const CommandInfo& dbmInfo);
341 * Restore has just been called (but not recorded), look back at the
342 * matching save* and see if we are in the configuration:
344 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
346 * where the saveLayer's color can be moved into the drawBitmap*'s paint
348 static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
349 SkPaintDictionary* paintDict) {
350 // back up to the save block
351 // TODO: add a stack to track save*/restore offsets rather than searching backwards
353 offset = writer->readTAt<uint32_t>(offset);
356 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
357 CommandInfo result[SK_ARRAY_COUNT(pattern)];
359 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
363 if (kSaveLayerWithBoundsSize == result[0].fSize) {
364 // The saveLayer's bound can offset where the dbm is drawn
368 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
369 result[0], result[1]);
373 * Convert the command code located at 'offset' to a NOOP. Leave the size
374 * field alone so the NOOP can be skipped later.
376 static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
377 uint32_t command = writer->readTAt<uint32_t>(offset);
378 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
382 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
383 * Return true on success; false otherwise.
385 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
386 SkPaintDictionary* paintDict,
387 const CommandInfo& saveLayerInfo,
388 const CommandInfo& dbmInfo) {
389 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
390 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
391 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
392 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
393 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
395 size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
396 size_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
398 // we have a match, now we need to get the paints involved
399 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
400 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
402 if (0 == saveLayerPaintId) {
403 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
404 // and signal the caller (by returning true) to not add the RESTORE op
405 convert_command_to_noop(writer, saveLayerInfo.fOffset);
409 if (0 == dbmPaintId) {
410 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
411 // and signal the caller (by returning true) to not add the RESTORE op
412 convert_command_to_noop(writer, saveLayerInfo.fOffset);
413 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
417 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
418 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
422 // For this optimization we only fold the saveLayer and drawBitmapRect
423 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
424 // and the only difference in the colors is that the saveLayer's can have
425 // an alpha while the drawBitmapRect's is opaque.
426 // TODO: it should be possible to fold them together even if they both
427 // have different non-255 alphas
428 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
430 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
431 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
435 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
436 SkColorGetA(saveLayerPaint->getColor()));
437 dbmPaint->setColor(newColor);
439 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
444 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
445 convert_command_to_noop(writer, saveLayerInfo.fOffset);
446 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
451 * Restore has just been called (but not recorded), look back at the
452 * matching save* and see if we are in the configuration:
453 * SAVE_LAYER (with NULL == bounds)
456 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
459 * where the saveLayer's color can be moved into the drawBitmap*'s paint
461 static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
462 SkPaintDictionary* paintDict) {
464 // back up to the save block
465 // TODO: add a stack to track save*/restore offsets rather than searching backwards
467 offset = writer->readTAt<uint32_t>(offset);
470 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
471 CommandInfo result[SK_ARRAY_COUNT(pattern)];
473 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
477 if (kSaveLayerWithBoundsSize == result[0].fSize) {
478 // The saveLayer's bound can offset where the dbm is drawn
482 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
483 result[0], result[3]);
486 static bool is_drawing_op(DrawType op) {
487 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
491 * Restore has just been called (but not recorded), so look back at the
492 * matching save(), and see if we can eliminate the pair of them, due to no
493 * intervening matrix/clip calls.
495 * If so, update the writer and return true, in which case we won't even record
496 * the restore() call. If we still need the restore(), return false.
498 static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
499 SkPaintDictionary* paintDict) {
500 #ifdef TRACK_COLLAPSE_STATS
504 int32_t restoreOffset = (int32_t)writer->bytesWritten();
506 // back up to the save block
508 offset = writer->readTAt<uint32_t>(offset);
511 // now offset points to a save
514 DrawType op = peek_op_and_size(writer, offset, &opSize);
515 if (SAVE_LAYER == op) {
516 // not ready to cull these out yet (mrr)
519 SkASSERT(SAVE == op);
520 SkASSERT(kSaveSize == opSize);
522 // get the save flag (last 4-bytes of the space allocated for the opSize)
523 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
524 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
525 // This function's optimization is only correct for kMatrixClip style saves.
526 // TODO: set checkMatrix & checkClip booleans here and then check for the
527 // offending operations in the following loop.
531 // Walk forward until we get back to either a draw-verb (abort) or we hit
532 // our restore (success).
533 int32_t saveOffset = offset;
536 while (offset < restoreOffset) {
537 op = peek_op_and_size(writer, offset, &opSize);
538 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
539 // drawing verb, abort
545 #ifdef TRACK_COLLAPSE_STATS
547 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
548 (double)gCollapseCount / gCollapseCalls, "%");
551 writer->rewindToOffset(saveOffset);
555 typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
556 SkPaintDictionary* paintDict);
557 enum PictureRecordOptType {
558 kRewind_OptType, // Optimization rewinds the command stream
559 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
562 enum PictureRecordOptFlags {
563 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
564 // SkPicture has a bounding box hierarchy.
567 struct PictureRecordOpt {
568 PictureRecordOptProc fProc;
569 PictureRecordOptType fType;
573 * A list of the optimizations that are tried upon seeing a restore
574 * TODO: add a real API for such optimizations
575 * Add the ability to fire optimizations on any op (not just RESTORE)
577 static const PictureRecordOpt gPictureRecordOpts[] = {
578 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
579 // because it is redundant with the state traversal optimization in
580 // SkPictureStateTree, and applying the optimization introduces significant
581 // record time overhead because it requires rewinding contents that were
582 // recorded into the BBoxHierarchy.
583 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
584 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
585 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
588 // This is called after an optimization has been applied to the command stream
589 // in order to adjust the contents and state of the bounding box hierarchy and
590 // state tree to reflect the optimization.
591 static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
592 SkBBoxHierarchy* boundingHierarchy) {
594 case kCollapseSaveLayer_OptType:
595 if (NULL != stateTree) {
596 stateTree->saveCollapsed();
599 case kRewind_OptType:
600 if (NULL != boundingHierarchy) {
601 boundingHierarchy->rewindInserts();
603 // Note: No need to touch the state tree for this to work correctly.
604 // Unused branches do not burden the playback, and pruning the tree
605 // would be O(N^2), so it is best to leave it alone.
612 void SkPictureRecord::willRestore() {
613 // FIXME: SkDeferredCanvas needs to be refactored to respect
614 // save/restore balancing so that the following test can be
615 // turned on permanently.
617 SkASSERT(fRestoreOffsetStack.count() > 1);
620 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
621 if (fMCMgr.getSaveCount() == 1) {
627 // check for underflow
628 if (fRestoreOffsetStack.count() == 0) {
632 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
633 fFirstSavedLayerIndex = kNoSavedLayerIndex;
638 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
639 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
640 && NULL != fBoundingHierarchy) {
643 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
644 // Some optimization fired so don't add the RESTORE
645 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
646 fStateTree, fBoundingHierarchy);
652 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
653 // No optimization fired so add the RESTORE
654 this->recordRestore();
657 fRestoreOffsetStack.pop();
660 this->INHERITED::willRestore();
663 void SkPictureRecord::recordRestore(bool fillInSkips) {
665 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
667 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
668 size_t initialOffset = this->addDraw(RESTORE, &size);
669 this->validate(initialOffset, size);
672 void SkPictureRecord::recordTranslate(const SkMatrix& m) {
673 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
676 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
677 size_t initialOffset = this->addDraw(TRANSLATE, &size);
678 this->addScalar(m.getTranslateX());
679 this->addScalar(m.getTranslateY());
680 this->validate(initialOffset, size);
683 void SkPictureRecord::recordScale(const SkMatrix& m) {
684 SkASSERT(SkMatrix::kScale_Mask == m.getType());
687 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
688 size_t initialOffset = this->addDraw(SCALE, &size);
689 this->addScalar(m.getScaleX());
690 this->addScalar(m.getScaleY());
691 this->validate(initialOffset, size);
694 void SkPictureRecord::didConcat(const SkMatrix& matrix) {
696 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
697 fMCMgr.concat(matrix);
699 switch (matrix.getType()) {
700 case SkMatrix::kTranslate_Mask:
701 this->recordTranslate(matrix);
703 case SkMatrix::kScale_Mask:
704 this->recordScale(matrix);
707 this->recordConcat(matrix);
711 this->INHERITED::didConcat(matrix);
714 void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
715 this->validate(fWriter.bytesWritten(), 0);
717 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
718 size_t initialOffset = this->addDraw(CONCAT, &size);
719 this->addMatrix(matrix);
720 this->validate(initialOffset, size);
723 void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
725 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
726 fMCMgr.setMatrix(matrix);
728 this->validate(fWriter.bytesWritten(), 0);
730 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
731 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
732 this->addMatrix(matrix);
733 this->validate(initialOffset, size);
735 this->INHERITED::didSetMatrix(matrix);
738 static bool regionOpExpands(SkRegion::Op op) {
740 case SkRegion::kUnion_Op:
741 case SkRegion::kXOR_Op:
742 case SkRegion::kReverseDifference_Op:
743 case SkRegion::kReplace_Op:
745 case SkRegion::kIntersect_Op:
746 case SkRegion::kDifference_Op:
749 SkDEBUGFAIL("unknown region op");
754 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
755 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
756 fMCMgr.fillInSkips(&fWriter, restoreOffset);
759 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
760 int32_t offset = fRestoreOffsetStack.top();
762 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
763 fWriter.overwriteTAt(offset, restoreOffset);
768 // assert that the final offset value points to a save verb
770 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
771 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
776 void SkPictureRecord::beginRecording() {
777 // we have to call this *after* our constructor, to ensure that it gets
778 // recorded. This is balanced by restoreToCount() call from endRecording,
779 // which in-turn calls our overridden restore(), so those get recorded too.
780 fInitialSaveCount = this->save();
783 void SkPictureRecord::endRecording() {
784 SkASSERT(kNoInitialSave != fInitialSaveCount);
785 this->restoreToCount(fInitialSaveCount);
786 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
791 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
792 int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
793 size_t offset = fWriter.bytesWritten();
798 size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
799 if (fRestoreOffsetStack.isEmpty()) {
803 // The RestoreOffset field is initially filled with a placeholder
804 // value that points to the offset of the previous RestoreOffset
805 // in the current stack level, thus forming a linked list so that
806 // the restore offsets can be filled in when the corresponding
807 // restore command is recorded.
808 int32_t prevOffset = fRestoreOffsetStack.top();
810 if (regionOpExpands(op)) {
811 // Run back through any previous clip ops, and mark their offset to
812 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
813 // they could hide this clips ability to expand the clip (i.e. go from
814 // empty to non-empty).
815 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
817 // Reset the pointer back to the previous clip so that subsequent
818 // restores don't overwrite the offsets we just cleared.
822 size_t offset = fWriter.bytesWritten();
823 this->addInt(prevOffset);
824 fRestoreOffsetStack.top() = SkToU32(offset);
829 void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
831 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
832 fMCMgr.clipRect(rect, op, doAA);
834 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
836 this->INHERITED::onClipRect(rect, op, edgeStyle);
839 size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
840 // id + rect + clip params
841 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
842 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
843 size += kUInt32Size; // + restore offset
845 // recordRestoreOffsetPlaceholder doesn't always write an offset
846 if (!fRestoreOffsetStack.isEmpty()) {
851 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
853 this->addInt(ClipParams_pack(op, doAA));
854 size_t offset = this->recordRestoreOffsetPlaceholder(op);
856 this->validate(initialOffset, size);
860 void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
862 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
863 fMCMgr.clipRRect(rrect, op, doAA);
865 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
867 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
868 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
870 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
874 size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
875 // op + rrect + clip params
876 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
877 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
878 size += kUInt32Size; // + restore offset
880 // recordRestoreOffsetPlaceholder doesn't always write an offset
881 if (!fRestoreOffsetStack.isEmpty()) {
886 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
887 this->addRRect(rrect);
888 this->addInt(ClipParams_pack(op, doAA));
889 size_t offset = recordRestoreOffsetPlaceholder(op);
890 this->validate(initialOffset, size);
894 void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
896 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
897 fMCMgr.clipPath(path, op, doAA);
899 int pathID = this->addPathToHeap(path);
900 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
903 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
904 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
905 path.isInverseFillType());
907 this->INHERITED::onClipPath(path, op, edgeStyle);
911 size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
912 // op + path index + clip params
913 size_t size = 3 * kUInt32Size;
914 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
915 size += kUInt32Size; // + restore offset
917 // recordRestoreOffsetPlaceholder doesn't always write an offset
918 if (!fRestoreOffsetStack.isEmpty()) {
923 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
924 this->addInt(pathID);
925 this->addInt(ClipParams_pack(op, doAA));
926 size_t offset = recordRestoreOffsetPlaceholder(op);
927 this->validate(initialOffset, size);
931 void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
933 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
934 fMCMgr.clipRegion(region, op);
936 this->recordClipRegion(region, op);
938 this->INHERITED::onClipRegion(region, op);
941 size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
942 // op + clip params + region
943 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
944 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
945 size += kUInt32Size; // + restore offset
947 // recordRestoreOffsetPlaceholder doesn't always write an offset
948 if (!fRestoreOffsetStack.isEmpty()) {
953 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
954 this->addRegion(region);
955 this->addInt(ClipParams_pack(op, false));
956 size_t offset = this->recordRestoreOffsetPlaceholder(op);
958 this->validate(initialOffset, size);
962 void SkPictureRecord::clear(SkColor color) {
964 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
965 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
969 size_t size = 2 * kUInt32Size;
970 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
972 this->validate(initialOffset, size);
975 void SkPictureRecord::drawPaint(const SkPaint& paint) {
977 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
978 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
982 size_t size = 2 * kUInt32Size;
983 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
984 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
985 this->addPaint(paint);
986 this->validate(initialOffset, size);
989 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
990 const SkPaint& paint) {
992 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
993 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
996 // op + paint index + mode + count + point data
997 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
998 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
999 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
1000 this->addPaint(paint);
1002 this->addInt(SkToInt(count));
1003 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1004 this->validate(initialOffset, size);
1007 void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
1009 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1010 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1013 // op + paint index + rect
1014 size_t size = 2 * kUInt32Size + sizeof(oval);
1015 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
1016 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
1017 this->addPaint(paint);
1018 this->addRect(oval);
1019 this->validate(initialOffset, size);
1022 void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
1024 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1025 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1028 // op + paint index + rect
1029 size_t size = 2 * kUInt32Size + sizeof(rect);
1030 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
1031 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
1032 this->addPaint(paint);
1033 this->addRect(rect);
1034 this->validate(initialOffset, size);
1037 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1039 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1040 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1043 if (rrect.isRect() && kBeClever) {
1044 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
1045 } else if (rrect.isOval() && kBeClever) {
1046 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
1048 // op + paint index + rrect
1049 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1050 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
1051 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
1052 this->addPaint(paint);
1053 this->addRRect(rrect);
1054 this->validate(initialOffset, size);
1058 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1059 const SkPaint& paint) {
1061 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1062 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1065 // op + paint index + rrects
1066 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1067 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
1068 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1069 this->addPaint(paint);
1070 this->addRRect(outer);
1071 this->addRRect(inner);
1072 this->validate(initialOffset, size);
1075 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
1077 if (paint.isAntiAlias() && !path.isConvex()) {
1078 fPicture->incAAConcavePaths();
1080 if (SkPaint::kStroke_Style == paint.getStyle() &&
1081 0 == paint.getStrokeWidth()) {
1082 fPicture->incAAHairlineConcavePaths();
1086 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1087 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1090 // op + paint index + path index
1091 size_t size = 3 * kUInt32Size;
1092 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
1093 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
1094 this->addPaint(paint);
1095 this->addPath(path);
1096 this->validate(initialOffset, size);
1099 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
1100 const SkPaint* paint = NULL) {
1101 if (bitmap.drawsNothing() && kBeClever) {
1105 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1106 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1109 // op + paint index + bitmap index + left + top
1110 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
1111 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
1112 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
1113 this->addPaintPtr(paint);
1114 this->addBitmap(bitmap);
1115 this->addScalar(left);
1116 this->addScalar(top);
1117 this->validate(initialOffset, size);
1120 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
1121 const SkRect& dst, const SkPaint* paint,
1122 DrawBitmapRectFlags flags) {
1123 if (bitmap.drawsNothing() && kBeClever) {
1127 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1128 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1130 // id + paint index + bitmap index + bool for 'src' + flags
1131 size_t size = 5 * kUInt32Size;
1133 size += sizeof(*src); // + rect
1135 size += sizeof(dst); // + rect
1137 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
1138 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1139 == fWriter.bytesWritten());
1140 this->addPaintPtr(paint);
1141 this->addBitmap(bitmap);
1142 this->addRectPtr(src); // may be null
1144 this->addInt(flags);
1145 this->validate(initialOffset, size);
1148 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1149 const SkPaint* paint) {
1150 if (bitmap.drawsNothing() && kBeClever) {
1154 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1155 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1158 // id + paint index + bitmap index + matrix
1159 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
1160 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
1161 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
1162 this->addPaintPtr(paint);
1163 this->addBitmap(bitmap);
1164 this->addMatrix(matrix);
1165 this->validate(initialOffset, size);
1168 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1169 const SkRect& dst, const SkPaint* paint) {
1170 if (bitmap.drawsNothing() && kBeClever) {
1174 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1175 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1178 // op + paint index + bitmap id + center + dst rect
1179 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
1180 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
1181 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
1182 this->addPaintPtr(paint);
1183 this->addBitmap(bitmap);
1184 this->addIRect(center);
1186 this->validate(initialOffset, size);
1189 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
1190 const SkPaint* paint = NULL) {
1191 if (bitmap.drawsNothing() && kBeClever) {
1195 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1196 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1199 // op + paint index + bitmap index + left + top
1200 size_t size = 5 * kUInt32Size;
1201 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
1202 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
1203 this->addPaintPtr(paint);
1204 this->addBitmap(bitmap);
1207 this->validate(initialOffset, size);
1210 void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
1211 SkPaint::FontMetrics metrics;
1212 paint.getFontMetrics(&metrics);
1214 // construct a rect so we can see any adjustments from the paint.
1215 // we use 0,1 for left,right, just so the rect isn't empty
1216 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
1217 (void)paint.computeFastBounds(bounds, &bounds);
1218 topbot[0] = bounds.fTop;
1219 topbot[1] = bounds.fBottom;
1222 void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
1223 SkScalar minY, SkScalar maxY) {
1224 WriteTopBot(paint, flat);
1225 this->addScalar(flat.topBot()[0] + minY);
1226 this->addScalar(flat.topBot()[1] + maxY);
1229 void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1230 const SkPaint& paint) {
1232 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1233 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1236 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1238 // op + paint index + length + 'length' worth of chars + x + y
1239 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1241 size += 2 * sizeof(SkScalar); // + top & bottom
1244 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
1245 size_t initialOffset = this->addDraw(op, &size);
1246 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
1247 const SkFlatData* flatPaintData = addPaint(paint);
1248 SkASSERT(flatPaintData);
1249 this->addText(text, byteLength);
1253 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
1255 this->validate(initialOffset, size);
1258 void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1259 const SkPaint& paint) {
1261 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1262 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1265 int points = paint.countText(text, byteLength);
1269 bool canUseDrawH = true;
1270 SkScalar minY = pos[0].fY;
1271 SkScalar maxY = pos[0].fY;
1272 // check if the caller really should have used drawPosTextH()
1274 const SkScalar firstY = pos[0].fY;
1275 for (int index = 1; index < points; index++) {
1276 if (pos[index].fY != firstY) {
1277 canUseDrawH = false;
1278 if (pos[index].fY < minY) {
1279 minY = pos[index].fY;
1280 } else if (pos[index].fY > maxY) {
1281 maxY = pos[index].fY;
1287 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1288 bool fast = canUseDrawH && fastBounds && kBeClever;
1290 // op + paint index + length + 'length' worth of data + num points
1291 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1294 size += 2 * sizeof(SkScalar); // + top & bottom
1296 // + y-pos + actual x-point data
1297 size += sizeof(SkScalar) + points * sizeof(SkScalar);
1300 size += points * sizeof(SkPoint);
1302 size += 2 * sizeof(SkScalar); // + top & bottom
1308 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1309 } else if (canUseDrawH) {
1310 op = DRAW_POS_TEXT_H;
1311 } else if (fastBounds) {
1312 op = DRAW_POS_TEXT_TOP_BOTTOM;
1316 size_t initialOffset = this->addDraw(op, &size);
1317 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
1318 const SkFlatData* flatPaintData = this->addPaint(paint);
1319 SkASSERT(flatPaintData);
1320 this->addText(text, byteLength);
1321 this->addInt(points);
1323 #ifdef SK_DEBUG_SIZE
1324 size_t start = fWriter.bytesWritten();
1328 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
1330 this->addScalar(pos[0].fY);
1331 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
1332 for (int index = 0; index < points; index++)
1333 *xptr++ = pos[index].fX;
1335 fWriter.writeMul4(pos, points * sizeof(SkPoint));
1337 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
1340 #ifdef SK_DEBUG_SIZE
1341 fPointBytes += fWriter.bytesWritten() - start;
1342 fPointWrites += points;
1344 this->validate(initialOffset, size);
1347 void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1348 SkScalar constY, const SkPaint& paint) {
1349 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1350 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1353 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
1354 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
1357 void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1358 const SkScalar xpos[], SkScalar constY,
1359 const SkPaint& paint, const SkFlatData* flatPaintData) {
1360 int points = paint.countText(text, byteLength);
1361 if (0 == points && kBeClever) {
1365 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1367 // op + paint index + length + 'length' worth of data + num points
1368 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1370 size += 2 * sizeof(SkScalar); // + top & bottom
1372 // + y + the actual points
1373 size += 1 * kUInt32Size + points * sizeof(SkScalar);
1374 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
1376 SkASSERT(flatPaintData);
1377 this->addFlatPaint(flatPaintData);
1379 this->addText(text, byteLength);
1380 this->addInt(points);
1382 #ifdef SK_DEBUG_SIZE
1383 size_t start = fWriter.bytesWritten();
1386 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
1388 this->addScalar(constY);
1389 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1390 #ifdef SK_DEBUG_SIZE
1391 fPointBytes += fWriter.bytesWritten() - start;
1392 fPointWrites += points;
1394 this->validate(initialOffset, size);
1397 void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
1398 const SkMatrix* matrix, const SkPaint& paint) {
1399 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1400 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1403 // op + paint index + length + 'length' worth of data + path index + matrix
1404 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1405 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
1406 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
1407 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
1408 this->addPaint(paint);
1409 this->addText(text, byteLength);
1410 this->addPath(path);
1412 this->validate(initialOffset, size);
1415 void SkPictureRecord::drawPicture(SkPicture& picture) {
1417 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1418 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1421 // op + picture index
1422 size_t size = 2 * kUInt32Size;
1423 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
1424 this->addPicture(picture);
1425 this->validate(initialOffset, size);
1428 void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1429 const SkPoint vertices[], const SkPoint texs[],
1430 const SkColor colors[], SkXfermode* xfer,
1431 const uint16_t indices[], int indexCount,
1432 const SkPaint& paint) {
1434 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1435 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1440 flags |= DRAW_VERTICES_HAS_TEXS;
1443 flags |= DRAW_VERTICES_HAS_COLORS;
1445 if (indexCount > 0) {
1446 flags |= DRAW_VERTICES_HAS_INDICES;
1449 SkXfermode::Mode mode;
1450 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1451 flags |= DRAW_VERTICES_HAS_XFER;
1455 // op + paint index + flags + vmode + vCount + vertices
1456 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1457 if (flags & DRAW_VERTICES_HAS_TEXS) {
1458 size += vertexCount * sizeof(SkPoint); // + uvs
1460 if (flags & DRAW_VERTICES_HAS_COLORS) {
1461 size += vertexCount * sizeof(SkColor); // + vert colors
1463 if (flags & DRAW_VERTICES_HAS_INDICES) {
1464 // + num indices + indices
1465 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1467 if (flags & DRAW_VERTICES_HAS_XFER) {
1468 size += kUInt32Size; // mode enum
1471 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
1472 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
1473 this->addPaint(paint);
1474 this->addInt(flags);
1475 this->addInt(vmode);
1476 this->addInt(vertexCount);
1477 this->addPoints(vertices, vertexCount);
1478 if (flags & DRAW_VERTICES_HAS_TEXS) {
1479 this->addPoints(texs, vertexCount);
1481 if (flags & DRAW_VERTICES_HAS_COLORS) {
1482 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1484 if (flags & DRAW_VERTICES_HAS_INDICES) {
1485 this->addInt(indexCount);
1486 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1488 if (flags & DRAW_VERTICES_HAS_XFER) {
1489 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1490 (void)xfer->asMode(&mode);
1493 this->validate(initialOffset, size);
1496 void SkPictureRecord::drawData(const void* data, size_t length) {
1498 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1499 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1502 // op + length + 'length' worth of data
1503 size_t size = 2 * kUInt32Size + SkAlign4(length);
1504 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
1505 this->addInt(SkToInt(length));
1506 fWriter.writePad(data, length);
1507 this->validate(initialOffset, size);
1510 void SkPictureRecord::beginCommentGroup(const char* description) {
1511 // op/size + length of string + \0 terminated chars
1512 size_t length = strlen(description);
1513 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
1514 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
1515 fWriter.writeString(description, length);
1516 this->validate(initialOffset, size);
1519 void SkPictureRecord::addComment(const char* kywd, const char* value) {
1520 // op/size + 2x length of string + 2x \0 terminated chars
1521 size_t kywdLen = strlen(kywd);
1522 size_t valueLen = strlen(value);
1523 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
1524 size_t initialOffset = this->addDraw(COMMENT, &size);
1525 fWriter.writeString(kywd, kywdLen);
1526 fWriter.writeString(value, valueLen);
1527 this->validate(initialOffset, size);
1530 void SkPictureRecord::endCommentGroup() {
1532 size_t size = 1 * kUInt32Size;
1533 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1534 this->validate(initialOffset, size);
1537 // [op/size] [rect] [skip offset]
1538 static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1539 void SkPictureRecord::onPushCull(const SkRect& cullRect) {
1540 size_t size = kPushCullOpSize;
1541 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1542 // PUSH_CULL's size should stay constant (used to rewind).
1543 SkASSERT(size == kPushCullOpSize);
1545 this->addRect(cullRect);
1546 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
1548 this->validate(initialOffset, size);
1551 void SkPictureRecord::onPopCull() {
1552 SkASSERT(!fCullOffsetStack.isEmpty());
1554 uint32_t cullSkipOffset = fCullOffsetStack.top();
1555 fCullOffsetStack.pop();
1557 // Collapse empty push/pop pairs.
1558 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeClever) {
1559 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1560 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1561 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1566 size_t size = kUInt32Size;
1567 size_t initialOffset = this->addDraw(POP_CULL, &size);
1569 // update the cull skip offset to point past this op.
1570 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
1572 this->validate(initialOffset, size);
1575 ///////////////////////////////////////////////////////////////////////////////
1577 SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
1581 int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
1582 const int index = fBitmapHeap->insert(bitmap);
1583 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1584 // release builds, the invalid value will be recorded so that the reader will know that there
1586 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
1587 this->addInt(index);
1591 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
1592 fWriter.writeMatrix(matrix);
1595 const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1596 return fPaints.findAndReturnFlat(paint);
1599 const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
1600 if (NULL != paint && NULL != paint->getPathEffect()) {
1601 fPicture->incPaintWithPathEffectUses();
1604 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1605 this->addFlatPaint(data);
1609 void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1610 int index = flatPaint ? flatPaint->index() : 0;
1611 this->addInt(index);
1614 int SkPictureRecord::addPathToHeap(const SkPath& path) {
1615 return fPicture->addPathToHeap(path);
1618 void SkPictureRecord::addPath(const SkPath& path) {
1619 this->addInt(this->addPathToHeap(path));
1622 void SkPictureRecord::addPicture(SkPicture& picture) {
1623 int index = fPictureRefs.find(&picture);
1624 if (index < 0) { // not found
1625 index = fPictureRefs.count();
1626 *fPictureRefs.append() = &picture;
1629 // follow the convention of recording a 1-based index
1630 this->addInt(index + 1);
1633 void SkPictureRecord::addPoint(const SkPoint& point) {
1634 #ifdef SK_DEBUG_SIZE
1635 size_t start = fWriter.bytesWritten();
1637 fWriter.writePoint(point);
1638 #ifdef SK_DEBUG_SIZE
1639 fPointBytes += fWriter.bytesWritten() - start;
1644 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1645 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1646 #ifdef SK_DEBUG_SIZE
1647 fPointBytes += count * sizeof(SkPoint);
1652 void SkPictureRecord::addRect(const SkRect& rect) {
1653 #ifdef SK_DEBUG_SIZE
1654 size_t start = fWriter.bytesWritten();
1656 fWriter.writeRect(rect);
1657 #ifdef SK_DEBUG_SIZE
1658 fRectBytes += fWriter.bytesWritten() - start;
1663 void SkPictureRecord::addRectPtr(const SkRect* rect) {
1664 if (fWriter.writeBool(rect != NULL)) {
1665 fWriter.writeRect(*rect);
1669 void SkPictureRecord::addIRect(const SkIRect& rect) {
1670 fWriter.write(&rect, sizeof(rect));
1673 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1674 if (fWriter.writeBool(rect != NULL)) {
1675 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1679 void SkPictureRecord::addRRect(const SkRRect& rrect) {
1680 fWriter.writeRRect(rrect);
1683 void SkPictureRecord::addRegion(const SkRegion& region) {
1684 fWriter.writeRegion(region);
1687 void SkPictureRecord::addText(const void* text, size_t byteLength) {
1688 #ifdef SK_DEBUG_SIZE
1689 size_t start = fWriter.bytesWritten();
1691 addInt(SkToInt(byteLength));
1692 fWriter.writePad(text, byteLength);
1693 #ifdef SK_DEBUG_SIZE
1694 fTextBytes += fWriter.bytesWritten() - start;
1699 ///////////////////////////////////////////////////////////////////////////////
1701 #ifdef SK_DEBUG_SIZE
1702 size_t SkPictureRecord::size() const {
1707 matrices(&sizeData);
1713 pictures(&sizeData);
1717 result += streamlen();
1721 int SkPictureRecord::bitmaps(size_t* size) const {
1723 int count = fBitmaps.count();
1724 for (int index = 0; index < count; index++)
1725 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1730 int SkPictureRecord::matrices(size_t* size) const {
1731 int count = fMatrices.count();
1732 *size = sizeof(fMatrices[0]) * count;
1736 int SkPictureRecord::paints(size_t* size) const {
1738 int count = fPaints.count();
1739 for (int index = 0; index < count; index++)
1740 result += sizeof(fPaints[index]) + fPaints[index]->size();
1745 int SkPictureRecord::paths(size_t* size) const {
1747 int count = fPaths.count();
1748 for (int index = 0; index < count; index++)
1749 result += sizeof(fPaths[index]) + fPaths[index]->size();
1754 int SkPictureRecord::regions(size_t* size) const {
1756 int count = fRegions.count();
1757 for (int index = 0; index < count; index++)
1758 result += sizeof(fRegions[index]) + fRegions[index]->size();
1763 size_t SkPictureRecord::streamlen() const {
1764 return fWriter.size();
1768 #ifdef SK_DEBUG_VALIDATE
1769 void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1770 SkASSERT(fWriter.size() == initialOffset + size);
1779 void SkPictureRecord::validateBitmaps() const {
1780 int count = fBitmapHeap->count();
1781 SkASSERT((unsigned) count < 0x1000);
1782 for (int index = 0; index < count; index++) {
1783 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
1789 void SkPictureRecord::validateMatrices() const {
1790 int count = fMatrices.count();
1791 SkASSERT((unsigned) count < 0x1000);
1792 for (int index = 0; index < count; index++) {
1793 const SkFlatData* matrix = fMatrices[index];
1795 // matrix->validate();
1799 void SkPictureRecord::validatePaints() const {
1800 int count = fPaints.count();
1801 SkASSERT((unsigned) count < 0x1000);
1802 for (int index = 0; index < count; index++) {
1803 const SkFlatData* paint = fPaints[index];
1805 // paint->validate();
1809 void SkPictureRecord::validatePaths() const {
1810 if (NULL == fPathHeap) {
1814 int count = fPathHeap->count();
1815 SkASSERT((unsigned) count < 0x1000);
1816 for (int index = 0; index < count; index++) {
1817 const SkPath& path = (*fPathHeap)[index];
1822 void SkPictureRecord::validateRegions() const {
1823 int count = fRegions.count();
1824 SkASSERT((unsigned) count < 0x1000);
1825 for (int index = 0; index < count; index++) {
1826 const SkFlatData* region = fRegions[index];
1828 // region->validate();