Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkPictureRecord.cpp
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  */
7
8 #include "SkPictureRecord.h"
9 #include "SkDevice.h"
10 #include "SkPatchUtils.h"
11 #include "SkPixelRef.h"
12 #include "SkRRect.h"
13 #include "SkTextBlob.h"
14 #include "SkTSearch.h"
15
16 #define HEAP_BLOCK_SIZE 4096
17
18 enum {
19     // just need a value that save or getSaveCount would never return
20     kNoInitialSave = -1,
21 };
22
23 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
24 static int const kUInt32Size = 4;
25
26 static const uint32_t kSaveSize = kUInt32Size;
27 #ifdef SK_DEBUG
28 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
29 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
30 #endif//SK_DEBUG
31
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) {
37
38     fBitmapHeap = SkNEW(SkBitmapHeap);
39     fFlattenableHeap.setBitmapStorage(fBitmapHeap);
40
41     fFirstSavedLayerIndex = kNoSavedLayerIndex;
42     fInitialSaveCount = kNoInitialSave;
43 }
44
45 SkPictureRecord::~SkPictureRecord() {
46     SkSafeUnref(fBitmapHeap);
47     fFlattenableHeap.setBitmapStorage(NULL);
48     fPictureRefs.unrefAll();
49     fTextBlobRefs.unrefAll();
50 }
51
52 ///////////////////////////////////////////////////////////////////////////////
53
54 #ifdef SK_DEBUG
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
57 // this method)
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
91         0,  // SAVE - no paint
92         0,  // SAVE_LAYER - see below - this paint's location varies
93         0,  // SCALE - no paint
94         0,  // SET_MATRIX - no paint
95         0,  // SKEW - no paint
96         0,  // TRANSLATE - no paint
97         0,  // NOOP - 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
107     };
108
109     SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
110                       need_to_be_in_sync);
111     SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
112
113     int overflow = 0;
114     if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
115         // This op's size overflows so an extra uint32_t will be written
116         // after the op code
117         overflow = sizeof(uint32_t);
118     }
119
120     if (SAVE_LAYER == op) {
121         static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
122         static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
123
124         if (kSaveLayerNoBoundsSize == opSize) {
125             return kSaveLayerNoBoundsPaintOffset + overflow;
126         } else {
127             SkASSERT(kSaveLayerWithBoundsSize == opSize);
128             return kSaveLayerWithBoundsPaintOffset + overflow;
129         }
130     }
131
132     SkASSERT(0 != gPaintOffsets[op]);   // really shouldn't be calling this method
133     return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
134 }
135 #endif//SK_DEBUG
136
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());
141     this->recordSave();
142
143     this->INHERITED::willSave();
144 }
145
146 void SkPictureRecord::recordSave() {
147     fContentInfo.onSave();
148
149     // op only
150     size_t size = kSaveSize;
151     size_t initialOffset = this->addDraw(SAVE, &size);
152
153     this->validate(initialOffset, size);
154 }
155
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();
164     }
165
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).
171      */
172     return kNoLayer_SaveLayerStrategy;
173 }
174
175 void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
176                                       SaveFlags flags) {
177     fContentInfo.onSaveLayer();
178
179     // op + bool for 'bounds'
180     size_t size = 2 * kUInt32Size;
181     if (bounds) {
182         size += sizeof(*bounds); // + rect
183     }
184     // + paint index + flags
185     size += 2 * kUInt32Size;
186
187     SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
188
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);
193     this->addInt(flags);
194
195     this->validate(initialOffset, size);
196 }
197
198 bool SkPictureRecord::isDrawingToLayer() const {
199     return fFirstSavedLayerIndex != kNoSavedLayerIndex;
200 }
201
202 #ifdef SK_DEBUG
203 /*
204  * Read the op code from 'offset' in 'writer' and extract the size too.
205  */
206 static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
207     uint32_t peek = writer->readTAt<uint32_t>(offset);
208
209     uint32_t op;
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);
214     }
215     return (DrawType) op;
216 }
217 #endif//SK_DEBUG
218
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.
223 #if 0
224     SkASSERT(fRestoreOffsetStack.count() > 1);
225 #endif
226
227     // check for underflow
228     if (fRestoreOffsetStack.count() == 0) {
229         return;
230     }
231
232     if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
233         fFirstSavedLayerIndex = kNoSavedLayerIndex;
234     }
235
236     this->recordRestore();
237
238     fRestoreOffsetStack.pop();
239
240     this->INHERITED::willRestore();
241 }
242
243 void SkPictureRecord::recordRestore(bool fillInSkips) {
244     fContentInfo.onRestore();
245
246     if (fillInSkips) {
247         this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
248     }
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);
252 }
253
254 void SkPictureRecord::recordTranslate(const SkMatrix& m) {
255     SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
256
257     // op + dx + dy
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);
263 }
264
265 void SkPictureRecord::recordScale(const SkMatrix& m) {
266     SkASSERT(SkMatrix::kScale_Mask == m.getType());
267
268     // op + sx + sy
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);
274 }
275
276 void SkPictureRecord::didConcat(const SkMatrix& matrix) {
277     switch (matrix.getType()) {
278         case SkMatrix::kTranslate_Mask:
279             this->recordTranslate(matrix);
280             break;
281         case SkMatrix::kScale_Mask:
282             this->recordScale(matrix);
283             break;
284         default:
285             this->recordConcat(matrix);
286             break;
287     }
288     this->INHERITED::didConcat(matrix);
289 }
290
291 void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
292     this->validate(fWriter.bytesWritten(), 0);
293     // op + matrix
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);
298 }
299
300 void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
301     this->validate(fWriter.bytesWritten(), 0);
302     // op + matrix
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);
308 }
309
310 static bool regionOpExpands(SkRegion::Op op) {
311     switch (op) {
312         case SkRegion::kUnion_Op:
313         case SkRegion::kXOR_Op:
314         case SkRegion::kReverseDifference_Op:
315         case SkRegion::kReplace_Op:
316             return true;
317         case SkRegion::kIntersect_Op:
318         case SkRegion::kDifference_Op:
319             return false;
320         default:
321             SkDEBUGFAIL("unknown region op");
322             return false;
323     }
324 }
325
326 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
327     int32_t offset = fRestoreOffsetStack.top();
328     while (offset > 0) {
329         uint32_t peek = fWriter.readTAt<uint32_t>(offset);
330         fWriter.overwriteTAt(offset, restoreOffset);
331         offset = peek;
332     }
333
334 #ifdef SK_DEBUG
335     // assert that the final offset value points to a save verb
336     uint32_t opSize;
337     DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
338     SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
339 #endif
340 }
341
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();
347 }
348
349 void SkPictureRecord::endRecording() {
350     SkASSERT(kNoInitialSave != fInitialSaveCount);
351     this->restoreToCount(fInitialSaveCount);
352 }
353
354 size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
355     if (fRestoreOffsetStack.isEmpty()) {
356         return -1;
357     }
358
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();
365
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);
372
373         // Reset the pointer back to the previous clip so that subsequent
374         // restores don't overwrite the offsets we just cleared.
375         prevOffset = 0;
376     }
377
378     size_t offset = fWriter.bytesWritten();
379     this->addInt(prevOffset);
380     fRestoreOffsetStack.top() = SkToU32(offset);
381     return offset;
382 }
383
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);
387 }
388
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()) {
394         // + restore offset
395         size += kUInt32Size;
396     }
397     size_t initialOffset = this->addDraw(CLIP_RECT, &size);
398     this->addRect(rect);
399     this->addInt(ClipParams_pack(op, doAA));
400     size_t offset = this->recordRestoreOffsetPlaceholder(op);
401
402     this->validate(initialOffset, size);
403     return offset;
404 }
405
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);
409 }
410
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()) {
416         // + restore offset
417         size += kUInt32Size;
418     }
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);
424     return offset;
425 }
426
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);
431 }
432
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()) {
438         // + restore offset
439         size += kUInt32Size;
440     }
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);
446     return offset;
447 }
448
449 void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
450     this->recordClipRegion(region, op);
451     this->INHERITED::onClipRegion(region, op);
452 }
453
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()) {
459         // + restore offset
460         size += kUInt32Size;
461     }
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);
466
467     this->validate(initialOffset, size);
468     return offset;
469 }
470
471 void SkPictureRecord::clear(SkColor color) {
472     // op + color
473     size_t size = 2 * kUInt32Size;
474     size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
475     this->addInt(color);
476     this->validate(initialOffset, size);
477 }
478
479 void SkPictureRecord::drawPaint(const SkPaint& paint) {
480     // op + paint index
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);
486 }
487
488 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
489                                  const SkPaint& paint) {
490     fContentInfo.onDrawPoints(count, paint);
491
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);
497
498     this->addInt(mode);
499     this->addInt(SkToInt(count));
500     fWriter.writeMul4(pts, count * sizeof(SkPoint));
501     this->validate(initialOffset, size);
502 }
503
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);
510     this->addRect(oval);
511     this->validate(initialOffset, size);
512 }
513
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);
520     this->addRect(rect);
521     this->validate(initialOffset, size);
522 }
523
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);
532 }
533
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);
544 }
545
546 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
547     fContentInfo.onDrawPath(path, paint);
548
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);
554     this->addPath(path);
555     this->validate(initialOffset, size);
556 }
557
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);
569 }
570
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;
576     if (src) {
577         size += sizeof(*src);   // + rect
578     }
579     size += sizeof(dst);        // + rect
580
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
587     this->addRect(dst);
588     this->addInt(flags);
589     this->validate(initialOffset, size);
590 }
591
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);
602 }
603
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);
613     this->addRect(dst);
614     this->validate(initialOffset, size);
615 }
616
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);
625     this->addInt(left);
626     this->addInt(top);
627     this->validate(initialOffset, size);
628 }
629
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);
634
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);
640     this->addScalar(x);
641     this->addScalar(y);
642     this->validate(initialOffset, size);
643 }
644
645 void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
646                                     const SkPaint& paint) {
647     int points = paint.countText(text, byteLength);
648
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);
651
652     DrawType op = DRAW_POS_TEXT;
653
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);
661 }
662
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);
666
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);
671
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);
679 }
680
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);
690     this->addPath(path);
691     this->addMatrix(m);
692     this->validate(initialOffset, size);
693 }
694
695 void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
696                                      const SkPaint& paint) {
697
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());
702
703     this->addPaint(paint);
704     this->addTextBlob(blob);
705     this->addScalar(x);
706     this->addScalar(y);
707
708     this->validate(initialOffset, size);
709 }
710
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;
716
717     if (NULL == matrix && NULL == paint) {
718         initialOffset = this->addDraw(DRAW_PICTURE, &size);
719         this->addPicture(picture);
720     } else {
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);
727         this->addMatrix(m);
728         this->addPicture(picture);
729     }
730     this->validate(initialOffset, size);
731 }
732
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) {
738     uint32_t flags = 0;
739     if (texs) {
740         flags |= DRAW_VERTICES_HAS_TEXS;
741     }
742     if (colors) {
743         flags |= DRAW_VERTICES_HAS_COLORS;
744     }
745     if (indexCount > 0) {
746         flags |= DRAW_VERTICES_HAS_INDICES;
747     }
748     if (xfer) {
749         SkXfermode::Mode mode;
750         if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
751             flags |= DRAW_VERTICES_HAS_XFER;
752         }
753     }
754
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
759     }
760     if (flags & DRAW_VERTICES_HAS_COLORS) {
761         size += vertexCount * sizeof(SkColor);  // + vert colors
762     }
763     if (flags & DRAW_VERTICES_HAS_INDICES) {
764         // + num indices + indices
765         size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
766     }
767     if (flags & DRAW_VERTICES_HAS_XFER) {
768         size += kUInt32Size;    // mode enum
769     }
770
771     size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
772     SkASSERT(initialOffset+get_paint_offset(DRAW_VERTICES, size) == fWriter.bytesWritten());
773     this->addPaint(paint);
774     this->addInt(flags);
775     this->addInt(vmode);
776     this->addInt(vertexCount);
777     this->addPoints(vertices, vertexCount);
778     if (flags & DRAW_VERTICES_HAS_TEXS) {
779         this->addPoints(texs, vertexCount);
780     }
781     if (flags & DRAW_VERTICES_HAS_COLORS) {
782         fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
783     }
784     if (flags & DRAW_VERTICES_HAS_INDICES) {
785         this->addInt(indexCount);
786         fWriter.writePad(indices, indexCount * sizeof(uint16_t));
787     }
788     if (flags & DRAW_VERTICES_HAS_XFER) {
789         SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
790         (void)xfer->asMode(&mode);
791         this->addInt(mode);
792     }
793     this->validate(initialOffset, size);
794 }
795
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;
801     uint32_t flag = 0;
802     if (colors) {
803         flag |= DRAW_VERTICES_HAS_COLORS;
804         size += SkPatchUtils::kNumCorners * sizeof(SkColor);
805     }
806     if (texCoords) {
807         flag |= DRAW_VERTICES_HAS_TEXS;
808         size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
809     }
810     if (xmode) {
811         SkXfermode::Mode mode;
812         if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
813             flag |= DRAW_VERTICES_HAS_XFER;
814             size += kUInt32Size;
815         }
816     }
817
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);
822     this->addInt(flag);
823
824     // write optional parameters
825     if (colors) {
826         fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
827     }
828     if (texCoords) {
829         fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
830     }
831     if (flag & DRAW_VERTICES_HAS_XFER) {
832         SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
833         xmode->asMode(&mode);
834         this->addInt(mode);
835     }
836     this->validate(initialOffset, size);
837 }
838
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);
846 }
847
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);
855 }
856
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);
866 }
867
868 void SkPictureRecord::endCommentGroup() {
869     // op/size
870     size_t size = 1 * kUInt32Size;
871     size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
872     this->validate(initialOffset, size);
873 }
874
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);
882
883     this->addRect(cullRect);
884     fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
885     this->addInt(0);
886     this->validate(initialOffset, size);
887 }
888
889 void SkPictureRecord::onPopCull() {
890     SkASSERT(!fCullOffsetStack.isEmpty());
891
892     uint32_t cullSkipOffset = fCullOffsetStack.top();
893     fCullOffsetStack.pop();
894
895     // op only
896     size_t size = kUInt32Size;
897     size_t initialOffset = this->addDraw(POP_CULL, &size);
898
899     // update the cull skip offset to point past this op.
900     fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
901
902     this->validate(initialOffset, size);
903 }
904
905 ///////////////////////////////////////////////////////////////////////////////
906
907 SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
908     return NULL;
909 }
910
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
915     // was a problem.
916     SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
917     this->addInt(index);
918     return index;
919 }
920
921 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
922     fWriter.writeMatrix(matrix);
923 }
924
925 void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
926     fContentInfo.onAddPaintPtr(paint);
927
928     if (paint) {
929         const SkFlatData* flat = fPaints.findAndReturnFlat(*paint);
930         SkASSERT(flat && flat->index() != 0);
931         this->addInt(flat->index());
932     } else {
933         this->addInt(0);
934     }
935 }
936
937 int SkPictureRecord::addPathToHeap(const SkPath& path) {
938     if (NULL == fPathHeap) {
939         fPathHeap.reset(SkNEW(SkPathHeap));
940     }
941 #ifdef SK_DEDUP_PICTURE_PATHS
942     return fPathHeap->insert(path);
943 #else
944     return fPathHeap->append(path);
945 #endif
946 }
947
948 void SkPictureRecord::addPath(const SkPath& path) {
949     this->addInt(this->addPathToHeap(path));
950 }
951
952 void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
953     fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
954 }
955
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;
961         picture->ref();
962     }
963     // follow the convention of recording a 1-based index
964     this->addInt(index + 1);
965 }
966
967 void SkPictureRecord::addPoint(const SkPoint& point) {
968     fWriter.writePoint(point);
969 }
970
971 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
972     fWriter.writeMul4(pts, count * sizeof(SkPoint));
973 }
974
975 void SkPictureRecord::addNoOp() {
976     size_t size = kUInt32Size; // op
977     this->addDraw(NOOP, &size);
978 }
979
980 void SkPictureRecord::addRect(const SkRect& rect) {
981     fWriter.writeRect(rect);
982 }
983
984 void SkPictureRecord::addRectPtr(const SkRect* rect) {
985     if (fWriter.writeBool(rect != NULL)) {
986         fWriter.writeRect(*rect);
987     }
988 }
989
990 void SkPictureRecord::addIRect(const SkIRect& rect) {
991     fWriter.write(&rect, sizeof(rect));
992 }
993
994 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
995     if (fWriter.writeBool(rect != NULL)) {
996         *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
997     }
998 }
999
1000 void SkPictureRecord::addRRect(const SkRRect& rrect) {
1001     fWriter.writeRRect(rrect);
1002 }
1003
1004 void SkPictureRecord::addRegion(const SkRegion& region) {
1005     fWriter.writeRegion(region);
1006 }
1007
1008 void SkPictureRecord::addText(const void* text, size_t byteLength) {
1009     fContentInfo.onDrawText();
1010     addInt(SkToInt(byteLength));
1011     fWriter.writePad(text, byteLength);
1012 }
1013
1014 void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
1015     int index = fTextBlobRefs.count();
1016     *fTextBlobRefs.append() = blob;
1017     blob->ref();
1018     // follow the convention of recording a 1-based index
1019     this->addInt(index + 1);
1020 }
1021
1022 ///////////////////////////////////////////////////////////////////////////////
1023