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