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