blob: 5180e5ed6cb2ab008ce527c8facb4733668e0e87 [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.comf9291502013-02-15 15:13:27 +0000355 // id + rect + clip params
356 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
357 if (!fRestoreOffsetStack.isEmpty()) {
358 // + restore offset
359 size += kUInt32Size;
360 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000361 uint32_t initialOffset = this->addDraw(CLIP_RECT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000363 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000364 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000365
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000366 validate(initialOffset, size);
reed@google.com071eef92011-10-12 11:52:53 +0000367 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368}
369
reed@google.com4ed0fb72012-12-12 20:48:18 +0000370bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
371 if (rrect.isRect()) {
372 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
373 }
374
robertphillips@google.comf9291502013-02-15 15:13:27 +0000375 // op + rrect + clip params
376 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
377 if (!fRestoreOffsetStack.isEmpty()) {
378 // + restore offset
379 size += kUInt32Size;
380 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000381 uint32_t initialOffset = this->addDraw(CLIP_RRECT, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000382 addRRect(rrect);
383 addInt(ClipParams_pack(op, doAA));
384 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000385
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000386 validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000387
388 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
389 return this->INHERITED::clipRect(rrect.getBounds(), op, doAA);
390 } else {
391 return this->INHERITED::clipRRect(rrect, op, doAA);
392 }
393}
394
reed@google.com071eef92011-10-12 11:52:53 +0000395bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000396
397 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000398 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000399 return this->clipRect(r, op, doAA);
400 }
401
robertphillips@google.comf9291502013-02-15 15:13:27 +0000402 // op + path index + clip params
403 uint32_t size = 3 * kUInt32Size;
404 if (!fRestoreOffsetStack.isEmpty()) {
405 // + restore offset
406 size += kUInt32Size;
407 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000408 uint32_t initialOffset = this->addDraw(CLIP_PATH, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000410 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000411 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000412
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000413 validate(initialOffset, size);
reed@google.com82065d62011-02-07 15:30:46 +0000414
reed@android.comae814c82009-02-13 14:56:09 +0000415 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
reed@google.com071eef92011-10-12 11:52:53 +0000416 return this->INHERITED::clipRect(path.getBounds(), op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000417 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000418 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000419 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000420}
421
422bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000423 // op + region index + clip params
424 uint32_t size = 3 * kUInt32Size;
425 if (!fRestoreOffsetStack.isEmpty()) {
426 // + restore offset
427 size += kUInt32Size;
428 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000429 uint32_t initialOffset = this->addDraw(CLIP_REGION, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000430 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000431 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000432 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000433
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000434 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435 return this->INHERITED::clipRegion(region, op);
436}
437
reed@google.com2a981812011-04-14 18:59:28 +0000438void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000439 // op + color
440 uint32_t size = 2 * kUInt32Size;
441 uint32_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
reed@google.com2a981812011-04-14 18:59:28 +0000442 addInt(color);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000443 validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000444}
445
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000447 // op + paint index
448 uint32_t size = 2 * kUInt32Size;
449 uint32_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000450 addPaint(paint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000451 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452}
453
454void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000455 const SkPaint& paint) {
456 // op + paint index + mode + count + point data
457 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
458 uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000459 addPaint(paint);
460 addInt(mode);
461 addInt(count);
462 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000463 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000464}
465
reed@google.com4ed0fb72012-12-12 20:48:18 +0000466void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000467 // op + paint index + rect
468 uint32_t size = 2 * kUInt32Size + sizeof(oval);
469 uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000470 addPaint(paint);
471 addRect(oval);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000472 validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000473}
474
reed@android.com8a1c16f2008-12-17 15:59:43 +0000475void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000476 // op + paint index + rect
477 uint32_t size = 2 * kUInt32Size + sizeof(rect);
478 uint32_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000479 addPaint(paint);
480 addRect(rect);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000481 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000482}
483
reed@google.com4ed0fb72012-12-12 20:48:18 +0000484void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000485 uint32_t initialOffset, size;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000486 if (rrect.isRect()) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000487 // op + paint index + rect
488 size = 2 * kUInt32Size + sizeof(SkRect);
489 initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000490 addPaint(paint);
491 addRect(rrect.getBounds());
492 } else if (rrect.isOval()) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000493 // op + paint index + rect
494 size = 2 * kUInt32Size + sizeof(SkRect);
495 initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000496 addPaint(paint);
497 addRect(rrect.getBounds());
498 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000499 // op + paint index + rrect
500 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
501 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000502 addPaint(paint);
503 addRRect(rrect);
504 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000505 validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000506}
507
reed@android.com8a1c16f2008-12-17 15:59:43 +0000508void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000509 // op + paint index + path index
510 uint32_t size = 3 * kUInt32Size;
511 uint32_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000512 addPaint(paint);
513 addPath(path);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000514 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000515}
516
517void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
518 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000519 // op + paint index + bitmap index + left + top
520 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
521 uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000522 addPaintPtr(paint);
523 addBitmap(bitmap);
524 addScalar(left);
525 addScalar(top);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000526 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000527}
528
reed@google.com71121732012-09-18 15:14:33 +0000529void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000531 // id + paint index + bitmap index + bool for 'src'
532 uint32_t size = 4 * kUInt32Size;
533 if (NULL != src) {
534 size += sizeof(*src); // + rect
535 }
536 size += sizeof(dst); // + rect
537
538 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000539 addPaintPtr(paint);
540 addBitmap(bitmap);
reed@google.com71121732012-09-18 15:14:33 +0000541 addRectPtr(src); // may be null
reed@android.com8a1c16f2008-12-17 15:59:43 +0000542 addRect(dst);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000543 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544}
545
546void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000547 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000548 // id + paint index + bitmap index + matrix index
549 uint32_t size = 4 * kUInt32Size;
550 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000551 addPaintPtr(paint);
552 addBitmap(bitmap);
553 addMatrix(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000554 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555}
556
reed@google.comf0b5e112011-09-07 11:57:34 +0000557void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
558 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000559 // op + paint index + bitmap id + center + dst rect
560 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
561 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000562 addPaintPtr(paint);
563 addBitmap(bitmap);
564 addIRect(center);
565 addRect(dst);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000566 validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000567}
568
reed@android.com8a1c16f2008-12-17 15:59:43 +0000569void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
570 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000571 // op + paint index + bitmap index + left + top
572 uint32_t size = 5 * kUInt32Size;
573 uint32_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574 addPaintPtr(paint);
575 addBitmap(bitmap);
576 addInt(left);
577 addInt(top);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000578 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000579}
580
reed@google.com45954262012-12-07 17:14:40 +0000581// Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been
582// tweaked by paint.computeFastBounds().
583//
584static void computeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000585 SkPaint::FontMetrics metrics;
586 paint.getFontMetrics(&metrics);
587 SkRect bounds;
588 // construct a rect so we can see any adjustments from the paint.
589 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +0000590 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000591 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +0000592 topbot[0] = bounds.fTop;
593 topbot[1] = bounds.fBottom;
594}
595
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000596void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +0000597 SkScalar minY, SkScalar maxY) {
junov@chromium.org3f5ecd62013-01-22 18:01:26 +0000598 if (!flat.isTopBotWritten()) {
599 computeFontMetricsTopBottom(paint, flat.writableTopBot());
600 SkASSERT(flat.isTopBotWritten());
reed@google.com45954262012-12-07 17:14:40 +0000601 }
junov@chromium.org3f5ecd62013-01-22 18:01:26 +0000602 addScalar(flat.topBot()[0] + minY);
603 addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000604}
605
reed@google.com82065d62011-02-07 15:30:46 +0000606void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000607 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +0000608 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +0000609
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000610 // op + paint index + length + 'length' worth of chars + x + y
611 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
612 if (fast) {
613 size += 2 * sizeof(SkScalar); // + top & bottom
614 }
615
616 uint32_t initialOffset = this->addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT, &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000617 const SkFlatData* flatPaintData = addPaint(paint);
618 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619 addText(text, byteLength);
620 addScalar(x);
621 addScalar(y);
622 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000623 addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000624 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000625 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000626}
627
reed@google.com82065d62011-02-07 15:30:46 +0000628void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000629 const SkPoint pos[], const SkPaint& paint) {
630 size_t points = paint.countText(text, byteLength);
631 if (0 == points)
632 return;
633
634 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +0000635 SkScalar minY = pos[0].fY;
636 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637 // check if the caller really should have used drawPosTextH()
638 {
639 const SkScalar firstY = pos[0].fY;
640 for (size_t index = 1; index < points; index++) {
641 if (pos[index].fY != firstY) {
642 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +0000643 if (pos[index].fY < minY) {
644 minY = pos[index].fY;
645 } else if (pos[index].fY > maxY) {
646 maxY = pos[index].fY;
647 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648 }
649 }
650 }
reed@google.com82065d62011-02-07 15:30:46 +0000651
reed@google.com2eb5bb12012-04-12 14:27:42 +0000652 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +0000653 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000655 // op + paint index + length + 'length' worth of data + num points
656 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
657 if (canUseDrawH) {
658 if (fast) {
659 size += 2 * sizeof(SkScalar); // + top & bottom
660 }
661 // + y-pos + actual x-point data
662 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000664 // + x&y point data
665 size += points * sizeof(SkPoint);
666 if (fastBounds) {
667 size += 2 * sizeof(SkScalar); // + top & bottom
668 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000669 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000670
671 DrawType op;
672 if (fast) {
673 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
674 } else if (canUseDrawH) {
675 op = DRAW_POS_TEXT_H;
676 } else if (fastBounds) {
677 op = DRAW_POS_TEXT_TOP_BOTTOM;
678 } else {
679 op = DRAW_POS_TEXT;
680 }
681 uint32_t initialOffset = this->addDraw(op, &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000682 const SkFlatData* flatPaintData = addPaint(paint);
683 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684 addText(text, byteLength);
685 addInt(points);
686
687#ifdef SK_DEBUG_SIZE
688 size_t start = fWriter.size();
689#endif
690 if (canUseDrawH) {
691 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000692 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693 }
694 addScalar(pos[0].fY);
695 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +0000696 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000698 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +0000700 if (fastBounds) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000701 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +0000702 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000703 }
704#ifdef SK_DEBUG_SIZE
705 fPointBytes += fWriter.size() - start;
706 fPointWrites += points;
707#endif
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000708 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000709}
710
711void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
712 const SkScalar xpos[], SkScalar constY,
713 const SkPaint& paint) {
714 size_t points = paint.countText(text, byteLength);
715 if (0 == points)
716 return;
reed@google.com82065d62011-02-07 15:30:46 +0000717
reed@google.com2eb5bb12012-04-12 14:27:42 +0000718 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000719
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000720 // op + paint index + length + 'length' worth of data + num points
721 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
722 if (fast) {
723 size += 2 * sizeof(SkScalar); // + top & bottom
724 }
725 // + y + the actual points
726 size += 1 * kUInt32Size + points * sizeof(SkScalar);
727
728 uint32_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
729 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000730 const SkFlatData* flatPaintData = addPaint(paint);
731 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732 addText(text, byteLength);
733 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +0000734
reed@android.com8a1c16f2008-12-17 15:59:43 +0000735#ifdef SK_DEBUG_SIZE
736 size_t start = fWriter.size();
737#endif
738 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000739 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740 }
741 addScalar(constY);
742 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
743#ifdef SK_DEBUG_SIZE
744 fPointBytes += fWriter.size() - start;
745 fPointWrites += points;
746#endif
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000747 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000748}
749
reed@google.com82065d62011-02-07 15:30:46 +0000750void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
751 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000752 const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000753 // op + paint index + length + 'length' worth of data + path index + matrix index
754 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size;
755 uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000756 addPaint(paint);
757 addText(text, byteLength);
758 addPath(path);
759 addMatrixPtr(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000760 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761}
762
763void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000764 // op + picture index
765 uint32_t size = 2 * kUInt32Size;
766 uint32_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000767 addPicture(picture);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000768 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769}
770
771void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
772 const SkPoint vertices[], const SkPoint texs[],
773 const SkColor colors[], SkXfermode*,
774 const uint16_t indices[], int indexCount,
775 const SkPaint& paint) {
776 uint32_t flags = 0;
777 if (texs) {
778 flags |= DRAW_VERTICES_HAS_TEXS;
779 }
780 if (colors) {
781 flags |= DRAW_VERTICES_HAS_COLORS;
782 }
783 if (indexCount > 0) {
784 flags |= DRAW_VERTICES_HAS_INDICES;
785 }
786
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000787 // op + paint index + flags + vmode + vCount + vertices
788 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
789 if (flags & DRAW_VERTICES_HAS_TEXS) {
790 size += vertexCount * sizeof(SkPoint); // + uvs
791 }
792 if (flags & DRAW_VERTICES_HAS_COLORS) {
793 size += vertexCount * sizeof(SkColor); // + vert colors
794 }
795 if (flags & DRAW_VERTICES_HAS_INDICES) {
796 // + num indices + indices
797 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
798 }
799
800 uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801 addPaint(paint);
802 addInt(flags);
803 addInt(vmode);
804 addInt(vertexCount);
805 addPoints(vertices, vertexCount);
806 if (flags & DRAW_VERTICES_HAS_TEXS) {
807 addPoints(texs, vertexCount);
808 }
809 if (flags & DRAW_VERTICES_HAS_COLORS) {
810 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
811 }
812 if (flags & DRAW_VERTICES_HAS_INDICES) {
813 addInt(indexCount);
814 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
815 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000816 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817}
818
reed@android.comcb608442009-12-04 21:32:27 +0000819void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000820 // op + length + 'length' worth of data
821 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
822 uint32_t initialOffset = this->addDraw(DRAW_DATA, &size);
reed@android.comcb608442009-12-04 21:32:27 +0000823 addInt(length);
824 fWriter.writePad(data, length);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000825 validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +0000826}
827
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000829
reed@android.com8a1c16f2008-12-17 15:59:43 +0000830void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +0000831 const int index = fBitmapHeap->insert(bitmap);
832 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
833 // release builds, the invalid value will be recorded so that the reader will know that there
834 // was a problem.
835 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
836 addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000837}
838
839void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
840 addMatrixPtr(&matrix);
841}
842
843void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
reed@google.com83ca3372012-07-12 15:27:54 +0000844 this->addInt(matrix ? fMatrices.find(*matrix) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845}
846
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000847const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
848 const SkFlatData* data = paint ? fPaints.findAndReturnFlat(*paint) : NULL;
849 int index = data ? data->index() : 0;
reed@google.com45954262012-12-07 17:14:40 +0000850 this->addInt(index);
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000851 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000852}
853
854void SkPictureRecord::addPath(const SkPath& path) {
855 if (NULL == fPathHeap) {
856 fPathHeap = SkNEW(SkPathHeap);
857 }
858 addInt(fPathHeap->append(path));
859}
860
861void SkPictureRecord::addPicture(SkPicture& picture) {
862 int index = fPictureRefs.find(&picture);
863 if (index < 0) { // not found
864 index = fPictureRefs.count();
865 *fPictureRefs.append() = &picture;
866 picture.ref();
867 }
868 // follow the convention of recording a 1-based index
869 addInt(index + 1);
870}
871
872void SkPictureRecord::addPoint(const SkPoint& point) {
873#ifdef SK_DEBUG_SIZE
874 size_t start = fWriter.size();
875#endif
876 fWriter.writePoint(point);
877#ifdef SK_DEBUG_SIZE
878 fPointBytes += fWriter.size() - start;
879 fPointWrites++;
880#endif
881}
reed@google.com82065d62011-02-07 15:30:46 +0000882
reed@android.com8a1c16f2008-12-17 15:59:43 +0000883void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
884 fWriter.writeMul4(pts, count * sizeof(SkPoint));
885#ifdef SK_DEBUG_SIZE
886 fPointBytes += count * sizeof(SkPoint);
887 fPointWrites++;
888#endif
889}
890
891void SkPictureRecord::addRect(const SkRect& rect) {
892#ifdef SK_DEBUG_SIZE
893 size_t start = fWriter.size();
894#endif
895 fWriter.writeRect(rect);
896#ifdef SK_DEBUG_SIZE
897 fRectBytes += fWriter.size() - start;
898 fRectWrites++;
899#endif
900}
901
902void SkPictureRecord::addRectPtr(const SkRect* rect) {
903 if (fWriter.writeBool(rect != NULL)) {
904 fWriter.writeRect(*rect);
905 }
906}
907
reed@google.comf0b5e112011-09-07 11:57:34 +0000908void SkPictureRecord::addIRect(const SkIRect& rect) {
909 fWriter.write(&rect, sizeof(rect));
910}
911
reed@android.com8a1c16f2008-12-17 15:59:43 +0000912void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
913 if (fWriter.writeBool(rect != NULL)) {
914 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
915 }
916}
917
reed@google.com4ed0fb72012-12-12 20:48:18 +0000918void SkPictureRecord::addRRect(const SkRRect& rrect) {
919 fWriter.writeRRect(rrect);
920}
921
reed@android.com8a1c16f2008-12-17 15:59:43 +0000922void SkPictureRecord::addRegion(const SkRegion& region) {
reed@google.com83ca3372012-07-12 15:27:54 +0000923 addInt(fRegions.find(region));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000924}
925
926void SkPictureRecord::addText(const void* text, size_t byteLength) {
927#ifdef SK_DEBUG_SIZE
928 size_t start = fWriter.size();
929#endif
930 addInt(byteLength);
931 fWriter.writePad(text, byteLength);
932#ifdef SK_DEBUG_SIZE
933 fTextBytes += fWriter.size() - start;
934 fTextWrites++;
935#endif
936}
937
938///////////////////////////////////////////////////////////////////////////////
939
reed@android.com8a1c16f2008-12-17 15:59:43 +0000940#ifdef SK_DEBUG_SIZE
941size_t SkPictureRecord::size() const {
942 size_t result = 0;
943 size_t sizeData;
944 bitmaps(&sizeData);
945 result += sizeData;
946 matrices(&sizeData);
947 result += sizeData;
948 paints(&sizeData);
949 result += sizeData;
950 paths(&sizeData);
951 result += sizeData;
952 pictures(&sizeData);
953 result += sizeData;
954 regions(&sizeData);
955 result += sizeData;
956 result += streamlen();
957 return result;
958}
959
960int SkPictureRecord::bitmaps(size_t* size) const {
961 size_t result = 0;
962 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +0000963 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
965 *size = result;
966 return count;
967}
968
969int SkPictureRecord::matrices(size_t* size) const {
970 int count = fMatrices.count();
971 *size = sizeof(fMatrices[0]) * count;
972 return count;
973}
974
975int SkPictureRecord::paints(size_t* size) const {
976 size_t result = 0;
977 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +0000978 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979 result += sizeof(fPaints[index]) + fPaints[index]->size();
980 *size = result;
981 return count;
982}
983
984int SkPictureRecord::paths(size_t* size) const {
985 size_t result = 0;
986 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +0000987 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988 result += sizeof(fPaths[index]) + fPaths[index]->size();
989 *size = result;
990 return count;
991}
992
993int SkPictureRecord::regions(size_t* size) const {
994 size_t result = 0;
995 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +0000996 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000997 result += sizeof(fRegions[index]) + fRegions[index]->size();
998 *size = result;
999 return count;
1000}
1001
1002size_t SkPictureRecord::streamlen() const {
1003 return fWriter.size();
1004}
1005#endif
1006
1007#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001008void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1009 SkASSERT(fWriter.size() == initialOffset + size);
1010
reed@android.com8a1c16f2008-12-17 15:59:43 +00001011 validateBitmaps();
1012 validateMatrices();
1013 validatePaints();
1014 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001015 validateRegions();
1016}
1017
1018void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001019 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001020 SkASSERT((unsigned) count < 0x1000);
1021 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001022 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023 SkASSERT(bitPtr);
1024 bitPtr->validate();
1025 }
1026}
1027
1028void SkPictureRecord::validateMatrices() const {
1029 int count = fMatrices.count();
1030 SkASSERT((unsigned) count < 0x1000);
1031 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001032 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001033 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001034// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001035 }
1036}
1037
1038void SkPictureRecord::validatePaints() const {
1039 int count = fPaints.count();
1040 SkASSERT((unsigned) count < 0x1000);
1041 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001042 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001043 SkASSERT(paint);
1044// paint->validate();
1045 }
1046}
1047
1048void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001049 if (NULL == fPathHeap) {
1050 return;
1051 }
1052
1053 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054 SkASSERT((unsigned) count < 0x1000);
1055 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001056 const SkPath& path = (*fPathHeap)[index];
1057 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058 }
1059}
1060
1061void SkPictureRecord::validateRegions() const {
1062 int count = fRegions.count();
1063 SkASSERT((unsigned) count < 0x1000);
1064 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001065 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001066 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001067// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001068 }
1069}
1070#endif