SkPictureRecord.cpp revision 4b90b1122c93e6600ea352f4ccf1dfc54c8bb146
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    const int index = fBitmapHeap->insert(bitmap);
661    // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
662    // release builds, the invalid value will be recorded so that the reader will know that there
663    // was a problem.
664    SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
665    addInt(index);
666}
667
668void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
669    addMatrixPtr(&matrix);
670}
671
672void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
673    this->addInt(matrix ? fMatrices.find(*matrix) : 0);
674}
675
676void SkPictureRecord::addPaint(const SkPaint& paint) {
677    addPaintPtr(&paint);
678}
679
680void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
681    this->addInt(paint ? fPaints.find(*paint) : 0);
682}
683
684void SkPictureRecord::addPath(const SkPath& path) {
685    if (NULL == fPathHeap) {
686        fPathHeap = SkNEW(SkPathHeap);
687    }
688    addInt(fPathHeap->append(path));
689}
690
691void SkPictureRecord::addPicture(SkPicture& picture) {
692    int index = fPictureRefs.find(&picture);
693    if (index < 0) {    // not found
694        index = fPictureRefs.count();
695        *fPictureRefs.append() = &picture;
696        picture.ref();
697    }
698    // follow the convention of recording a 1-based index
699    addInt(index + 1);
700}
701
702void SkPictureRecord::addPoint(const SkPoint& point) {
703#ifdef SK_DEBUG_SIZE
704    size_t start = fWriter.size();
705#endif
706    fWriter.writePoint(point);
707#ifdef SK_DEBUG_SIZE
708    fPointBytes += fWriter.size() - start;
709    fPointWrites++;
710#endif
711}
712
713void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
714    fWriter.writeMul4(pts, count * sizeof(SkPoint));
715#ifdef SK_DEBUG_SIZE
716    fPointBytes += count * sizeof(SkPoint);
717    fPointWrites++;
718#endif
719}
720
721void SkPictureRecord::addRect(const SkRect& rect) {
722#ifdef SK_DEBUG_SIZE
723    size_t start = fWriter.size();
724#endif
725    fWriter.writeRect(rect);
726#ifdef SK_DEBUG_SIZE
727    fRectBytes += fWriter.size() - start;
728    fRectWrites++;
729#endif
730}
731
732void SkPictureRecord::addRectPtr(const SkRect* rect) {
733    if (fWriter.writeBool(rect != NULL)) {
734        fWriter.writeRect(*rect);
735    }
736}
737
738void SkPictureRecord::addIRect(const SkIRect& rect) {
739    fWriter.write(&rect, sizeof(rect));
740}
741
742void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
743    if (fWriter.writeBool(rect != NULL)) {
744        *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
745    }
746}
747
748void SkPictureRecord::addRegion(const SkRegion& region) {
749    addInt(fRegions.find(region));
750}
751
752void SkPictureRecord::addText(const void* text, size_t byteLength) {
753#ifdef SK_DEBUG_SIZE
754    size_t start = fWriter.size();
755#endif
756    addInt(byteLength);
757    fWriter.writePad(text, byteLength);
758#ifdef SK_DEBUG_SIZE
759    fTextBytes += fWriter.size() - start;
760    fTextWrites++;
761#endif
762}
763
764///////////////////////////////////////////////////////////////////////////////
765
766#ifdef SK_DEBUG_SIZE
767size_t SkPictureRecord::size() const {
768    size_t result = 0;
769    size_t sizeData;
770    bitmaps(&sizeData);
771    result += sizeData;
772    matrices(&sizeData);
773    result += sizeData;
774    paints(&sizeData);
775    result += sizeData;
776    paths(&sizeData);
777    result += sizeData;
778    pictures(&sizeData);
779    result += sizeData;
780    regions(&sizeData);
781    result += sizeData;
782    result += streamlen();
783    return result;
784}
785
786int SkPictureRecord::bitmaps(size_t* size) const {
787    size_t result = 0;
788    int count = fBitmaps.count();
789    for (int index = 0; index < count; index++)
790        result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
791    *size = result;
792    return count;
793}
794
795int SkPictureRecord::matrices(size_t* size) const {
796    int count = fMatrices.count();
797    *size = sizeof(fMatrices[0]) * count;
798    return count;
799}
800
801int SkPictureRecord::paints(size_t* size) const {
802    size_t result = 0;
803    int count = fPaints.count();
804    for (int index = 0; index < count; index++)
805        result += sizeof(fPaints[index]) + fPaints[index]->size();
806    *size = result;
807    return count;
808}
809
810int SkPictureRecord::paths(size_t* size) const {
811    size_t result = 0;
812    int count = fPaths.count();
813    for (int index = 0; index < count; index++)
814        result += sizeof(fPaths[index]) + fPaths[index]->size();
815    *size = result;
816    return count;
817}
818
819int SkPictureRecord::regions(size_t* size) const {
820    size_t result = 0;
821    int count = fRegions.count();
822    for (int index = 0; index < count; index++)
823        result += sizeof(fRegions[index]) + fRegions[index]->size();
824    *size = result;
825    return count;
826}
827
828size_t SkPictureRecord::streamlen() const {
829    return fWriter.size();
830}
831#endif
832
833#ifdef SK_DEBUG_VALIDATE
834void SkPictureRecord::validate() const {
835    validateBitmaps();
836    validateMatrices();
837    validatePaints();
838    validatePaths();
839    validatePictures();
840    validateRegions();
841}
842
843void SkPictureRecord::validateBitmaps() const {
844    int count = fBitmaps.count();
845    SkASSERT((unsigned) count < 0x1000);
846    for (int index = 0; index < count; index++) {
847        const SkFlatBitmap* bitPtr = fBitmaps[index];
848        SkASSERT(bitPtr);
849        bitPtr->validate();
850    }
851}
852
853void SkPictureRecord::validateMatrices() const {
854    int count = fMatrices.count();
855    SkASSERT((unsigned) count < 0x1000);
856    for (int index = 0; index < count; index++) {
857        const SkFlatMatrix* matrix = fMatrices[index];
858        SkASSERT(matrix);
859        matrix->validate();
860    }
861}
862
863void SkPictureRecord::validatePaints() const {
864    int count = fPaints.count();
865    SkASSERT((unsigned) count < 0x1000);
866    for (int index = 0; index < count; index++) {
867        const SkFlatPaint* paint = fPaints[index];
868        SkASSERT(paint);
869//            paint->validate();
870    }
871}
872
873void SkPictureRecord::validatePaths() const {
874    int count = fPaths.count();
875    SkASSERT((unsigned) count < 0x1000);
876    for (int index = 0; index < count; index++) {
877        const SkFlatPath* path = fPaths[index];
878        SkASSERT(path);
879        path->validate();
880    }
881}
882
883void SkPictureRecord::validateRegions() const {
884    int count = fRegions.count();
885    SkASSERT((unsigned) count < 0x1000);
886    for (int index = 0; index < count; index++) {
887        const SkFlatRegion* region = fRegions[index];
888        SkASSERT(region);
889        region->validate();
890    }
891}
892#endif
893
894