1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkPictureRecord.h"
9#include "SkImage_Base.h"
10#include "SkPatchUtils.h"
11#include "SkPixelRef.h"
12#include "SkRRect.h"
13#include "SkRSXform.h"
14#include "SkTextBlob.h"
15#include "SkTSearch.h"
16#include "SkClipOpPriv.h"
17
18#define HEAP_BLOCK_SIZE 4096
19
20enum {
21    // just need a value that save or getSaveCount would never return
22    kNoInitialSave = -1,
23};
24
25// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
26static int const kUInt32Size = 4;
27
28SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
29    : INHERITED(dimensions.width(), dimensions.height())
30    , fRecordFlags(flags)
31    , fInitialSaveCount(kNoInitialSave) {
32}
33
34SkPictureRecord::~SkPictureRecord() {
35    fImageRefs.unrefAll();
36    fPictureRefs.unrefAll();
37    fDrawableRefs.unrefAll();
38    fTextBlobRefs.unrefAll();
39    fVerticesRefs.unrefAll();
40}
41
42///////////////////////////////////////////////////////////////////////////////
43
44void SkPictureRecord::willSave() {
45    // record the offset to us, making it non-positive to distinguish a save
46    // from a clip entry.
47    fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
48    this->recordSave();
49
50    this->INHERITED::willSave();
51}
52
53void SkPictureRecord::recordSave() {
54    fContentInfo.onSave();
55
56    // op only
57    size_t size = sizeof(kUInt32Size);
58    size_t initialOffset = this->addDraw(SAVE, &size);
59
60    this->validate(initialOffset, size);
61}
62
63SkCanvas::SaveLayerStrategy SkPictureRecord::getSaveLayerStrategy(const SaveLayerRec& rec) {
64    // record the offset to us, making it non-positive to distinguish a save
65    // from a clip entry.
66    fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
67    this->recordSaveLayer(rec);
68
69    (void)this->INHERITED::getSaveLayerStrategy(rec);
70    /*  No need for a (potentially very big) layer which we don't actually need
71        at this time (and may not be able to afford since during record our
72        clip starts out the size of the picture, which is often much larger
73        than the size of the actual device we'll use during playback).
74     */
75    return kNoLayer_SaveLayerStrategy;
76}
77
78void SkPictureRecord::recordSaveLayer(const SaveLayerRec& rec) {
79    fContentInfo.onSaveLayer();
80
81    // op + flatflags
82    size_t size = 2 * kUInt32Size;
83    uint32_t flatFlags = 0;
84
85    if (rec.fBounds) {
86        flatFlags |= SAVELAYERREC_HAS_BOUNDS;
87        size += sizeof(*rec.fBounds);
88    }
89    if (rec.fPaint) {
90        flatFlags |= SAVELAYERREC_HAS_PAINT;
91        size += sizeof(uint32_t); // index
92    }
93    if (rec.fBackdrop) {
94        flatFlags |= SAVELAYERREC_HAS_BACKDROP;
95        size += sizeof(uint32_t); // (paint) index
96    }
97    if (rec.fSaveLayerFlags) {
98        flatFlags |= SAVELAYERREC_HAS_FLAGS;
99        size += sizeof(uint32_t);
100    }
101
102    const size_t initialOffset = this->addDraw(SAVE_LAYER_SAVELAYERREC, &size);
103    this->addInt(flatFlags);
104    if (flatFlags & SAVELAYERREC_HAS_BOUNDS) {
105        this->addRect(*rec.fBounds);
106    }
107    if (flatFlags & SAVELAYERREC_HAS_PAINT) {
108        this->addPaintPtr(rec.fPaint);
109    }
110    if (flatFlags & SAVELAYERREC_HAS_BACKDROP) {
111        // overkill, but we didn't already track single flattenables, so using a paint for that
112        SkPaint paint;
113        paint.setImageFilter(sk_ref_sp(const_cast<SkImageFilter*>(rec.fBackdrop)));
114        this->addPaint(paint);
115    }
116    if (flatFlags & SAVELAYERREC_HAS_FLAGS) {
117        this->addInt(rec.fSaveLayerFlags);
118    }
119    this->validate(initialOffset, size);
120}
121
122#ifdef SK_DEBUG
123/*
124 * Read the op code from 'offset' in 'writer' and extract the size too.
125 */
126static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
127    uint32_t peek = writer->readTAt<uint32_t>(offset);
128
129    uint32_t op;
130    UNPACK_8_24(peek, op, *size);
131    if (MASK_24 == *size) {
132        // size required its own slot right after the op code
133        *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
134    }
135    return (DrawType) op;
136}
137#endif//SK_DEBUG
138
139void SkPictureRecord::willRestore() {
140#if 0
141    SkASSERT(fRestoreOffsetStack.count() > 1);
142#endif
143
144    // check for underflow
145    if (fRestoreOffsetStack.count() == 0) {
146        return;
147    }
148
149    this->recordRestore();
150
151    fRestoreOffsetStack.pop();
152
153    this->INHERITED::willRestore();
154}
155
156void SkPictureRecord::recordRestore(bool fillInSkips) {
157    fContentInfo.onRestore();
158
159    if (fillInSkips) {
160        this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
161    }
162    size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
163    size_t initialOffset = this->addDraw(RESTORE, &size);
164    this->validate(initialOffset, size);
165}
166
167void SkPictureRecord::recordTranslate(const SkMatrix& m) {
168    SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
169
170    // op + dx + dy
171    size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
172    size_t initialOffset = this->addDraw(TRANSLATE, &size);
173    this->addScalar(m.getTranslateX());
174    this->addScalar(m.getTranslateY());
175    this->validate(initialOffset, size);
176}
177
178void SkPictureRecord::recordScale(const SkMatrix& m) {
179    SkASSERT(SkMatrix::kScale_Mask == m.getType());
180
181    // op + sx + sy
182    size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
183    size_t initialOffset = this->addDraw(SCALE, &size);
184    this->addScalar(m.getScaleX());
185    this->addScalar(m.getScaleY());
186    this->validate(initialOffset, size);
187}
188
189void SkPictureRecord::didConcat(const SkMatrix& matrix) {
190    switch (matrix.getType()) {
191        case SkMatrix::kTranslate_Mask:
192            this->recordTranslate(matrix);
193            break;
194        case SkMatrix::kScale_Mask:
195            this->recordScale(matrix);
196            break;
197        default:
198            this->recordConcat(matrix);
199            break;
200    }
201    this->INHERITED::didConcat(matrix);
202}
203
204void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
205    this->validate(fWriter.bytesWritten(), 0);
206    // op + matrix
207    size_t size = kUInt32Size + matrix.writeToMemory(nullptr);
208    size_t initialOffset = this->addDraw(CONCAT, &size);
209    this->addMatrix(matrix);
210    this->validate(initialOffset, size);
211}
212
213void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
214    this->validate(fWriter.bytesWritten(), 0);
215    // op + matrix
216    size_t size = kUInt32Size + matrix.writeToMemory(nullptr);
217    size_t initialOffset = this->addDraw(SET_MATRIX, &size);
218    this->addMatrix(matrix);
219    this->validate(initialOffset, size);
220    this->INHERITED::didSetMatrix(matrix);
221}
222
223void SkPictureRecord::didTranslateZ(SkScalar z) {
224#ifdef SK_EXPERIMENTAL_SHADOWING
225    this->validate(fWriter.bytesWritten(), 0);
226    // op + scalar
227    size_t size = 1 * kUInt32Size + 1 * sizeof(SkScalar);
228    size_t initialOffset = this->addDraw(TRANSLATE_Z, &size);
229    this->addScalar(z);
230    this->validate(initialOffset, size);
231    this->INHERITED::didTranslateZ(z);
232#endif
233}
234
235static bool clipOpExpands(SkClipOp op) {
236    switch (op) {
237        case kUnion_SkClipOp:
238        case kXOR_SkClipOp:
239        case kReverseDifference_SkClipOp:
240        case kReplace_SkClipOp:
241            return true;
242        case kIntersect_SkClipOp:
243        case kDifference_SkClipOp:
244            return false;
245        default:
246            SkDEBUGFAIL("unknown clipop");
247            return false;
248    }
249}
250
251void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
252    int32_t offset = fRestoreOffsetStack.top();
253    while (offset > 0) {
254        uint32_t peek = fWriter.readTAt<uint32_t>(offset);
255        fWriter.overwriteTAt(offset, restoreOffset);
256        offset = peek;
257    }
258
259#ifdef SK_DEBUG
260    // offset of 0 has been disabled, so we skip it
261    if (offset > 0) {
262        // assert that the final offset value points to a save verb
263        uint32_t opSize;
264        DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
265        SkASSERT(SAVE_LAYER_SAVEFLAGS_DEPRECATED != drawOp);
266        SkASSERT(SAVE_LAYER_SAVELAYERFLAGS_DEPRECATED_JAN_2016 != drawOp);
267        SkASSERT(SAVE == drawOp || SAVE_LAYER_SAVELAYERREC == drawOp);
268    }
269#endif
270}
271
272void SkPictureRecord::beginRecording() {
273    // we have to call this *after* our constructor, to ensure that it gets
274    // recorded. This is balanced by restoreToCount() call from endRecording,
275    // which in-turn calls our overridden restore(), so those get recorded too.
276    fInitialSaveCount = this->save();
277}
278
279void SkPictureRecord::endRecording() {
280    SkASSERT(kNoInitialSave != fInitialSaveCount);
281    this->restoreToCount(fInitialSaveCount);
282}
283
284size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkClipOp op) {
285    if (fRestoreOffsetStack.isEmpty()) {
286        return -1;
287    }
288
289    // The RestoreOffset field is initially filled with a placeholder
290    // value that points to the offset of the previous RestoreOffset
291    // in the current stack level, thus forming a linked list so that
292    // the restore offsets can be filled in when the corresponding
293    // restore command is recorded.
294    int32_t prevOffset = fRestoreOffsetStack.top();
295
296    if (clipOpExpands(op)) {
297        // Run back through any previous clip ops, and mark their offset to
298        // be 0, disabling their ability to trigger a jump-to-restore, otherwise
299        // they could hide this clips ability to expand the clip (i.e. go from
300        // empty to non-empty).
301        this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
302
303        // Reset the pointer back to the previous clip so that subsequent
304        // restores don't overwrite the offsets we just cleared.
305        prevOffset = 0;
306    }
307
308    size_t offset = fWriter.bytesWritten();
309    this->addInt(prevOffset);
310    fRestoreOffsetStack.top() = SkToU32(offset);
311    return offset;
312}
313
314void SkPictureRecord::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
315    this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
316    this->INHERITED::onClipRect(rect, op, edgeStyle);
317}
318
319size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkClipOp op, bool doAA) {
320    // id + rect + clip params
321    size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
322    // recordRestoreOffsetPlaceholder doesn't always write an offset
323    if (!fRestoreOffsetStack.isEmpty()) {
324        // + restore offset
325        size += kUInt32Size;
326    }
327    size_t initialOffset = this->addDraw(CLIP_RECT, &size);
328    this->addRect(rect);
329    this->addInt(ClipParams_pack(op, doAA));
330    size_t offset = this->recordRestoreOffsetPlaceholder(op);
331
332    this->validate(initialOffset, size);
333    return offset;
334}
335
336void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
337    this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
338    this->INHERITED::onClipRRect(rrect, op, edgeStyle);
339}
340
341size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
342    // op + rrect + clip params
343    size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
344    // recordRestoreOffsetPlaceholder doesn't always write an offset
345    if (!fRestoreOffsetStack.isEmpty()) {
346        // + restore offset
347        size += kUInt32Size;
348    }
349    size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
350    this->addRRect(rrect);
351    this->addInt(ClipParams_pack(op, doAA));
352    size_t offset = recordRestoreOffsetPlaceholder(op);
353    this->validate(initialOffset, size);
354    return offset;
355}
356
357void SkPictureRecord::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
358    int pathID = this->addPathToHeap(path);
359    this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
360    this->INHERITED::onClipPath(path, op, edgeStyle);
361}
362
363size_t SkPictureRecord::recordClipPath(int pathID, SkClipOp op, bool doAA) {
364    // op + path index + clip params
365    size_t size = 3 * kUInt32Size;
366    // recordRestoreOffsetPlaceholder doesn't always write an offset
367    if (!fRestoreOffsetStack.isEmpty()) {
368        // + restore offset
369        size += kUInt32Size;
370    }
371    size_t initialOffset = this->addDraw(CLIP_PATH, &size);
372    this->addInt(pathID);
373    this->addInt(ClipParams_pack(op, doAA));
374    size_t offset = recordRestoreOffsetPlaceholder(op);
375    this->validate(initialOffset, size);
376    return offset;
377}
378
379void SkPictureRecord::onClipRegion(const SkRegion& region, SkClipOp op) {
380    this->recordClipRegion(region, op);
381    this->INHERITED::onClipRegion(region, op);
382}
383
384size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkClipOp op) {
385    // op + clip params + region
386    size_t size = 2 * kUInt32Size + region.writeToMemory(nullptr);
387    // recordRestoreOffsetPlaceholder doesn't always write an offset
388    if (!fRestoreOffsetStack.isEmpty()) {
389        // + restore offset
390        size += kUInt32Size;
391    }
392    size_t initialOffset = this->addDraw(CLIP_REGION, &size);
393    this->addRegion(region);
394    this->addInt(ClipParams_pack(op, false));
395    size_t offset = this->recordRestoreOffsetPlaceholder(op);
396
397    this->validate(initialOffset, size);
398    return offset;
399}
400
401void SkPictureRecord::onDrawPaint(const SkPaint& paint) {
402    // op + paint index
403    size_t size = 2 * kUInt32Size;
404    size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
405    this->addPaint(paint);
406    this->validate(initialOffset, size);
407}
408
409void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
410                                   const SkPaint& paint) {
411    fContentInfo.onDrawPoints(count, paint);
412
413    // op + paint index + mode + count + point data
414    size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
415    size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
416    this->addPaint(paint);
417
418    this->addInt(mode);
419    this->addInt(SkToInt(count));
420    fWriter.writeMul4(pts, count * sizeof(SkPoint));
421    this->validate(initialOffset, size);
422}
423
424void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) {
425    // op + paint index + rect
426    size_t size = 2 * kUInt32Size + sizeof(oval);
427    size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
428    this->addPaint(paint);
429    this->addRect(oval);
430    this->validate(initialOffset, size);
431}
432
433void SkPictureRecord::onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
434                                bool useCenter, const SkPaint& paint) {
435    // op + paint index + rect + start + sweep + bool (as int)
436    size_t size = 2 * kUInt32Size + sizeof(oval) + sizeof(startAngle) + sizeof(sweepAngle) +
437                  sizeof(int);
438    size_t initialOffset = this->addDraw(DRAW_ARC, &size);
439    this->addPaint(paint);
440    this->addRect(oval);
441    this->addScalar(startAngle);
442    this->addScalar(sweepAngle);
443    this->addInt(useCenter);
444    this->validate(initialOffset, size);
445}
446
447void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) {
448    // op + paint index + rect
449    size_t size = 2 * kUInt32Size + sizeof(rect);
450    size_t initialOffset = this->addDraw(DRAW_RECT, &size);
451    this->addPaint(paint);
452    this->addRect(rect);
453    this->validate(initialOffset, size);
454}
455
456void SkPictureRecord::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
457    // op + paint index + region
458    size_t regionBytes = region.writeToMemory(nullptr);
459    size_t size = 2 * kUInt32Size + regionBytes;
460    size_t initialOffset = this->addDraw(DRAW_REGION, &size);
461    this->addPaint(paint);
462    fWriter.writeRegion(region);
463    this->validate(initialOffset, size);
464}
465
466void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
467    // op + paint index + rrect
468    size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
469    size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
470    this->addPaint(paint);
471    this->addRRect(rrect);
472    this->validate(initialOffset, size);
473}
474
475void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
476                                   const SkPaint& paint) {
477    // op + paint index + rrects
478    size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
479    size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
480    this->addPaint(paint);
481    this->addRRect(outer);
482    this->addRRect(inner);
483    this->validate(initialOffset, size);
484}
485
486void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) {
487    fContentInfo.onDrawPath(path, paint);
488
489    // op + paint index + path index
490    size_t size = 3 * kUInt32Size;
491    size_t initialOffset = this->addDraw(DRAW_PATH, &size);
492    this->addPaint(paint);
493    this->addPath(path);
494    this->validate(initialOffset, size);
495}
496
497void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
498                                  const SkPaint* paint) {
499    // op + paint_index + image_index + x + y
500    size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
501    size_t initialOffset = this->addDraw(DRAW_IMAGE, &size);
502    this->addPaintPtr(paint);
503    this->addImage(image);
504    this->addScalar(x);
505    this->addScalar(y);
506    this->validate(initialOffset, size);
507}
508
509void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
510                                      const SkPaint* paint, SrcRectConstraint constraint) {
511    // id + paint_index + image_index + bool_for_src + constraint
512    size_t size = 5 * kUInt32Size;
513    if (src) {
514        size += sizeof(*src);   // + rect
515    }
516    size += sizeof(dst);        // + rect
517
518    size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT, &size);
519    this->addPaintPtr(paint);
520    this->addImage(image);
521    this->addRectPtr(src);  // may be null
522    this->addRect(dst);
523    this->addInt(constraint);
524    this->validate(initialOffset, size);
525}
526
527void SkPictureRecord::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst,
528                                      const SkPaint* paint) {
529    // id + paint_index + image_index + center + dst
530    size_t size = 3 * kUInt32Size + sizeof(SkIRect) + sizeof(SkRect);
531
532    size_t initialOffset = this->addDraw(DRAW_IMAGE_NINE, &size);
533    this->addPaintPtr(paint);
534    this->addImage(img);
535    this->addIRect(center);
536    this->addRect(dst);
537    this->validate(initialOffset, size);
538}
539
540void SkPictureRecord::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
541                                         const SkRect& dst, const SkPaint* paint) {
542    // xCount + xDivs + yCount+ yDivs
543    int flagCount = (nullptr == lattice.fFlags) ? 0 : (lattice.fXCount + 1) * (lattice.fYCount + 1);
544    size_t latticeSize = (1 + lattice.fXCount + 1 + lattice.fYCount + 1) * kUInt32Size +
545                         SkAlign4(flagCount * sizeof(SkCanvas::Lattice::Flags)) + sizeof(SkIRect);
546
547    // op + paint index + image index + lattice + dst rect
548    size_t size = 3 * kUInt32Size + latticeSize + sizeof(dst);
549    size_t initialOffset = this->addDraw(DRAW_IMAGE_LATTICE, &size);
550    this->addPaintPtr(paint);
551    this->addImage(image);
552    this->addInt(lattice.fXCount);
553    fWriter.writePad(lattice.fXDivs, lattice.fXCount * kUInt32Size);
554    this->addInt(lattice.fYCount);
555    fWriter.writePad(lattice.fYDivs, lattice.fYCount * kUInt32Size);
556    this->addInt(flagCount);
557    fWriter.writePad(lattice.fFlags, flagCount * sizeof(SkCanvas::Lattice::Flags));
558    SkASSERT(lattice.fBounds);
559    this->addIRect(*lattice.fBounds);
560    this->addRect(dst);
561    this->validate(initialOffset, size);
562}
563
564void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
565                                 const SkPaint& paint) {
566    // op + paint index + length + 'length' worth of chars + x + y
567    size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
568
569    DrawType op = DRAW_TEXT;
570    size_t initialOffset = this->addDraw(op, &size);
571    this->addPaint(paint);
572    this->addText(text, byteLength);
573    this->addScalar(x);
574    this->addScalar(y);
575    this->validate(initialOffset, size);
576}
577
578void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
579                                    const SkPaint& paint) {
580    int points = paint.countText(text, byteLength);
581
582    // op + paint index + length + 'length' worth of data + num points + x&y point data
583    size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint);
584
585    DrawType op = DRAW_POS_TEXT;
586
587    size_t initialOffset = this->addDraw(op, &size);
588    this->addPaint(paint);
589    this->addText(text, byteLength);
590    this->addInt(points);
591    fWriter.writeMul4(pos, points * sizeof(SkPoint));
592    this->validate(initialOffset, size);
593}
594
595void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
596                                     SkScalar constY, const SkPaint& paint) {
597    int points = paint.countText(text, byteLength);
598
599    // op + paint index + length + 'length' worth of data + num points
600    size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
601    // + y + the actual points
602    size += 1 * kUInt32Size + points * sizeof(SkScalar);
603
604    size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size);
605    this->addPaint(paint);
606    this->addText(text, byteLength);
607    this->addInt(points);
608    this->addScalar(constY);
609    fWriter.writeMul4(xpos, points * sizeof(SkScalar));
610    this->validate(initialOffset, size);
611}
612
613void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
614                                       const SkMatrix* matrix, const SkPaint& paint) {
615    // op + paint index + length + 'length' worth of data + path index + matrix
616    const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
617    size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(nullptr);
618    size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
619    this->addPaint(paint);
620    this->addText(text, byteLength);
621    this->addPath(path);
622    this->addMatrix(m);
623    this->validate(initialOffset, size);
624}
625
626void SkPictureRecord::onDrawTextRSXform(const void* text, size_t byteLength,
627                                        const SkRSXform xform[], const SkRect* cull,
628                                        const SkPaint& paint) {
629    const int count = paint.countText(text, byteLength);
630    // [op + paint-index + count + flags + length] + [text] + [xform] + cull
631    size_t size = 5 * kUInt32Size + SkAlign4(byteLength) + count * sizeof(SkRSXform);
632    uint32_t flags = 0;
633    if (cull) {
634        flags |= DRAW_TEXT_RSXFORM_HAS_CULL;
635        size += sizeof(SkRect);
636    }
637
638    size_t initialOffset = this->addDraw(DRAW_TEXT_RSXFORM, &size);
639    this->addPaint(paint);
640    this->addInt(count);
641    this->addInt(flags);
642    this->addText(text, byteLength);
643    fWriter.write(xform, count * sizeof(SkRSXform));
644    if (cull) {
645        fWriter.write(cull, sizeof(SkRect));
646    }
647    this->validate(initialOffset, size);
648}
649
650void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
651                                     const SkPaint& paint) {
652
653    // op + paint index + blob index + x/y
654    size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
655    size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
656
657    this->addPaint(paint);
658    this->addTextBlob(blob);
659    this->addScalar(x);
660    this->addScalar(y);
661
662    this->validate(initialOffset, size);
663}
664
665void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
666                                    const SkPaint* paint) {
667    // op + picture index
668    size_t size = 2 * kUInt32Size;
669    size_t initialOffset;
670
671    if (nullptr == matrix && nullptr == paint) {
672        initialOffset = this->addDraw(DRAW_PICTURE, &size);
673        this->addPicture(picture);
674    } else {
675        const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
676        size += m.writeToMemory(nullptr) + kUInt32Size;    // matrix + paint
677        initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
678        this->addPaintPtr(paint);
679        this->addMatrix(m);
680        this->addPicture(picture);
681    }
682    this->validate(initialOffset, size);
683}
684
685void SkPictureRecord::onDrawShadowedPicture(const SkPicture* picture,
686                                            const SkMatrix* matrix,
687                                            const SkPaint* paint,
688                                            const SkShadowParams& params) {
689    // op + picture index
690    size_t size = 2 * kUInt32Size;
691    size_t initialOffset;
692
693    // TODO: handle recording params.
694    if (nullptr == matrix && nullptr == paint) {
695        initialOffset = this->addDraw(DRAW_PICTURE, &size);
696        this->addPicture(picture);
697    } else {
698        const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
699        size += m.writeToMemory(nullptr) + kUInt32Size;    // matrix + paint
700        initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
701        this->addPaintPtr(paint);
702        this->addMatrix(m);
703        this->addPicture(picture);
704    }
705    this->validate(initialOffset, size);
706}
707
708void SkPictureRecord::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
709    // op + drawable index
710    size_t size = 2 * kUInt32Size;
711    size_t initialOffset;
712
713    if (nullptr == matrix) {
714        initialOffset = this->addDraw(DRAW_DRAWABLE, &size);
715        this->addDrawable(drawable);
716    } else {
717        size += matrix->writeToMemory(nullptr);    // matrix
718        initialOffset = this->addDraw(DRAW_DRAWABLE_MATRIX, &size);
719        this->addMatrix(*matrix);
720        this->addDrawable(drawable);
721    }
722    this->validate(initialOffset, size);
723}
724
725void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode,
726                                           const SkPaint& paint) {
727    // op + paint index + vertices index + mode
728    size_t size = 4 * kUInt32Size;
729    size_t initialOffset = this->addDraw(DRAW_VERTICES_OBJECT, &size);
730
731    this->addPaint(paint);
732    this->addVertices(vertices);
733    this->addInt(static_cast<uint32_t>(mode));
734
735    this->validate(initialOffset, size);
736}
737
738void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
739                                  const SkPoint texCoords[4], SkBlendMode bmode,
740                                  const SkPaint& paint) {
741    // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
742    size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
743    uint32_t flag = 0;
744    if (colors) {
745        flag |= DRAW_VERTICES_HAS_COLORS;
746        size += SkPatchUtils::kNumCorners * sizeof(SkColor);
747    }
748    if (texCoords) {
749        flag |= DRAW_VERTICES_HAS_TEXS;
750        size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
751    }
752    if (SkBlendMode::kModulate != bmode) {
753        flag |= DRAW_VERTICES_HAS_XFER;
754        size += kUInt32Size;
755    }
756
757    size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
758    this->addPaint(paint);
759    this->addPatch(cubics);
760    this->addInt(flag);
761
762    // write optional parameters
763    if (colors) {
764        fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
765    }
766    if (texCoords) {
767        fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
768    }
769    if (flag & DRAW_VERTICES_HAS_XFER) {
770        this->addInt((int)bmode);
771    }
772    this->validate(initialOffset, size);
773}
774
775void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
776                                  const SkColor colors[], int count, SkBlendMode mode,
777                                  const SkRect* cull, const SkPaint* paint) {
778    // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
779    size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
780    uint32_t flags = 0;
781    if (colors) {
782        flags |= DRAW_ATLAS_HAS_COLORS;
783        size += count * sizeof(SkColor);
784        size += sizeof(uint32_t);   // xfermode::mode
785    }
786    if (cull) {
787        flags |= DRAW_ATLAS_HAS_CULL;
788        size += sizeof(SkRect);
789    }
790
791    size_t initialOffset = this->addDraw(DRAW_ATLAS, &size);
792    this->addPaintPtr(paint);
793    this->addImage(atlas);
794    this->addInt(flags);
795    this->addInt(count);
796    fWriter.write(xform, count * sizeof(SkRSXform));
797    fWriter.write(tex, count * sizeof(SkRect));
798
799    // write optional parameters
800    if (colors) {
801        fWriter.write(colors, count * sizeof(SkColor));
802        this->addInt((int)mode);
803    }
804    if (cull) {
805        fWriter.write(cull, sizeof(SkRect));
806    }
807    this->validate(initialOffset, size);
808}
809
810void SkPictureRecord::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
811    size_t keyLen = fWriter.WriteStringSize(key);
812    size_t valueLen = fWriter.WriteDataSize(value);
813    size_t size = 4 + sizeof(SkRect) + keyLen + valueLen;
814
815    size_t initialOffset = this->addDraw(DRAW_ANNOTATION, &size);
816    this->addRect(rect);
817    fWriter.writeString(key);
818    fWriter.writeData(value);
819    this->validate(initialOffset, size);
820}
821
822///////////////////////////////////////////////////////////////////////////////
823
824template <typename T> int find_or_append_uniqueID(SkTDArray<const T*>& array, const T* obj) {
825    int index = array.select([&](const T* elem) {
826        return elem->uniqueID() == obj->uniqueID();
827    });
828    if (index < 0) {
829        index = array.count();
830        *array.append() = SkRef(obj);
831    }
832    return index;
833}
834
835sk_sp<SkSurface> SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
836    return nullptr;
837}
838
839void SkPictureRecord::addImage(const SkImage* image) {
840    // convention for images is 0-based index
841    this->addInt(find_or_append_uniqueID(fImageRefs, image));
842}
843
844void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
845    fWriter.writeMatrix(matrix);
846}
847
848void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
849    fContentInfo.onAddPaintPtr(paint);
850
851    if (paint) {
852        fPaints.push_back(*paint);
853        this->addInt(fPaints.count());
854    } else {
855        this->addInt(0);
856    }
857}
858
859int SkPictureRecord::addPathToHeap(const SkPath& path) {
860    if (int* n = fPaths.find(path)) {
861        return *n;
862    }
863    int n = fPaths.count() + 1;  // 0 is reserved for null / error.
864    fPaths.set(path, n);
865    return n;
866}
867
868void SkPictureRecord::addPath(const SkPath& path) {
869    this->addInt(this->addPathToHeap(path));
870}
871
872void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
873    fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
874}
875
876void SkPictureRecord::addPicture(const SkPicture* picture) {
877    // follow the convention of recording a 1-based index
878    this->addInt(find_or_append_uniqueID(fPictureRefs, picture) + 1);
879}
880
881void SkPictureRecord::addDrawable(SkDrawable* drawable) {
882    int index = fDrawableRefs.find(drawable);
883    if (index < 0) {    // not found
884        index = fDrawableRefs.count();
885        *fDrawableRefs.append() = drawable;
886        drawable->ref();
887    }
888    // follow the convention of recording a 1-based index
889    this->addInt(index + 1);
890}
891
892void SkPictureRecord::addPoint(const SkPoint& point) {
893    fWriter.writePoint(point);
894}
895
896void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
897    fWriter.writeMul4(pts, count * sizeof(SkPoint));
898}
899
900void SkPictureRecord::addNoOp() {
901    size_t size = kUInt32Size; // op
902    this->addDraw(NOOP, &size);
903}
904
905void SkPictureRecord::addRect(const SkRect& rect) {
906    fWriter.writeRect(rect);
907}
908
909void SkPictureRecord::addRectPtr(const SkRect* rect) {
910    if (fWriter.writeBool(rect != nullptr)) {
911        fWriter.writeRect(*rect);
912    }
913}
914
915void SkPictureRecord::addIRect(const SkIRect& rect) {
916    fWriter.write(&rect, sizeof(rect));
917}
918
919void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
920    if (fWriter.writeBool(rect != nullptr)) {
921        *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
922    }
923}
924
925void SkPictureRecord::addRRect(const SkRRect& rrect) {
926    fWriter.writeRRect(rrect);
927}
928
929void SkPictureRecord::addRegion(const SkRegion& region) {
930    fWriter.writeRegion(region);
931}
932
933void SkPictureRecord::addText(const void* text, size_t byteLength) {
934    fContentInfo.onDrawText();
935    addInt(SkToInt(byteLength));
936    fWriter.writePad(text, byteLength);
937}
938
939void SkPictureRecord::addTextBlob(const SkTextBlob* blob) {
940    // follow the convention of recording a 1-based index
941    this->addInt(find_or_append_uniqueID(fTextBlobRefs, blob) + 1);
942}
943
944void SkPictureRecord::addVertices(const SkVertices* vertices) {
945    // follow the convention of recording a 1-based index
946    this->addInt(find_or_append_uniqueID(fVerticesRefs, vertices) + 1);
947}
948
949///////////////////////////////////////////////////////////////////////////////
950