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"
15 #include "SkSurface.h"
17 #define HEAP_BLOCK_SIZE 4096
20 // just need a value that save or getSaveCount would never return
24 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
25 static int const kUInt32Size = 4;
27 static const uint32_t kSaveSize = 2 * kUInt32Size;
28 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
29 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
31 SkPictureRecord::SkPictureRecord(uint32_t flags, SkBaseDevice* device)
33 , fBoundingHierarchy(NULL)
35 , fFlattenableHeap(HEAP_BLOCK_SIZE)
36 , fPaints(&fFlattenableHeap)
37 , fRecordFlags(flags) {
39 fPointBytes = fRectBytes = fTextBytes = 0;
40 fPointWrites = fRectWrites = fTextWrites = 0;
43 fBitmapHeap = SkNEW(SkBitmapHeap);
44 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
45 fPathHeap = NULL; // lazy allocate
46 #ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
47 fFirstSavedLayerIndex = kNoSavedLayerIndex;
50 fInitialSaveCount = kNoInitialSave;
52 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
57 SkPictureRecord::~SkPictureRecord() {
58 SkSafeUnref(fBitmapHeap);
59 SkSafeUnref(fPathHeap);
60 SkSafeUnref(fBoundingHierarchy);
61 SkSafeUnref(fStateTree);
62 fFlattenableHeap.setBitmapStorage(NULL);
63 fPictureRefs.unrefAll();
66 ///////////////////////////////////////////////////////////////////////////////
68 // Return the offset of the paint inside a given op's byte stream. A zero
69 // return value means there is no paint (and you really shouldn't be calling
71 static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
72 // These offsets are where the paint would be if the op size doesn't overflow
73 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
74 0, // UNUSED - no paint
75 0, // CLIP_PATH - no paint
76 0, // CLIP_REGION - no paint
77 0, // CLIP_RECT - no paint
78 0, // CLIP_RRECT - no paint
79 0, // CONCAT - no paint
80 1, // DRAW_BITMAP - right after op code
81 1, // DRAW_BITMAP_MATRIX - right after op code
82 1, // DRAW_BITMAP_NINE - right after op code
83 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
84 0, // DRAW_CLEAR - no paint
85 0, // DRAW_DATA - no paint
86 1, // DRAW_OVAL - right after op code
87 1, // DRAW_PAINT - right after op code
88 1, // DRAW_PATH - right after op code
89 0, // DRAW_PICTURE - no paint
90 1, // DRAW_POINTS - right after op code
91 1, // DRAW_POS_TEXT - right after op code
92 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
93 1, // DRAW_POS_TEXT_H - right after op code
94 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
95 1, // DRAW_RECT - right after op code
96 1, // DRAW_RRECT - right after op code
97 1, // DRAW_SPRITE - right after op code
98 1, // DRAW_TEXT - right after op code
99 1, // DRAW_TEXT_ON_PATH - right after op code
100 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
101 1, // DRAW_VERTICES - right after op code
102 0, // RESTORE - no paint
103 0, // ROTATE - no paint
104 0, // SAVE - no paint
105 0, // SAVE_LAYER - see below - this paint's location varies
106 0, // SCALE - no paint
107 0, // SET_MATRIX - no paint
108 0, // SKEW - no paint
109 0, // TRANSLATE - no paint
110 0, // NOOP - no paint
111 0, // BEGIN_GROUP - no paint
112 0, // COMMENT - no paint
113 0, // END_GROUP - no paint
116 SkASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1);
117 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
120 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
121 // This op's size overflows so an extra uint32_t will be written
123 overflow = sizeof(uint32_t);
126 if (SAVE_LAYER == op) {
127 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
128 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
130 if (kSaveLayerNoBoundsSize == opSize) {
131 return kSaveLayerNoBoundsPaintOffset + overflow;
133 SkASSERT(kSaveLayerWithBoundsSize == opSize);
134 return kSaveLayerWithBoundsPaintOffset + overflow;
138 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
139 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
142 SkBaseDevice* SkPictureRecord::setDevice(SkBaseDevice* device) {
143 SkDEBUGFAIL("eeek, don't try to change the device on a recording canvas");
144 return this->INHERITED::setDevice(device);
147 int SkPictureRecord::save(SaveFlags flags) {
149 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
152 // record the offset to us, making it non-positive to distinguish a save
153 // from a clip entry.
154 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
155 this->recordSave(flags);
157 return this->INHERITED::save(flags);
160 void SkPictureRecord::recordSave(SaveFlags flags) {
162 uint32_t size = kSaveSize;
163 size_t initialOffset = this->addDraw(SAVE, &size);
166 this->validate(initialOffset, size);
169 int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
173 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
174 count = fMCMgr.saveLayer(bounds, paint, flags);
176 // record the offset to us, making it non-positive to distinguish a save
177 // from a clip entry.
178 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
179 this->recordSaveLayer(bounds, paint, flags);
180 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
181 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
185 /* Don't actually call INHERITED::saveLayer, because that will try to allocate
186 an offscreen device (potentially very big) which we don't actually need
187 at this time (and may not be able to afford since during record our
188 clip starts out the size of the picture, which is often much larger
189 than the size of the actual device we'll use during playback).
191 count = this->INHERITED::save(flags);
192 this->clipRectBounds(bounds, flags, NULL);
196 void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
198 // op + bool for 'bounds'
199 uint32_t size = 2 * kUInt32Size;
200 if (NULL != bounds) {
201 size += sizeof(*bounds); // + rect
203 // + paint index + flags
204 size += 2 * kUInt32Size;
206 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
208 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
209 this->addRectPtr(bounds);
210 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
211 this->addPaintPtr(paint);
214 this->validate(initialOffset, size);
217 bool SkPictureRecord::isDrawingToLayer() const {
218 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
219 return fMCMgr.isDrawingToLayer();
221 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
226 * Read the op code from 'offset' in 'writer' and extract the size too.
228 static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
229 uint32_t peek = writer->readTAt<uint32_t>(offset);
232 UNPACK_8_24(peek, op, *size);
233 if (MASK_24 == *size) {
234 // size required its own slot right after the op code
235 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
237 return (DrawType) op;
240 #ifdef TRACK_COLLAPSE_STATS
241 static int gCollapseCount, gCollapseCalls;
244 // Is the supplied paint simply a color?
245 static bool is_simple(const SkPaint& p) {
246 intptr_t orAccum = (intptr_t)p.getPathEffect() |
247 (intptr_t)p.getShader() |
248 (intptr_t)p.getXfermode() |
249 (intptr_t)p.getMaskFilter() |
250 (intptr_t)p.getColorFilter() |
251 (intptr_t)p.getRasterizer() |
252 (intptr_t)p.getLooper() |
253 (intptr_t)p.getImageFilter();
257 // CommandInfos are fed to the 'match' method and filled in with command
266 * Attempt to match the provided pattern of commands starting at 'offset'
267 * in the byte stream and stopping at the end of the stream. Upon success,
268 * return true with all the pattern information filled out in the result
269 * array (i.e., actual ops, offsets and sizes).
270 * Note this method skips any NOOPs seen in the stream
272 static bool match(SkWriter32* writer, uint32_t offset,
273 int* pattern, CommandInfo* result, int numCommands) {
274 SkASSERT(offset < writer->bytesWritten());
276 uint32_t curOffset = offset;
277 uint32_t curSize = 0;
279 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
280 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
281 while (NOOP == op && curOffset < writer->bytesWritten()) {
282 curOffset += curSize;
283 op = peek_op_and_size(writer, curOffset, &curSize);
286 if (curOffset >= writer->bytesWritten()) {
287 return false; // ran out of byte stream
290 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
291 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
292 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
295 } else if (op != pattern[numMatched]) {
299 result[numMatched].fActualOp = op;
300 result[numMatched].fOffset = curOffset;
301 result[numMatched].fSize = curSize;
303 curOffset += curSize;
306 if (numMatched != numCommands) {
310 curOffset += curSize;
311 if (curOffset < writer->bytesWritten()) {
312 // Something else between the last command and the end of the stream
319 // temporarily here to make code review easier
320 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
321 SkPaintDictionary* paintDict,
322 const CommandInfo& saveLayerInfo,
323 const CommandInfo& dbmInfo);
326 * Restore has just been called (but not recorded), look back at the
327 * matching save* and see if we are in the configuration:
329 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
331 * where the saveLayer's color can be moved into the drawBitmap*'s paint
333 static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
334 SkPaintDictionary* paintDict) {
335 // back up to the save block
336 // TODO: add a stack to track save*/restore offsets rather than searching backwards
338 offset = writer->readTAt<uint32_t>(offset);
341 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
342 CommandInfo result[SK_ARRAY_COUNT(pattern)];
344 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
348 if (kSaveLayerWithBoundsSize == result[0].fSize) {
349 // The saveLayer's bound can offset where the dbm is drawn
353 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
354 result[0], result[1]);
358 * Convert the command code located at 'offset' to a NOOP. Leave the size
359 * field alone so the NOOP can be skipped later.
361 static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
362 uint32_t command = writer->readTAt<uint32_t>(offset);
363 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
367 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
368 * Return true on success; false otherwise.
370 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
371 SkPaintDictionary* paintDict,
372 const CommandInfo& saveLayerInfo,
373 const CommandInfo& dbmInfo) {
374 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
375 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
376 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
377 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
378 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
380 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
381 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
383 // we have a match, now we need to get the paints involved
384 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
385 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
387 if (0 == saveLayerPaintId) {
388 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
389 // and signal the caller (by returning true) to not add the RESTORE op
390 convert_command_to_noop(writer, saveLayerInfo.fOffset);
394 if (0 == dbmPaintId) {
395 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
396 // and signal the caller (by returning true) to not add the RESTORE op
397 convert_command_to_noop(writer, saveLayerInfo.fOffset);
398 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
402 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
403 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
407 // For this optimization we only fold the saveLayer and drawBitmapRect
408 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
409 // and the only difference in the colors is that the saveLayer's can have
410 // an alpha while the drawBitmapRect's is opaque.
411 // TODO: it should be possible to fold them together even if they both
412 // have different non-255 alphas
413 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
415 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
416 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
420 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
421 SkColorGetA(saveLayerPaint->getColor()));
422 dbmPaint->setColor(newColor);
424 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
429 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
430 convert_command_to_noop(writer, saveLayerInfo.fOffset);
431 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
436 * Restore has just been called (but not recorded), look back at the
437 * matching save* and see if we are in the configuration:
438 * SAVE_LAYER (with NULL == bounds)
441 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
444 * where the saveLayer's color can be moved into the drawBitmap*'s paint
446 static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
447 SkPaintDictionary* paintDict) {
449 // back up to the save block
450 // TODO: add a stack to track save*/restore offsets rather than searching backwards
452 offset = writer->readTAt<uint32_t>(offset);
455 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
456 CommandInfo result[SK_ARRAY_COUNT(pattern)];
458 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
462 if (kSaveLayerWithBoundsSize == result[0].fSize) {
463 // The saveLayer's bound can offset where the dbm is drawn
467 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
468 result[0], result[3]);
472 * Restore has just been called (but not recorded), so look back at the
473 * matching save(), and see if we can eliminate the pair of them, due to no
474 * intervening matrix/clip calls.
476 * If so, update the writer and return true, in which case we won't even record
477 * the restore() call. If we still need the restore(), return false.
479 static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
480 SkPaintDictionary* paintDict) {
481 #ifdef TRACK_COLLAPSE_STATS
485 int32_t restoreOffset = (int32_t)writer->bytesWritten();
487 // back up to the save block
489 offset = writer->readTAt<uint32_t>(offset);
492 // now offset points to a save
495 DrawType op = peek_op_and_size(writer, offset, &opSize);
496 if (SAVE_LAYER == op) {
497 // not ready to cull these out yet (mrr)
500 SkASSERT(SAVE == op);
501 SkASSERT(kSaveSize == opSize);
503 // get the save flag (last 4-bytes of the space allocated for the opSize)
504 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
505 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
506 // This function's optimization is only correct for kMatrixClip style saves.
507 // TODO: set checkMatrix & checkClip booleans here and then check for the
508 // offending operations in the following loop.
512 // Walk forward until we get back to either a draw-verb (abort) or we hit
513 // our restore (success).
514 int32_t saveOffset = offset;
517 while (offset < restoreOffset) {
518 op = peek_op_and_size(writer, offset, &opSize);
519 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
520 // drawing verb, abort
526 #ifdef TRACK_COLLAPSE_STATS
528 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
529 (double)gCollapseCount / gCollapseCalls, "%");
532 writer->rewindToOffset(saveOffset);
536 typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
537 SkPaintDictionary* paintDict);
538 enum PictureRecordOptType {
539 kRewind_OptType, // Optimization rewinds the command stream
540 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
543 enum PictureRecordOptFlags {
544 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
545 // SkPicture has a bounding box hierarchy.
548 struct PictureRecordOpt {
549 PictureRecordOptProc fProc;
550 PictureRecordOptType fType;
554 * A list of the optimizations that are tried upon seeing a restore
555 * TODO: add a real API for such optimizations
556 * Add the ability to fire optimizations on any op (not just RESTORE)
558 static const PictureRecordOpt gPictureRecordOpts[] = {
559 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
560 // because it is redundant with the state traversal optimization in
561 // SkPictureStateTree, and applying the optimization introduces significant
562 // record time overhead because it requires rewinding contents that were
563 // recorded into the BBoxHierarchy.
564 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
565 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
566 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
569 // This is called after an optimization has been applied to the command stream
570 // in order to adjust the contents and state of the bounding box hierarchy and
571 // state tree to reflect the optimization.
572 static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
573 SkBBoxHierarchy* boundingHierarchy) {
575 case kCollapseSaveLayer_OptType:
576 if (NULL != stateTree) {
577 stateTree->saveCollapsed();
580 case kRewind_OptType:
581 if (NULL != boundingHierarchy) {
582 boundingHierarchy->rewindInserts();
584 // Note: No need to touch the state tree for this to work correctly.
585 // Unused branches do not burden the playback, and pruning the tree
586 // would be O(N^2), so it is best to leave it alone.
593 void SkPictureRecord::restore() {
594 // FIXME: SkDeferredCanvas needs to be refactored to respect
595 // save/restore balancing so that the following test can be
596 // turned on permanently.
598 SkASSERT(fRestoreOffsetStack.count() > 1);
601 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
602 if (fMCMgr.getSaveCount() == 1) {
606 // TODO: don't write the restore to the op stream for normal saves
609 // check for underflow
610 if (fRestoreOffsetStack.count() == 0) {
614 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
615 fFirstSavedLayerIndex = kNoSavedLayerIndex;
619 if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
620 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
621 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
622 && NULL != fBoundingHierarchy) {
625 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
626 // Some optimization fired so don't add the RESTORE
627 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
628 fStateTree, fBoundingHierarchy);
634 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
635 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
636 // No optimization fired so add the RESTORE
637 this->recordRestore();
640 fRestoreOffsetStack.pop();
643 return this->INHERITED::restore();
646 void SkPictureRecord::recordRestore(bool fillInSkips) {
647 uint32_t initialOffset, size;
649 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
651 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
652 initialOffset = this->addDraw(RESTORE, &size);
653 this->validate(initialOffset, size);
656 bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
657 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
658 fMCMgr.translate(dx, dy);
661 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
662 size_t initialOffset = this->addDraw(TRANSLATE, &size);
665 this->validate(initialOffset, size);
667 return this->INHERITED::translate(dx, dy);
670 bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
672 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
673 fMCMgr.scale(sx, sy);
676 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
677 size_t initialOffset = this->addDraw(SCALE, &size);
680 this->validate(initialOffset, size);
682 return this->INHERITED::scale(sx, sy);
685 bool SkPictureRecord::rotate(SkScalar degrees) {
687 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
688 fMCMgr.rotate(degrees);
691 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
692 size_t initialOffset = this->addDraw(ROTATE, &size);
693 this->addScalar(degrees);
694 this->validate(initialOffset, size);
696 return this->INHERITED::rotate(degrees);
699 bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
701 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
705 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
706 size_t initialOffset = this->addDraw(SKEW, &size);
709 this->validate(initialOffset, size);
711 return this->INHERITED::skew(sx, sy);
714 bool SkPictureRecord::concat(const SkMatrix& matrix) {
716 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
717 fMCMgr.concat(matrix);
719 this->recordConcat(matrix);
721 return this->INHERITED::concat(matrix);
724 void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
725 this->validate(fWriter.bytesWritten(), 0);
727 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
728 size_t initialOffset = this->addDraw(CONCAT, &size);
729 this->addMatrix(matrix);
730 this->validate(initialOffset, size);
733 void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
735 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
736 fMCMgr.setMatrix(matrix);
738 this->validate(fWriter.bytesWritten(), 0);
740 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
741 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
742 this->addMatrix(matrix);
743 this->validate(initialOffset, size);
745 this->INHERITED::setMatrix(matrix);
748 static bool regionOpExpands(SkRegion::Op op) {
750 case SkRegion::kUnion_Op:
751 case SkRegion::kXOR_Op:
752 case SkRegion::kReverseDifference_Op:
753 case SkRegion::kReplace_Op:
755 case SkRegion::kIntersect_Op:
756 case SkRegion::kDifference_Op:
759 SkDEBUGFAIL("unknown region op");
764 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
765 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
766 fMCMgr.fillInSkips(&fWriter, restoreOffset);
769 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
770 int32_t offset = fRestoreOffsetStack.top();
772 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
773 fWriter.overwriteTAt(offset, restoreOffset);
778 // assert that the final offset value points to a save verb
780 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
781 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
786 void SkPictureRecord::beginRecording() {
787 // we have to call this *after* our constructor, to ensure that it gets
788 // recorded. This is balanced by restoreToCount() call from endRecording,
789 // which in-turn calls our overridden restore(), so those get recorded too.
790 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
793 void SkPictureRecord::endRecording() {
794 SkASSERT(kNoInitialSave != fInitialSaveCount);
795 this->restoreToCount(fInitialSaveCount);
796 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
801 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
802 int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
803 size_t offset = fWriter.bytesWritten();
808 int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
809 if (fRestoreOffsetStack.isEmpty()) {
813 // The RestoreOffset field is initially filled with a placeholder
814 // value that points to the offset of the previous RestoreOffset
815 // in the current stack level, thus forming a linked list so that
816 // the restore offsets can be filled in when the corresponding
817 // restore command is recorded.
818 int32_t prevOffset = fRestoreOffsetStack.top();
820 if (regionOpExpands(op)) {
821 // Run back through any previous clip ops, and mark their offset to
822 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
823 // they could hide this clips ability to expand the clip (i.e. go from
824 // empty to non-empty).
825 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
827 // Reset the pointer back to the previous clip so that subsequent
828 // restores don't overwrite the offsets we just cleared.
832 size_t offset = fWriter.bytesWritten();
833 this->addInt(prevOffset);
834 fRestoreOffsetStack.top() = offset;
839 bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
841 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
842 fMCMgr.clipRect(rect, op, doAA);
844 this->recordClipRect(rect, op, doAA);
846 return this->INHERITED::clipRect(rect, op, doAA);
849 int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
850 // id + rect + clip params
851 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
852 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
853 size += kUInt32Size; // + restore offset
855 // recordRestoreOffsetPlaceholder doesn't always write an offset
856 if (!fRestoreOffsetStack.isEmpty()) {
861 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
863 this->addInt(ClipParams_pack(op, doAA));
864 int offset = this->recordRestoreOffsetPlaceholder(op);
866 this->validate(initialOffset, size);
870 bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
871 if (rrect.isRect()) {
872 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
875 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
876 fMCMgr.clipRRect(rrect, op, doAA);
878 this->recordClipRRect(rrect, op, doAA);
880 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
881 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
883 return this->INHERITED::clipRRect(rrect, op, doAA);
887 int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
888 // op + rrect + clip params
889 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
890 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
891 size += kUInt32Size; // + restore offset
893 // recordRestoreOffsetPlaceholder doesn't always write an offset
894 if (!fRestoreOffsetStack.isEmpty()) {
899 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
900 this->addRRect(rrect);
901 this->addInt(ClipParams_pack(op, doAA));
902 int offset = recordRestoreOffsetPlaceholder(op);
903 this->validate(initialOffset, size);
907 bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
910 if (!path.isInverseFillType() && path.isRect(&r)) {
911 return this->clipRect(r, op, doAA);
914 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
915 fMCMgr.clipPath(path, op, doAA);
917 int pathID = this->addPathToHeap(path);
918 this->recordClipPath(pathID, op, doAA);
921 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
922 return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
923 path.isInverseFillType());
925 return this->INHERITED::clipPath(path, op, doAA);
929 int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
930 // op + path index + clip params
931 uint32_t size = 3 * kUInt32Size;
932 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
933 size += kUInt32Size; // + restore offset
935 // recordRestoreOffsetPlaceholder doesn't always write an offset
936 if (!fRestoreOffsetStack.isEmpty()) {
941 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
942 this->addInt(pathID);
943 this->addInt(ClipParams_pack(op, doAA));
944 int offset = recordRestoreOffsetPlaceholder(op);
945 this->validate(initialOffset, size);
949 bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
951 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
952 fMCMgr.clipRegion(region, op);
954 this->recordClipRegion(region, op);
956 return this->INHERITED::clipRegion(region, op);
959 int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
960 // op + clip params + region
961 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
962 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
963 size += kUInt32Size; // + restore offset
965 // recordRestoreOffsetPlaceholder doesn't always write an offset
966 if (!fRestoreOffsetStack.isEmpty()) {
971 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
972 this->addRegion(region);
973 this->addInt(ClipParams_pack(op, false));
974 int offset = this->recordRestoreOffsetPlaceholder(op);
976 this->validate(initialOffset, size);
980 void SkPictureRecord::clear(SkColor color) {
982 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
983 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
987 uint32_t size = 2 * kUInt32Size;
988 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
990 this->validate(initialOffset, size);
993 void SkPictureRecord::drawPaint(const SkPaint& paint) {
995 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
996 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1000 uint32_t size = 2 * kUInt32Size;
1001 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
1002 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
1003 this->addPaint(paint);
1004 this->validate(initialOffset, size);
1007 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1008 const SkPaint& paint) {
1010 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1011 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1014 // op + paint index + mode + count + point data
1015 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
1016 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
1017 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
1018 this->addPaint(paint);
1020 this->addInt(count);
1021 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1022 this->validate(initialOffset, size);
1025 void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
1027 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1028 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1031 // op + paint index + rect
1032 uint32_t size = 2 * kUInt32Size + sizeof(oval);
1033 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
1034 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
1035 this->addPaint(paint);
1036 this->addRect(oval);
1037 this->validate(initialOffset, size);
1040 void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
1042 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1043 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1046 // op + paint index + rect
1047 uint32_t size = 2 * kUInt32Size + sizeof(rect);
1048 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
1049 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
1050 this->addPaint(paint);
1051 this->addRect(rect);
1052 this->validate(initialOffset, size);
1055 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1057 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1058 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1061 if (rrect.isRect()) {
1062 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
1063 } else if (rrect.isOval()) {
1064 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
1066 // op + paint index + rrect
1067 uint32_t initialOffset, size;
1068 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1069 initialOffset = this->addDraw(DRAW_RRECT, &size);
1070 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
1071 this->addPaint(paint);
1072 this->addRRect(rrect);
1073 this->validate(initialOffset, size);
1077 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
1079 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1080 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1083 // op + paint index + path index
1084 uint32_t size = 3 * kUInt32Size;
1085 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
1086 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
1087 this->addPaint(paint);
1088 this->addPath(path);
1089 this->validate(initialOffset, size);
1092 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
1093 const SkPaint* paint = NULL) {
1094 if (bitmap.drawsNothing()) {
1098 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1099 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1102 // op + paint index + bitmap index + left + top
1103 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
1104 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
1105 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
1106 this->addPaintPtr(paint);
1107 this->addBitmap(bitmap);
1108 this->addScalar(left);
1109 this->addScalar(top);
1110 this->validate(initialOffset, size);
1113 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
1114 const SkRect& dst, const SkPaint* paint,
1115 DrawBitmapRectFlags flags) {
1116 if (bitmap.drawsNothing()) {
1120 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1121 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1123 // id + paint index + bitmap index + bool for 'src' + flags
1124 uint32_t size = 5 * kUInt32Size;
1126 size += sizeof(*src); // + rect
1128 size += sizeof(dst); // + rect
1130 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
1131 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1132 == fWriter.bytesWritten());
1133 this->addPaintPtr(paint);
1134 this->addBitmap(bitmap);
1135 this->addRectPtr(src); // may be null
1137 this->addInt(flags);
1138 this->validate(initialOffset, size);
1141 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1142 const SkPaint* paint) {
1143 if (bitmap.drawsNothing()) {
1147 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1148 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1151 // id + paint index + bitmap index + matrix
1152 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
1153 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
1154 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
1155 this->addPaintPtr(paint);
1156 this->addBitmap(bitmap);
1157 this->addMatrix(matrix);
1158 this->validate(initialOffset, size);
1161 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1162 const SkRect& dst, const SkPaint* paint) {
1163 if (bitmap.drawsNothing()) {
1167 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1168 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1171 // op + paint index + bitmap id + center + dst rect
1172 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
1173 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
1174 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
1175 this->addPaintPtr(paint);
1176 this->addBitmap(bitmap);
1177 this->addIRect(center);
1179 this->validate(initialOffset, size);
1182 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
1183 const SkPaint* paint = NULL) {
1184 if (bitmap.drawsNothing()) {
1188 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1189 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1192 // op + paint index + bitmap index + left + top
1193 uint32_t size = 5 * kUInt32Size;
1194 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
1195 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
1196 this->addPaintPtr(paint);
1197 this->addBitmap(bitmap);
1200 this->validate(initialOffset, size);
1203 void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
1204 SkPaint::FontMetrics metrics;
1205 paint.getFontMetrics(&metrics);
1207 // construct a rect so we can see any adjustments from the paint.
1208 // we use 0,1 for left,right, just so the rect isn't empty
1209 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
1210 (void)paint.computeFastBounds(bounds, &bounds);
1211 topbot[0] = bounds.fTop;
1212 topbot[1] = bounds.fBottom;
1215 void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
1216 SkScalar minY, SkScalar maxY) {
1217 WriteTopBot(paint, flat);
1218 this->addScalar(flat.topBot()[0] + minY);
1219 this->addScalar(flat.topBot()[1] + maxY);
1222 void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
1223 SkScalar y, const SkPaint& paint) {
1225 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1226 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1229 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
1231 // op + paint index + length + 'length' worth of chars + x + y
1232 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1234 size += 2 * sizeof(SkScalar); // + top & bottom
1237 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
1238 size_t initialOffset = this->addDraw(op, &size);
1239 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
1240 const SkFlatData* flatPaintData = addPaint(paint);
1241 SkASSERT(flatPaintData);
1242 this->addText(text, byteLength);
1246 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
1248 this->validate(initialOffset, size);
1251 void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
1252 const SkPoint pos[], const SkPaint& paint) {
1254 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1255 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1258 size_t points = paint.countText(text, byteLength);
1262 bool canUseDrawH = true;
1263 SkScalar minY = pos[0].fY;
1264 SkScalar maxY = pos[0].fY;
1265 // check if the caller really should have used drawPosTextH()
1267 const SkScalar firstY = pos[0].fY;
1268 for (size_t index = 1; index < points; index++) {
1269 if (pos[index].fY != firstY) {
1270 canUseDrawH = false;
1271 if (pos[index].fY < minY) {
1272 minY = pos[index].fY;
1273 } else if (pos[index].fY > maxY) {
1274 maxY = pos[index].fY;
1280 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
1281 bool fast = canUseDrawH && fastBounds;
1283 // op + paint index + length + 'length' worth of data + num points
1284 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1287 size += 2 * sizeof(SkScalar); // + top & bottom
1289 // + y-pos + actual x-point data
1290 size += sizeof(SkScalar) + points * sizeof(SkScalar);
1293 size += points * sizeof(SkPoint);
1295 size += 2 * sizeof(SkScalar); // + top & bottom
1301 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1302 } else if (canUseDrawH) {
1303 op = DRAW_POS_TEXT_H;
1304 } else if (fastBounds) {
1305 op = DRAW_POS_TEXT_TOP_BOTTOM;
1309 size_t initialOffset = this->addDraw(op, &size);
1310 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
1311 const SkFlatData* flatPaintData = this->addPaint(paint);
1312 SkASSERT(flatPaintData);
1313 this->addText(text, byteLength);
1314 this->addInt(points);
1316 #ifdef SK_DEBUG_SIZE
1317 size_t start = fWriter.bytesWritten();
1321 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
1323 this->addScalar(pos[0].fY);
1324 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
1325 for (size_t index = 0; index < points; index++)
1326 *xptr++ = pos[index].fX;
1328 fWriter.writeMul4(pos, points * sizeof(SkPoint));
1330 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
1333 #ifdef SK_DEBUG_SIZE
1334 fPointBytes += fWriter.bytesWritten() - start;
1335 fPointWrites += points;
1337 this->validate(initialOffset, size);
1340 void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1341 const SkScalar xpos[], SkScalar constY,
1342 const SkPaint& paint) {
1344 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1345 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1348 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
1349 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
1352 void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1353 const SkScalar xpos[], SkScalar constY,
1354 const SkPaint& paint, const SkFlatData* flatPaintData) {
1355 size_t points = paint.countText(text, byteLength);
1359 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
1361 // op + paint index + length + 'length' worth of data + num points
1362 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1364 size += 2 * sizeof(SkScalar); // + top & bottom
1366 // + y + the actual points
1367 size += 1 * kUInt32Size + points * sizeof(SkScalar);
1368 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
1370 SkASSERT(flatPaintData);
1371 this->addFlatPaint(flatPaintData);
1373 this->addText(text, byteLength);
1374 this->addInt(points);
1376 #ifdef SK_DEBUG_SIZE
1377 size_t start = fWriter.bytesWritten();
1380 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
1382 this->addScalar(constY);
1383 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1384 #ifdef SK_DEBUG_SIZE
1385 fPointBytes += fWriter.bytesWritten() - start;
1386 fPointWrites += points;
1388 this->validate(initialOffset, size);
1391 void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1392 const SkPath& path, const SkMatrix* matrix,
1393 const SkPaint& paint) {
1395 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1396 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1399 // op + paint index + length + 'length' worth of data + path index + matrix
1400 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1401 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
1402 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
1403 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
1404 this->addPaint(paint);
1405 this->addText(text, byteLength);
1406 this->addPath(path);
1408 this->validate(initialOffset, size);
1411 void SkPictureRecord::drawPicture(SkPicture& picture) {
1413 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1414 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1417 // op + picture index
1418 uint32_t size = 2 * kUInt32Size;
1419 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
1420 this->addPicture(picture);
1421 this->validate(initialOffset, size);
1424 void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1425 const SkPoint vertices[], const SkPoint texs[],
1426 const SkColor colors[], SkXfermode* xfer,
1427 const uint16_t indices[], int indexCount,
1428 const SkPaint& paint) {
1430 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1431 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1436 flags |= DRAW_VERTICES_HAS_TEXS;
1439 flags |= DRAW_VERTICES_HAS_COLORS;
1441 if (indexCount > 0) {
1442 flags |= DRAW_VERTICES_HAS_INDICES;
1445 SkXfermode::Mode mode;
1446 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1447 flags |= DRAW_VERTICES_HAS_XFER;
1451 // op + paint index + flags + vmode + vCount + vertices
1452 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1453 if (flags & DRAW_VERTICES_HAS_TEXS) {
1454 size += vertexCount * sizeof(SkPoint); // + uvs
1456 if (flags & DRAW_VERTICES_HAS_COLORS) {
1457 size += vertexCount * sizeof(SkColor); // + vert colors
1459 if (flags & DRAW_VERTICES_HAS_INDICES) {
1460 // + num indices + indices
1461 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1463 if (flags & DRAW_VERTICES_HAS_XFER) {
1464 size += kUInt32Size; // mode enum
1467 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
1468 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
1469 this->addPaint(paint);
1470 this->addInt(flags);
1471 this->addInt(vmode);
1472 this->addInt(vertexCount);
1473 this->addPoints(vertices, vertexCount);
1474 if (flags & DRAW_VERTICES_HAS_TEXS) {
1475 this->addPoints(texs, vertexCount);
1477 if (flags & DRAW_VERTICES_HAS_COLORS) {
1478 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1480 if (flags & DRAW_VERTICES_HAS_INDICES) {
1481 this->addInt(indexCount);
1482 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1484 if (flags & DRAW_VERTICES_HAS_XFER) {
1485 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1486 (void)xfer->asMode(&mode);
1489 this->validate(initialOffset, size);
1492 void SkPictureRecord::drawData(const void* data, size_t length) {
1494 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1495 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1498 // op + length + 'length' worth of data
1499 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
1500 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
1501 this->addInt(length);
1502 fWriter.writePad(data, length);
1503 this->validate(initialOffset, size);
1506 void SkPictureRecord::beginCommentGroup(const char* description) {
1507 // op/size + length of string + \0 terminated chars
1508 int length = strlen(description);
1509 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
1510 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
1511 fWriter.writeString(description, length);
1512 this->validate(initialOffset, size);
1515 void SkPictureRecord::addComment(const char* kywd, const char* value) {
1516 // op/size + 2x length of string + 2x \0 terminated chars
1517 int kywdLen = strlen(kywd);
1518 int valueLen = strlen(value);
1519 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
1520 size_t initialOffset = this->addDraw(COMMENT, &size);
1521 fWriter.writeString(kywd, kywdLen);
1522 fWriter.writeString(value, valueLen);
1523 this->validate(initialOffset, size);
1526 void SkPictureRecord::endCommentGroup() {
1528 uint32_t size = 1 * kUInt32Size;
1529 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1530 this->validate(initialOffset, size);
1533 ///////////////////////////////////////////////////////////////////////////////
1535 SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
1536 return SkSurface::NewPicture(info.fWidth, info.fHeight);
1539 void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
1540 const int index = fBitmapHeap->insert(bitmap);
1541 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1542 // release builds, the invalid value will be recorded so that the reader will know that there
1544 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
1545 this->addInt(index);
1548 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
1549 fWriter.writeMatrix(matrix);
1552 const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1553 return fPaints.findAndReturnFlat(paint);
1556 const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
1557 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1558 this->addFlatPaint(data);
1562 void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1563 int index = flatPaint ? flatPaint->index() : 0;
1564 this->addInt(index);
1567 int SkPictureRecord::addPathToHeap(const SkPath& path) {
1568 if (NULL == fPathHeap) {
1569 fPathHeap = SkNEW(SkPathHeap);
1571 return fPathHeap->append(path);
1574 void SkPictureRecord::addPath(const SkPath& path) {
1575 this->addInt(this->addPathToHeap(path));
1578 void SkPictureRecord::addPicture(SkPicture& picture) {
1579 int index = fPictureRefs.find(&picture);
1580 if (index < 0) { // not found
1581 index = fPictureRefs.count();
1582 *fPictureRefs.append() = &picture;
1585 // follow the convention of recording a 1-based index
1586 this->addInt(index + 1);
1589 void SkPictureRecord::addPoint(const SkPoint& point) {
1590 #ifdef SK_DEBUG_SIZE
1591 size_t start = fWriter.bytesWritten();
1593 fWriter.writePoint(point);
1594 #ifdef SK_DEBUG_SIZE
1595 fPointBytes += fWriter.bytesWritten() - start;
1600 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1601 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1602 #ifdef SK_DEBUG_SIZE
1603 fPointBytes += count * sizeof(SkPoint);
1608 void SkPictureRecord::addRect(const SkRect& rect) {
1609 #ifdef SK_DEBUG_SIZE
1610 size_t start = fWriter.bytesWritten();
1612 fWriter.writeRect(rect);
1613 #ifdef SK_DEBUG_SIZE
1614 fRectBytes += fWriter.bytesWritten() - start;
1619 void SkPictureRecord::addRectPtr(const SkRect* rect) {
1620 if (fWriter.writeBool(rect != NULL)) {
1621 fWriter.writeRect(*rect);
1625 void SkPictureRecord::addIRect(const SkIRect& rect) {
1626 fWriter.write(&rect, sizeof(rect));
1629 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1630 if (fWriter.writeBool(rect != NULL)) {
1631 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1635 void SkPictureRecord::addRRect(const SkRRect& rrect) {
1636 fWriter.writeRRect(rrect);
1639 void SkPictureRecord::addRegion(const SkRegion& region) {
1640 fWriter.writeRegion(region);
1643 void SkPictureRecord::addText(const void* text, size_t byteLength) {
1644 #ifdef SK_DEBUG_SIZE
1645 size_t start = fWriter.bytesWritten();
1648 fWriter.writePad(text, byteLength);
1649 #ifdef SK_DEBUG_SIZE
1650 fTextBytes += fWriter.bytesWritten() - start;
1655 ///////////////////////////////////////////////////////////////////////////////
1657 #ifdef SK_DEBUG_SIZE
1658 size_t SkPictureRecord::size() const {
1663 matrices(&sizeData);
1669 pictures(&sizeData);
1673 result += streamlen();
1677 int SkPictureRecord::bitmaps(size_t* size) const {
1679 int count = fBitmaps.count();
1680 for (int index = 0; index < count; index++)
1681 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1686 int SkPictureRecord::matrices(size_t* size) const {
1687 int count = fMatrices.count();
1688 *size = sizeof(fMatrices[0]) * count;
1692 int SkPictureRecord::paints(size_t* size) const {
1694 int count = fPaints.count();
1695 for (int index = 0; index < count; index++)
1696 result += sizeof(fPaints[index]) + fPaints[index]->size();
1701 int SkPictureRecord::paths(size_t* size) const {
1703 int count = fPaths.count();
1704 for (int index = 0; index < count; index++)
1705 result += sizeof(fPaths[index]) + fPaths[index]->size();
1710 int SkPictureRecord::regions(size_t* size) const {
1712 int count = fRegions.count();
1713 for (int index = 0; index < count; index++)
1714 result += sizeof(fRegions[index]) + fRegions[index]->size();
1719 size_t SkPictureRecord::streamlen() const {
1720 return fWriter.size();
1724 #ifdef SK_DEBUG_VALIDATE
1725 void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1726 SkASSERT(fWriter.size() == initialOffset + size);
1735 void SkPictureRecord::validateBitmaps() const {
1736 int count = fBitmapHeap->count();
1737 SkASSERT((unsigned) count < 0x1000);
1738 for (int index = 0; index < count; index++) {
1739 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
1745 void SkPictureRecord::validateMatrices() const {
1746 int count = fMatrices.count();
1747 SkASSERT((unsigned) count < 0x1000);
1748 for (int index = 0; index < count; index++) {
1749 const SkFlatData* matrix = fMatrices[index];
1751 // matrix->validate();
1755 void SkPictureRecord::validatePaints() const {
1756 int count = fPaints.count();
1757 SkASSERT((unsigned) count < 0x1000);
1758 for (int index = 0; index < count; index++) {
1759 const SkFlatData* paint = fPaints[index];
1761 // paint->validate();
1765 void SkPictureRecord::validatePaths() const {
1766 if (NULL == fPathHeap) {
1770 int count = fPathHeap->count();
1771 SkASSERT((unsigned) count < 0x1000);
1772 for (int index = 0; index < count; index++) {
1773 const SkPath& path = (*fPathHeap)[index];
1778 void SkPictureRecord::validateRegions() const {
1779 int count = fRegions.count();
1780 SkASSERT((unsigned) count < 0x1000);
1781 for (int index = 0; index < count; index++) {
1782 const SkFlatData* region = fRegions[index];
1784 // region->validate();