SkPictureRecord.cpp revision 2ff1fcede1e9525285c5de1f35fb2dcb0fab32bd
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
18enum {
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.
24static int const kUInt32Size = 4;
25
26static const uint32_t kSaveSize = kUInt32Size;
27#ifdef SK_DEBUG
28static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
29static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
30#endif//SK_DEBUG
31
32SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
33    : INHERITED(dimensions.width(), dimensions.height())
34    , fFirstSavedLayerIndex(kNoSavedLayerIndex)
35    , fRecordFlags(flags)
36    , fInitialSaveCount(kNoInitialSave) {
37}
38
39SkPictureRecord::~SkPictureRecord() {
40    fPictureRefs.unrefAll();
41    fTextBlobRefs.unrefAll();
42}
43
44///////////////////////////////////////////////////////////////////////////////
45
46#ifdef SK_DEBUG
47// Return the offset of the paint inside a given op's byte stream. A zero
48// return value means there is no paint (and you really shouldn't be calling
49// this method)
50static inline size_t get_paint_offset(DrawType op, size_t opSize) {
51    // These offsets are where the paint would be if the op size doesn't overflow
52    static const uint8_t gPaintOffsets[] = {
53        0,  // UNUSED - no paint
54        0,  // CLIP_PATH - no paint
55        0,  // CLIP_REGION - no paint
56        0,  // CLIP_RECT - no paint
57        0,  // CLIP_RRECT - no paint
58        0,  // CONCAT - no paint
59        1,  // DRAW_BITMAP - right after op code
60        1,  // DRAW_BITMAP_MATRIX - right after op code, deprecated
61        1,  // DRAW_BITMAP_NINE - right after op code
62        1,  // DRAW_BITMAP_RECT_TO_RECT - right after op code
63        0,  // DRAW_CLEAR - no paint
64        0,  // DRAW_DATA - no paint
65        1,  // DRAW_OVAL - right after op code
66        1,  // DRAW_PAINT - right after op code
67        1,  // DRAW_PATH - right after op code
68        0,  // DRAW_PICTURE - no paint
69        1,  // DRAW_POINTS - right after op code
70        1,  // DRAW_POS_TEXT - right after op code
71        1,  // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
72        1,  // DRAW_POS_TEXT_H - right after op code
73        1,  // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
74        1,  // DRAW_RECT - right after op code
75        1,  // DRAW_RRECT - right after op code
76        1,  // DRAW_SPRITE - right after op code
77        1,  // DRAW_TEXT - right after op code
78        1,  // DRAW_TEXT_ON_PATH - right after op code
79        1,  // DRAW_TEXT_TOP_BOTTOM - right after op code
80        1,  // DRAW_VERTICES - right after op code
81        0,  // RESTORE - no paint
82        0,  // ROTATE - no paint
83        0,  // SAVE - no paint
84        0,  // SAVE_LAYER - see below - this paint's location varies
85        0,  // SCALE - no paint
86        0,  // SET_MATRIX - no paint
87        0,  // SKEW - no paint
88        0,  // TRANSLATE - no paint
89        0,  // NOOP - no paint
90        0,  // BEGIN_GROUP - no paint
91        0,  // COMMENT - no paint
92        0,  // END_GROUP - no paint
93        1,  // DRAWDRRECT - right after op code
94        0,  // PUSH_CULL - no paint
95        0,  // POP_CULL - no paint
96        1,  // DRAW_PATCH - right after op code
97        1,  // DRAW_PICTURE_MATRIX_PAINT - right after op code
98        1,  // DRAW_TEXT_BLOB- right after op code
99    };
100
101    SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
102                      need_to_be_in_sync);
103    SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
104
105    int overflow = 0;
106    if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
107        // This op's size overflows so an extra uint32_t will be written
108        // after the op code
109        overflow = sizeof(uint32_t);
110    }
111
112    if (SAVE_LAYER == op) {
113        static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
114        static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
115
116        if (kSaveLayerNoBoundsSize == opSize) {
117            return kSaveLayerNoBoundsPaintOffset + overflow;
118        } else {
119            SkASSERT(kSaveLayerWithBoundsSize == opSize);
120            return kSaveLayerWithBoundsPaintOffset + overflow;
121        }
122    }
123
124    SkASSERT(0 != gPaintOffsets[op]);   // really shouldn't be calling this method
125    return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
126}
127#endif//SK_DEBUG
128
129void SkPictureRecord::willSave() {
130    // record the offset to us, making it non-positive to distinguish a save
131    // from a clip entry.
132    fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
133    this->recordSave();
134
135    this->INHERITED::willSave();
136}
137
138void SkPictureRecord::recordSave() {
139    fContentInfo.onSave();
140
141    // op only
142    size_t size = kSaveSize;
143    size_t initialOffset = this->addDraw(SAVE, &size);
144
145    this->validate(initialOffset, size);
146}
147
148SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
149                                                           const SkPaint* paint, SaveFlags flags) {
150    // record the offset to us, making it non-positive to distinguish a save
151    // from a clip entry.
152    fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
153    this->recordSaveLayer(bounds, paint, flags);
154    if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
155        fFirstSavedLayerIndex = fRestoreOffsetStack.count();
156    }
157
158    this->INHERITED::willSaveLayer(bounds, paint, flags);
159    /*  No need for a (potentially very big) layer which we don't actually need
160        at this time (and may not be able to afford since during record our
161        clip starts out the size of the picture, which is often much larger
162        than the size of the actual device we'll use during playback).
163     */
164    return kNoLayer_SaveLayerStrategy;
165}
166
167void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
168                                      SaveFlags flags) {
169    fContentInfo.onSaveLayer();
170
171    // op + bool for 'bounds'
172    size_t size = 2 * kUInt32Size;
173    if (bounds) {
174        size += sizeof(*bounds); // + rect
175    }
176    // + paint index + flags
177    size += 2 * kUInt32Size;
178
179    SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
180
181    size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
182    this->addRectPtr(bounds);
183    SkASSERT(initialOffset+get_paint_offset(SAVE_LAYER, size) == fWriter.bytesWritten());
184    this->addPaintPtr(paint);
185    this->addInt(flags);
186
187    this->validate(initialOffset, size);
188}
189
190bool SkPictureRecord::isDrawingToLayer() const {
191    return fFirstSavedLayerIndex != kNoSavedLayerIndex;
192}
193
194#ifdef SK_DEBUG
195/*
196 * Read the op code from 'offset' in 'writer' and extract the size too.
197 */
198static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
199    uint32_t peek = writer->readTAt<uint32_t>(offset);
200
201    uint32_t op;
202    UNPACK_8_24(peek, op, *size);
203    if (MASK_24 == *size) {
204        // size required its own slot right after the op code
205        *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
206    }
207    return (DrawType) op;
208}
209#endif//SK_DEBUG
210
211void SkPictureRecord::willRestore() {
212    // FIXME: SkDeferredCanvas needs to be refactored to respect
213    // save/restore balancing so that the following test can be
214    // turned on permanently.
215#if 0
216    SkASSERT(fRestoreOffsetStack.count() > 1);
217#endif
218
219    // check for underflow
220    if (fRestoreOffsetStack.count() == 0) {
221        return;
222    }
223
224    if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
225        fFirstSavedLayerIndex = kNoSavedLayerIndex;
226    }
227
228    this->recordRestore();
229
230    fRestoreOffsetStack.pop();
231
232    this->INHERITED::willRestore();
233}
234
235void SkPictureRecord::recordRestore(bool fillInSkips) {
236    fContentInfo.onRestore();
237
238    if (fillInSkips) {
239        this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
240    }
241    size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
242    size_t initialOffset = this->addDraw(RESTORE, &size);
243    this->validate(initialOffset, size);
244}
245
246void SkPictureRecord::recordTranslate(const SkMatrix& m) {
247    SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
248
249    // op + dx + dy
250    size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
251    size_t initialOffset = this->addDraw(TRANSLATE, &size);
252    this->addScalar(m.getTranslateX());
253    this->addScalar(m.getTranslateY());
254    this->validate(initialOffset, size);
255}
256
257void SkPictureRecord::recordScale(const SkMatrix& m) {
258    SkASSERT(SkMatrix::kScale_Mask == m.getType());
259
260    // op + sx + sy
261    size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
262    size_t initialOffset = this->addDraw(SCALE, &size);
263    this->addScalar(m.getScaleX());
264    this->addScalar(m.getScaleY());
265    this->validate(initialOffset, size);
266}
267
268void SkPictureRecord::didConcat(const SkMatrix& matrix) {
269    switch (matrix.getType()) {
270        case SkMatrix::kTranslate_Mask:
271            this->recordTranslate(matrix);
272            break;
273        case SkMatrix::kScale_Mask:
274            this->recordScale(matrix);
275            break;
276        default:
277            this->recordConcat(matrix);
278            break;
279    }
280    this->INHERITED::didConcat(matrix);
281}
282
283void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
284    this->validate(fWriter.bytesWritten(), 0);
285    // op + matrix
286    size_t size = kUInt32Size + matrix.writeToMemory(NULL);
287    size_t initialOffset = this->addDraw(CONCAT, &size);
288    this->addMatrix(matrix);
289    this->validate(initialOffset, size);
290}
291
292void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
293    this->validate(fWriter.bytesWritten(), 0);
294    // op + matrix
295    size_t size = kUInt32Size + matrix.writeToMemory(NULL);
296    size_t initialOffset = this->addDraw(SET_MATRIX, &size);
297    this->addMatrix(matrix);
298    this->validate(initialOffset, size);
299    this->INHERITED::didSetMatrix(matrix);
300}
301
302static bool regionOpExpands(SkRegion::Op op) {
303    switch (op) {
304        case SkRegion::kUnion_Op:
305        case SkRegion::kXOR_Op:
306        case SkRegion::kReverseDifference_Op:
307        case SkRegion::kReplace_Op:
308            return true;
309        case SkRegion::kIntersect_Op:
310        case SkRegion::kDifference_Op:
311            return false;
312        default:
313            SkDEBUGFAIL("unknown region op");
314            return false;
315    }
316}
317
318void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
319    int32_t offset = fRestoreOffsetStack.top();
320    while (offset > 0) {
321        uint32_t peek = fWriter.readTAt<uint32_t>(offset);
322        fWriter.overwriteTAt(offset, restoreOffset);
323        offset = peek;
324    }
325
326#ifdef SK_DEBUG
327    // offset of 0 has been disabled, so we skip it
328    if (offset > 0) {
329        // assert that the final offset value points to a save verb
330        uint32_t opSize;
331        DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
332        SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
333    }
334#endif
335}
336
337void SkPictureRecord::beginRecording() {
338    // we have to call this *after* our constructor, to ensure that it gets
339    // recorded. This is balanced by restoreToCount() call from endRecording,
340    // which in-turn calls our overridden restore(), so those get recorded too.
341    fInitialSaveCount = this->save();
342}
343
344void SkPictureRecord::endRecording() {
345    SkASSERT(kNoInitialSave != fInitialSaveCount);
346    this->restoreToCount(fInitialSaveCount);
347}
348
349size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
350    if (fRestoreOffsetStack.isEmpty()) {
351        return -1;
352    }
353
354    // The RestoreOffset field is initially filled with a placeholder
355    // value that points to the offset of the previous RestoreOffset
356    // in the current stack level, thus forming a linked list so that
357    // the restore offsets can be filled in when the corresponding
358    // restore command is recorded.
359    int32_t prevOffset = fRestoreOffsetStack.top();
360
361    if (regionOpExpands(op)) {
362        // Run back through any previous clip ops, and mark their offset to
363        // be 0, disabling their ability to trigger a jump-to-restore, otherwise
364        // they could hide this clips ability to expand the clip (i.e. go from
365        // empty to non-empty).
366        this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
367
368        // Reset the pointer back to the previous clip so that subsequent
369        // restores don't overwrite the offsets we just cleared.
370        prevOffset = 0;
371    }
372
373    size_t offset = fWriter.bytesWritten();
374    this->addInt(prevOffset);
375    fRestoreOffsetStack.top() = SkToU32(offset);
376    return offset;
377}
378
379void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
380    this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
381    this->INHERITED::onClipRect(rect, op, edgeStyle);
382}
383
384size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
385    // id + rect + clip params
386    size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
387    // recordRestoreOffsetPlaceholder doesn't always write an offset
388    if (!fRestoreOffsetStack.isEmpty()) {
389        // + restore offset
390        size += kUInt32Size;
391    }
392    size_t initialOffset = this->addDraw(CLIP_RECT, &size);
393    this->addRect(rect);
394    this->addInt(ClipParams_pack(op, doAA));
395    size_t offset = this->recordRestoreOffsetPlaceholder(op);
396
397    this->validate(initialOffset, size);
398    return offset;
399}
400
401void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
402    this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
403    this->INHERITED::onClipRRect(rrect, op, edgeStyle);
404}
405
406size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
407    // op + rrect + clip params
408    size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
409    // recordRestoreOffsetPlaceholder doesn't always write an offset
410    if (!fRestoreOffsetStack.isEmpty()) {
411        // + restore offset
412        size += kUInt32Size;
413    }
414    size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
415    this->addRRect(rrect);
416    this->addInt(ClipParams_pack(op, doAA));
417    size_t offset = recordRestoreOffsetPlaceholder(op);
418    this->validate(initialOffset, size);
419    return offset;
420}
421
422void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
423    int pathID = this->addPathToHeap(path);
424    this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
425    this->INHERITED::onClipPath(path, op, edgeStyle);
426}
427
428size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
429    // op + path index + clip params
430    size_t size = 3 * kUInt32Size;
431    // recordRestoreOffsetPlaceholder doesn't always write an offset
432    if (!fRestoreOffsetStack.isEmpty()) {
433        // + restore offset
434        size += kUInt32Size;
435    }
436    size_t initialOffset = this->addDraw(CLIP_PATH, &size);
437    this->addInt(pathID);
438    this->addInt(ClipParams_pack(op, doAA));
439    size_t offset = recordRestoreOffsetPlaceholder(op);
440    this->validate(initialOffset, size);
441    return offset;
442}
443
444void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
445    this->recordClipRegion(region, op);
446    this->INHERITED::onClipRegion(region, op);
447}
448
449size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
450    // op + clip params + region
451    size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
452    // recordRestoreOffsetPlaceholder doesn't always write an offset
453    if (!fRestoreOffsetStack.isEmpty()) {
454        // + restore offset
455        size += kUInt32Size;
456    }
457    size_t initialOffset = this->addDraw(CLIP_REGION, &size);
458    this->addRegion(region);
459    this->addInt(ClipParams_pack(op, false));
460    size_t offset = this->recordRestoreOffsetPlaceholder(op);
461
462    this->validate(initialOffset, size);
463    return offset;
464}
465
466void SkPictureRecord::drawPaint(const SkPaint& paint) {
467    // op + paint index
468    size_t size = 2 * kUInt32Size;
469    size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
470    SkASSERT(initialOffset+get_paint_offset(DRAW_PAINT, size) == fWriter.bytesWritten());
471    this->addPaint(paint);
472    this->validate(initialOffset, size);
473}
474
475void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
476                                 const SkPaint& paint) {
477    fContentInfo.onDrawPoints(count, paint);
478
479    // op + paint index + mode + count + point data
480    size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
481    size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
482    SkASSERT(initialOffset+get_paint_offset(DRAW_POINTS, size) == fWriter.bytesWritten());
483    this->addPaint(paint);
484
485    this->addInt(mode);
486    this->addInt(SkToInt(count));
487    fWriter.writeMul4(pts, count * sizeof(SkPoint));
488    this->validate(initialOffset, size);
489}
490
491void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
492    // op + paint index + rect
493    size_t size = 2 * kUInt32Size + sizeof(oval);
494    size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
495    SkASSERT(initialOffset+get_paint_offset(DRAW_OVAL, size) == fWriter.bytesWritten());
496    this->addPaint(paint);
497    this->addRect(oval);
498    this->validate(initialOffset, size);
499}
500
501void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
502    // op + paint index + rect
503    size_t size = 2 * kUInt32Size + sizeof(rect);
504    size_t initialOffset = this->addDraw(DRAW_RECT, &size);
505    SkASSERT(initialOffset+get_paint_offset(DRAW_RECT, size) == fWriter.bytesWritten());
506    this->addPaint(paint);
507    this->addRect(rect);
508    this->validate(initialOffset, size);
509}
510
511void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
512    // op + paint index + rrect
513    size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
514    size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
515    SkASSERT(initialOffset+get_paint_offset(DRAW_RRECT, size) == fWriter.bytesWritten());
516    this->addPaint(paint);
517    this->addRRect(rrect);
518    this->validate(initialOffset, size);
519}
520
521void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
522                                   const SkPaint& paint) {
523    // op + paint index + rrects
524    size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
525    size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
526    SkASSERT(initialOffset+get_paint_offset(DRAW_DRRECT, size) == fWriter.bytesWritten());
527    this->addPaint(paint);
528    this->addRRect(outer);
529    this->addRRect(inner);
530    this->validate(initialOffset, size);
531}
532
533void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
534    fContentInfo.onDrawPath(path, paint);
535
536    // op + paint index + path index
537    size_t size = 3 * kUInt32Size;
538    size_t initialOffset = this->addDraw(DRAW_PATH, &size);
539    SkASSERT(initialOffset+get_paint_offset(DRAW_PATH, size) == fWriter.bytesWritten());
540    this->addPaint(paint);
541    this->addPath(path);
542    this->validate(initialOffset, size);
543}
544
545void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
546                                 const SkPaint* paint = NULL) {
547    // op + paint index + bitmap index + left + top
548    size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
549    size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
550    SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP, size) == fWriter.bytesWritten());
551    this->addPaintPtr(paint);
552    this->addBitmap(bitmap);
553    this->addScalar(left);
554    this->addScalar(top);
555    this->validate(initialOffset, size);
556}
557
558void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
559                                           const SkRect& dst, const SkPaint* paint,
560                                           DrawBitmapRectFlags flags) {
561    // id + paint index + bitmap index + bool for 'src' + flags
562    size_t size = 5 * kUInt32Size;
563    if (src) {
564        size += sizeof(*src);   // + rect
565    }
566    size += sizeof(dst);        // + rect
567
568    size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
569    SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_RECT_TO_RECT, size)
570             == fWriter.bytesWritten());
571    this->addPaintPtr(paint);
572    this->addBitmap(bitmap);
573    this->addRectPtr(src);  // may be null
574    this->addRect(dst);
575    this->addInt(flags);
576    this->validate(initialOffset, size);
577}
578
579void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
580                                     const SkRect& dst, const SkPaint* paint) {
581    // op + paint index + bitmap id + center + dst rect
582    size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
583    size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
584    SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
585    this->addPaintPtr(paint);
586    this->addBitmap(bitmap);
587    this->addIRect(center);
588    this->addRect(dst);
589    this->validate(initialOffset, size);
590}
591
592void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
593                                 const SkPaint* paint = NULL) {
594    // op + paint index + bitmap index + left + top
595    size_t size = 5 * kUInt32Size;
596    size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
597    SkASSERT(initialOffset+get_paint_offset(DRAW_SPRITE, size) == fWriter.bytesWritten());
598    this->addPaintPtr(paint);
599    this->addBitmap(bitmap);
600    this->addInt(left);
601    this->addInt(top);
602    this->validate(initialOffset, size);
603}
604
605void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
606                                 const SkPaint& paint) {
607    // op + paint index + length + 'length' worth of chars + x + y
608    size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
609
610    DrawType op = DRAW_TEXT;
611    size_t initialOffset = this->addDraw(op, &size);
612    SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
613    this->addPaint(paint);
614    this->addText(text, byteLength);
615    this->addScalar(x);
616    this->addScalar(y);
617    this->validate(initialOffset, size);
618}
619
620void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
621                                    const SkPaint& paint) {
622    int points = paint.countText(text, byteLength);
623
624    // op + paint index + length + 'length' worth of data + num points + x&y point data
625    size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint);
626
627    DrawType op = DRAW_POS_TEXT;
628
629    size_t initialOffset = this->addDraw(op, &size);
630    SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
631    this->addPaint(paint);
632    this->addText(text, byteLength);
633    this->addInt(points);
634    fWriter.writeMul4(pos, points * sizeof(SkPoint));
635    this->validate(initialOffset, size);
636}
637
638void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
639                                     SkScalar constY, const SkPaint& paint) {
640    int points = paint.countText(text, byteLength);
641
642    // op + paint index + length + 'length' worth of data + num points
643    size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
644    // + y + the actual points
645    size += 1 * kUInt32Size + points * sizeof(SkScalar);
646
647    size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size);
648    this->addPaint(paint);
649    this->addText(text, byteLength);
650    this->addInt(points);
651    this->addScalar(constY);
652    fWriter.writeMul4(xpos, points * sizeof(SkScalar));
653    this->validate(initialOffset, size);
654}
655
656void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
657                                       const SkMatrix* matrix, const SkPaint& paint) {
658    // op + paint index + length + 'length' worth of data + path index + matrix
659    const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
660    size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
661    size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
662    SkASSERT(initialOffset+get_paint_offset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
663    this->addPaint(paint);
664    this->addText(text, byteLength);
665    this->addPath(path);
666    this->addMatrix(m);
667    this->validate(initialOffset, size);
668}
669
670void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
671                                     const SkPaint& paint) {
672
673    // op + paint index + blob index + x/y
674    size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
675    size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
676    SkASSERT(initialOffset + get_paint_offset(DRAW_TEXT_BLOB, size) == fWriter.bytesWritten());
677
678    this->addPaint(paint);
679    this->addTextBlob(blob);
680    this->addScalar(x);
681    this->addScalar(y);
682
683    this->validate(initialOffset, size);
684}
685
686void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
687                                    const SkPaint* paint) {
688    // op + picture index
689    size_t size = 2 * kUInt32Size;
690    size_t initialOffset;
691
692    if (NULL == matrix && NULL == paint) {
693        initialOffset = this->addDraw(DRAW_PICTURE, &size);
694        this->addPicture(picture);
695    } else {
696        const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
697        size += m.writeToMemory(NULL) + kUInt32Size;    // matrix + paint
698        initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
699        SkASSERT(initialOffset + get_paint_offset(DRAW_PICTURE_MATRIX_PAINT, size)
700                 == fWriter.bytesWritten());
701        this->addPaintPtr(paint);
702        this->addMatrix(m);
703        this->addPicture(picture);
704    }
705    this->validate(initialOffset, size);
706}
707
708void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
709                          const SkPoint vertices[], const SkPoint texs[],
710                          const SkColor colors[], SkXfermode* xfer,
711                          const uint16_t indices[], int indexCount,
712                          const SkPaint& paint) {
713    uint32_t flags = 0;
714    if (texs) {
715        flags |= DRAW_VERTICES_HAS_TEXS;
716    }
717    if (colors) {
718        flags |= DRAW_VERTICES_HAS_COLORS;
719    }
720    if (indexCount > 0) {
721        flags |= DRAW_VERTICES_HAS_INDICES;
722    }
723    if (xfer) {
724        SkXfermode::Mode mode;
725        if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
726            flags |= DRAW_VERTICES_HAS_XFER;
727        }
728    }
729
730    // op + paint index + flags + vmode + vCount + vertices
731    size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
732    if (flags & DRAW_VERTICES_HAS_TEXS) {
733        size += vertexCount * sizeof(SkPoint);  // + uvs
734    }
735    if (flags & DRAW_VERTICES_HAS_COLORS) {
736        size += vertexCount * sizeof(SkColor);  // + vert colors
737    }
738    if (flags & DRAW_VERTICES_HAS_INDICES) {
739        // + num indices + indices
740        size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
741    }
742    if (flags & DRAW_VERTICES_HAS_XFER) {
743        size += kUInt32Size;    // mode enum
744    }
745
746    size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
747    SkASSERT(initialOffset+get_paint_offset(DRAW_VERTICES, size) == fWriter.bytesWritten());
748    this->addPaint(paint);
749    this->addInt(flags);
750    this->addInt(vmode);
751    this->addInt(vertexCount);
752    this->addPoints(vertices, vertexCount);
753    if (flags & DRAW_VERTICES_HAS_TEXS) {
754        this->addPoints(texs, vertexCount);
755    }
756    if (flags & DRAW_VERTICES_HAS_COLORS) {
757        fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
758    }
759    if (flags & DRAW_VERTICES_HAS_INDICES) {
760        this->addInt(indexCount);
761        fWriter.writePad(indices, indexCount * sizeof(uint16_t));
762    }
763    if (flags & DRAW_VERTICES_HAS_XFER) {
764        SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
765        (void)xfer->asMode(&mode);
766        this->addInt(mode);
767    }
768    this->validate(initialOffset, size);
769}
770
771void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
772                                  const SkPoint texCoords[4], SkXfermode* xmode,
773                                  const SkPaint& paint) {
774    // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
775    size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
776    uint32_t flag = 0;
777    if (colors) {
778        flag |= DRAW_VERTICES_HAS_COLORS;
779        size += SkPatchUtils::kNumCorners * sizeof(SkColor);
780    }
781    if (texCoords) {
782        flag |= DRAW_VERTICES_HAS_TEXS;
783        size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
784    }
785    if (xmode) {
786        SkXfermode::Mode mode;
787        if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
788            flag |= DRAW_VERTICES_HAS_XFER;
789            size += kUInt32Size;
790        }
791    }
792
793    size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
794    SkASSERT(initialOffset+get_paint_offset(DRAW_PATCH, size) == fWriter.bytesWritten());
795    this->addPaint(paint);
796    this->addPatch(cubics);
797    this->addInt(flag);
798
799    // write optional parameters
800    if (colors) {
801        fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
802    }
803    if (texCoords) {
804        fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
805    }
806    if (flag & DRAW_VERTICES_HAS_XFER) {
807        SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
808        xmode->asMode(&mode);
809        this->addInt(mode);
810    }
811    this->validate(initialOffset, size);
812}
813
814void SkPictureRecord::drawData(const void* data, size_t length) {
815    // op + length + 'length' worth of data
816    size_t size = 2 * kUInt32Size + SkAlign4(length);
817    size_t initialOffset = this->addDraw(DRAW_DATA, &size);
818    this->addInt(SkToInt(length));
819    fWriter.writePad(data, length);
820    this->validate(initialOffset, size);
821}
822
823void SkPictureRecord::beginCommentGroup(const char* description) {
824    // op/size + length of string + \0 terminated chars
825    size_t length = strlen(description);
826    size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
827    size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
828    fWriter.writeString(description, length);
829    this->validate(initialOffset, size);
830}
831
832void SkPictureRecord::addComment(const char* kywd, const char* value) {
833    // op/size + 2x length of string + 2x \0 terminated chars
834    size_t kywdLen = strlen(kywd);
835    size_t valueLen = strlen(value);
836    size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
837    size_t initialOffset = this->addDraw(COMMENT, &size);
838    fWriter.writeString(kywd, kywdLen);
839    fWriter.writeString(value, valueLen);
840    this->validate(initialOffset, size);
841}
842
843void SkPictureRecord::endCommentGroup() {
844    // op/size
845    size_t size = 1 * kUInt32Size;
846    size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
847    this->validate(initialOffset, size);
848}
849
850// [op/size] [rect] [skip offset]
851static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
852void SkPictureRecord::onPushCull(const SkRect& cullRect) {
853    size_t size = kPushCullOpSize;
854    size_t initialOffset = this->addDraw(PUSH_CULL, &size);
855    // PUSH_CULL's size should stay constant (used to rewind).
856    SkASSERT(size == kPushCullOpSize);
857
858    this->addRect(cullRect);
859    fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
860    this->addInt(0);
861    this->validate(initialOffset, size);
862}
863
864void SkPictureRecord::onPopCull() {
865    SkASSERT(!fCullOffsetStack.isEmpty());
866
867    uint32_t cullSkipOffset = fCullOffsetStack.top();
868    fCullOffsetStack.pop();
869
870    // op only
871    size_t size = kUInt32Size;
872    size_t initialOffset = this->addDraw(POP_CULL, &size);
873
874    // update the cull skip offset to point past this op.
875    fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
876
877    this->validate(initialOffset, size);
878}
879
880///////////////////////////////////////////////////////////////////////////////
881
882SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
883    return NULL;
884}
885
886// If we already have a stored, can we reuse it instead of also storing b?
887static bool equivalent(const SkBitmap& a, const SkBitmap& b) {
888    if (a.info() != b.info() || a.pixelRefOrigin() != b.pixelRefOrigin()) {
889        // Requiring a.info() == b.info() may be overkill in some cases (alphatype mismatch),
890        // but it sure makes things easier to reason about below.
891        return false;
892    }
893    if (a.pixelRef() == b.pixelRef()) {
894        return true;  // Same shape and same pixels -> same bitmap.
895    }
896
897    // From here down we're going to have to look at the bitmap data, so we require pixelRefs().
898    if (!a.pixelRef() || !b.pixelRef()) {
899        return false;
900    }
901
902    // If the bitmaps have encoded data, check first before locking pixels so they don't decode.
903    SkAutoTUnref<SkData> encA(a.pixelRef()->refEncodedData()),
904                         encB(b.pixelRef()->refEncodedData());
905    if (encA && encB) {
906        return encA->equals(encB);
907    } else if (encA || encB) {
908        return false;   // One has encoded data but the other does not.
909    }
910
911    // As a last resort, we have to look at the pixels.  This will read back textures.
912    SkAutoLockPixels al(a), bl(b);
913    const char* ap = (const char*)a.getPixels();
914    const char* bp = (const char*)b.getPixels();
915    if (ap && bp) {
916        // We check row by row; row bytes might differ.
917        SkASSERT(a.info() == b.info());          // We checked this above.
918        SkASSERT(a.info().bytesPerPixel() > 0);  // If we have pixelRefs, this better be true.
919        const SkImageInfo info = a.info();
920        const size_t bytesToCompare = info.width() * info.bytesPerPixel();
921        for (int row = 0; row < info.height(); row++) {
922            if (0 != memcmp(ap, bp, bytesToCompare)) {
923                return false;
924            }
925            ap += a.rowBytes();
926            bp += b.rowBytes();
927        }
928        return true;
929    }
930    return false;  // Couldn't get pixels for both bitmaps.
931}
932
933void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
934    // First see if we already have this bitmap.  This deduplication should really
935    // only be important for our tests, where bitmaps tend not to be tagged immutable.
936    // In Chrome (and hopefully Android?) they're typically immutable.
937    for (int i = 0; i < fBitmaps.count(); i++) {
938        if (equivalent(fBitmaps[i], bitmap)) {
939            this->addInt(i);  // Unlike the rest, bitmap indices are 0-based.
940            return;
941        }
942    }
943    // Don't have it.  We'll add it to our list, making sure it's tagged as immutable.
944    if (bitmap.isImmutable()) {
945        // Shallow copies of bitmaps are cheap, so immutable == fast.
946        fBitmaps.push_back(bitmap);
947    } else {
948        // If you see this block on a memory profile, it's a good opportunity to reduce RAM usage.
949        SkBitmap copy;
950        bitmap.copyTo(&copy);
951        copy.setImmutable();
952        fBitmaps.push_back(copy);
953    }
954    this->addInt(fBitmaps.count()-1);  // Remember, 0-based.
955}
956
957void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
958    fWriter.writeMatrix(matrix);
959}
960
961void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
962    fContentInfo.onAddPaintPtr(paint);
963
964    if (paint) {
965        fPaints.push_back(*paint);
966        this->addInt(fPaints.count());
967    } else {
968        this->addInt(0);
969    }
970}
971
972int SkPictureRecord::addPathToHeap(const SkPath& path) {
973    fPaths.push_back(path);
974    return fPaths.count();
975}
976
977void SkPictureRecord::addPath(const SkPath& path) {
978    this->addInt(this->addPathToHeap(path));
979}
980
981void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
982    fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
983}
984
985void SkPictureRecord::addPicture(const SkPicture* picture) {
986    int index = fPictureRefs.find(picture);
987    if (index < 0) {    // not found
988        index = fPictureRefs.count();
989        *fPictureRefs.append() = picture;
990        picture->ref();
991    }
992    // follow the convention of recording a 1-based index
993    this->addInt(index + 1);
994}
995
996void SkPictureRecord::addPoint(const SkPoint& point) {
997    fWriter.writePoint(point);
998}
999
1000void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1001    fWriter.writeMul4(pts, count * sizeof(SkPoint));
1002}
1003
1004void SkPictureRecord::addNoOp() {
1005    size_t size = kUInt32Size; // op
1006    this->addDraw(NOOP, &size);
1007}
1008
1009void SkPictureRecord::addRect(const SkRect& rect) {
1010    fWriter.writeRect(rect);
1011}
1012
1013void SkPictureRecord::addRectPtr(const SkRect* rect) {
1014    if (fWriter.writeBool(rect != NULL)) {
1015        fWriter.writeRect(*rect);
1016    }
1017}
1018
1019void SkPictureRecord::addIRect(const SkIRect& rect) {
1020    fWriter.write(&rect, sizeof(rect));
1021}
1022
1023void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1024    if (fWriter.writeBool(rect != NULL)) {
1025        *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1026    }
1027}
1028
1029void SkPictureRecord::addRRect(const SkRRect& rrect) {
1030    fWriter.writeRRect(rrect);
1031}
1032
1033void SkPictureRecord::addRegion(const SkRegion& region) {
1034    fWriter.writeRegion(region);
1035}
1036
1037void SkPictureRecord::addText(const void* text, size_t byteLength) {
1038    fContentInfo.onDrawText();
1039    addInt(SkToInt(byteLength));
1040    fWriter.writePad(text, byteLength);
1041}
1042
1043void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
1044    int index = fTextBlobRefs.count();
1045    *fTextBlobRefs.append() = blob;
1046    blob->ref();
1047    // follow the convention of recording a 1-based index
1048    this->addInt(index + 1);
1049}
1050
1051///////////////////////////////////////////////////////////////////////////////
1052
1053