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