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