b2f9216df6a7b17b5bf1934af4ebfe93fda6b781
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkPictureRecord.cpp
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 "SkDevice.h"
14 #include "SkPictureStateTree.h"
15
16 #define HEAP_BLOCK_SIZE 4096
17
18 enum {
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.
24 static int const kUInt32Size = 4;
25
26 static const uint32_t kSaveSize = 2 * kUInt32Size;
27 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
28 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
29
30 SkPictureRecord::SkPictureRecord(uint32_t flags, SkBaseDevice* device) :
31         INHERITED(device),
32         fBoundingHierarchy(NULL),
33         fStateTree(NULL),
34         fFlattenableHeap(HEAP_BLOCK_SIZE),
35         fPaints(&fFlattenableHeap),
36         fRecordFlags(flags) {
37 #ifdef SK_DEBUG_SIZE
38     fPointBytes = fRectBytes = fTextBytes = 0;
39     fPointWrites = fRectWrites = fTextWrites = 0;
40 #endif
41
42     fBitmapHeap = SkNEW(SkBitmapHeap);
43     fFlattenableHeap.setBitmapStorage(fBitmapHeap);
44     fPathHeap = NULL;   // lazy allocate
45     fFirstSavedLayerIndex = kNoSavedLayerIndex;
46
47     fInitialSaveCount = kNoInitialSave;
48 }
49
50 SkPictureRecord::~SkPictureRecord() {
51     SkSafeUnref(fBitmapHeap);
52     SkSafeUnref(fPathHeap);
53     SkSafeUnref(fBoundingHierarchy);
54     SkSafeUnref(fStateTree);
55     fFlattenableHeap.setBitmapStorage(NULL);
56     fPictureRefs.unrefAll();
57 }
58
59 ///////////////////////////////////////////////////////////////////////////////
60
61 // Return the offset of the paint inside a given op's byte stream. A zero
62 // return value means there is no paint (and you really shouldn't be calling
63 // this method)
64 static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
65     // These offsets are where the paint would be if the op size doesn't overflow
66     static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
67         0,  // UNUSED - no paint
68         0,  // CLIP_PATH - no paint
69         0,  // CLIP_REGION - no paint
70         0,  // CLIP_RECT - no paint
71         0,  // CLIP_RRECT - no paint
72         0,  // CONCAT - no paint
73         1,  // DRAW_BITMAP - right after op code
74         1,  // DRAW_BITMAP_MATRIX - right after op code
75         1,  // DRAW_BITMAP_NINE - right after op code
76         1,  // DRAW_BITMAP_RECT_TO_RECT - right after op code
77         0,  // DRAW_CLEAR - no paint
78         0,  // DRAW_DATA - no paint
79         1,  // DRAW_OVAL - right after op code
80         1,  // DRAW_PAINT - right after op code
81         1,  // DRAW_PATH - right after op code
82         0,  // DRAW_PICTURE - no paint
83         1,  // DRAW_POINTS - right after op code
84         1,  // DRAW_POS_TEXT - right after op code
85         1,  // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
86         1,  // DRAW_POS_TEXT_H - right after op code
87         1,  // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
88         1,  // DRAW_RECT - right after op code
89         1,  // DRAW_RRECT - right after op code
90         1,  // DRAW_SPRITE - right after op code
91         1,  // DRAW_TEXT - right after op code
92         1,  // DRAW_TEXT_ON_PATH - right after op code
93         1,  // DRAW_TEXT_TOP_BOTTOM - right after op code
94         1,  // DRAW_VERTICES - right after op code
95         0,  // RESTORE - no paint
96         0,  // ROTATE - no paint
97         0,  // SAVE - no paint
98         0,  // SAVE_LAYER - see below - this paint's location varies
99         0,  // SCALE - no paint
100         0,  // SET_MATRIX - no paint
101         0,  // SKEW - no paint
102         0,  // TRANSLATE - no paint
103         0,  // NOOP - no paint
104         0,  // BEGIN_GROUP - no paint
105         0,  // COMMENT - no paint
106         0,  // END_GROUP - no paint
107     };
108
109     SkASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1);
110     SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
111
112     int overflow = 0;
113     if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
114         // This op's size overflows so an extra uint32_t will be written
115         // after the op code
116         overflow = sizeof(uint32_t);
117     }
118
119     if (SAVE_LAYER == op) {
120         static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
121         static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
122
123         if (kSaveLayerNoBoundsSize == opSize) {
124             return kSaveLayerNoBoundsPaintOffset + overflow;
125         } else {
126             SkASSERT(kSaveLayerWithBoundsSize == opSize);
127             return kSaveLayerWithBoundsPaintOffset + overflow;
128         }
129     }
130
131     SkASSERT(0 != gPaintOffsets[op]);   // really shouldn't be calling this method
132     return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
133 }
134
135 SkBaseDevice* SkPictureRecord::setDevice(SkBaseDevice* device) {
136     SkDEBUGFAIL("eeek, don't try to change the device on a recording canvas");
137     return this->INHERITED::setDevice(device);
138 }
139
140 int SkPictureRecord::save(SaveFlags flags) {
141     // record the offset to us, making it non-positive to distinguish a save
142     // from a clip entry.
143     fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
144
145     // op + flags
146     uint32_t size = kSaveSize;
147     size_t initialOffset = this->addDraw(SAVE, &size);
148     addInt(flags);
149
150     this->validate(initialOffset, size);
151     return this->INHERITED::save(flags);
152 }
153
154 int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
155                                SaveFlags flags) {
156     // record the offset to us, making it non-positive to distinguish a save
157     // from a clip entry.
158     fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
159
160     // op + bool for 'bounds'
161     uint32_t size = 2 * kUInt32Size;
162     if (NULL != bounds) {
163         size += sizeof(*bounds); // + rect
164     }
165     // + paint index + flags
166     size += 2 * kUInt32Size;
167
168     SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
169
170     size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
171     addRectPtr(bounds);
172     SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
173     addPaintPtr(paint);
174     addInt(flags);
175
176     if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
177         fFirstSavedLayerIndex = fRestoreOffsetStack.count();
178     }
179
180     this->validate(initialOffset, size);
181     /*  Don't actually call saveLayer, because that will try to allocate an
182         offscreen device (potentially very big) which we don't actually need
183         at this time (and may not be able to afford since during record our
184         clip starts out the size of the picture, which is often much larger
185         than the size of the actual device we'll use during playback).
186      */
187     int count = this->INHERITED::save(flags);
188     this->clipRectBounds(bounds, flags, NULL);
189     return count;
190 }
191
192 bool SkPictureRecord::isDrawingToLayer() const {
193     return fFirstSavedLayerIndex != kNoSavedLayerIndex;
194 }
195
196 /*
197  * Read the op code from 'offset' in 'writer' and extract the size too.
198  */
199 static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
200     uint32_t* peek = writer->peek32(offset);
201
202     uint32_t op;
203     UNPACK_8_24(*peek, op, *size);
204     if (MASK_24 == *size) {
205         // size required its own slot right after the op code
206         *size = *writer->peek32(offset+kUInt32Size);
207     }
208     return (DrawType) op;
209 }
210
211 #ifdef TRACK_COLLAPSE_STATS
212     static int gCollapseCount, gCollapseCalls;
213 #endif
214
215 // Is the supplied paint simply a color?
216 static bool is_simple(const SkPaint& p) {
217     intptr_t orAccum = (intptr_t)p.getPathEffect()  |
218                        (intptr_t)p.getShader()      |
219                        (intptr_t)p.getXfermode()    |
220                        (intptr_t)p.getMaskFilter()  |
221                        (intptr_t)p.getColorFilter() |
222                        (intptr_t)p.getRasterizer()  |
223                        (intptr_t)p.getLooper()      |
224                        (intptr_t)p.getImageFilter();
225     return 0 == orAccum;
226 }
227
228 // CommandInfos are fed to the 'match' method and filled in with command
229 // information.
230 struct CommandInfo {
231     DrawType fActualOp;
232     uint32_t fOffset;
233     uint32_t fSize;
234 };
235
236 /*
237  * Attempt to match the provided pattern of commands starting at 'offset'
238  * in the byte stream and stopping at the end of the stream. Upon success,
239  * return true with all the pattern information filled out in the result
240  * array (i.e., actual ops, offsets and sizes).
241  * Note this method skips any NOOPs seen in the stream
242  */
243 static bool match(SkWriter32* writer, uint32_t offset,
244                   int* pattern, CommandInfo* result, int numCommands) {
245     SkASSERT(offset < writer->bytesWritten());
246
247     uint32_t curOffset = offset;
248     uint32_t curSize = 0;
249     int numMatched;
250     for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
251         DrawType op = peek_op_and_size(writer, curOffset, &curSize);
252         while (NOOP == op && curOffset < writer->bytesWritten()) {
253             curOffset += curSize;
254             op = peek_op_and_size(writer, curOffset, &curSize);
255         }
256
257         if (curOffset >= writer->bytesWritten()) {
258             return false; // ran out of byte stream
259         }
260
261         if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
262             if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
263                 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
264                 return false;
265             }
266         } else if (op != pattern[numMatched]) {
267             return false;
268         }
269
270         result[numMatched].fActualOp = op;
271         result[numMatched].fOffset = curOffset;
272         result[numMatched].fSize = curSize;
273
274         curOffset += curSize;
275     }
276
277     if (numMatched != numCommands) {
278         return false;
279     }
280
281     curOffset += curSize;
282     if (curOffset < writer->bytesWritten()) {
283         // Something else between the last command and the end of the stream
284         return false;
285     }
286
287     return true;
288 }
289
290 // temporarily here to make code review easier
291 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
292                                                  SkPaintDictionary* paintDict,
293                                                  const CommandInfo& saveLayerInfo,
294                                                  const CommandInfo& dbmInfo);
295
296 /*
297  * Restore has just been called (but not recorded), look back at the
298  * matching save* and see if we are in the configuration:
299  *   SAVE_LAYER
300  *       DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
301  *   RESTORE
302  * where the saveLayer's color can be moved into the drawBitmap*'s paint
303  */
304 static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
305                                SkPaintDictionary* paintDict) {
306     // back up to the save block
307     // TODO: add a stack to track save*/restore offsets rather than searching backwards
308     while (offset > 0) {
309         offset = *writer->peek32(offset);
310     }
311
312     int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
313     CommandInfo result[SK_ARRAY_COUNT(pattern)];
314
315     if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
316         return false;
317     }
318
319     if (kSaveLayerWithBoundsSize == result[0].fSize) {
320         // The saveLayer's bound can offset where the dbm is drawn
321         return false;
322     }
323
324
325     return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
326                                                 result[0], result[1]);
327 }
328
329 /*
330  * Convert the command code located at 'offset' to a NOOP. Leave the size
331  * field alone so the NOOP can be skipped later.
332  */
333 static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
334     uint32_t* ptr = writer->peek32(offset);
335     *ptr = (*ptr & MASK_24) | (NOOP << 24);
336 }
337
338 /*
339  * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
340  * Return true on success; false otherwise.
341  */
342 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
343                                                  SkPaintDictionary* paintDict,
344                                                  const CommandInfo& saveLayerInfo,
345                                                  const CommandInfo& dbmInfo) {
346     SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
347     SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
348              DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
349              DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
350              DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
351
352     uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
353     uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
354
355     // we have a match, now we need to get the paints involved
356     uint32_t dbmPaintId = *writer->peek32(dbmInfo.fOffset+dbmPaintOffset);
357     uint32_t saveLayerPaintId = *writer->peek32(saveLayerInfo.fOffset+slPaintOffset);
358
359     if (0 == saveLayerPaintId) {
360         // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
361         // and signal the caller (by returning true) to not add the RESTORE op
362         convert_command_to_noop(writer, saveLayerInfo.fOffset);
363         return true;
364     }
365
366     if (0 == dbmPaintId) {
367         // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
368         // and signal the caller (by returning true) to not add the RESTORE op
369         convert_command_to_noop(writer, saveLayerInfo.fOffset);
370         uint32_t* ptr = writer->peek32(dbmInfo.fOffset+dbmPaintOffset);
371         SkASSERT(0 == *ptr);
372         *ptr = saveLayerPaintId;
373         return true;
374     }
375
376     SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
377     if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
378         return false;
379     }
380
381     // For this optimization we only fold the saveLayer and drawBitmapRect
382     // together if the saveLayer's draw is simple (i.e., no fancy effects) and
383     // and the only difference in the colors is that the saveLayer's can have
384     // an alpha while the drawBitmapRect's is opaque.
385     // TODO: it should be possible to fold them together even if they both
386     // have different non-255 alphas
387     SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
388
389     SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
390     if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
391         return false;
392     }
393
394     SkColor newColor = SkColorSetA(dbmPaint->getColor(),
395                                    SkColorGetA(saveLayerPaint->getColor()));
396     dbmPaint->setColor(newColor);
397
398     const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
399     if (NULL == data) {
400         return false;
401     }
402
403     // kill the saveLayer and alter the DBMR2R's paint to be the modified one
404     convert_command_to_noop(writer, saveLayerInfo.fOffset);
405     uint32_t* ptr = writer->peek32(dbmInfo.fOffset+dbmPaintOffset);
406     SkASSERT(dbmPaintId == *ptr);
407     *ptr = data->index();
408     return true;
409 }
410
411 /*
412  * Restore has just been called (but not recorded), look back at the
413  * matching save* and see if we are in the configuration:
414  *   SAVE_LAYER (with NULL == bounds)
415  *      SAVE
416  *         CLIP_RECT
417  *         DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
418  *      RESTORE
419  *   RESTORE
420  * where the saveLayer's color can be moved into the drawBitmap*'s paint
421  */
422 static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
423                                SkPaintDictionary* paintDict) {
424
425     // back up to the save block
426     // TODO: add a stack to track save*/restore offsets rather than searching backwards
427     while (offset > 0) {
428         offset = *writer->peek32(offset);
429     }
430
431     int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
432     CommandInfo result[SK_ARRAY_COUNT(pattern)];
433
434     if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
435         return false;
436     }
437
438     if (kSaveLayerWithBoundsSize == result[0].fSize) {
439         // The saveLayer's bound can offset where the dbm is drawn
440         return false;
441     }
442
443     return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
444                                                 result[0], result[3]);
445 }
446
447 /*
448  *  Restore has just been called (but not recorded), so look back at the
449  *  matching save(), and see if we can eliminate the pair of them, due to no
450  *  intervening matrix/clip calls.
451  *
452  *  If so, update the writer and return true, in which case we won't even record
453  *  the restore() call. If we still need the restore(), return false.
454  */
455 static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
456                                        SkPaintDictionary* paintDict) {
457 #ifdef TRACK_COLLAPSE_STATS
458     gCollapseCalls += 1;
459 #endif
460
461     int32_t restoreOffset = (int32_t)writer->bytesWritten();
462
463     // back up to the save block
464     while (offset > 0) {
465         offset = *writer->peek32(offset);
466     }
467
468     // now offset points to a save
469     offset = -offset;
470     uint32_t opSize;
471     DrawType op = peek_op_and_size(writer, offset, &opSize);
472     if (SAVE_LAYER == op) {
473         // not ready to cull these out yet (mrr)
474         return false;
475     }
476     SkASSERT(SAVE == op);
477     SkASSERT(kSaveSize == opSize);
478
479     // get the save flag (last 4-bytes of the space allocated for the opSize)
480     SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) *writer->peek32(offset+4);
481     if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
482         // This function's optimization is only correct for kMatrixClip style saves.
483         // TODO: set checkMatrix & checkClip booleans here and then check for the
484         // offending operations in the following loop.
485         return false;
486     }
487
488     // Walk forward until we get back to either a draw-verb (abort) or we hit
489     // our restore (success).
490     int32_t saveOffset = offset;
491
492     offset += opSize;
493     while (offset < restoreOffset) {
494         op = peek_op_and_size(writer, offset, &opSize);
495         if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
496             // drawing verb, abort
497             return false;
498         }
499         offset += opSize;
500     }
501
502 #ifdef TRACK_COLLAPSE_STATS
503     gCollapseCount += 1;
504     SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
505              (double)gCollapseCount / gCollapseCalls, "%");
506 #endif
507
508     writer->rewindToOffset(saveOffset);
509     return true;
510 }
511
512 typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
513                                      SkPaintDictionary* paintDict);
514 enum PictureRecordOptType {
515     kRewind_OptType,  // Optimization rewinds the command stream
516     kCollapseSaveLayer_OptType,  // Optimization eliminates a save/restore pair
517 };
518
519 enum PictureRecordOptFlags {
520     kSkipIfBBoxHierarchy_Flag = 0x1,  // Optimization should be skipped if the
521                                       // SkPicture has a bounding box hierarchy.
522 };
523
524 struct PictureRecordOpt {
525     PictureRecordOptProc fProc;
526     PictureRecordOptType fType;
527     unsigned fFlags;
528 };
529 /*
530  * A list of the optimizations that are tried upon seeing a restore
531  * TODO: add a real API for such optimizations
532  *       Add the ability to fire optimizations on any op (not just RESTORE)
533  */
534 static const PictureRecordOpt gPictureRecordOpts[] = {
535     // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
536     // because it is redundant with the state traversal optimization in
537     // SkPictureStateTree, and applying the optimization introduces significant
538     // record time overhead because it requires rewinding contents that were
539     // recorded into the BBoxHierarchy.
540     { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
541     { remove_save_layer1,         kCollapseSaveLayer_OptType, 0 },
542     { remove_save_layer2,         kCollapseSaveLayer_OptType, 0 }
543 };
544
545 // This is called after an optimization has been applied to the command stream
546 // in order to adjust the contents and state of the bounding box hierarchy and
547 // state tree to reflect the optimization.
548 static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
549                                       SkBBoxHierarchy* boundingHierarchy) {
550     switch (opt) {
551     case kCollapseSaveLayer_OptType:
552         if (NULL != stateTree) {
553             stateTree->saveCollapsed();
554         }
555         break;
556     case kRewind_OptType:
557         if (NULL != boundingHierarchy) {
558             boundingHierarchy->rewindInserts();
559         }
560         // Note: No need to touch the state tree for this to work correctly.
561         // Unused branches do not burden the playback, and pruning the tree
562         // would be O(N^2), so it is best to leave it alone.
563         break;
564     default:
565         SkASSERT(0);
566     }
567 }
568
569 void SkPictureRecord::restore() {
570     // FIXME: SkDeferredCanvas needs to be refactored to respect
571     // save/restore balancing so that the following test can be
572     // turned on permanently.
573 #if 0
574     SkASSERT(fRestoreOffsetStack.count() > 1);
575 #endif
576
577     // check for underflow
578     if (fRestoreOffsetStack.count() == 0) {
579         return;
580     }
581
582     if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
583         fFirstSavedLayerIndex = kNoSavedLayerIndex;
584     }
585
586     uint32_t initialOffset, size;
587     size_t opt = 0;
588     if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
589         for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
590             if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
591                 && NULL != fBoundingHierarchy) {
592                 continue;
593             }
594             if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
595                 // Some optimization fired so don't add the RESTORE
596                 size = 0;
597                 initialOffset = fWriter.bytesWritten();
598                 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
599                                           fStateTree, fBoundingHierarchy);
600                 break;
601             }
602         }
603     }
604
605     if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
606         SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
607         // No optimization fired so add the RESTORE
608         fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
609         size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
610         initialOffset = this->addDraw(RESTORE, &size);
611     }
612
613     fRestoreOffsetStack.pop();
614
615     this->validate(initialOffset, size);
616     return this->INHERITED::restore();
617 }
618
619 bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
620     // op + dx + dy
621     uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
622     size_t initialOffset = this->addDraw(TRANSLATE, &size);
623     addScalar(dx);
624     addScalar(dy);
625     this->validate(initialOffset, size);
626     return this->INHERITED::translate(dx, dy);
627 }
628
629 bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
630     // op + sx + sy
631     uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
632     size_t initialOffset = this->addDraw(SCALE, &size);
633     addScalar(sx);
634     addScalar(sy);
635     this->validate(initialOffset, size);
636     return this->INHERITED::scale(sx, sy);
637 }
638
639 bool SkPictureRecord::rotate(SkScalar degrees) {
640     // op + degrees
641     uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
642     size_t initialOffset = this->addDraw(ROTATE, &size);
643     addScalar(degrees);
644     this->validate(initialOffset, size);
645     return this->INHERITED::rotate(degrees);
646 }
647
648 bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
649     // op + sx + sy
650     uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
651     size_t initialOffset = this->addDraw(SKEW, &size);
652     addScalar(sx);
653     addScalar(sy);
654     this->validate(initialOffset, size);
655     return this->INHERITED::skew(sx, sy);
656 }
657
658 bool SkPictureRecord::concat(const SkMatrix& matrix) {
659     this->validate(fWriter.bytesWritten(), 0);
660     // op + matrix
661     uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
662     size_t initialOffset = this->addDraw(CONCAT, &size);
663     addMatrix(matrix);
664     this->validate(initialOffset, size);
665     return this->INHERITED::concat(matrix);
666 }
667
668 void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
669     this->validate(fWriter.bytesWritten(), 0);
670     // op + matrix
671     uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
672     size_t initialOffset = this->addDraw(SET_MATRIX, &size);
673     addMatrix(matrix);
674     this->validate(initialOffset, size);
675     this->INHERITED::setMatrix(matrix);
676 }
677
678 static bool regionOpExpands(SkRegion::Op op) {
679     switch (op) {
680         case SkRegion::kUnion_Op:
681         case SkRegion::kXOR_Op:
682         case SkRegion::kReverseDifference_Op:
683         case SkRegion::kReplace_Op:
684             return true;
685         case SkRegion::kIntersect_Op:
686         case SkRegion::kDifference_Op:
687             return false;
688         default:
689             SkDEBUGFAIL("unknown region op");
690             return false;
691     }
692 }
693
694 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
695     int32_t offset = fRestoreOffsetStack.top();
696     while (offset > 0) {
697         uint32_t* peek = fWriter.peek32(offset);
698         offset = *peek;
699         *peek = restoreOffset;
700     }
701
702 #ifdef SK_DEBUG
703     // assert that the final offset value points to a save verb
704     uint32_t opSize;
705     DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
706     SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
707 #endif
708 }
709
710 void SkPictureRecord::beginRecording() {
711     // we have to call this *after* our constructor, to ensure that it gets
712     // recorded. This is balanced by restoreToCount() call from endRecording,
713     // which in-turn calls our overridden restore(), so those get recorded too.
714     fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
715 }
716
717 void SkPictureRecord::endRecording() {
718     SkASSERT(kNoInitialSave != fInitialSaveCount);
719     this->restoreToCount(fInitialSaveCount);
720 }
721
722 void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
723     if (fRestoreOffsetStack.isEmpty()) {
724         return;
725     }
726
727     // The RestoreOffset field is initially filled with a placeholder
728     // value that points to the offset of the previous RestoreOffset
729     // in the current stack level, thus forming a linked list so that
730     // the restore offsets can be filled in when the corresponding
731     // restore command is recorded.
732     int32_t prevOffset = fRestoreOffsetStack.top();
733
734     if (regionOpExpands(op)) {
735         // Run back through any previous clip ops, and mark their offset to
736         // be 0, disabling their ability to trigger a jump-to-restore, otherwise
737         // they could hide this clips ability to expand the clip (i.e. go from
738         // empty to non-empty).
739         fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
740
741         // Reset the pointer back to the previous clip so that subsequent
742         // restores don't overwrite the offsets we just cleared.
743         prevOffset = 0;
744     }
745
746     size_t offset = fWriter.bytesWritten();
747     addInt(prevOffset);
748     fRestoreOffsetStack.top() = offset;
749 }
750
751 bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
752     // id + rect + clip params
753     uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
754     // recordRestoreOffsetPlaceholder doesn't always write an offset
755     if (!fRestoreOffsetStack.isEmpty()) {
756         // + restore offset
757         size += kUInt32Size;
758     }
759     size_t initialOffset = this->addDraw(CLIP_RECT, &size);
760     addRect(rect);
761     addInt(ClipParams_pack(op, doAA));
762     recordRestoreOffsetPlaceholder(op);
763
764     this->validate(initialOffset, size);
765     return this->INHERITED::clipRect(rect, op, doAA);
766 }
767
768 bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
769     if (rrect.isRect()) {
770         return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
771     }
772
773     // op + rrect + clip params
774     uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
775     // recordRestoreOffsetPlaceholder doesn't always write an offset
776     if (!fRestoreOffsetStack.isEmpty()) {
777         // + restore offset
778         size += kUInt32Size;
779     }
780     size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
781     addRRect(rrect);
782     addInt(ClipParams_pack(op, doAA));
783     recordRestoreOffsetPlaceholder(op);
784
785     this->validate(initialOffset, size);
786
787     if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
788         return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
789     } else {
790         return this->INHERITED::clipRRect(rrect, op, doAA);
791     }
792 }
793
794 bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
795
796     SkRect r;
797     if (!path.isInverseFillType() && path.isRect(&r)) {
798         return this->clipRect(r, op, doAA);
799     }
800
801     // op + path index + clip params
802     uint32_t size = 3 * kUInt32Size;
803     // recordRestoreOffsetPlaceholder doesn't always write an offset
804     if (!fRestoreOffsetStack.isEmpty()) {
805         // + restore offset
806         size += kUInt32Size;
807     }
808     size_t initialOffset = this->addDraw(CLIP_PATH, &size);
809     addPath(path);
810     addInt(ClipParams_pack(op, doAA));
811     recordRestoreOffsetPlaceholder(op);
812
813     this->validate(initialOffset, size);
814
815     if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
816         return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
817                                                          path.isInverseFillType());
818     } else {
819         return this->INHERITED::clipPath(path, op, doAA);
820     }
821 }
822
823 bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
824     // op + clip params + region
825     uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
826     // recordRestoreOffsetPlaceholder doesn't always write an offset
827     if (!fRestoreOffsetStack.isEmpty()) {
828         // + restore offset
829         size += kUInt32Size;
830     }
831     size_t initialOffset = this->addDraw(CLIP_REGION, &size);
832     addRegion(region);
833     addInt(ClipParams_pack(op, false));
834     recordRestoreOffsetPlaceholder(op);
835
836     this->validate(initialOffset, size);
837     return this->INHERITED::clipRegion(region, op);
838 }
839
840 void SkPictureRecord::clear(SkColor color) {
841     // op + color
842     uint32_t size = 2 * kUInt32Size;
843     size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
844     addInt(color);
845     this->validate(initialOffset, size);
846 }
847
848 void SkPictureRecord::drawPaint(const SkPaint& paint) {
849     // op + paint index
850     uint32_t size = 2 * kUInt32Size;
851     size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
852     SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
853     addPaint(paint);
854     this->validate(initialOffset, size);
855 }
856
857 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
858                                  const SkPaint& paint) {
859     // op + paint index + mode + count + point data
860     uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
861     size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
862     SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
863     addPaint(paint);
864     addInt(mode);
865     addInt(count);
866     fWriter.writeMul4(pts, count * sizeof(SkPoint));
867     this->validate(initialOffset, size);
868 }
869
870 void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
871     // op + paint index + rect
872     uint32_t size = 2 * kUInt32Size + sizeof(oval);
873     size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
874     SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
875     addPaint(paint);
876     addRect(oval);
877     this->validate(initialOffset, size);
878 }
879
880 void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
881     // op + paint index + rect
882     uint32_t size = 2 * kUInt32Size + sizeof(rect);
883     size_t initialOffset = this->addDraw(DRAW_RECT, &size);
884     SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
885     addPaint(paint);
886     addRect(rect);
887     this->validate(initialOffset, size);
888 }
889
890 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
891     if (rrect.isRect()) {
892         this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
893     } else if (rrect.isOval()) {
894         this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
895     } else {
896         // op + paint index + rrect
897         uint32_t initialOffset, size;
898         size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
899         initialOffset = this->addDraw(DRAW_RRECT, &size);
900         SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
901         addPaint(paint);
902         addRRect(rrect);
903         this->validate(initialOffset, size);
904     }
905 }
906
907 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
908     // op + paint index + path index
909     uint32_t size = 3 * kUInt32Size;
910     size_t initialOffset = this->addDraw(DRAW_PATH, &size);
911     SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
912     addPaint(paint);
913     addPath(path);
914     this->validate(initialOffset, size);
915 }
916
917 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
918                         const SkPaint* paint = NULL) {
919     // op + paint index + bitmap index + left + top
920     uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
921     size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
922     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
923     addPaintPtr(paint);
924     addBitmap(bitmap);
925     addScalar(left);
926     addScalar(top);
927     this->validate(initialOffset, size);
928 }
929
930 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
931                                            const SkRect& dst, const SkPaint* paint,
932                                            DrawBitmapRectFlags flags) {
933     // id + paint index + bitmap index + bool for 'src' + flags
934     uint32_t size = 5 * kUInt32Size;
935     if (NULL != src) {
936         size += sizeof(*src);   // + rect
937     }
938     size += sizeof(dst);        // + rect
939
940     size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
941     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.bytesWritten());
942     addPaintPtr(paint);
943     addBitmap(bitmap);
944     addRectPtr(src);  // may be null
945     addRect(dst);
946     addInt(flags);
947     this->validate(initialOffset, size);
948 }
949
950 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
951                                        const SkPaint* paint) {
952     // id + paint index + bitmap index + matrix
953     uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
954     size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
955     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
956     addPaintPtr(paint);
957     addBitmap(bitmap);
958     addMatrix(matrix);
959     this->validate(initialOffset, size);
960 }
961
962 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
963                                      const SkRect& dst, const SkPaint* paint) {
964     // op + paint index + bitmap id + center + dst rect
965     uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
966     size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
967     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
968     addPaintPtr(paint);
969     addBitmap(bitmap);
970     addIRect(center);
971     addRect(dst);
972     this->validate(initialOffset, size);
973 }
974
975 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
976                         const SkPaint* paint = NULL) {
977     // op + paint index + bitmap index + left + top
978     uint32_t size = 5 * kUInt32Size;
979     size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
980     SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
981     addPaintPtr(paint);
982     addBitmap(bitmap);
983     addInt(left);
984     addInt(top);
985     this->validate(initialOffset, size);
986 }
987
988 void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
989     SkPaint::FontMetrics metrics;
990     paint.getFontMetrics(&metrics);
991     SkRect bounds;
992     // construct a rect so we can see any adjustments from the paint.
993     // we use 0,1 for left,right, just so the rect isn't empty
994     bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
995     (void)paint.computeFastBounds(bounds, &bounds);
996     topbot[0] = bounds.fTop;
997     topbot[1] = bounds.fBottom;
998 }
999
1000 void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
1001                                               SkScalar minY, SkScalar maxY) {
1002     WriteTopBot(paint, flat);
1003     addScalar(flat.topBot()[0] + minY);
1004     addScalar(flat.topBot()[1] + maxY);
1005 }
1006
1007 void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
1008                       SkScalar y, const SkPaint& paint) {
1009     bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
1010
1011     // op + paint index + length + 'length' worth of chars + x + y
1012     uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1013     if (fast) {
1014         size += 2 * sizeof(SkScalar); // + top & bottom
1015     }
1016
1017     DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
1018     size_t initialOffset = this->addDraw(op, &size);
1019     SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
1020     const SkFlatData* flatPaintData = addPaint(paint);
1021     SkASSERT(flatPaintData);
1022     addText(text, byteLength);
1023     addScalar(x);
1024     addScalar(y);
1025     if (fast) {
1026         addFontMetricsTopBottom(paint, *flatPaintData, y, y);
1027     }
1028     this->validate(initialOffset, size);
1029 }
1030
1031 void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
1032                          const SkPoint pos[], const SkPaint& paint) {
1033     size_t points = paint.countText(text, byteLength);
1034     if (0 == points)
1035         return;
1036
1037     bool canUseDrawH = true;
1038     SkScalar minY = pos[0].fY;
1039     SkScalar maxY = pos[0].fY;
1040     // check if the caller really should have used drawPosTextH()
1041     {
1042         const SkScalar firstY = pos[0].fY;
1043         for (size_t index = 1; index < points; index++) {
1044             if (pos[index].fY != firstY) {
1045                 canUseDrawH = false;
1046                 if (pos[index].fY < minY) {
1047                     minY = pos[index].fY;
1048                 } else if (pos[index].fY > maxY) {
1049                     maxY = pos[index].fY;
1050                 }
1051             }
1052         }
1053     }
1054
1055     bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
1056     bool fast = canUseDrawH && fastBounds;
1057
1058     // op + paint index + length + 'length' worth of data + num points
1059     uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1060     if (canUseDrawH) {
1061         if (fast) {
1062             size += 2 * sizeof(SkScalar); // + top & bottom
1063         }
1064         // + y-pos + actual x-point data
1065         size += sizeof(SkScalar) + points * sizeof(SkScalar);
1066     } else {
1067         // + x&y point data
1068         size += points * sizeof(SkPoint);
1069         if (fastBounds) {
1070             size += 2 * sizeof(SkScalar); // + top & bottom
1071         }
1072     }
1073
1074     DrawType op;
1075     if (fast) {
1076         op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1077     } else if (canUseDrawH) {
1078         op = DRAW_POS_TEXT_H;
1079     } else if (fastBounds) {
1080         op = DRAW_POS_TEXT_TOP_BOTTOM;
1081     } else {
1082         op = DRAW_POS_TEXT;
1083     }
1084     size_t initialOffset = this->addDraw(op, &size);
1085     SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
1086     const SkFlatData* flatPaintData = addPaint(paint);
1087     SkASSERT(flatPaintData);
1088     addText(text, byteLength);
1089     addInt(points);
1090
1091 #ifdef SK_DEBUG_SIZE
1092     size_t start = fWriter.bytesWritten();
1093 #endif
1094     if (canUseDrawH) {
1095         if (fast) {
1096             addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
1097         }
1098         addScalar(pos[0].fY);
1099         SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
1100         for (size_t index = 0; index < points; index++)
1101             *xptr++ = pos[index].fX;
1102     } else {
1103         fWriter.writeMul4(pos, points * sizeof(SkPoint));
1104         if (fastBounds) {
1105             addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
1106         }
1107     }
1108 #ifdef SK_DEBUG_SIZE
1109     fPointBytes += fWriter.bytesWritten() - start;
1110     fPointWrites += points;
1111 #endif
1112     this->validate(initialOffset, size);
1113 }
1114
1115 void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1116                           const SkScalar xpos[], SkScalar constY,
1117                           const SkPaint& paint) {
1118
1119     const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
1120     drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
1121 }
1122
1123 void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1124                           const SkScalar xpos[], SkScalar constY,
1125                           const SkPaint& paint, const SkFlatData* flatPaintData) {
1126     size_t points = paint.countText(text, byteLength);
1127     if (0 == points)
1128         return;
1129
1130     bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
1131
1132     // op + paint index + length + 'length' worth of data + num points
1133     uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1134     if (fast) {
1135         size += 2 * sizeof(SkScalar); // + top & bottom
1136     }
1137     // + y + the actual points
1138     size += 1 * kUInt32Size + points * sizeof(SkScalar);
1139     size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
1140                                            &size);
1141     SkASSERT(flatPaintData);
1142     addFlatPaint(flatPaintData);
1143
1144     addText(text, byteLength);
1145     addInt(points);
1146
1147 #ifdef SK_DEBUG_SIZE
1148     size_t start = fWriter.bytesWritten();
1149 #endif
1150     if (fast) {
1151         addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
1152     }
1153     addScalar(constY);
1154     fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1155 #ifdef SK_DEBUG_SIZE
1156     fPointBytes += fWriter.bytesWritten() - start;
1157     fPointWrites += points;
1158 #endif
1159     this->validate(initialOffset, size);
1160 }
1161
1162 void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1163                             const SkPath& path, const SkMatrix* matrix,
1164                             const SkPaint& paint) {
1165     // op + paint index + length + 'length' worth of data + path index + matrix
1166     const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1167     uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
1168     size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
1169     SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
1170     addPaint(paint);
1171     addText(text, byteLength);
1172     addPath(path);
1173     addMatrix(m);
1174     this->validate(initialOffset, size);
1175 }
1176
1177 void SkPictureRecord::drawPicture(SkPicture& picture) {
1178     // op + picture index
1179     uint32_t size = 2 * kUInt32Size;
1180     size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
1181     addPicture(picture);
1182     this->validate(initialOffset, size);
1183 }
1184
1185 void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1186                           const SkPoint vertices[], const SkPoint texs[],
1187                           const SkColor colors[], SkXfermode* xfer,
1188                           const uint16_t indices[], int indexCount,
1189                           const SkPaint& paint) {
1190     uint32_t flags = 0;
1191     if (texs) {
1192         flags |= DRAW_VERTICES_HAS_TEXS;
1193     }
1194     if (colors) {
1195         flags |= DRAW_VERTICES_HAS_COLORS;
1196     }
1197     if (indexCount > 0) {
1198         flags |= DRAW_VERTICES_HAS_INDICES;
1199     }
1200     if (NULL != xfer) {
1201         SkXfermode::Mode mode;
1202         if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1203             flags |= DRAW_VERTICES_HAS_XFER;
1204         }
1205     }
1206
1207     // op + paint index + flags + vmode + vCount + vertices
1208     uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1209     if (flags & DRAW_VERTICES_HAS_TEXS) {
1210         size += vertexCount * sizeof(SkPoint);  // + uvs
1211     }
1212     if (flags & DRAW_VERTICES_HAS_COLORS) {
1213         size += vertexCount * sizeof(SkColor);  // + vert colors
1214     }
1215     if (flags & DRAW_VERTICES_HAS_INDICES) {
1216         // + num indices + indices
1217         size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1218     }
1219     if (flags & DRAW_VERTICES_HAS_XFER) {
1220         size += kUInt32Size;    // mode enum
1221     }
1222
1223     size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
1224     SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
1225     addPaint(paint);
1226     addInt(flags);
1227     addInt(vmode);
1228     addInt(vertexCount);
1229     addPoints(vertices, vertexCount);
1230     if (flags & DRAW_VERTICES_HAS_TEXS) {
1231         addPoints(texs, vertexCount);
1232     }
1233     if (flags & DRAW_VERTICES_HAS_COLORS) {
1234         fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1235     }
1236     if (flags & DRAW_VERTICES_HAS_INDICES) {
1237         addInt(indexCount);
1238         fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1239     }
1240     if (flags & DRAW_VERTICES_HAS_XFER) {
1241         SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1242         (void)xfer->asMode(&mode);
1243         addInt(mode);
1244     }
1245     this->validate(initialOffset, size);
1246 }
1247
1248 void SkPictureRecord::drawData(const void* data, size_t length) {
1249     // op + length + 'length' worth of data
1250     uint32_t size = 2 * kUInt32Size + SkAlign4(length);
1251     size_t initialOffset = this->addDraw(DRAW_DATA, &size);
1252     addInt(length);
1253     fWriter.writePad(data, length);
1254     this->validate(initialOffset, size);
1255 }
1256
1257 void SkPictureRecord::beginCommentGroup(const char* description) {
1258     // op/size + length of string + \0 terminated chars
1259     int length = strlen(description);
1260     uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
1261     size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
1262     fWriter.writeString(description, length);
1263     this->validate(initialOffset, size);
1264 }
1265
1266 void SkPictureRecord::addComment(const char* kywd, const char* value) {
1267     // op/size + 2x length of string + 2x \0 terminated chars
1268     int kywdLen = strlen(kywd);
1269     int valueLen = strlen(value);
1270     uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
1271     size_t initialOffset = this->addDraw(COMMENT, &size);
1272     fWriter.writeString(kywd, kywdLen);
1273     fWriter.writeString(value, valueLen);
1274     this->validate(initialOffset, size);
1275 }
1276
1277 void SkPictureRecord::endCommentGroup() {
1278     // op/size
1279     uint32_t size = 1 * kUInt32Size;
1280     size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1281     this->validate(initialOffset, size);
1282 }
1283
1284 ///////////////////////////////////////////////////////////////////////////////
1285
1286 void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
1287     const int index = fBitmapHeap->insert(bitmap);
1288     // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1289     // release builds, the invalid value will be recorded so that the reader will know that there
1290     // was a problem.
1291     SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
1292     addInt(index);
1293 }
1294
1295 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
1296     fWriter.writeMatrix(matrix);
1297 }
1298
1299 const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1300     return fPaints.findAndReturnFlat(paint);
1301 }
1302
1303 const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
1304     const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1305     this->addFlatPaint(data);
1306     return data;
1307 }
1308
1309 void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1310     int index = flatPaint ? flatPaint->index() : 0;
1311     this->addInt(index);
1312 }
1313
1314 void SkPictureRecord::addPath(const SkPath& path) {
1315     if (NULL == fPathHeap) {
1316         fPathHeap = SkNEW(SkPathHeap);
1317     }
1318     addInt(fPathHeap->append(path));
1319 }
1320
1321 void SkPictureRecord::addPicture(SkPicture& picture) {
1322     int index = fPictureRefs.find(&picture);
1323     if (index < 0) {    // not found
1324         index = fPictureRefs.count();
1325         *fPictureRefs.append() = &picture;
1326         picture.ref();
1327     }
1328     // follow the convention of recording a 1-based index
1329     addInt(index + 1);
1330 }
1331
1332 void SkPictureRecord::addPoint(const SkPoint& point) {
1333 #ifdef SK_DEBUG_SIZE
1334     size_t start = fWriter.bytesWritten();
1335 #endif
1336     fWriter.writePoint(point);
1337 #ifdef SK_DEBUG_SIZE
1338     fPointBytes += fWriter.bytesWritten() - start;
1339     fPointWrites++;
1340 #endif
1341 }
1342
1343 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1344     fWriter.writeMul4(pts, count * sizeof(SkPoint));
1345 #ifdef SK_DEBUG_SIZE
1346     fPointBytes += count * sizeof(SkPoint);
1347     fPointWrites++;
1348 #endif
1349 }
1350
1351 void SkPictureRecord::addRect(const SkRect& rect) {
1352 #ifdef SK_DEBUG_SIZE
1353     size_t start = fWriter.bytesWritten();
1354 #endif
1355     fWriter.writeRect(rect);
1356 #ifdef SK_DEBUG_SIZE
1357     fRectBytes += fWriter.bytesWritten() - start;
1358     fRectWrites++;
1359 #endif
1360 }
1361
1362 void SkPictureRecord::addRectPtr(const SkRect* rect) {
1363     if (fWriter.writeBool(rect != NULL)) {
1364         fWriter.writeRect(*rect);
1365     }
1366 }
1367
1368 void SkPictureRecord::addIRect(const SkIRect& rect) {
1369     fWriter.write(&rect, sizeof(rect));
1370 }
1371
1372 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1373     if (fWriter.writeBool(rect != NULL)) {
1374         *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1375     }
1376 }
1377
1378 void SkPictureRecord::addRRect(const SkRRect& rrect) {
1379     fWriter.writeRRect(rrect);
1380 }
1381
1382 void SkPictureRecord::addRegion(const SkRegion& region) {
1383     fWriter.writeRegion(region);
1384 }
1385
1386 void SkPictureRecord::addText(const void* text, size_t byteLength) {
1387 #ifdef SK_DEBUG_SIZE
1388     size_t start = fWriter.bytesWritten();
1389 #endif
1390     addInt(byteLength);
1391     fWriter.writePad(text, byteLength);
1392 #ifdef SK_DEBUG_SIZE
1393     fTextBytes += fWriter.bytesWritten() - start;
1394     fTextWrites++;
1395 #endif
1396 }
1397
1398 ///////////////////////////////////////////////////////////////////////////////
1399
1400 #ifdef SK_DEBUG_SIZE
1401 size_t SkPictureRecord::size() const {
1402     size_t result = 0;
1403     size_t sizeData;
1404     bitmaps(&sizeData);
1405     result += sizeData;
1406     matrices(&sizeData);
1407     result += sizeData;
1408     paints(&sizeData);
1409     result += sizeData;
1410     paths(&sizeData);
1411     result += sizeData;
1412     pictures(&sizeData);
1413     result += sizeData;
1414     regions(&sizeData);
1415     result += sizeData;
1416     result += streamlen();
1417     return result;
1418 }
1419
1420 int SkPictureRecord::bitmaps(size_t* size) const {
1421     size_t result = 0;
1422     int count = fBitmaps.count();
1423     for (int index = 0; index < count; index++)
1424         result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1425     *size = result;
1426     return count;
1427 }
1428
1429 int SkPictureRecord::matrices(size_t* size) const {
1430     int count = fMatrices.count();
1431     *size = sizeof(fMatrices[0]) * count;
1432     return count;
1433 }
1434
1435 int SkPictureRecord::paints(size_t* size) const {
1436     size_t result = 0;
1437     int count = fPaints.count();
1438     for (int index = 0; index < count; index++)
1439         result += sizeof(fPaints[index]) + fPaints[index]->size();
1440     *size = result;
1441     return count;
1442 }
1443
1444 int SkPictureRecord::paths(size_t* size) const {
1445     size_t result = 0;
1446     int count = fPaths.count();
1447     for (int index = 0; index < count; index++)
1448         result += sizeof(fPaths[index]) + fPaths[index]->size();
1449     *size = result;
1450     return count;
1451 }
1452
1453 int SkPictureRecord::regions(size_t* size) const {
1454     size_t result = 0;
1455     int count = fRegions.count();
1456     for (int index = 0; index < count; index++)
1457         result += sizeof(fRegions[index]) + fRegions[index]->size();
1458     *size = result;
1459     return count;
1460 }
1461
1462 size_t SkPictureRecord::streamlen() const {
1463     return fWriter.size();
1464 }
1465 #endif
1466
1467 #ifdef SK_DEBUG_VALIDATE
1468 void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1469     SkASSERT(fWriter.size() == initialOffset + size);
1470
1471     validateBitmaps();
1472     validateMatrices();
1473     validatePaints();
1474     validatePaths();
1475     validateRegions();
1476 }
1477
1478 void SkPictureRecord::validateBitmaps() const {
1479     int count = fBitmapHeap->count();
1480     SkASSERT((unsigned) count < 0x1000);
1481     for (int index = 0; index < count; index++) {
1482         const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
1483         SkASSERT(bitPtr);
1484         bitPtr->validate();
1485     }
1486 }
1487
1488 void SkPictureRecord::validateMatrices() const {
1489     int count = fMatrices.count();
1490     SkASSERT((unsigned) count < 0x1000);
1491     for (int index = 0; index < count; index++) {
1492         const SkFlatData* matrix = fMatrices[index];
1493         SkASSERT(matrix);
1494 //        matrix->validate();
1495     }
1496 }
1497
1498 void SkPictureRecord::validatePaints() const {
1499     int count = fPaints.count();
1500     SkASSERT((unsigned) count < 0x1000);
1501     for (int index = 0; index < count; index++) {
1502         const SkFlatData* paint = fPaints[index];
1503         SkASSERT(paint);
1504 //            paint->validate();
1505     }
1506 }
1507
1508 void SkPictureRecord::validatePaths() const {
1509     if (NULL == fPathHeap) {
1510         return;
1511     }
1512
1513     int count = fPathHeap->count();
1514     SkASSERT((unsigned) count < 0x1000);
1515     for (int index = 0; index < count; index++) {
1516         const SkPath& path = (*fPathHeap)[index];
1517         path.validate();
1518     }
1519 }
1520
1521 void SkPictureRecord::validateRegions() const {
1522     int count = fRegions.count();
1523     SkASSERT((unsigned) count < 0x1000);
1524     for (int index = 0; index < count; index++) {
1525         const SkFlatData* region = fRegions[index];
1526         SkASSERT(region);
1527 //        region->validate();
1528     }
1529 }
1530 #endif