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