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