blob: 45cc48d2145dec085965194f230dd5c2152d4956 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkPictureRecord.h"
9#include "SkTSearch.h"
junov@chromium.org4866cc02012-06-01 21:23:07 +000010#include "SkPixelRef.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000011#include "SkRRect.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000012#include "SkBBoxHierarchy.h"
13#include "SkPictureStateTree.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
15#define MIN_WRITER_SIZE 16384
16#define HEAP_BLOCK_SIZE 4096
17
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000018enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000019 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000020 kNoInitialSave = -1,
21};
22
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000023// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
24static int const kUInt32Size = 4;
25
reed@google.comd86e7ab2012-09-27 20:31:31 +000026SkPictureRecord::SkPictureRecord(uint32_t flags, SkDevice* device) :
27 INHERITED(device),
robertphillips@google.com178a2672012-09-13 13:25:30 +000028 fBoundingHierarchy(NULL),
29 fStateTree(NULL),
djsollen@google.com21830d92012-08-07 19:49:41 +000030 fFlattenableHeap(HEAP_BLOCK_SIZE),
31 fMatrices(&fFlattenableHeap),
32 fPaints(&fFlattenableHeap),
33 fRegions(&fFlattenableHeap),
djsollen@google.comd2700ee2012-05-30 16:54:13 +000034 fWriter(MIN_WRITER_SIZE),
35 fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000036#ifdef SK_DEBUG_SIZE
37 fPointBytes = fRectBytes = fTextBytes = 0;
38 fPointWrites = fRectWrites = fTextWrites = 0;
39#endif
40
41 fRestoreOffsetStack.setReserve(32);
reed@google.com82065d62011-02-07 15:30:46 +000042
djsollen@google.comc9ab9872012-08-29 18:52:07 +000043 fBitmapHeap = SkNEW(SkBitmapHeap);
44 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 fPathHeap = NULL; // lazy allocate
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000046 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@google.comd86e7ab2012-09-27 20:31:31 +000047
48 fInitialSaveCount = kNoInitialSave;
reed@android.com8a1c16f2008-12-17 15:59:43 +000049}
50
51SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000052 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000053 SkSafeUnref(fPathHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000054 SkSafeUnref(fBoundingHierarchy);
55 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000056 fFlattenableHeap.setBitmapStorage(NULL);
57 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000058}
59
60///////////////////////////////////////////////////////////////////////////////
61
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000062SkDevice* SkPictureRecord::setDevice(SkDevice* device) {
reed@google.comd86e7ab2012-09-27 20:31:31 +000063 SkASSERT(!"eeek, don't try to change the device on a recording canvas");
64 return this->INHERITED::setDevice(device);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000065}
66
reed@android.com8a1c16f2008-12-17 15:59:43 +000067int SkPictureRecord::save(SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +000068 // record the offset to us, making it non-positive to distinguish a save
69 // from a clip entry.
70 fRestoreOffsetStack.push(-(int32_t)fWriter.size());
skia.committer@gmail.com11f86922012-08-31 17:14:46 +000071
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000072 // op + flags
73 uint32_t size = 2 * kUInt32Size;
74 uint32_t initialOffset = this->addDraw(SAVE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +000076
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000077 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +000078 return this->INHERITED::save(flags);
79}
80
81int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
82 SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +000083 // record the offset to us, making it non-positive to distinguish a save
84 // from a clip entry.
85 fRestoreOffsetStack.push(-(int32_t)fWriter.size());
skia.committer@gmail.com11f86922012-08-31 17:14:46 +000086
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000087 // op + bool for 'bounds'
88 uint32_t size = 2 * kUInt32Size;
89 if (NULL != bounds) {
90 size += sizeof(*bounds); // + rect
91 }
92 // + paint index + flags
93 size += 2 * kUInt32Size;
94
95 uint32_t initialOffset = this->addDraw(SAVE_LAYER, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +000096 addRectPtr(bounds);
97 addPaintPtr(paint);
98 addInt(flags);
99
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000100 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
101 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
102 }
103
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000104 validate(initialOffset, size);
reed@android.com261ae4d2009-10-02 16:37:46 +0000105 /* Don't actually call saveLayer, because that will try to allocate an
106 offscreen device (potentially very big) which we don't actually need
107 at this time (and may not be able to afford since during record our
108 clip starts out the size of the picture, which is often much larger
109 than the size of the actual device we'll use during playback).
110 */
junov@chromium.orga907ac32012-02-24 21:54:07 +0000111 int count = this->INHERITED::save(flags);
112 this->clipRectBounds(bounds, flags, NULL);
113 return count;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114}
115
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000116bool SkPictureRecord::isDrawingToLayer() const {
117 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
118}
119
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000120/*
121 * Read the op code from 'offset' in 'writer' and extract the size too.
122 */
123static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
124 uint32_t* peek = writer->peek32(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000125
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000126 uint32_t op;
127 UNPACK_8_24(*peek, op, *size);
128 if (MASK_24 == *size) {
129 // size required its own slot right after the op code
130 *size = *writer->peek32(offset+kUInt32Size);
131 }
132 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000133}
134
135#ifdef TRACK_COLLAPSE_STATS
136 static int gCollapseCount, gCollapseCalls;
137#endif
138
139/*
140 * Restore has just been called (but not recoreded), so look back at the
141 * matching save(), and see if we can eliminate the pair of them, due to no
142 * intervening matrix/clip calls.
143 *
144 * If so, update the writer and return true, in which case we won't even record
145 * the restore() call. If we still need the restore(), return false.
146 */
147static bool collapseSaveClipRestore(SkWriter32* writer, int32_t offset) {
148#ifdef TRACK_COLLAPSE_STATS
149 gCollapseCalls += 1;
150#endif
151
152 int32_t restoreOffset = (int32_t)writer->size();
153
154 // back up to the save block
155 while (offset > 0) {
156 offset = *writer->peek32(offset);
157 }
158
159 // now offset points to a save
160 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000161 uint32_t opSize;
162 DrawType op = peek_op_and_size(writer, offset, &opSize);
163 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000164 // not ready to cull these out yet (mrr)
165 return false;
166 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000167 SkASSERT(SAVE == op);
reed@google.comffacd3c2012-08-30 15:31:23 +0000168
169 // Walk forward until we get back to either a draw-verb (abort) or we hit
170 // our restore (success).
171 int32_t saveOffset = offset;
172
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000173 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000174 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000175 op = peek_op_and_size(writer, offset, &opSize);
176 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000177 // drawing verb, abort
178 return false;
179 }
180 offset += opSize;
181 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000182
reed@google.comffacd3c2012-08-30 15:31:23 +0000183#ifdef TRACK_COLLAPSE_STATS
184 gCollapseCount += 1;
185 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
186 (double)gCollapseCount / gCollapseCalls, "%");
187#endif
188
189 writer->rewindToOffset(saveOffset);
190 return true;
191}
192
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000194 // FIXME: SkDeferredCanvas needs to be refactored to respect
195 // save/restore balancing so that the following test can be
196 // turned on permanently.
197#if 0
198 SkASSERT(fRestoreOffsetStack.count() > 1);
199#endif
200
reed@android.comb4e22d62009-07-09 15:20:25 +0000201 // check for underflow
202 if (fRestoreOffsetStack.count() == 0) {
203 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000205
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000206 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
207 fFirstSavedLayerIndex = kNoSavedLayerIndex;
208 }
209
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000210 uint32_t initialOffset, size;
reed@google.comffacd3c2012-08-30 15:31:23 +0000211 if (!collapseSaveClipRestore(&fWriter, fRestoreOffsetStack.top())) {
212 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size());
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000213 // op
214 size = 1 * kUInt32Size;
215 initialOffset = this->addDraw(RESTORE, &size);
216 } else {
217 size = 0;
218 initialOffset = fWriter.size();
reed@google.comffacd3c2012-08-30 15:31:23 +0000219 }
220
reed@android.comb4e22d62009-07-09 15:20:25 +0000221 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000222
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000223 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 return this->INHERITED::restore();
225}
226
227bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000228 // op + dx + dy
229 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
230 uint32_t initialOffset = this->addDraw(TRANSLATE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 addScalar(dx);
232 addScalar(dy);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000233 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 return this->INHERITED::translate(dx, dy);
235}
236
237bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000238 // op + sx + sy
239 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
240 uint32_t initialOffset = this->addDraw(SCALE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 addScalar(sx);
242 addScalar(sy);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000243 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 return this->INHERITED::scale(sx, sy);
245}
246
247bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000248 // op + degrees
249 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
250 uint32_t initialOffset = this->addDraw(ROTATE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000251 addScalar(degrees);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000252 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 return this->INHERITED::rotate(degrees);
254}
255
256bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000257 // op + sx + sy
258 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
259 uint32_t initialOffset = this->addDraw(SKEW, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260 addScalar(sx);
261 addScalar(sy);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000262 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 return this->INHERITED::skew(sx, sy);
264}
265
266bool SkPictureRecord::concat(const SkMatrix& matrix) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000267 validate(fWriter.size(), 0);
268 // op + matrix index
269 uint32_t size = 2 * kUInt32Size;
270 uint32_t initialOffset = this->addDraw(CONCAT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 addMatrix(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000272 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273 return this->INHERITED::concat(matrix);
274}
275
reed@android.com6e073b92009-01-06 15:03:30 +0000276void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000277 validate(fWriter.size(), 0);
278 // op + matrix index
279 uint32_t size = 2 * kUInt32Size;
280 uint32_t initialOffset = this->addDraw(SET_MATRIX, &size);
reed@android.com6e073b92009-01-06 15:03:30 +0000281 addMatrix(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000282 validate(initialOffset, size);
reed@android.com6e073b92009-01-06 15:03:30 +0000283 this->INHERITED::setMatrix(matrix);
284}
285
reed@google.com45482d12011-08-29 19:02:39 +0000286static bool regionOpExpands(SkRegion::Op op) {
287 switch (op) {
288 case SkRegion::kUnion_Op:
289 case SkRegion::kXOR_Op:
290 case SkRegion::kReverseDifference_Op:
291 case SkRegion::kReplace_Op:
292 return true;
293 case SkRegion::kIntersect_Op:
294 case SkRegion::kDifference_Op:
295 return false;
296 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000297 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000298 return false;
299 }
300}
301
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000302void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(
303 uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000304 int32_t offset = fRestoreOffsetStack.top();
305 while (offset > 0) {
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000306 uint32_t* peek = fWriter.peek32(offset);
307 offset = *peek;
308 *peek = restoreOffset;
309 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000310
reed@google.comffacd3c2012-08-30 15:31:23 +0000311#ifdef SK_DEBUG
312 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000313 uint32_t opSize;
314 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000315 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
316#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000317}
318
reed@google.comd86e7ab2012-09-27 20:31:31 +0000319void SkPictureRecord::beginRecording() {
320 // we have to call this *after* our constructor, to ensure that it gets
321 // recorded. This is balanced by restoreToCount() call from endRecording,
322 // which in-turn calls our overridden restore(), so those get recorded too.
323 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
324}
325
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000326void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000327 SkASSERT(kNoInitialSave != fInitialSaveCount);
328 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000329}
330
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000331void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000332 if (fRestoreOffsetStack.isEmpty()) {
333 return;
334 }
335
reed@google.com45482d12011-08-29 19:02:39 +0000336 if (regionOpExpands(op)) {
337 // Run back through any previous clip ops, and mark their offset to
338 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
339 // they could hide this clips ability to expand the clip (i.e. go from
340 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000341 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
reed@google.com45482d12011-08-29 19:02:39 +0000342 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000343
reed@google.com45482d12011-08-29 19:02:39 +0000344 size_t offset = fWriter.size();
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000345 // The RestoreOffset field is initially filled with a placeholder
346 // value that points to the offset of the previous RestoreOffset
347 // in the current stack level, thus forming a linked list so that
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000348 // the restore offsets can be filled in when the corresponding
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000349 // restore command is recorded.
reed@google.com45482d12011-08-29 19:02:39 +0000350 addInt(fRestoreOffsetStack.top());
351 fRestoreOffsetStack.top() = offset;
352}
353
reed@google.com071eef92011-10-12 11:52:53 +0000354bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000355 // id + rect + clip params + restore offset
356 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 2 * kUInt32Size;
357 uint32_t initialOffset = this->addDraw(CLIP_RECT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000359 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000360 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000361
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000362 validate(initialOffset, size);
reed@google.com071eef92011-10-12 11:52:53 +0000363 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364}
365
reed@google.com4ed0fb72012-12-12 20:48:18 +0000366bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
367 if (rrect.isRect()) {
368 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
369 }
370
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000371 // op + rrect + clip params + restore offset
372 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 2 * kUInt32Size;
373 uint32_t initialOffset = this->addDraw(CLIP_RRECT, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000374 addRRect(rrect);
375 addInt(ClipParams_pack(op, doAA));
376 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000377
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000378 validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000379
380 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
381 return this->INHERITED::clipRect(rrect.getBounds(), op, doAA);
382 } else {
383 return this->INHERITED::clipRRect(rrect, op, doAA);
384 }
385}
386
reed@google.com071eef92011-10-12 11:52:53 +0000387bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000388
389 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000390 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000391 return this->clipRect(r, op, doAA);
392 }
393
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000394 // op + path index + clip params + restore offset
395 uint32_t size = 4 * kUInt32Size;
396 uint32_t initialOffset = this->addDraw(CLIP_PATH, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000397 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000398 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000399 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000400
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000401 validate(initialOffset, size);
reed@google.com82065d62011-02-07 15:30:46 +0000402
reed@android.comae814c82009-02-13 14:56:09 +0000403 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
reed@google.com071eef92011-10-12 11:52:53 +0000404 return this->INHERITED::clipRect(path.getBounds(), op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000405 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000406 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000407 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000408}
409
410bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000411 // op + region index + clip params + restore offset
412 uint32_t size = 4 * kUInt32Size;
413 uint32_t initialOffset = this->addDraw(CLIP_REGION, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000414 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000415 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000416 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000417
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000418 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000419 return this->INHERITED::clipRegion(region, op);
420}
421
reed@google.com2a981812011-04-14 18:59:28 +0000422void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000423 // op + color
424 uint32_t size = 2 * kUInt32Size;
425 uint32_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
reed@google.com2a981812011-04-14 18:59:28 +0000426 addInt(color);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000427 validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000428}
429
reed@android.com8a1c16f2008-12-17 15:59:43 +0000430void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000431 // op + paint index
432 uint32_t size = 2 * kUInt32Size;
433 uint32_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434 addPaint(paint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000435 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000436}
437
438void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000439 const SkPaint& paint) {
440 // op + paint index + mode + count + point data
441 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
442 uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443 addPaint(paint);
444 addInt(mode);
445 addInt(count);
446 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000447 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000448}
449
reed@google.com4ed0fb72012-12-12 20:48:18 +0000450void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000451 // op + paint index + rect
452 uint32_t size = 2 * kUInt32Size + sizeof(oval);
453 uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000454 addPaint(paint);
455 addRect(oval);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000456 validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000457}
458
reed@android.com8a1c16f2008-12-17 15:59:43 +0000459void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000460 // op + paint index + rect
461 uint32_t size = 2 * kUInt32Size + sizeof(rect);
462 uint32_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000463 addPaint(paint);
464 addRect(rect);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000465 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466}
467
reed@google.com4ed0fb72012-12-12 20:48:18 +0000468void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000469 uint32_t initialOffset, size;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000470 if (rrect.isRect()) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000471 // op + paint index + rect
472 size = 2 * kUInt32Size + sizeof(SkRect);
473 initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000474 addPaint(paint);
475 addRect(rrect.getBounds());
476 } else if (rrect.isOval()) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000477 // op + paint index + rect
478 size = 2 * kUInt32Size + sizeof(SkRect);
479 initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000480 addPaint(paint);
481 addRect(rrect.getBounds());
482 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000483 // op + paint index + rrect
484 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
485 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000486 addPaint(paint);
487 addRRect(rrect);
488 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000489 validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000490}
491
reed@android.com8a1c16f2008-12-17 15:59:43 +0000492void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000493 // op + paint index + path index
494 uint32_t size = 3 * kUInt32Size;
495 uint32_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000496 addPaint(paint);
497 addPath(path);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000498 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000499}
500
501void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
502 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000503 // op + paint index + bitmap index + left + top
504 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
505 uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506 addPaintPtr(paint);
507 addBitmap(bitmap);
508 addScalar(left);
509 addScalar(top);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000510 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000511}
512
reed@google.com71121732012-09-18 15:14:33 +0000513void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000515 // id + paint index + bitmap index + bool for 'src'
516 uint32_t size = 4 * kUInt32Size;
517 if (NULL != src) {
518 size += sizeof(*src); // + rect
519 }
520 size += sizeof(dst); // + rect
521
522 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523 addPaintPtr(paint);
524 addBitmap(bitmap);
reed@google.com71121732012-09-18 15:14:33 +0000525 addRectPtr(src); // may be null
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526 addRect(dst);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000527 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528}
529
530void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000531 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000532 // id + paint index + bitmap index + matrix index
533 uint32_t size = 4 * kUInt32Size;
534 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000535 addPaintPtr(paint);
536 addBitmap(bitmap);
537 addMatrix(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000538 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000539}
540
reed@google.comf0b5e112011-09-07 11:57:34 +0000541void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
542 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000543 // op + paint index + bitmap id + center + dst rect
544 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
545 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000546 addPaintPtr(paint);
547 addBitmap(bitmap);
548 addIRect(center);
549 addRect(dst);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000550 validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000551}
552
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
554 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000555 // op + paint index + bitmap index + left + top
556 uint32_t size = 5 * kUInt32Size;
557 uint32_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000558 addPaintPtr(paint);
559 addBitmap(bitmap);
560 addInt(left);
561 addInt(top);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000562 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563}
564
reed@google.com45954262012-12-07 17:14:40 +0000565// Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been
566// tweaked by paint.computeFastBounds().
567//
568static void computeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000569 SkPaint::FontMetrics metrics;
570 paint.getFontMetrics(&metrics);
571 SkRect bounds;
572 // construct a rect so we can see any adjustments from the paint.
573 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +0000574 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +0000576 topbot[0] = bounds.fTop;
577 topbot[1] = bounds.fBottom;
578}
579
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000580void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +0000581 SkScalar minY, SkScalar maxY) {
junov@chromium.org3f5ecd62013-01-22 18:01:26 +0000582 if (!flat.isTopBotWritten()) {
583 computeFontMetricsTopBottom(paint, flat.writableTopBot());
584 SkASSERT(flat.isTopBotWritten());
reed@google.com45954262012-12-07 17:14:40 +0000585 }
junov@chromium.org3f5ecd62013-01-22 18:01:26 +0000586 addScalar(flat.topBot()[0] + minY);
587 addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588}
589
reed@google.com82065d62011-02-07 15:30:46 +0000590void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000591 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +0000592 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +0000593
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000594 // op + paint index + length + 'length' worth of chars + x + y
595 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
596 if (fast) {
597 size += 2 * sizeof(SkScalar); // + top & bottom
598 }
599
600 uint32_t initialOffset = this->addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT, &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000601 const SkFlatData* flatPaintData = addPaint(paint);
602 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603 addText(text, byteLength);
604 addScalar(x);
605 addScalar(y);
606 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000607 addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000608 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000609 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000610}
611
reed@google.com82065d62011-02-07 15:30:46 +0000612void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000613 const SkPoint pos[], const SkPaint& paint) {
614 size_t points = paint.countText(text, byteLength);
615 if (0 == points)
616 return;
617
618 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +0000619 SkScalar minY = pos[0].fY;
620 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000621 // check if the caller really should have used drawPosTextH()
622 {
623 const SkScalar firstY = pos[0].fY;
624 for (size_t index = 1; index < points; index++) {
625 if (pos[index].fY != firstY) {
626 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +0000627 if (pos[index].fY < minY) {
628 minY = pos[index].fY;
629 } else if (pos[index].fY > maxY) {
630 maxY = pos[index].fY;
631 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000632 }
633 }
634 }
reed@google.com82065d62011-02-07 15:30:46 +0000635
reed@google.com2eb5bb12012-04-12 14:27:42 +0000636 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +0000637 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000639 // op + paint index + length + 'length' worth of data + num points
640 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
641 if (canUseDrawH) {
642 if (fast) {
643 size += 2 * sizeof(SkScalar); // + top & bottom
644 }
645 // + y-pos + actual x-point data
646 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000648 // + x&y point data
649 size += points * sizeof(SkPoint);
650 if (fastBounds) {
651 size += 2 * sizeof(SkScalar); // + top & bottom
652 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000654
655 DrawType op;
656 if (fast) {
657 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
658 } else if (canUseDrawH) {
659 op = DRAW_POS_TEXT_H;
660 } else if (fastBounds) {
661 op = DRAW_POS_TEXT_TOP_BOTTOM;
662 } else {
663 op = DRAW_POS_TEXT;
664 }
665 uint32_t initialOffset = this->addDraw(op, &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000666 const SkFlatData* flatPaintData = addPaint(paint);
667 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668 addText(text, byteLength);
669 addInt(points);
670
671#ifdef SK_DEBUG_SIZE
672 size_t start = fWriter.size();
673#endif
674 if (canUseDrawH) {
675 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000676 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677 }
678 addScalar(pos[0].fY);
679 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +0000680 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000682 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000683 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +0000684 if (fastBounds) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000685 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +0000686 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687 }
688#ifdef SK_DEBUG_SIZE
689 fPointBytes += fWriter.size() - start;
690 fPointWrites += points;
691#endif
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000692 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693}
694
695void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
696 const SkScalar xpos[], SkScalar constY,
697 const SkPaint& paint) {
698 size_t points = paint.countText(text, byteLength);
699 if (0 == points)
700 return;
reed@google.com82065d62011-02-07 15:30:46 +0000701
reed@google.com2eb5bb12012-04-12 14:27:42 +0000702 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000703
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000704 // op + paint index + length + 'length' worth of data + num points
705 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
706 if (fast) {
707 size += 2 * sizeof(SkScalar); // + top & bottom
708 }
709 // + y + the actual points
710 size += 1 * kUInt32Size + points * sizeof(SkScalar);
711
712 uint32_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
713 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000714 const SkFlatData* flatPaintData = addPaint(paint);
715 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000716 addText(text, byteLength);
717 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +0000718
reed@android.com8a1c16f2008-12-17 15:59:43 +0000719#ifdef SK_DEBUG_SIZE
720 size_t start = fWriter.size();
721#endif
722 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000723 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000724 }
725 addScalar(constY);
726 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
727#ifdef SK_DEBUG_SIZE
728 fPointBytes += fWriter.size() - start;
729 fPointWrites += points;
730#endif
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000731 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732}
733
reed@google.com82065d62011-02-07 15:30:46 +0000734void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
735 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000736 const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000737 // op + paint index + length + 'length' worth of data + path index + matrix index
738 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size;
739 uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740 addPaint(paint);
741 addText(text, byteLength);
742 addPath(path);
743 addMatrixPtr(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000744 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000745}
746
747void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000748 // op + picture index
749 uint32_t size = 2 * kUInt32Size;
750 uint32_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000751 addPicture(picture);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000752 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753}
754
755void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
756 const SkPoint vertices[], const SkPoint texs[],
757 const SkColor colors[], SkXfermode*,
758 const uint16_t indices[], int indexCount,
759 const SkPaint& paint) {
760 uint32_t flags = 0;
761 if (texs) {
762 flags |= DRAW_VERTICES_HAS_TEXS;
763 }
764 if (colors) {
765 flags |= DRAW_VERTICES_HAS_COLORS;
766 }
767 if (indexCount > 0) {
768 flags |= DRAW_VERTICES_HAS_INDICES;
769 }
770
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000771 // op + paint index + flags + vmode + vCount + vertices
772 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
773 if (flags & DRAW_VERTICES_HAS_TEXS) {
774 size += vertexCount * sizeof(SkPoint); // + uvs
775 }
776 if (flags & DRAW_VERTICES_HAS_COLORS) {
777 size += vertexCount * sizeof(SkColor); // + vert colors
778 }
779 if (flags & DRAW_VERTICES_HAS_INDICES) {
780 // + num indices + indices
781 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
782 }
783
784 uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000785 addPaint(paint);
786 addInt(flags);
787 addInt(vmode);
788 addInt(vertexCount);
789 addPoints(vertices, vertexCount);
790 if (flags & DRAW_VERTICES_HAS_TEXS) {
791 addPoints(texs, vertexCount);
792 }
793 if (flags & DRAW_VERTICES_HAS_COLORS) {
794 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
795 }
796 if (flags & DRAW_VERTICES_HAS_INDICES) {
797 addInt(indexCount);
798 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
799 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000800 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801}
802
reed@android.comcb608442009-12-04 21:32:27 +0000803void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000804 // op + length + 'length' worth of data
805 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
806 uint32_t initialOffset = this->addDraw(DRAW_DATA, &size);
reed@android.comcb608442009-12-04 21:32:27 +0000807 addInt(length);
808 fWriter.writePad(data, length);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000809 validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +0000810}
811
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000813
reed@android.com8a1c16f2008-12-17 15:59:43 +0000814void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +0000815 const int index = fBitmapHeap->insert(bitmap);
816 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
817 // release builds, the invalid value will be recorded so that the reader will know that there
818 // was a problem.
819 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
820 addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821}
822
823void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
824 addMatrixPtr(&matrix);
825}
826
827void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
reed@google.com83ca3372012-07-12 15:27:54 +0000828 this->addInt(matrix ? fMatrices.find(*matrix) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000829}
830
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000831const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
832 const SkFlatData* data = paint ? fPaints.findAndReturnFlat(*paint) : NULL;
833 int index = data ? data->index() : 0;
reed@google.com45954262012-12-07 17:14:40 +0000834 this->addInt(index);
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000835 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836}
837
838void SkPictureRecord::addPath(const SkPath& path) {
839 if (NULL == fPathHeap) {
840 fPathHeap = SkNEW(SkPathHeap);
841 }
842 addInt(fPathHeap->append(path));
843}
844
845void SkPictureRecord::addPicture(SkPicture& picture) {
846 int index = fPictureRefs.find(&picture);
847 if (index < 0) { // not found
848 index = fPictureRefs.count();
849 *fPictureRefs.append() = &picture;
850 picture.ref();
851 }
852 // follow the convention of recording a 1-based index
853 addInt(index + 1);
854}
855
856void SkPictureRecord::addPoint(const SkPoint& point) {
857#ifdef SK_DEBUG_SIZE
858 size_t start = fWriter.size();
859#endif
860 fWriter.writePoint(point);
861#ifdef SK_DEBUG_SIZE
862 fPointBytes += fWriter.size() - start;
863 fPointWrites++;
864#endif
865}
reed@google.com82065d62011-02-07 15:30:46 +0000866
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
868 fWriter.writeMul4(pts, count * sizeof(SkPoint));
869#ifdef SK_DEBUG_SIZE
870 fPointBytes += count * sizeof(SkPoint);
871 fPointWrites++;
872#endif
873}
874
875void SkPictureRecord::addRect(const SkRect& rect) {
876#ifdef SK_DEBUG_SIZE
877 size_t start = fWriter.size();
878#endif
879 fWriter.writeRect(rect);
880#ifdef SK_DEBUG_SIZE
881 fRectBytes += fWriter.size() - start;
882 fRectWrites++;
883#endif
884}
885
886void SkPictureRecord::addRectPtr(const SkRect* rect) {
887 if (fWriter.writeBool(rect != NULL)) {
888 fWriter.writeRect(*rect);
889 }
890}
891
reed@google.comf0b5e112011-09-07 11:57:34 +0000892void SkPictureRecord::addIRect(const SkIRect& rect) {
893 fWriter.write(&rect, sizeof(rect));
894}
895
reed@android.com8a1c16f2008-12-17 15:59:43 +0000896void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
897 if (fWriter.writeBool(rect != NULL)) {
898 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
899 }
900}
901
reed@google.com4ed0fb72012-12-12 20:48:18 +0000902void SkPictureRecord::addRRect(const SkRRect& rrect) {
903 fWriter.writeRRect(rrect);
904}
905
reed@android.com8a1c16f2008-12-17 15:59:43 +0000906void SkPictureRecord::addRegion(const SkRegion& region) {
reed@google.com83ca3372012-07-12 15:27:54 +0000907 addInt(fRegions.find(region));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000908}
909
910void SkPictureRecord::addText(const void* text, size_t byteLength) {
911#ifdef SK_DEBUG_SIZE
912 size_t start = fWriter.size();
913#endif
914 addInt(byteLength);
915 fWriter.writePad(text, byteLength);
916#ifdef SK_DEBUG_SIZE
917 fTextBytes += fWriter.size() - start;
918 fTextWrites++;
919#endif
920}
921
922///////////////////////////////////////////////////////////////////////////////
923
reed@android.com8a1c16f2008-12-17 15:59:43 +0000924#ifdef SK_DEBUG_SIZE
925size_t SkPictureRecord::size() const {
926 size_t result = 0;
927 size_t sizeData;
928 bitmaps(&sizeData);
929 result += sizeData;
930 matrices(&sizeData);
931 result += sizeData;
932 paints(&sizeData);
933 result += sizeData;
934 paths(&sizeData);
935 result += sizeData;
936 pictures(&sizeData);
937 result += sizeData;
938 regions(&sizeData);
939 result += sizeData;
940 result += streamlen();
941 return result;
942}
943
944int SkPictureRecord::bitmaps(size_t* size) const {
945 size_t result = 0;
946 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +0000947 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000948 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
949 *size = result;
950 return count;
951}
952
953int SkPictureRecord::matrices(size_t* size) const {
954 int count = fMatrices.count();
955 *size = sizeof(fMatrices[0]) * count;
956 return count;
957}
958
959int SkPictureRecord::paints(size_t* size) const {
960 size_t result = 0;
961 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +0000962 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000963 result += sizeof(fPaints[index]) + fPaints[index]->size();
964 *size = result;
965 return count;
966}
967
968int SkPictureRecord::paths(size_t* size) const {
969 size_t result = 0;
970 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +0000971 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000972 result += sizeof(fPaths[index]) + fPaths[index]->size();
973 *size = result;
974 return count;
975}
976
977int SkPictureRecord::regions(size_t* size) const {
978 size_t result = 0;
979 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +0000980 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981 result += sizeof(fRegions[index]) + fRegions[index]->size();
982 *size = result;
983 return count;
984}
985
986size_t SkPictureRecord::streamlen() const {
987 return fWriter.size();
988}
989#endif
990
991#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000992void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
993 SkASSERT(fWriter.size() == initialOffset + size);
994
reed@android.com8a1c16f2008-12-17 15:59:43 +0000995 validateBitmaps();
996 validateMatrices();
997 validatePaints();
998 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000999 validateRegions();
1000}
1001
1002void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001003 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001004 SkASSERT((unsigned) count < 0x1000);
1005 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001006 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001007 SkASSERT(bitPtr);
1008 bitPtr->validate();
1009 }
1010}
1011
1012void SkPictureRecord::validateMatrices() const {
1013 int count = fMatrices.count();
1014 SkASSERT((unsigned) count < 0x1000);
1015 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001016 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001017 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001018// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001019 }
1020}
1021
1022void SkPictureRecord::validatePaints() const {
1023 int count = fPaints.count();
1024 SkASSERT((unsigned) count < 0x1000);
1025 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001026 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001027 SkASSERT(paint);
1028// paint->validate();
1029 }
1030}
1031
1032void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001033 if (NULL == fPathHeap) {
1034 return;
1035 }
1036
1037 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001038 SkASSERT((unsigned) count < 0x1000);
1039 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001040 const SkPath& path = (*fPathHeap)[index];
1041 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001042 }
1043}
1044
1045void SkPictureRecord::validateRegions() const {
1046 int count = fRegions.count();
1047 SkASSERT((unsigned) count < 0x1000);
1048 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001049 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001050 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001051// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001052 }
1053}
1054#endif