SkPictureRecord.cpp revision e4ce5b82627d7ef7cab34b808ff88dc208aef7bc
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
193// This function is just a toy example and will not be delivered with this
194// CL
195static bool noClips(SkWriter32* writer, int32_t offset) {
196
197    int32_t restoreOffset = (int32_t)writer->size();
198
199    // back up to the save block
200    while (offset > 0) {
201        offset = *writer->peek32(offset);
202    }
203
204    // now offset points to a save
205    offset = -offset;
206    uint32_t opSize;
207    DrawType op = peek_op_and_size(writer, offset, &opSize);
208    SkASSERT(SAVE == op || SAVE_LAYER == op);
209
210    // Walk forward until until we hit our restore, nuking all clips
211    // along the way
212    offset += opSize;
213    while (offset < restoreOffset) {
214        op = peek_op_and_size(writer, offset, &opSize);
215
216        if (CLIP_RECT == op || CLIP_RRECT == op) {
217            uint32_t* ptr = writer->peek32(offset);
218            *ptr = (*ptr & MASK_24) | (NOOP << 24);
219        }
220        offset += opSize;
221    }
222
223    return true;
224}
225
226void SkPictureRecord::restore() {
227    // FIXME: SkDeferredCanvas needs to be refactored to respect
228    // save/restore balancing so that the following test can be
229    // turned on permanently.
230#if 0
231    SkASSERT(fRestoreOffsetStack.count() > 1);
232#endif
233
234    // check for underflow
235    if (fRestoreOffsetStack.count() == 0) {
236        return;
237    }
238
239    if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
240        fFirstSavedLayerIndex = kNoSavedLayerIndex;
241    }
242
243    // This call will not be delivered either
244    noClips(&fWriter, fRestoreOffsetStack.top());
245
246    uint32_t initialOffset, size;
247    if (!collapseSaveClipRestore(&fWriter, fRestoreOffsetStack.top())) {
248        fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size());
249        // op
250        size = 1 * kUInt32Size;
251        initialOffset = this->addDraw(RESTORE, &size);
252    } else {
253        size = 0;
254        initialOffset = fWriter.size();
255    }
256
257    fRestoreOffsetStack.pop();
258
259    validate(initialOffset, size);
260    return this->INHERITED::restore();
261}
262
263bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
264    // op + dx + dy
265    uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
266    uint32_t initialOffset = this->addDraw(TRANSLATE, &size);
267    addScalar(dx);
268    addScalar(dy);
269    validate(initialOffset, size);
270    return this->INHERITED::translate(dx, dy);
271}
272
273bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
274    // op + sx + sy
275    uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
276    uint32_t initialOffset = this->addDraw(SCALE, &size);
277    addScalar(sx);
278    addScalar(sy);
279    validate(initialOffset, size);
280    return this->INHERITED::scale(sx, sy);
281}
282
283bool SkPictureRecord::rotate(SkScalar degrees) {
284    // op + degrees
285    uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
286    uint32_t initialOffset = this->addDraw(ROTATE, &size);
287    addScalar(degrees);
288    validate(initialOffset, size);
289    return this->INHERITED::rotate(degrees);
290}
291
292bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
293    // op + sx + sy
294    uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
295    uint32_t initialOffset = this->addDraw(SKEW, &size);
296    addScalar(sx);
297    addScalar(sy);
298    validate(initialOffset, size);
299    return this->INHERITED::skew(sx, sy);
300}
301
302bool SkPictureRecord::concat(const SkMatrix& matrix) {
303    validate(fWriter.size(), 0);
304    // op + matrix index
305    uint32_t size = 2 * kUInt32Size;
306    uint32_t initialOffset = this->addDraw(CONCAT, &size);
307    addMatrix(matrix);
308    validate(initialOffset, size);
309    return this->INHERITED::concat(matrix);
310}
311
312void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
313    validate(fWriter.size(), 0);
314    // op + matrix index
315    uint32_t size = 2 * kUInt32Size;
316    uint32_t initialOffset = this->addDraw(SET_MATRIX, &size);
317    addMatrix(matrix);
318    validate(initialOffset, size);
319    this->INHERITED::setMatrix(matrix);
320}
321
322static bool regionOpExpands(SkRegion::Op op) {
323    switch (op) {
324        case SkRegion::kUnion_Op:
325        case SkRegion::kXOR_Op:
326        case SkRegion::kReverseDifference_Op:
327        case SkRegion::kReplace_Op:
328            return true;
329        case SkRegion::kIntersect_Op:
330        case SkRegion::kDifference_Op:
331            return false;
332        default:
333            SkDEBUGFAIL("unknown region op");
334            return false;
335    }
336}
337
338void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(
339    uint32_t restoreOffset) {
340    int32_t offset = fRestoreOffsetStack.top();
341    while (offset > 0) {
342        uint32_t* peek = fWriter.peek32(offset);
343        offset = *peek;
344        *peek = restoreOffset;
345    }
346
347#ifdef SK_DEBUG
348    // assert that the final offset value points to a save verb
349    uint32_t opSize;
350    DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
351    SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
352#endif
353}
354
355void SkPictureRecord::beginRecording() {
356    // we have to call this *after* our constructor, to ensure that it gets
357    // recorded. This is balanced by restoreToCount() call from endRecording,
358    // which in-turn calls our overridden restore(), so those get recorded too.
359    fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
360}
361
362void SkPictureRecord::endRecording() {
363    SkASSERT(kNoInitialSave != fInitialSaveCount);
364    this->restoreToCount(fInitialSaveCount);
365}
366
367void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
368    if (fRestoreOffsetStack.isEmpty()) {
369        return;
370    }
371
372    if (regionOpExpands(op)) {
373        // Run back through any previous clip ops, and mark their offset to
374        // be 0, disabling their ability to trigger a jump-to-restore, otherwise
375        // they could hide this clips ability to expand the clip (i.e. go from
376        // empty to non-empty).
377        fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
378    }
379
380    size_t offset = fWriter.size();
381    // The RestoreOffset field is initially filled with a placeholder
382    // value that points to the offset of the previous RestoreOffset
383    // in the current stack level, thus forming a linked list so that
384    // the restore offsets can be filled in when the corresponding
385    // restore command is recorded.
386    addInt(fRestoreOffsetStack.top());
387    fRestoreOffsetStack.top() = offset;
388}
389
390bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
391    // id + rect + clip params
392    uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
393    if (!fRestoreOffsetStack.isEmpty()) {
394        // + restore offset
395        size += kUInt32Size;
396    }
397    uint32_t initialOffset = this->addDraw(CLIP_RECT, &size);
398    addRect(rect);
399    addInt(ClipParams_pack(op, doAA));
400    recordRestoreOffsetPlaceholder(op);
401
402    validate(initialOffset, size);
403    return this->INHERITED::clipRect(rect, op, doAA);
404}
405
406bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
407    if (rrect.isRect()) {
408        return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
409    }
410
411    // op + rrect + clip params
412    uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
413    if (!fRestoreOffsetStack.isEmpty()) {
414        // + restore offset
415        size += kUInt32Size;
416    }
417    uint32_t initialOffset = this->addDraw(CLIP_RRECT, &size);
418    addRRect(rrect);
419    addInt(ClipParams_pack(op, doAA));
420    recordRestoreOffsetPlaceholder(op);
421
422    validate(initialOffset, size);
423
424    if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
425        return this->INHERITED::clipRect(rrect.getBounds(), op, doAA);
426    } else {
427        return this->INHERITED::clipRRect(rrect, op, doAA);
428    }
429}
430
431bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
432
433    SkRect r;
434    if (!path.isInverseFillType() && path.isRect(&r)) {
435        return this->clipRect(r, op, doAA);
436    }
437
438    // op + path index + clip params
439    uint32_t size = 3 * kUInt32Size;
440    if (!fRestoreOffsetStack.isEmpty()) {
441        // + restore offset
442        size += kUInt32Size;
443    }
444    uint32_t initialOffset = this->addDraw(CLIP_PATH, &size);
445    addPath(path);
446    addInt(ClipParams_pack(op, doAA));
447    recordRestoreOffsetPlaceholder(op);
448
449    validate(initialOffset, size);
450
451    if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
452        return this->INHERITED::clipRect(path.getBounds(), op, doAA);
453    } else {
454        return this->INHERITED::clipPath(path, op, doAA);
455    }
456}
457
458bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
459    // op + region index + clip params
460    uint32_t size = 3 * kUInt32Size;
461    if (!fRestoreOffsetStack.isEmpty()) {
462        // + restore offset
463        size += kUInt32Size;
464    }
465    uint32_t initialOffset = this->addDraw(CLIP_REGION, &size);
466    addRegion(region);
467    addInt(ClipParams_pack(op, false));
468    recordRestoreOffsetPlaceholder(op);
469
470    validate(initialOffset, size);
471    return this->INHERITED::clipRegion(region, op);
472}
473
474void SkPictureRecord::clear(SkColor color) {
475    // op + color
476    uint32_t size = 2 * kUInt32Size;
477    uint32_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
478    addInt(color);
479    validate(initialOffset, size);
480}
481
482void SkPictureRecord::drawPaint(const SkPaint& paint) {
483    // op + paint index
484    uint32_t size = 2 * kUInt32Size;
485    uint32_t initialOffset = this->addDraw(DRAW_PAINT, &size);
486    addPaint(paint);
487    validate(initialOffset, size);
488}
489
490void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
491                                 const SkPaint& paint) {
492    // op + paint index + mode + count + point data
493    uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
494    uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size);
495    addPaint(paint);
496    addInt(mode);
497    addInt(count);
498    fWriter.writeMul4(pts, count * sizeof(SkPoint));
499    validate(initialOffset, size);
500}
501
502void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
503    // op + paint index + rect
504    uint32_t size = 2 * kUInt32Size + sizeof(oval);
505    uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size);
506    addPaint(paint);
507    addRect(oval);
508    validate(initialOffset, size);
509}
510
511void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
512    // op + paint index + rect
513    uint32_t size = 2 * kUInt32Size + sizeof(rect);
514    uint32_t initialOffset = this->addDraw(DRAW_RECT, &size);
515    addPaint(paint);
516    addRect(rect);
517    validate(initialOffset, size);
518}
519
520void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
521    uint32_t initialOffset, size;
522    if (rrect.isRect()) {
523        // op + paint index + rect
524        size = 2 * kUInt32Size + sizeof(SkRect);
525        initialOffset = this->addDraw(DRAW_RECT, &size);
526        addPaint(paint);
527        addRect(rrect.getBounds());
528    } else if (rrect.isOval()) {
529        // op + paint index + rect
530        size = 2 * kUInt32Size + sizeof(SkRect);
531        initialOffset = this->addDraw(DRAW_OVAL, &size);
532        addPaint(paint);
533        addRect(rrect.getBounds());
534    } else {
535        // op + paint index + rrect
536        size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
537        initialOffset = this->addDraw(DRAW_RRECT, &size);
538        addPaint(paint);
539        addRRect(rrect);
540    }
541    validate(initialOffset, size);
542}
543
544void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
545    // op + paint index + path index
546    uint32_t size = 3 * kUInt32Size;
547    uint32_t initialOffset = this->addDraw(DRAW_PATH, &size);
548    addPaint(paint);
549    addPath(path);
550    validate(initialOffset, size);
551}
552
553void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
554                        const SkPaint* paint = NULL) {
555    // op + paint index + bitmap index + left + top
556    uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
557    uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
558    addPaintPtr(paint);
559    addBitmap(bitmap);
560    addScalar(left);
561    addScalar(top);
562    validate(initialOffset, size);
563}
564
565void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
566                            const SkRect& dst, const SkPaint* paint) {
567    // id + paint index + bitmap index + bool for 'src'
568    uint32_t size = 4 * kUInt32Size;
569    if (NULL != src) {
570        size += sizeof(*src);   // + rect
571    }
572    size += sizeof(dst);        // + rect
573
574    uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
575    addPaintPtr(paint);
576    addBitmap(bitmap);
577    addRectPtr(src);  // may be null
578    addRect(dst);
579    validate(initialOffset, size);
580}
581
582void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
583                                       const SkPaint* paint) {
584    // id + paint index + bitmap index + matrix index
585    uint32_t size = 4 * kUInt32Size;
586    uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
587    addPaintPtr(paint);
588    addBitmap(bitmap);
589    addMatrix(matrix);
590    validate(initialOffset, size);
591}
592
593void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
594                                     const SkRect& dst, const SkPaint* paint) {
595    // op + paint index + bitmap id + center + dst rect
596    uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
597    uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
598    addPaintPtr(paint);
599    addBitmap(bitmap);
600    addIRect(center);
601    addRect(dst);
602    validate(initialOffset, size);
603}
604
605void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
606                        const SkPaint* paint = NULL) {
607    // op + paint index + bitmap index + left + top
608    uint32_t size = 5 * kUInt32Size;
609    uint32_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
610    addPaintPtr(paint);
611    addBitmap(bitmap);
612    addInt(left);
613    addInt(top);
614    validate(initialOffset, size);
615}
616
617// Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been
618// tweaked by paint.computeFastBounds().
619//
620static void computeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
621    SkPaint::FontMetrics metrics;
622    paint.getFontMetrics(&metrics);
623    SkRect bounds;
624    // construct a rect so we can see any adjustments from the paint.
625    // we use 0,1 for left,right, just so the rect isn't empty
626    bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
627    (void)paint.computeFastBounds(bounds, &bounds);
628    topbot[0] = bounds.fTop;
629    topbot[1] = bounds.fBottom;
630}
631
632void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
633                                              SkScalar minY, SkScalar maxY) {
634    if (!flat.isTopBotWritten()) {
635        computeFontMetricsTopBottom(paint, flat.writableTopBot());
636        SkASSERT(flat.isTopBotWritten());
637    }
638    addScalar(flat.topBot()[0] + minY);
639    addScalar(flat.topBot()[1] + maxY);
640}
641
642void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
643                      SkScalar y, const SkPaint& paint) {
644    bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
645
646    // op + paint index + length + 'length' worth of chars + x + y
647    uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
648    if (fast) {
649        size += 2 * sizeof(SkScalar); // + top & bottom
650    }
651
652    uint32_t initialOffset = this->addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT, &size);
653    const SkFlatData* flatPaintData = addPaint(paint);
654    SkASSERT(flatPaintData);
655    addText(text, byteLength);
656    addScalar(x);
657    addScalar(y);
658    if (fast) {
659        addFontMetricsTopBottom(paint, *flatPaintData, y, y);
660    }
661    validate(initialOffset, size);
662}
663
664void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
665                         const SkPoint pos[], const SkPaint& paint) {
666    size_t points = paint.countText(text, byteLength);
667    if (0 == points)
668        return;
669
670    bool canUseDrawH = true;
671    SkScalar minY = pos[0].fY;
672    SkScalar maxY = pos[0].fY;
673    // check if the caller really should have used drawPosTextH()
674    {
675        const SkScalar firstY = pos[0].fY;
676        for (size_t index = 1; index < points; index++) {
677            if (pos[index].fY != firstY) {
678                canUseDrawH = false;
679                if (pos[index].fY < minY) {
680                    minY = pos[index].fY;
681                } else if (pos[index].fY > maxY) {
682                    maxY = pos[index].fY;
683                }
684            }
685        }
686    }
687
688    bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
689    bool fast = canUseDrawH && fastBounds;
690
691    // op + paint index + length + 'length' worth of data + num points
692    uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
693    if (canUseDrawH) {
694        if (fast) {
695            size += 2 * sizeof(SkScalar); // + top & bottom
696        }
697        // + y-pos + actual x-point data
698        size += sizeof(SkScalar) + points * sizeof(SkScalar);
699    } else {
700        // + x&y point data
701        size += points * sizeof(SkPoint);
702        if (fastBounds) {
703            size += 2 * sizeof(SkScalar); // + top & bottom
704        }
705    }
706
707    DrawType op;
708    if (fast) {
709        op = DRAW_POS_TEXT_H_TOP_BOTTOM;
710    } else if (canUseDrawH) {
711        op = DRAW_POS_TEXT_H;
712    } else if (fastBounds) {
713        op = DRAW_POS_TEXT_TOP_BOTTOM;
714    } else {
715        op = DRAW_POS_TEXT;
716    }
717    uint32_t initialOffset = this->addDraw(op, &size);
718    const SkFlatData* flatPaintData = addPaint(paint);
719    SkASSERT(flatPaintData);
720    addText(text, byteLength);
721    addInt(points);
722
723#ifdef SK_DEBUG_SIZE
724    size_t start = fWriter.size();
725#endif
726    if (canUseDrawH) {
727        if (fast) {
728            addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
729        }
730        addScalar(pos[0].fY);
731        SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
732        for (size_t index = 0; index < points; index++)
733            *xptr++ = pos[index].fX;
734    } else {
735        fWriter.writeMul4(pos, points * sizeof(SkPoint));
736        if (fastBounds) {
737            addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
738        }
739    }
740#ifdef SK_DEBUG_SIZE
741    fPointBytes += fWriter.size() - start;
742    fPointWrites += points;
743#endif
744    validate(initialOffset, size);
745}
746
747void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
748                          const SkScalar xpos[], SkScalar constY,
749                          const SkPaint& paint) {
750    size_t points = paint.countText(text, byteLength);
751    if (0 == points)
752        return;
753
754    bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
755
756    // op + paint index + length + 'length' worth of data + num points
757    uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
758    if (fast) {
759        size += 2 * sizeof(SkScalar); // + top & bottom
760    }
761    // + y + the actual points
762    size += 1 * kUInt32Size + points * sizeof(SkScalar);
763
764    uint32_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
765                                           &size);
766    const SkFlatData* flatPaintData = addPaint(paint);
767    SkASSERT(flatPaintData);
768    addText(text, byteLength);
769    addInt(points);
770
771#ifdef SK_DEBUG_SIZE
772    size_t start = fWriter.size();
773#endif
774    if (fast) {
775        addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
776    }
777    addScalar(constY);
778    fWriter.writeMul4(xpos, points * sizeof(SkScalar));
779#ifdef SK_DEBUG_SIZE
780    fPointBytes += fWriter.size() - start;
781    fPointWrites += points;
782#endif
783    validate(initialOffset, size);
784}
785
786void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
787                            const SkPath& path, const SkMatrix* matrix,
788                            const SkPaint& paint) {
789    // op + paint index + length + 'length' worth of data + path index + matrix index
790    uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size;
791    uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
792    addPaint(paint);
793    addText(text, byteLength);
794    addPath(path);
795    addMatrixPtr(matrix);
796    validate(initialOffset, size);
797}
798
799void SkPictureRecord::drawPicture(SkPicture& picture) {
800    // op + picture index
801    uint32_t size = 2 * kUInt32Size;
802    uint32_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
803    addPicture(picture);
804    validate(initialOffset, size);
805}
806
807void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
808                          const SkPoint vertices[], const SkPoint texs[],
809                          const SkColor colors[], SkXfermode*,
810                          const uint16_t indices[], int indexCount,
811                          const SkPaint& paint) {
812    uint32_t flags = 0;
813    if (texs) {
814        flags |= DRAW_VERTICES_HAS_TEXS;
815    }
816    if (colors) {
817        flags |= DRAW_VERTICES_HAS_COLORS;
818    }
819    if (indexCount > 0) {
820        flags |= DRAW_VERTICES_HAS_INDICES;
821    }
822
823    // op + paint index + flags + vmode + vCount + vertices
824    uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
825    if (flags & DRAW_VERTICES_HAS_TEXS) {
826        size += vertexCount * sizeof(SkPoint);  // + uvs
827    }
828    if (flags & DRAW_VERTICES_HAS_COLORS) {
829        size += vertexCount * sizeof(SkColor);  // + vert colors
830    }
831    if (flags & DRAW_VERTICES_HAS_INDICES) {
832        // + num indices + indices
833        size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
834    }
835
836    uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
837    addPaint(paint);
838    addInt(flags);
839    addInt(vmode);
840    addInt(vertexCount);
841    addPoints(vertices, vertexCount);
842    if (flags & DRAW_VERTICES_HAS_TEXS) {
843        addPoints(texs, vertexCount);
844    }
845    if (flags & DRAW_VERTICES_HAS_COLORS) {
846        fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
847    }
848    if (flags & DRAW_VERTICES_HAS_INDICES) {
849        addInt(indexCount);
850        fWriter.writePad(indices, indexCount * sizeof(uint16_t));
851    }
852    validate(initialOffset, size);
853}
854
855void SkPictureRecord::drawData(const void* data, size_t length) {
856    // op + length + 'length' worth of data
857    uint32_t size = 2 * kUInt32Size + SkAlign4(length);
858    uint32_t initialOffset = this->addDraw(DRAW_DATA, &size);
859    addInt(length);
860    fWriter.writePad(data, length);
861    validate(initialOffset, size);
862}
863
864///////////////////////////////////////////////////////////////////////////////
865
866void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
867    const int index = fBitmapHeap->insert(bitmap);
868    // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
869    // release builds, the invalid value will be recorded so that the reader will know that there
870    // was a problem.
871    SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
872    addInt(index);
873}
874
875void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
876    addMatrixPtr(&matrix);
877}
878
879void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
880    this->addInt(matrix ? fMatrices.find(*matrix) : 0);
881}
882
883const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
884    const SkFlatData* data = paint ? fPaints.findAndReturnFlat(*paint) : NULL;
885    int index = data ? data->index() : 0;
886    this->addInt(index);
887    return data;
888}
889
890void SkPictureRecord::addPath(const SkPath& path) {
891    if (NULL == fPathHeap) {
892        fPathHeap = SkNEW(SkPathHeap);
893    }
894    addInt(fPathHeap->append(path));
895}
896
897void SkPictureRecord::addPicture(SkPicture& picture) {
898    int index = fPictureRefs.find(&picture);
899    if (index < 0) {    // not found
900        index = fPictureRefs.count();
901        *fPictureRefs.append() = &picture;
902        picture.ref();
903    }
904    // follow the convention of recording a 1-based index
905    addInt(index + 1);
906}
907
908void SkPictureRecord::addPoint(const SkPoint& point) {
909#ifdef SK_DEBUG_SIZE
910    size_t start = fWriter.size();
911#endif
912    fWriter.writePoint(point);
913#ifdef SK_DEBUG_SIZE
914    fPointBytes += fWriter.size() - start;
915    fPointWrites++;
916#endif
917}
918
919void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
920    fWriter.writeMul4(pts, count * sizeof(SkPoint));
921#ifdef SK_DEBUG_SIZE
922    fPointBytes += count * sizeof(SkPoint);
923    fPointWrites++;
924#endif
925}
926
927void SkPictureRecord::addRect(const SkRect& rect) {
928#ifdef SK_DEBUG_SIZE
929    size_t start = fWriter.size();
930#endif
931    fWriter.writeRect(rect);
932#ifdef SK_DEBUG_SIZE
933    fRectBytes += fWriter.size() - start;
934    fRectWrites++;
935#endif
936}
937
938void SkPictureRecord::addRectPtr(const SkRect* rect) {
939    if (fWriter.writeBool(rect != NULL)) {
940        fWriter.writeRect(*rect);
941    }
942}
943
944void SkPictureRecord::addIRect(const SkIRect& rect) {
945    fWriter.write(&rect, sizeof(rect));
946}
947
948void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
949    if (fWriter.writeBool(rect != NULL)) {
950        *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
951    }
952}
953
954void SkPictureRecord::addRRect(const SkRRect& rrect) {
955    fWriter.writeRRect(rrect);
956}
957
958void SkPictureRecord::addRegion(const SkRegion& region) {
959    addInt(fRegions.find(region));
960}
961
962void SkPictureRecord::addText(const void* text, size_t byteLength) {
963#ifdef SK_DEBUG_SIZE
964    size_t start = fWriter.size();
965#endif
966    addInt(byteLength);
967    fWriter.writePad(text, byteLength);
968#ifdef SK_DEBUG_SIZE
969    fTextBytes += fWriter.size() - start;
970    fTextWrites++;
971#endif
972}
973
974///////////////////////////////////////////////////////////////////////////////
975
976#ifdef SK_DEBUG_SIZE
977size_t SkPictureRecord::size() const {
978    size_t result = 0;
979    size_t sizeData;
980    bitmaps(&sizeData);
981    result += sizeData;
982    matrices(&sizeData);
983    result += sizeData;
984    paints(&sizeData);
985    result += sizeData;
986    paths(&sizeData);
987    result += sizeData;
988    pictures(&sizeData);
989    result += sizeData;
990    regions(&sizeData);
991    result += sizeData;
992    result += streamlen();
993    return result;
994}
995
996int SkPictureRecord::bitmaps(size_t* size) const {
997    size_t result = 0;
998    int count = fBitmaps.count();
999    for (int index = 0; index < count; index++)
1000        result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1001    *size = result;
1002    return count;
1003}
1004
1005int SkPictureRecord::matrices(size_t* size) const {
1006    int count = fMatrices.count();
1007    *size = sizeof(fMatrices[0]) * count;
1008    return count;
1009}
1010
1011int SkPictureRecord::paints(size_t* size) const {
1012    size_t result = 0;
1013    int count = fPaints.count();
1014    for (int index = 0; index < count; index++)
1015        result += sizeof(fPaints[index]) + fPaints[index]->size();
1016    *size = result;
1017    return count;
1018}
1019
1020int SkPictureRecord::paths(size_t* size) const {
1021    size_t result = 0;
1022    int count = fPaths.count();
1023    for (int index = 0; index < count; index++)
1024        result += sizeof(fPaths[index]) + fPaths[index]->size();
1025    *size = result;
1026    return count;
1027}
1028
1029int SkPictureRecord::regions(size_t* size) const {
1030    size_t result = 0;
1031    int count = fRegions.count();
1032    for (int index = 0; index < count; index++)
1033        result += sizeof(fRegions[index]) + fRegions[index]->size();
1034    *size = result;
1035    return count;
1036}
1037
1038size_t SkPictureRecord::streamlen() const {
1039    return fWriter.size();
1040}
1041#endif
1042
1043#ifdef SK_DEBUG_VALIDATE
1044void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1045    SkASSERT(fWriter.size() == initialOffset + size);
1046
1047    validateBitmaps();
1048    validateMatrices();
1049    validatePaints();
1050    validatePaths();
1051    validateRegions();
1052}
1053
1054void SkPictureRecord::validateBitmaps() const {
1055    int count = fBitmapHeap->count();
1056    SkASSERT((unsigned) count < 0x1000);
1057    for (int index = 0; index < count; index++) {
1058        const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
1059        SkASSERT(bitPtr);
1060        bitPtr->validate();
1061    }
1062}
1063
1064void SkPictureRecord::validateMatrices() const {
1065    int count = fMatrices.count();
1066    SkASSERT((unsigned) count < 0x1000);
1067    for (int index = 0; index < count; index++) {
1068        const SkFlatData* matrix = fMatrices[index];
1069        SkASSERT(matrix);
1070//        matrix->validate();
1071    }
1072}
1073
1074void SkPictureRecord::validatePaints() const {
1075    int count = fPaints.count();
1076    SkASSERT((unsigned) count < 0x1000);
1077    for (int index = 0; index < count; index++) {
1078        const SkFlatData* paint = fPaints[index];
1079        SkASSERT(paint);
1080//            paint->validate();
1081    }
1082}
1083
1084void SkPictureRecord::validatePaths() const {
1085    if (NULL == fPathHeap) {
1086        return;
1087    }
1088
1089    int count = fPathHeap->count();
1090    SkASSERT((unsigned) count < 0x1000);
1091    for (int index = 0; index < count; index++) {
1092        const SkPath& path = (*fPathHeap)[index];
1093        path.validate();
1094    }
1095}
1096
1097void SkPictureRecord::validateRegions() const {
1098    int count = fRegions.count();
1099    SkASSERT((unsigned) count < 0x1000);
1100    for (int index = 0; index < count; index++) {
1101        const SkFlatData* region = fRegions[index];
1102        SkASSERT(region);
1103//        region->validate();
1104    }
1105}
1106#endif
1107