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