2 * Copyright 2011 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkPictureRecord.h"
10 #include "SkPatchUtils.h"
11 #include "SkPixelRef.h"
13 #include "SkTextBlob.h"
14 #include "SkTSearch.h"
16 #define HEAP_BLOCK_SIZE 4096
19 // just need a value that save or getSaveCount would never return
23 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
24 static int const kUInt32Size = 4;
26 static const uint32_t kSaveSize = kUInt32Size;
28 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
29 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 , fFlattenableHeap(HEAP_BLOCK_SIZE)
35 , fPaints(&fFlattenableHeap)
36 , fRecordFlags(flags) {
38 fBitmapHeap = SkNEW(SkBitmapHeap);
39 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
41 fFirstSavedLayerIndex = kNoSavedLayerIndex;
42 fInitialSaveCount = kNoInitialSave;
45 SkPictureRecord::~SkPictureRecord() {
46 SkSafeUnref(fBitmapHeap);
47 fFlattenableHeap.setBitmapStorage(NULL);
48 fPictureRefs.unrefAll();
49 fTextBlobRefs.unrefAll();
52 ///////////////////////////////////////////////////////////////////////////////
55 // Return the offset of the paint inside a given op's byte stream. A zero
56 // return value means there is no paint (and you really shouldn't be calling
58 static inline size_t get_paint_offset(DrawType op, size_t opSize) {
59 // These offsets are where the paint would be if the op size doesn't overflow
60 static const uint8_t gPaintOffsets[] = {
61 0, // UNUSED - no paint
62 0, // CLIP_PATH - no paint
63 0, // CLIP_REGION - no paint
64 0, // CLIP_RECT - no paint
65 0, // CLIP_RRECT - no paint
66 0, // CONCAT - no paint
67 1, // DRAW_BITMAP - right after op code
68 1, // DRAW_BITMAP_MATRIX - right after op code
69 1, // DRAW_BITMAP_NINE - right after op code
70 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
71 0, // DRAW_CLEAR - no paint
72 0, // DRAW_DATA - no paint
73 1, // DRAW_OVAL - right after op code
74 1, // DRAW_PAINT - right after op code
75 1, // DRAW_PATH - right after op code
76 0, // DRAW_PICTURE - no paint
77 1, // DRAW_POINTS - right after op code
78 1, // DRAW_POS_TEXT - right after op code
79 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
80 1, // DRAW_POS_TEXT_H - right after op code
81 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
82 1, // DRAW_RECT - right after op code
83 1, // DRAW_RRECT - right after op code
84 1, // DRAW_SPRITE - right after op code
85 1, // DRAW_TEXT - right after op code
86 1, // DRAW_TEXT_ON_PATH - right after op code
87 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
88 1, // DRAW_VERTICES - right after op code
89 0, // RESTORE - no paint
90 0, // ROTATE - no paint
92 0, // SAVE_LAYER - see below - this paint's location varies
93 0, // SCALE - no paint
94 0, // SET_MATRIX - no paint
96 0, // TRANSLATE - no paint
98 0, // BEGIN_GROUP - no paint
99 0, // COMMENT - no paint
100 0, // END_GROUP - no paint
101 1, // DRAWDRRECT - right after op code
102 0, // PUSH_CULL - no paint
103 0, // POP_CULL - no paint
104 1, // DRAW_PATCH - right after op code
105 1, // DRAW_PICTURE_MATRIX_PAINT - right after op code
106 1, // DRAW_TEXT_BLOB- right after op code
109 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
111 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
114 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
115 // This op's size overflows so an extra uint32_t will be written
117 overflow = sizeof(uint32_t);
120 if (SAVE_LAYER == op) {
121 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
122 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
124 if (kSaveLayerNoBoundsSize == opSize) {
125 return kSaveLayerNoBoundsPaintOffset + overflow;
127 SkASSERT(kSaveLayerWithBoundsSize == opSize);
128 return kSaveLayerWithBoundsPaintOffset + overflow;
132 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
133 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
137 void SkPictureRecord::willSave() {
138 // record the offset to us, making it non-positive to distinguish a save
139 // from a clip entry.
140 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
143 this->INHERITED::willSave();
146 void SkPictureRecord::recordSave() {
147 fContentInfo.onSave();
150 size_t size = kSaveSize;
151 size_t initialOffset = this->addDraw(SAVE, &size);
153 this->validate(initialOffset, size);
156 SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
157 const SkPaint* paint, SaveFlags flags) {
158 // record the offset to us, making it non-positive to distinguish a save
159 // from a clip entry.
160 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
161 this->recordSaveLayer(bounds, paint, flags);
162 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
163 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
166 this->INHERITED::willSaveLayer(bounds, paint, flags);
167 /* No need for a (potentially very big) layer which we don't actually need
168 at this time (and may not be able to afford since during record our
169 clip starts out the size of the picture, which is often much larger
170 than the size of the actual device we'll use during playback).
172 return kNoLayer_SaveLayerStrategy;
175 void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
177 fContentInfo.onSaveLayer();
179 // op + bool for 'bounds'
180 size_t size = 2 * kUInt32Size;
182 size += sizeof(*bounds); // + rect
184 // + paint index + flags
185 size += 2 * kUInt32Size;
187 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
189 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
190 this->addRectPtr(bounds);
191 SkASSERT(initialOffset+get_paint_offset(SAVE_LAYER, size) == fWriter.bytesWritten());
192 this->addPaintPtr(paint);
195 this->validate(initialOffset, size);
198 bool SkPictureRecord::isDrawingToLayer() const {
199 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
204 * Read the op code from 'offset' in 'writer' and extract the size too.
206 static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
207 uint32_t peek = writer->readTAt<uint32_t>(offset);
210 UNPACK_8_24(peek, op, *size);
211 if (MASK_24 == *size) {
212 // size required its own slot right after the op code
213 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
215 return (DrawType) op;
219 void SkPictureRecord::willRestore() {
220 // FIXME: SkDeferredCanvas needs to be refactored to respect
221 // save/restore balancing so that the following test can be
222 // turned on permanently.
224 SkASSERT(fRestoreOffsetStack.count() > 1);
227 // check for underflow
228 if (fRestoreOffsetStack.count() == 0) {
232 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
233 fFirstSavedLayerIndex = kNoSavedLayerIndex;
236 this->recordRestore();
238 fRestoreOffsetStack.pop();
240 this->INHERITED::willRestore();
243 void SkPictureRecord::recordRestore(bool fillInSkips) {
244 fContentInfo.onRestore();
247 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
249 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
250 size_t initialOffset = this->addDraw(RESTORE, &size);
251 this->validate(initialOffset, size);
254 void SkPictureRecord::recordTranslate(const SkMatrix& m) {
255 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
258 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
259 size_t initialOffset = this->addDraw(TRANSLATE, &size);
260 this->addScalar(m.getTranslateX());
261 this->addScalar(m.getTranslateY());
262 this->validate(initialOffset, size);
265 void SkPictureRecord::recordScale(const SkMatrix& m) {
266 SkASSERT(SkMatrix::kScale_Mask == m.getType());
269 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
270 size_t initialOffset = this->addDraw(SCALE, &size);
271 this->addScalar(m.getScaleX());
272 this->addScalar(m.getScaleY());
273 this->validate(initialOffset, size);
276 void SkPictureRecord::didConcat(const SkMatrix& matrix) {
277 switch (matrix.getType()) {
278 case SkMatrix::kTranslate_Mask:
279 this->recordTranslate(matrix);
281 case SkMatrix::kScale_Mask:
282 this->recordScale(matrix);
285 this->recordConcat(matrix);
288 this->INHERITED::didConcat(matrix);
291 void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
292 this->validate(fWriter.bytesWritten(), 0);
294 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
295 size_t initialOffset = this->addDraw(CONCAT, &size);
296 this->addMatrix(matrix);
297 this->validate(initialOffset, size);
300 void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
301 this->validate(fWriter.bytesWritten(), 0);
303 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
304 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
305 this->addMatrix(matrix);
306 this->validate(initialOffset, size);
307 this->INHERITED::didSetMatrix(matrix);
310 static bool regionOpExpands(SkRegion::Op op) {
312 case SkRegion::kUnion_Op:
313 case SkRegion::kXOR_Op:
314 case SkRegion::kReverseDifference_Op:
315 case SkRegion::kReplace_Op:
317 case SkRegion::kIntersect_Op:
318 case SkRegion::kDifference_Op:
321 SkDEBUGFAIL("unknown region op");
326 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
327 int32_t offset = fRestoreOffsetStack.top();
329 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
330 fWriter.overwriteTAt(offset, restoreOffset);
335 // assert that the final offset value points to a save verb
337 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
338 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
342 void SkPictureRecord::beginRecording() {
343 // we have to call this *after* our constructor, to ensure that it gets
344 // recorded. This is balanced by restoreToCount() call from endRecording,
345 // which in-turn calls our overridden restore(), so those get recorded too.
346 fInitialSaveCount = this->save();
349 void SkPictureRecord::endRecording() {
350 SkASSERT(kNoInitialSave != fInitialSaveCount);
351 this->restoreToCount(fInitialSaveCount);
354 size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
355 if (fRestoreOffsetStack.isEmpty()) {
359 // The RestoreOffset field is initially filled with a placeholder
360 // value that points to the offset of the previous RestoreOffset
361 // in the current stack level, thus forming a linked list so that
362 // the restore offsets can be filled in when the corresponding
363 // restore command is recorded.
364 int32_t prevOffset = fRestoreOffsetStack.top();
366 if (regionOpExpands(op)) {
367 // Run back through any previous clip ops, and mark their offset to
368 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
369 // they could hide this clips ability to expand the clip (i.e. go from
370 // empty to non-empty).
371 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
373 // Reset the pointer back to the previous clip so that subsequent
374 // restores don't overwrite the offsets we just cleared.
378 size_t offset = fWriter.bytesWritten();
379 this->addInt(prevOffset);
380 fRestoreOffsetStack.top() = SkToU32(offset);
384 void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
385 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
386 this->INHERITED::onClipRect(rect, op, edgeStyle);
389 size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
390 // id + rect + clip params
391 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
392 // recordRestoreOffsetPlaceholder doesn't always write an offset
393 if (!fRestoreOffsetStack.isEmpty()) {
397 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
399 this->addInt(ClipParams_pack(op, doAA));
400 size_t offset = this->recordRestoreOffsetPlaceholder(op);
402 this->validate(initialOffset, size);
406 void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
407 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
408 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
411 size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
412 // op + rrect + clip params
413 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
414 // recordRestoreOffsetPlaceholder doesn't always write an offset
415 if (!fRestoreOffsetStack.isEmpty()) {
419 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
420 this->addRRect(rrect);
421 this->addInt(ClipParams_pack(op, doAA));
422 size_t offset = recordRestoreOffsetPlaceholder(op);
423 this->validate(initialOffset, size);
427 void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
428 int pathID = this->addPathToHeap(path);
429 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
430 this->INHERITED::onClipPath(path, op, edgeStyle);
433 size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
434 // op + path index + clip params
435 size_t size = 3 * kUInt32Size;
436 // recordRestoreOffsetPlaceholder doesn't always write an offset
437 if (!fRestoreOffsetStack.isEmpty()) {
441 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
442 this->addInt(pathID);
443 this->addInt(ClipParams_pack(op, doAA));
444 size_t offset = recordRestoreOffsetPlaceholder(op);
445 this->validate(initialOffset, size);
449 void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
450 this->recordClipRegion(region, op);
451 this->INHERITED::onClipRegion(region, op);
454 size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
455 // op + clip params + region
456 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
457 // recordRestoreOffsetPlaceholder doesn't always write an offset
458 if (!fRestoreOffsetStack.isEmpty()) {
462 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
463 this->addRegion(region);
464 this->addInt(ClipParams_pack(op, false));
465 size_t offset = this->recordRestoreOffsetPlaceholder(op);
467 this->validate(initialOffset, size);
471 void SkPictureRecord::clear(SkColor color) {
473 size_t size = 2 * kUInt32Size;
474 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
476 this->validate(initialOffset, size);
479 void SkPictureRecord::drawPaint(const SkPaint& paint) {
481 size_t size = 2 * kUInt32Size;
482 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
483 SkASSERT(initialOffset+get_paint_offset(DRAW_PAINT, size) == fWriter.bytesWritten());
484 this->addPaint(paint);
485 this->validate(initialOffset, size);
488 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
489 const SkPaint& paint) {
490 fContentInfo.onDrawPoints(count, paint);
492 // op + paint index + mode + count + point data
493 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
494 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
495 SkASSERT(initialOffset+get_paint_offset(DRAW_POINTS, size) == fWriter.bytesWritten());
496 this->addPaint(paint);
499 this->addInt(SkToInt(count));
500 fWriter.writeMul4(pts, count * sizeof(SkPoint));
501 this->validate(initialOffset, size);
504 void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
505 // op + paint index + rect
506 size_t size = 2 * kUInt32Size + sizeof(oval);
507 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
508 SkASSERT(initialOffset+get_paint_offset(DRAW_OVAL, size) == fWriter.bytesWritten());
509 this->addPaint(paint);
511 this->validate(initialOffset, size);
514 void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
515 // op + paint index + rect
516 size_t size = 2 * kUInt32Size + sizeof(rect);
517 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
518 SkASSERT(initialOffset+get_paint_offset(DRAW_RECT, size) == fWriter.bytesWritten());
519 this->addPaint(paint);
521 this->validate(initialOffset, size);
524 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
525 // op + paint index + rrect
526 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
527 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
528 SkASSERT(initialOffset+get_paint_offset(DRAW_RRECT, size) == fWriter.bytesWritten());
529 this->addPaint(paint);
530 this->addRRect(rrect);
531 this->validate(initialOffset, size);
534 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
535 const SkPaint& paint) {
536 // op + paint index + rrects
537 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
538 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
539 SkASSERT(initialOffset+get_paint_offset(DRAW_DRRECT, size) == fWriter.bytesWritten());
540 this->addPaint(paint);
541 this->addRRect(outer);
542 this->addRRect(inner);
543 this->validate(initialOffset, size);
546 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
547 fContentInfo.onDrawPath(path, paint);
549 // op + paint index + path index
550 size_t size = 3 * kUInt32Size;
551 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
552 SkASSERT(initialOffset+get_paint_offset(DRAW_PATH, size) == fWriter.bytesWritten());
553 this->addPaint(paint);
555 this->validate(initialOffset, size);
558 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
559 const SkPaint* paint = NULL) {
560 // op + paint index + bitmap index + left + top
561 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
562 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
563 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP, size) == fWriter.bytesWritten());
564 this->addPaintPtr(paint);
565 this->addBitmap(bitmap);
566 this->addScalar(left);
567 this->addScalar(top);
568 this->validate(initialOffset, size);
571 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
572 const SkRect& dst, const SkPaint* paint,
573 DrawBitmapRectFlags flags) {
574 // id + paint index + bitmap index + bool for 'src' + flags
575 size_t size = 5 * kUInt32Size;
577 size += sizeof(*src); // + rect
579 size += sizeof(dst); // + rect
581 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
582 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_RECT_TO_RECT, size)
583 == fWriter.bytesWritten());
584 this->addPaintPtr(paint);
585 this->addBitmap(bitmap);
586 this->addRectPtr(src); // may be null
589 this->validate(initialOffset, size);
592 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
593 const SkPaint* paint) {
594 // id + paint index + bitmap index + matrix
595 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
596 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
597 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
598 this->addPaintPtr(paint);
599 this->addBitmap(bitmap);
600 this->addMatrix(matrix);
601 this->validate(initialOffset, size);
604 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
605 const SkRect& dst, const SkPaint* paint) {
606 // op + paint index + bitmap id + center + dst rect
607 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
608 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
609 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
610 this->addPaintPtr(paint);
611 this->addBitmap(bitmap);
612 this->addIRect(center);
614 this->validate(initialOffset, size);
617 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
618 const SkPaint* paint = NULL) {
619 // op + paint index + bitmap index + left + top
620 size_t size = 5 * kUInt32Size;
621 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
622 SkASSERT(initialOffset+get_paint_offset(DRAW_SPRITE, size) == fWriter.bytesWritten());
623 this->addPaintPtr(paint);
624 this->addBitmap(bitmap);
627 this->validate(initialOffset, size);
630 void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
631 const SkPaint& paint) {
632 // op + paint index + length + 'length' worth of chars + x + y
633 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
635 DrawType op = DRAW_TEXT;
636 size_t initialOffset = this->addDraw(op, &size);
637 SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
638 this->addPaint(paint);
639 this->addText(text, byteLength);
642 this->validate(initialOffset, size);
645 void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
646 const SkPaint& paint) {
647 int points = paint.countText(text, byteLength);
649 // op + paint index + length + 'length' worth of data + num points + x&y point data
650 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint);
652 DrawType op = DRAW_POS_TEXT;
654 size_t initialOffset = this->addDraw(op, &size);
655 SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
656 this->addPaint(paint);
657 this->addText(text, byteLength);
658 this->addInt(points);
659 fWriter.writeMul4(pos, points * sizeof(SkPoint));
660 this->validate(initialOffset, size);
663 void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
664 SkScalar constY, const SkPaint& paint) {
665 int points = paint.countText(text, byteLength);
667 // op + paint index + length + 'length' worth of data + num points
668 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
669 // + y + the actual points
670 size += 1 * kUInt32Size + points * sizeof(SkScalar);
672 size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size);
673 this->addPaint(paint);
674 this->addText(text, byteLength);
675 this->addInt(points);
676 this->addScalar(constY);
677 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
678 this->validate(initialOffset, size);
681 void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
682 const SkMatrix* matrix, const SkPaint& paint) {
683 // op + paint index + length + 'length' worth of data + path index + matrix
684 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
685 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
686 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
687 SkASSERT(initialOffset+get_paint_offset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
688 this->addPaint(paint);
689 this->addText(text, byteLength);
692 this->validate(initialOffset, size);
695 void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
696 const SkPaint& paint) {
698 // op + paint index + blob index + x/y
699 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
700 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
701 SkASSERT(initialOffset + get_paint_offset(DRAW_TEXT_BLOB, size) == fWriter.bytesWritten());
703 this->addPaint(paint);
704 this->addTextBlob(blob);
708 this->validate(initialOffset, size);
711 void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
712 const SkPaint* paint) {
713 // op + picture index
714 size_t size = 2 * kUInt32Size;
715 size_t initialOffset;
717 if (NULL == matrix && NULL == paint) {
718 initialOffset = this->addDraw(DRAW_PICTURE, &size);
719 this->addPicture(picture);
721 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
722 size += m.writeToMemory(NULL) + kUInt32Size; // matrix + paint
723 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
724 SkASSERT(initialOffset + get_paint_offset(DRAW_PICTURE_MATRIX_PAINT, size)
725 == fWriter.bytesWritten());
726 this->addPaintPtr(paint);
728 this->addPicture(picture);
730 this->validate(initialOffset, size);
733 void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
734 const SkPoint vertices[], const SkPoint texs[],
735 const SkColor colors[], SkXfermode* xfer,
736 const uint16_t indices[], int indexCount,
737 const SkPaint& paint) {
740 flags |= DRAW_VERTICES_HAS_TEXS;
743 flags |= DRAW_VERTICES_HAS_COLORS;
745 if (indexCount > 0) {
746 flags |= DRAW_VERTICES_HAS_INDICES;
749 SkXfermode::Mode mode;
750 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
751 flags |= DRAW_VERTICES_HAS_XFER;
755 // op + paint index + flags + vmode + vCount + vertices
756 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
757 if (flags & DRAW_VERTICES_HAS_TEXS) {
758 size += vertexCount * sizeof(SkPoint); // + uvs
760 if (flags & DRAW_VERTICES_HAS_COLORS) {
761 size += vertexCount * sizeof(SkColor); // + vert colors
763 if (flags & DRAW_VERTICES_HAS_INDICES) {
764 // + num indices + indices
765 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
767 if (flags & DRAW_VERTICES_HAS_XFER) {
768 size += kUInt32Size; // mode enum
771 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
772 SkASSERT(initialOffset+get_paint_offset(DRAW_VERTICES, size) == fWriter.bytesWritten());
773 this->addPaint(paint);
776 this->addInt(vertexCount);
777 this->addPoints(vertices, vertexCount);
778 if (flags & DRAW_VERTICES_HAS_TEXS) {
779 this->addPoints(texs, vertexCount);
781 if (flags & DRAW_VERTICES_HAS_COLORS) {
782 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
784 if (flags & DRAW_VERTICES_HAS_INDICES) {
785 this->addInt(indexCount);
786 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
788 if (flags & DRAW_VERTICES_HAS_XFER) {
789 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
790 (void)xfer->asMode(&mode);
793 this->validate(initialOffset, size);
796 void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
797 const SkPoint texCoords[4], SkXfermode* xmode,
798 const SkPaint& paint) {
799 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
800 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
803 flag |= DRAW_VERTICES_HAS_COLORS;
804 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
807 flag |= DRAW_VERTICES_HAS_TEXS;
808 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
811 SkXfermode::Mode mode;
812 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
813 flag |= DRAW_VERTICES_HAS_XFER;
818 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
819 SkASSERT(initialOffset+get_paint_offset(DRAW_PATCH, size) == fWriter.bytesWritten());
820 this->addPaint(paint);
821 this->addPatch(cubics);
824 // write optional parameters
826 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
829 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
831 if (flag & DRAW_VERTICES_HAS_XFER) {
832 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
833 xmode->asMode(&mode);
836 this->validate(initialOffset, size);
839 void SkPictureRecord::drawData(const void* data, size_t length) {
840 // op + length + 'length' worth of data
841 size_t size = 2 * kUInt32Size + SkAlign4(length);
842 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
843 this->addInt(SkToInt(length));
844 fWriter.writePad(data, length);
845 this->validate(initialOffset, size);
848 void SkPictureRecord::beginCommentGroup(const char* description) {
849 // op/size + length of string + \0 terminated chars
850 size_t length = strlen(description);
851 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
852 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
853 fWriter.writeString(description, length);
854 this->validate(initialOffset, size);
857 void SkPictureRecord::addComment(const char* kywd, const char* value) {
858 // op/size + 2x length of string + 2x \0 terminated chars
859 size_t kywdLen = strlen(kywd);
860 size_t valueLen = strlen(value);
861 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
862 size_t initialOffset = this->addDraw(COMMENT, &size);
863 fWriter.writeString(kywd, kywdLen);
864 fWriter.writeString(value, valueLen);
865 this->validate(initialOffset, size);
868 void SkPictureRecord::endCommentGroup() {
870 size_t size = 1 * kUInt32Size;
871 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
872 this->validate(initialOffset, size);
875 // [op/size] [rect] [skip offset]
876 static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
877 void SkPictureRecord::onPushCull(const SkRect& cullRect) {
878 size_t size = kPushCullOpSize;
879 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
880 // PUSH_CULL's size should stay constant (used to rewind).
881 SkASSERT(size == kPushCullOpSize);
883 this->addRect(cullRect);
884 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
886 this->validate(initialOffset, size);
889 void SkPictureRecord::onPopCull() {
890 SkASSERT(!fCullOffsetStack.isEmpty());
892 uint32_t cullSkipOffset = fCullOffsetStack.top();
893 fCullOffsetStack.pop();
896 size_t size = kUInt32Size;
897 size_t initialOffset = this->addDraw(POP_CULL, &size);
899 // update the cull skip offset to point past this op.
900 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
902 this->validate(initialOffset, size);
905 ///////////////////////////////////////////////////////////////////////////////
907 SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
911 int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
912 const int index = fBitmapHeap->insert(bitmap);
913 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
914 // release builds, the invalid value will be recorded so that the reader will know that there
916 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
921 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
922 fWriter.writeMatrix(matrix);
925 void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
926 fContentInfo.onAddPaintPtr(paint);
929 const SkFlatData* flat = fPaints.findAndReturnFlat(*paint);
930 SkASSERT(flat && flat->index() != 0);
931 this->addInt(flat->index());
937 int SkPictureRecord::addPathToHeap(const SkPath& path) {
938 if (NULL == fPathHeap) {
939 fPathHeap.reset(SkNEW(SkPathHeap));
941 #ifdef SK_DEDUP_PICTURE_PATHS
942 return fPathHeap->insert(path);
944 return fPathHeap->append(path);
948 void SkPictureRecord::addPath(const SkPath& path) {
949 this->addInt(this->addPathToHeap(path));
952 void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
953 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
956 void SkPictureRecord::addPicture(const SkPicture* picture) {
957 int index = fPictureRefs.find(picture);
958 if (index < 0) { // not found
959 index = fPictureRefs.count();
960 *fPictureRefs.append() = picture;
963 // follow the convention of recording a 1-based index
964 this->addInt(index + 1);
967 void SkPictureRecord::addPoint(const SkPoint& point) {
968 fWriter.writePoint(point);
971 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
972 fWriter.writeMul4(pts, count * sizeof(SkPoint));
975 void SkPictureRecord::addNoOp() {
976 size_t size = kUInt32Size; // op
977 this->addDraw(NOOP, &size);
980 void SkPictureRecord::addRect(const SkRect& rect) {
981 fWriter.writeRect(rect);
984 void SkPictureRecord::addRectPtr(const SkRect* rect) {
985 if (fWriter.writeBool(rect != NULL)) {
986 fWriter.writeRect(*rect);
990 void SkPictureRecord::addIRect(const SkIRect& rect) {
991 fWriter.write(&rect, sizeof(rect));
994 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
995 if (fWriter.writeBool(rect != NULL)) {
996 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1000 void SkPictureRecord::addRRect(const SkRRect& rrect) {
1001 fWriter.writeRRect(rrect);
1004 void SkPictureRecord::addRegion(const SkRegion& region) {
1005 fWriter.writeRegion(region);
1008 void SkPictureRecord::addText(const void* text, size_t byteLength) {
1009 fContentInfo.onDrawText();
1010 addInt(SkToInt(byteLength));
1011 fWriter.writePad(text, byteLength);
1014 void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
1015 int index = fTextBlobRefs.count();
1016 *fTextBlobRefs.append() = blob;
1018 // follow the convention of recording a 1-based index
1019 this->addInt(index + 1);
1022 ///////////////////////////////////////////////////////////////////////////////