SkPictureRecord.cpp revision 5f0add3ad6e1d6129307276c81ba6624f92ca112
1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SkPictureRecord.h"
9#include "SkTSearch.h"
10#include "SkPixelRef.h"
11#include "SkBBoxHierarchy.h"
12#include "SkPictureStateTree.h"
13
14#define MIN_WRITER_SIZE 16384
15#define HEAP_BLOCK_SIZE 4096
16
17enum {
18    // just need a value that save or getSaveCount would never return
19    kNoInitialSave = -1,
20};
21
22SkPictureRecord::SkPictureRecord(uint32_t flags, SkDevice* device) :
23        INHERITED(device),
24        fBoundingHierarchy(NULL),
25        fStateTree(NULL),
26        fFlattenableHeap(HEAP_BLOCK_SIZE),
27        fMatrices(&fFlattenableHeap),
28        fPaints(&fFlattenableHeap),
29        fRegions(&fFlattenableHeap),
30        fWriter(MIN_WRITER_SIZE),
31        fRecordFlags(flags) {
32#ifdef SK_DEBUG_SIZE
33    fPointBytes = fRectBytes = fTextBytes = 0;
34    fPointWrites = fRectWrites = fTextWrites = 0;
35#endif
36
37    fRestoreOffsetStack.setReserve(32);
38
39    fBitmapHeap = SkNEW(SkBitmapHeap);
40    fFlattenableHeap.setBitmapStorage(fBitmapHeap);
41    fPathHeap = NULL;   // lazy allocate
42    fFirstSavedLayerIndex = kNoSavedLayerIndex;
43
44    fInitialSaveCount = kNoInitialSave;
45}
46
47SkPictureRecord::~SkPictureRecord() {
48    SkSafeUnref(fBitmapHeap);
49    SkSafeUnref(fPathHeap);
50    SkSafeUnref(fBoundingHierarchy);
51    SkSafeUnref(fStateTree);
52    fFlattenableHeap.setBitmapStorage(NULL);
53    fPictureRefs.unrefAll();
54}
55
56///////////////////////////////////////////////////////////////////////////////
57
58SkDevice* SkPictureRecord::setDevice(SkDevice* device) {
59    SkASSERT(!"eeek, don't try to change the device on a recording canvas");
60    return this->INHERITED::setDevice(device);
61}
62
63int SkPictureRecord::save(SaveFlags flags) {
64    // record the offset to us, making it non-positive to distinguish a save
65    // from a clip entry.
66    fRestoreOffsetStack.push(-(int32_t)fWriter.size());
67
68    addDraw(SAVE);
69    addInt(flags);
70
71    validate();
72    return this->INHERITED::save(flags);
73}
74
75int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
76                               SaveFlags flags) {
77    // record the offset to us, making it non-positive to distinguish a save
78    // from a clip entry.
79    fRestoreOffsetStack.push(-(int32_t)fWriter.size());
80
81    addDraw(SAVE_LAYER);
82    addRectPtr(bounds);
83    addPaintPtr(paint);
84    addInt(flags);
85
86    if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
87        fFirstSavedLayerIndex = fRestoreOffsetStack.count();
88    }
89
90    validate();
91    /*  Don't actually call saveLayer, because that will try to allocate an
92        offscreen device (potentially very big) which we don't actually need
93        at this time (and may not be able to afford since during record our
94        clip starts out the size of the picture, which is often much larger
95        than the size of the actual device we'll use during playback).
96     */
97    int count = this->INHERITED::save(flags);
98    this->clipRectBounds(bounds, flags, NULL);
99    return count;
100}
101
102bool SkPictureRecord::isDrawingToLayer() const {
103    return fFirstSavedLayerIndex != kNoSavedLayerIndex;
104}
105
106// Return the size of the specified drawType's recorded block, or 0 if this verb
107// is variable sized, and therefore not known.
108static inline uint32_t getSkipableSize(unsigned drawType) {
109    static const uint8_t gSizes[LAST_DRAWTYPE_ENUM + 1] = {
110        0,  // UNUSED,
111        4,  // CLIP_PATH,
112        4,  // CLIP_REGION,
113        7,  // CLIP_RECT,
114        2,  // CONCAT,
115        0,  // DRAW_BITMAP,
116        0,  // DRAW_BITMAP_MATRIX,
117        0,  // DRAW_BITMAP_NINE,
118        0,  // DRAW_BITMAP_RECT,
119        0,  // DRAW_CLEAR,
120        0,  // DRAW_DATA,
121        0,  // DRAW_PAINT,
122        0,  // DRAW_PATH,
123        0,  // DRAW_PICTURE,
124        0,  // DRAW_POINTS,
125        0,  // DRAW_POS_TEXT,
126        0,  // DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
127        0,  // DRAW_POS_TEXT_H,
128        0,  // DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
129        0,  // DRAW_RECT,
130        0,  // DRAW_SPRITE,
131        0,  // DRAW_TEXT,
132        0,  // DRAW_TEXT_ON_PATH,
133        0,  // DRAW_TEXT_TOP_BOTTOM,   // fast variant of DRAW_TEXT
134        0,  // DRAW_VERTICES,
135        0,  // RESTORE,
136        2,  // ROTATE,
137        2,  // SAVE,
138        0,  // SAVE_LAYER,
139        3,  // SCALE,
140        2,  // SET_MATRIX,
141        3,  // SKEW,
142        3,  // TRANSLATE,
143    };
144
145    SkASSERT(sizeof(gSizes) == LAST_DRAWTYPE_ENUM + 1);
146    SkASSERT((unsigned)drawType <= (unsigned)LAST_DRAWTYPE_ENUM);
147    return gSizes[drawType] * sizeof(uint32_t);
148}
149
150#ifdef TRACK_COLLAPSE_STATS
151    static int gCollapseCount, gCollapseCalls;
152#endif
153
154/*
155 *  Restore has just been called (but not recoreded), so look back at the
156 *  matching save(), and see if we can eliminate the pair of them, due to no
157 *  intervening matrix/clip calls.
158 *
159 *  If so, update the writer and return true, in which case we won't even record
160 *  the restore() call. If we still need the restore(), return false.
161 */
162static bool collapseSaveClipRestore(SkWriter32* writer, int32_t offset) {
163#ifdef TRACK_COLLAPSE_STATS
164    gCollapseCalls += 1;
165#endif
166
167    int32_t restoreOffset = (int32_t)writer->size();
168
169    // back up to the save block
170    while (offset > 0) {
171        offset = *writer->peek32(offset);
172    }
173
174    // now offset points to a save
175    offset = -offset;
176    if (SAVE_LAYER == *writer->peek32(offset)) {
177        // not ready to cull these out yet (mrr)
178        return false;
179    }
180    SkASSERT(SAVE == *writer->peek32(offset));
181
182    // Walk forward until we get back to either a draw-verb (abort) or we hit
183    // our restore (success).
184    int32_t saveOffset = offset;
185
186    offset += getSkipableSize(SAVE);
187    while (offset < restoreOffset) {
188        uint32_t* block = writer->peek32(offset);
189        uint32_t op = *block;
190        uint32_t opSize = getSkipableSize(op);
191        if (0 == opSize) {
192            // drawing verb, abort
193            return false;
194        }
195        offset += opSize;
196    }
197
198#ifdef TRACK_COLLAPSE_STATS
199    gCollapseCount += 1;
200    SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
201             (double)gCollapseCount / gCollapseCalls, "%");
202#endif
203
204    writer->rewindToOffset(saveOffset);
205    return true;
206}
207
208void SkPictureRecord::restore() {
209    // FIXME: SkDeferredCanvas needs to be refactored to respect
210    // save/restore balancing so that the following test can be
211    // turned on permanently.
212#if 0
213    SkASSERT(fRestoreOffsetStack.count() > 1);
214#endif
215
216    // check for underflow
217    if (fRestoreOffsetStack.count() == 0) {
218        return;
219    }
220
221    if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
222        fFirstSavedLayerIndex = kNoSavedLayerIndex;
223    }
224
225    if (!collapseSaveClipRestore(&fWriter, fRestoreOffsetStack.top())) {
226        fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size());
227        this->addDraw(RESTORE);
228    }
229
230    fRestoreOffsetStack.pop();
231
232    validate();
233    return this->INHERITED::restore();
234}
235
236bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
237    addDraw(TRANSLATE);
238    addScalar(dx);
239    addScalar(dy);
240    validate();
241    return this->INHERITED::translate(dx, dy);
242}
243
244bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
245    addDraw(SCALE);
246    addScalar(sx);
247    addScalar(sy);
248    validate();
249    return this->INHERITED::scale(sx, sy);
250}
251
252bool SkPictureRecord::rotate(SkScalar degrees) {
253    addDraw(ROTATE);
254    addScalar(degrees);
255    validate();
256    return this->INHERITED::rotate(degrees);
257}
258
259bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
260    addDraw(SKEW);
261    addScalar(sx);
262    addScalar(sy);
263    validate();
264    return this->INHERITED::skew(sx, sy);
265}
266
267bool SkPictureRecord::concat(const SkMatrix& matrix) {
268    validate();
269    addDraw(CONCAT);
270    addMatrix(matrix);
271    validate();
272    return this->INHERITED::concat(matrix);
273}
274
275void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
276    validate();
277    addDraw(SET_MATRIX);
278    addMatrix(matrix);
279    validate();
280    this->INHERITED::setMatrix(matrix);
281}
282
283static bool regionOpExpands(SkRegion::Op op) {
284    switch (op) {
285        case SkRegion::kUnion_Op:
286        case SkRegion::kXOR_Op:
287        case SkRegion::kReverseDifference_Op:
288        case SkRegion::kReplace_Op:
289            return true;
290        case SkRegion::kIntersect_Op:
291        case SkRegion::kDifference_Op:
292            return false;
293        default:
294            SkDEBUGFAIL("unknown region op");
295            return false;
296    }
297}
298
299void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(
300    uint32_t restoreOffset) {
301    int32_t offset = fRestoreOffsetStack.top();
302    while (offset > 0) {
303        uint32_t* peek = fWriter.peek32(offset);
304        offset = *peek;
305        *peek = restoreOffset;
306    }
307
308#ifdef SK_DEBUG
309    // assert that the final offset value points to a save verb
310    uint32_t drawOp = *fWriter.peek32(-offset);
311    SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
312#endif
313}
314
315void SkPictureRecord::beginRecording() {
316    // we have to call this *after* our constructor, to ensure that it gets
317    // recorded. This is balanced by restoreToCount() call from endRecording,
318    // which in-turn calls our overridden restore(), so those get recorded too.
319    fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
320}
321
322void SkPictureRecord::endRecording() {
323    SkASSERT(kNoInitialSave != fInitialSaveCount);
324    this->restoreToCount(fInitialSaveCount);
325}
326
327void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
328    if (fRestoreOffsetStack.isEmpty()) {
329        return;
330    }
331
332    if (regionOpExpands(op)) {
333        // Run back through any previous clip ops, and mark their offset to
334        // be 0, disabling their ability to trigger a jump-to-restore, otherwise
335        // they could hide this clips ability to expand the clip (i.e. go from
336        // empty to non-empty).
337        fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
338    }
339
340    size_t offset = fWriter.size();
341    // The RestoreOffset field is initially filled with a placeholder
342    // value that points to the offset of the previous RestoreOffset
343    // in the current stack level, thus forming a linked list so that
344    // the restore offsets can be filled in when the corresponding
345    // restore command is recorded.
346    addInt(fRestoreOffsetStack.top());
347    fRestoreOffsetStack.top() = offset;
348}
349
350bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
351    addDraw(CLIP_RECT);
352    addRect(rect);
353    addInt(ClipParams_pack(op, doAA));
354    recordRestoreOffsetPlaceholder(op);
355
356    validate();
357    return this->INHERITED::clipRect(rect, op, doAA);
358}
359
360bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
361
362    SkRect r;
363    if (path.isRect(&r)) {
364        return this->clipRect(r, op, doAA);
365    }
366
367    addDraw(CLIP_PATH);
368    addPath(path);
369    addInt(ClipParams_pack(op, doAA));
370    recordRestoreOffsetPlaceholder(op);
371
372    validate();
373
374    if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
375        return this->INHERITED::clipRect(path.getBounds(), op, doAA);
376    } else {
377        return this->INHERITED::clipPath(path, op, doAA);
378    }
379}
380
381bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
382    addDraw(CLIP_REGION);
383    addRegion(region);
384    addInt(ClipParams_pack(op, false));
385    recordRestoreOffsetPlaceholder(op);
386
387    validate();
388    return this->INHERITED::clipRegion(region, op);
389}
390
391void SkPictureRecord::clear(SkColor color) {
392    addDraw(DRAW_CLEAR);
393    addInt(color);
394    validate();
395}
396
397void SkPictureRecord::drawPaint(const SkPaint& paint) {
398    addDraw(DRAW_PAINT);
399    addPaint(paint);
400    validate();
401}
402
403void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
404                        const SkPaint& paint) {
405    addDraw(DRAW_POINTS);
406    addPaint(paint);
407    addInt(mode);
408    addInt(count);
409    fWriter.writeMul4(pts, count * sizeof(SkPoint));
410    validate();
411}
412
413void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
414    addDraw(DRAW_RECT);
415    addPaint(paint);
416    addRect(rect);
417    validate();
418}
419
420void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
421    addDraw(DRAW_PATH);
422    addPaint(paint);
423    addPath(path);
424    validate();
425}
426
427void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
428                        const SkPaint* paint = NULL) {
429    addDraw(DRAW_BITMAP);
430    addPaintPtr(paint);
431    addBitmap(bitmap);
432    addScalar(left);
433    addScalar(top);
434    validate();
435}
436
437void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
438                            const SkRect& dst, const SkPaint* paint) {
439    addDraw(DRAW_BITMAP_RECT_TO_RECT);
440    addPaintPtr(paint);
441    addBitmap(bitmap);
442    addRectPtr(src);  // may be null
443    addRect(dst);
444    validate();
445}
446
447void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
448                                       const SkPaint* paint) {
449    addDraw(DRAW_BITMAP_MATRIX);
450    addPaintPtr(paint);
451    addBitmap(bitmap);
452    addMatrix(matrix);
453    validate();
454}
455
456void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
457                                     const SkRect& dst, const SkPaint* paint) {
458    addDraw(DRAW_BITMAP_NINE);
459    addPaintPtr(paint);
460    addBitmap(bitmap);
461    addIRect(center);
462    addRect(dst);
463    validate();
464}
465
466void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
467                        const SkPaint* paint = NULL) {
468    addDraw(DRAW_SPRITE);
469    addPaintPtr(paint);
470    addBitmap(bitmap);
471    addInt(left);
472    addInt(top);
473    validate();
474}
475
476void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint,
477                                              SkScalar minY, SkScalar maxY) {
478    SkPaint::FontMetrics metrics;
479    paint.getFontMetrics(&metrics);
480    SkRect bounds;
481    // construct a rect so we can see any adjustments from the paint.
482    // we use 0,1 for left,right, just so the rect isn't empty
483    bounds.set(0, metrics.fTop + minY,
484               SK_Scalar1, metrics.fBottom + maxY);
485    (void)paint.computeFastBounds(bounds, &bounds);
486    // now record the top and bottom
487    addScalar(bounds.fTop);
488    addScalar(bounds.fBottom);
489}
490
491void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
492                      SkScalar y, const SkPaint& paint) {
493    bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
494
495    addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT);
496    addPaint(paint);
497    addText(text, byteLength);
498    addScalar(x);
499    addScalar(y);
500    if (fast) {
501        addFontMetricsTopBottom(paint, y, y);
502    }
503    validate();
504}
505
506void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
507                         const SkPoint pos[], const SkPaint& paint) {
508    size_t points = paint.countText(text, byteLength);
509    if (0 == points)
510        return;
511
512    bool canUseDrawH = true;
513    SkScalar minY = pos[0].fY;
514    SkScalar maxY = pos[0].fY;
515    // check if the caller really should have used drawPosTextH()
516    {
517        const SkScalar firstY = pos[0].fY;
518        for (size_t index = 1; index < points; index++) {
519            if (pos[index].fY != firstY) {
520                canUseDrawH = false;
521                if (pos[index].fY < minY) {
522                    minY = pos[index].fY;
523                } else if (pos[index].fY > maxY) {
524                    maxY = pos[index].fY;
525                }
526            }
527        }
528    }
529
530    bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
531    bool fast = canUseDrawH && fastBounds;
532
533    if (fast) {
534        addDraw(DRAW_POS_TEXT_H_TOP_BOTTOM);
535    } else if (canUseDrawH) {
536        addDraw(DRAW_POS_TEXT_H);
537    } else if (fastBounds) {
538        addDraw(DRAW_POS_TEXT_TOP_BOTTOM);
539    } else {
540        addDraw(DRAW_POS_TEXT);
541    }
542    addPaint(paint);
543    addText(text, byteLength);
544    addInt(points);
545
546#ifdef SK_DEBUG_SIZE
547    size_t start = fWriter.size();
548#endif
549    if (canUseDrawH) {
550        if (fast) {
551            addFontMetricsTopBottom(paint, pos[0].fY, pos[0].fY);
552        }
553        addScalar(pos[0].fY);
554        SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
555        for (size_t index = 0; index < points; index++)
556            *xptr++ = pos[index].fX;
557    }
558    else {
559        fWriter.writeMul4(pos, points * sizeof(SkPoint));
560        if (fastBounds) {
561            addFontMetricsTopBottom(paint, minY, maxY);
562        }
563    }
564#ifdef SK_DEBUG_SIZE
565    fPointBytes += fWriter.size() - start;
566    fPointWrites += points;
567#endif
568    validate();
569}
570
571void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
572                          const SkScalar xpos[], SkScalar constY,
573                          const SkPaint& paint) {
574    size_t points = paint.countText(text, byteLength);
575    if (0 == points)
576        return;
577
578    bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
579
580    addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H);
581    addPaint(paint);
582    addText(text, byteLength);
583    addInt(points);
584
585#ifdef SK_DEBUG_SIZE
586    size_t start = fWriter.size();
587#endif
588    if (fast) {
589        addFontMetricsTopBottom(paint, constY, constY);
590    }
591    addScalar(constY);
592    fWriter.writeMul4(xpos, points * sizeof(SkScalar));
593#ifdef SK_DEBUG_SIZE
594    fPointBytes += fWriter.size() - start;
595    fPointWrites += points;
596#endif
597    validate();
598}
599
600void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
601                            const SkPath& path, const SkMatrix* matrix,
602                            const SkPaint& paint) {
603    addDraw(DRAW_TEXT_ON_PATH);
604    addPaint(paint);
605    addText(text, byteLength);
606    addPath(path);
607    addMatrixPtr(matrix);
608    validate();
609}
610
611void SkPictureRecord::drawPicture(SkPicture& picture) {
612    addDraw(DRAW_PICTURE);
613    addPicture(picture);
614    validate();
615}
616
617void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
618                          const SkPoint vertices[], const SkPoint texs[],
619                          const SkColor colors[], SkXfermode*,
620                          const uint16_t indices[], int indexCount,
621                          const SkPaint& paint) {
622    uint32_t flags = 0;
623    if (texs) {
624        flags |= DRAW_VERTICES_HAS_TEXS;
625    }
626    if (colors) {
627        flags |= DRAW_VERTICES_HAS_COLORS;
628    }
629    if (indexCount > 0) {
630        flags |= DRAW_VERTICES_HAS_INDICES;
631    }
632
633    addDraw(DRAW_VERTICES);
634    addPaint(paint);
635    addInt(flags);
636    addInt(vmode);
637    addInt(vertexCount);
638    addPoints(vertices, vertexCount);
639    if (flags & DRAW_VERTICES_HAS_TEXS) {
640        addPoints(texs, vertexCount);
641    }
642    if (flags & DRAW_VERTICES_HAS_COLORS) {
643        fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
644    }
645    if (flags & DRAW_VERTICES_HAS_INDICES) {
646        addInt(indexCount);
647        fWriter.writePad(indices, indexCount * sizeof(uint16_t));
648    }
649}
650
651void SkPictureRecord::drawData(const void* data, size_t length) {
652    addDraw(DRAW_DATA);
653    addInt(length);
654    fWriter.writePad(data, length);
655}
656
657///////////////////////////////////////////////////////////////////////////////
658
659void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
660    addInt(fBitmapHeap->insert(bitmap));
661}
662
663void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
664    addMatrixPtr(&matrix);
665}
666
667void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
668    this->addInt(matrix ? fMatrices.find(*matrix) : 0);
669}
670
671void SkPictureRecord::addPaint(const SkPaint& paint) {
672    addPaintPtr(&paint);
673}
674
675void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
676    this->addInt(paint ? fPaints.find(*paint) : 0);
677}
678
679void SkPictureRecord::addPath(const SkPath& path) {
680    if (NULL == fPathHeap) {
681        fPathHeap = SkNEW(SkPathHeap);
682    }
683    addInt(fPathHeap->append(path));
684}
685
686void SkPictureRecord::addPicture(SkPicture& picture) {
687    int index = fPictureRefs.find(&picture);
688    if (index < 0) {    // not found
689        index = fPictureRefs.count();
690        *fPictureRefs.append() = &picture;
691        picture.ref();
692    }
693    // follow the convention of recording a 1-based index
694    addInt(index + 1);
695}
696
697void SkPictureRecord::addPoint(const SkPoint& point) {
698#ifdef SK_DEBUG_SIZE
699    size_t start = fWriter.size();
700#endif
701    fWriter.writePoint(point);
702#ifdef SK_DEBUG_SIZE
703    fPointBytes += fWriter.size() - start;
704    fPointWrites++;
705#endif
706}
707
708void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
709    fWriter.writeMul4(pts, count * sizeof(SkPoint));
710#ifdef SK_DEBUG_SIZE
711    fPointBytes += count * sizeof(SkPoint);
712    fPointWrites++;
713#endif
714}
715
716void SkPictureRecord::addRect(const SkRect& rect) {
717#ifdef SK_DEBUG_SIZE
718    size_t start = fWriter.size();
719#endif
720    fWriter.writeRect(rect);
721#ifdef SK_DEBUG_SIZE
722    fRectBytes += fWriter.size() - start;
723    fRectWrites++;
724#endif
725}
726
727void SkPictureRecord::addRectPtr(const SkRect* rect) {
728    if (fWriter.writeBool(rect != NULL)) {
729        fWriter.writeRect(*rect);
730    }
731}
732
733void SkPictureRecord::addIRect(const SkIRect& rect) {
734    fWriter.write(&rect, sizeof(rect));
735}
736
737void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
738    if (fWriter.writeBool(rect != NULL)) {
739        *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
740    }
741}
742
743void SkPictureRecord::addRegion(const SkRegion& region) {
744    addInt(fRegions.find(region));
745}
746
747void SkPictureRecord::addText(const void* text, size_t byteLength) {
748#ifdef SK_DEBUG_SIZE
749    size_t start = fWriter.size();
750#endif
751    addInt(byteLength);
752    fWriter.writePad(text, byteLength);
753#ifdef SK_DEBUG_SIZE
754    fTextBytes += fWriter.size() - start;
755    fTextWrites++;
756#endif
757}
758
759///////////////////////////////////////////////////////////////////////////////
760
761#ifdef SK_DEBUG_SIZE
762size_t SkPictureRecord::size() const {
763    size_t result = 0;
764    size_t sizeData;
765    bitmaps(&sizeData);
766    result += sizeData;
767    matrices(&sizeData);
768    result += sizeData;
769    paints(&sizeData);
770    result += sizeData;
771    paths(&sizeData);
772    result += sizeData;
773    pictures(&sizeData);
774    result += sizeData;
775    regions(&sizeData);
776    result += sizeData;
777    result += streamlen();
778    return result;
779}
780
781int SkPictureRecord::bitmaps(size_t* size) const {
782    size_t result = 0;
783    int count = fBitmaps.count();
784    for (int index = 0; index < count; index++)
785        result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
786    *size = result;
787    return count;
788}
789
790int SkPictureRecord::matrices(size_t* size) const {
791    int count = fMatrices.count();
792    *size = sizeof(fMatrices[0]) * count;
793    return count;
794}
795
796int SkPictureRecord::paints(size_t* size) const {
797    size_t result = 0;
798    int count = fPaints.count();
799    for (int index = 0; index < count; index++)
800        result += sizeof(fPaints[index]) + fPaints[index]->size();
801    *size = result;
802    return count;
803}
804
805int SkPictureRecord::paths(size_t* size) const {
806    size_t result = 0;
807    int count = fPaths.count();
808    for (int index = 0; index < count; index++)
809        result += sizeof(fPaths[index]) + fPaths[index]->size();
810    *size = result;
811    return count;
812}
813
814int SkPictureRecord::regions(size_t* size) const {
815    size_t result = 0;
816    int count = fRegions.count();
817    for (int index = 0; index < count; index++)
818        result += sizeof(fRegions[index]) + fRegions[index]->size();
819    *size = result;
820    return count;
821}
822
823size_t SkPictureRecord::streamlen() const {
824    return fWriter.size();
825}
826#endif
827
828#ifdef SK_DEBUG_VALIDATE
829void SkPictureRecord::validate() const {
830    validateBitmaps();
831    validateMatrices();
832    validatePaints();
833    validatePaths();
834    validatePictures();
835    validateRegions();
836}
837
838void SkPictureRecord::validateBitmaps() const {
839    int count = fBitmaps.count();
840    SkASSERT((unsigned) count < 0x1000);
841    for (int index = 0; index < count; index++) {
842        const SkFlatBitmap* bitPtr = fBitmaps[index];
843        SkASSERT(bitPtr);
844        bitPtr->validate();
845    }
846}
847
848void SkPictureRecord::validateMatrices() const {
849    int count = fMatrices.count();
850    SkASSERT((unsigned) count < 0x1000);
851    for (int index = 0; index < count; index++) {
852        const SkFlatMatrix* matrix = fMatrices[index];
853        SkASSERT(matrix);
854        matrix->validate();
855    }
856}
857
858void SkPictureRecord::validatePaints() const {
859    int count = fPaints.count();
860    SkASSERT((unsigned) count < 0x1000);
861    for (int index = 0; index < count; index++) {
862        const SkFlatPaint* paint = fPaints[index];
863        SkASSERT(paint);
864//            paint->validate();
865    }
866}
867
868void SkPictureRecord::validatePaths() const {
869    int count = fPaths.count();
870    SkASSERT((unsigned) count < 0x1000);
871    for (int index = 0; index < count; index++) {
872        const SkFlatPath* path = fPaths[index];
873        SkASSERT(path);
874        path->validate();
875    }
876}
877
878void SkPictureRecord::validateRegions() const {
879    int count = fRegions.count();
880    SkASSERT((unsigned) count < 0x1000);
881    for (int index = 0; index < count; index++) {
882        const SkFlatRegion* region = fRegions[index];
883        SkASSERT(region);
884        region->validate();
885    }
886}
887#endif
888
889