blob: 60e51d1829cbf4eba4ca620c03bf78e96e47995b [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"
rileya@google.com9f5898d2012-09-11 20:21:44 +000011#include "SkBBoxHierarchy.h"
12#include "SkPictureStateTree.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013
14#define MIN_WRITER_SIZE 16384
15#define HEAP_BLOCK_SIZE 4096
16
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000017enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000018 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000019 kNoInitialSave = -1,
20};
21
reed@google.comd86e7ab2012-09-27 20:31:31 +000022SkPictureRecord::SkPictureRecord(uint32_t flags, SkDevice* device) :
23 INHERITED(device),
robertphillips@google.com178a2672012-09-13 13:25:30 +000024 fBoundingHierarchy(NULL),
25 fStateTree(NULL),
djsollen@google.com21830d92012-08-07 19:49:41 +000026 fFlattenableHeap(HEAP_BLOCK_SIZE),
27 fMatrices(&fFlattenableHeap),
28 fPaints(&fFlattenableHeap),
29 fRegions(&fFlattenableHeap),
djsollen@google.comd2700ee2012-05-30 16:54:13 +000030 fWriter(MIN_WRITER_SIZE),
31 fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000032#ifdef SK_DEBUG_SIZE
33 fPointBytes = fRectBytes = fTextBytes = 0;
34 fPointWrites = fRectWrites = fTextWrites = 0;
35#endif
36
37 fRestoreOffsetStack.setReserve(32);
reed@google.com82065d62011-02-07 15:30:46 +000038
djsollen@google.comc9ab9872012-08-29 18:52:07 +000039 fBitmapHeap = SkNEW(SkBitmapHeap);
40 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000041 fPathHeap = NULL; // lazy allocate
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000042 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@google.comd86e7ab2012-09-27 20:31:31 +000043
44 fInitialSaveCount = kNoInitialSave;
reed@android.com8a1c16f2008-12-17 15:59:43 +000045}
46
47SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000048 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000049 SkSafeUnref(fPathHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000050 SkSafeUnref(fBoundingHierarchy);
51 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000052 fFlattenableHeap.setBitmapStorage(NULL);
53 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000054}
55
56///////////////////////////////////////////////////////////////////////////////
57
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000058SkDevice* SkPictureRecord::setDevice(SkDevice* device) {
reed@google.comd86e7ab2012-09-27 20:31:31 +000059 SkASSERT(!"eeek, don't try to change the device on a recording canvas");
60 return this->INHERITED::setDevice(device);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000061}
62
reed@android.com8a1c16f2008-12-17 15:59:43 +000063int SkPictureRecord::save(SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +000064 // record the offset to us, making it non-positive to distinguish a save
65 // from a clip entry.
66 fRestoreOffsetStack.push(-(int32_t)fWriter.size());
skia.committer@gmail.com11f86922012-08-31 17:14:46 +000067
reed@android.com8a1c16f2008-12-17 15:59:43 +000068 addDraw(SAVE);
69 addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +000070
reed@android.com8a1c16f2008-12-17 15:59:43 +000071 validate();
72 return this->INHERITED::save(flags);
73}
74
75int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
76 SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +000077 // record the offset to us, making it non-positive to distinguish a save
78 // from a clip entry.
79 fRestoreOffsetStack.push(-(int32_t)fWriter.size());
skia.committer@gmail.com11f86922012-08-31 17:14:46 +000080
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 addDraw(SAVE_LAYER);
82 addRectPtr(bounds);
83 addPaintPtr(paint);
84 addInt(flags);
85
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000086 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
87 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
88 }
89
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 validate();
reed@android.com261ae4d2009-10-02 16:37:46 +000091 /* Don't actually call saveLayer, because that will try to allocate an
92 offscreen device (potentially very big) which we don't actually need
93 at this time (and may not be able to afford since during record our
94 clip starts out the size of the picture, which is often much larger
95 than the size of the actual device we'll use during playback).
96 */
junov@chromium.orga907ac32012-02-24 21:54:07 +000097 int count = this->INHERITED::save(flags);
98 this->clipRectBounds(bounds, flags, NULL);
99 return count;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100}
101
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000102bool SkPictureRecord::isDrawingToLayer() const {
103 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
104}
105
reed@google.comffacd3c2012-08-30 15:31:23 +0000106// Return the size of the specified drawType's recorded block, or 0 if this verb
107// is variable sized, and therefore not known.
108static inline uint32_t getSkipableSize(unsigned drawType) {
109 static const uint8_t gSizes[LAST_DRAWTYPE_ENUM + 1] = {
110 0, // UNUSED,
111 4, // CLIP_PATH,
112 4, // CLIP_REGION,
113 7, // CLIP_RECT,
114 2, // CONCAT,
115 0, // DRAW_BITMAP,
116 0, // DRAW_BITMAP_MATRIX,
117 0, // DRAW_BITMAP_NINE,
118 0, // DRAW_BITMAP_RECT,
119 0, // DRAW_CLEAR,
120 0, // DRAW_DATA,
121 0, // DRAW_PAINT,
122 0, // DRAW_PATH,
123 0, // DRAW_PICTURE,
124 0, // DRAW_POINTS,
125 0, // DRAW_POS_TEXT,
126 0, // DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
127 0, // DRAW_POS_TEXT_H,
128 0, // DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
129 0, // DRAW_RECT,
130 0, // DRAW_SPRITE,
131 0, // DRAW_TEXT,
132 0, // DRAW_TEXT_ON_PATH,
133 0, // DRAW_TEXT_TOP_BOTTOM, // fast variant of DRAW_TEXT
134 0, // DRAW_VERTICES,
135 0, // RESTORE,
136 2, // ROTATE,
137 2, // SAVE,
138 0, // SAVE_LAYER,
139 3, // SCALE,
140 2, // SET_MATRIX,
141 3, // SKEW,
142 3, // TRANSLATE,
143 };
144
145 SkASSERT(sizeof(gSizes) == LAST_DRAWTYPE_ENUM + 1);
146 SkASSERT((unsigned)drawType <= (unsigned)LAST_DRAWTYPE_ENUM);
147 return gSizes[drawType] * sizeof(uint32_t);
148}
149
150#ifdef TRACK_COLLAPSE_STATS
151 static int gCollapseCount, gCollapseCalls;
152#endif
153
154/*
155 * Restore has just been called (but not recoreded), so look back at the
156 * matching save(), and see if we can eliminate the pair of them, due to no
157 * intervening matrix/clip calls.
158 *
159 * If so, update the writer and return true, in which case we won't even record
160 * the restore() call. If we still need the restore(), return false.
161 */
162static bool collapseSaveClipRestore(SkWriter32* writer, int32_t offset) {
reed@google.com6132eb92012-09-14 19:07:28 +0000163 // Some unexplained crashes in Chrome may be caused by this. Disabling
164 // for now to see if it helps.
165 // crbug.com/147406
166#if 1
167 return false;
168#endif
169
reed@google.comffacd3c2012-08-30 15:31:23 +0000170#ifdef TRACK_COLLAPSE_STATS
171 gCollapseCalls += 1;
172#endif
173
174 int32_t restoreOffset = (int32_t)writer->size();
175
176 // back up to the save block
177 while (offset > 0) {
178 offset = *writer->peek32(offset);
179 }
180
181 // now offset points to a save
182 offset = -offset;
183 if (SAVE_LAYER == *writer->peek32(offset)) {
184 // not ready to cull these out yet (mrr)
185 return false;
186 }
187 SkASSERT(SAVE == *writer->peek32(offset));
188
189 // Walk forward until we get back to either a draw-verb (abort) or we hit
190 // our restore (success).
191 int32_t saveOffset = offset;
192
193 offset += getSkipableSize(SAVE);
194 while (offset < restoreOffset) {
195 uint32_t* block = writer->peek32(offset);
196 uint32_t op = *block;
197 uint32_t opSize = getSkipableSize(op);
198 if (0 == opSize) {
199 // drawing verb, abort
200 return false;
201 }
202 offset += opSize;
203 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000204
reed@google.comffacd3c2012-08-30 15:31:23 +0000205#ifdef TRACK_COLLAPSE_STATS
206 gCollapseCount += 1;
207 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
208 (double)gCollapseCount / gCollapseCalls, "%");
209#endif
210
211 writer->rewindToOffset(saveOffset);
212 return true;
213}
214
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000216 // FIXME: SkDeferredCanvas needs to be refactored to respect
217 // save/restore balancing so that the following test can be
218 // turned on permanently.
219#if 0
220 SkASSERT(fRestoreOffsetStack.count() > 1);
221#endif
222
reed@android.comb4e22d62009-07-09 15:20:25 +0000223 // check for underflow
224 if (fRestoreOffsetStack.count() == 0) {
225 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000227
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000228 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
229 fFirstSavedLayerIndex = kNoSavedLayerIndex;
230 }
231
reed@google.comffacd3c2012-08-30 15:31:23 +0000232 if (!collapseSaveClipRestore(&fWriter, fRestoreOffsetStack.top())) {
233 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size());
234 this->addDraw(RESTORE);
235 }
236
reed@android.comb4e22d62009-07-09 15:20:25 +0000237 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000238
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 validate();
240 return this->INHERITED::restore();
241}
242
243bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
244 addDraw(TRANSLATE);
245 addScalar(dx);
246 addScalar(dy);
247 validate();
248 return this->INHERITED::translate(dx, dy);
249}
250
251bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
reed@google.com82065d62011-02-07 15:30:46 +0000252 addDraw(SCALE);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 addScalar(sx);
254 addScalar(sy);
255 validate();
256 return this->INHERITED::scale(sx, sy);
257}
258
259bool SkPictureRecord::rotate(SkScalar degrees) {
reed@google.com82065d62011-02-07 15:30:46 +0000260 addDraw(ROTATE);
261 addScalar(degrees);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262 validate();
263 return this->INHERITED::rotate(degrees);
264}
265
266bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
reed@google.com82065d62011-02-07 15:30:46 +0000267 addDraw(SKEW);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 addScalar(sx);
269 addScalar(sy);
270 validate();
271 return this->INHERITED::skew(sx, sy);
272}
273
274bool SkPictureRecord::concat(const SkMatrix& matrix) {
275 validate();
276 addDraw(CONCAT);
277 addMatrix(matrix);
278 validate();
279 return this->INHERITED::concat(matrix);
280}
281
reed@android.com6e073b92009-01-06 15:03:30 +0000282void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
283 validate();
284 addDraw(SET_MATRIX);
285 addMatrix(matrix);
286 validate();
287 this->INHERITED::setMatrix(matrix);
288}
289
reed@google.com45482d12011-08-29 19:02:39 +0000290static bool regionOpExpands(SkRegion::Op op) {
291 switch (op) {
292 case SkRegion::kUnion_Op:
293 case SkRegion::kXOR_Op:
294 case SkRegion::kReverseDifference_Op:
295 case SkRegion::kReplace_Op:
296 return true;
297 case SkRegion::kIntersect_Op:
298 case SkRegion::kDifference_Op:
299 return false;
300 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000301 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000302 return false;
303 }
304}
305
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000306void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(
307 uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000308 int32_t offset = fRestoreOffsetStack.top();
309 while (offset > 0) {
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000310 uint32_t* peek = fWriter.peek32(offset);
311 offset = *peek;
312 *peek = restoreOffset;
313 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000314
reed@google.comffacd3c2012-08-30 15:31:23 +0000315#ifdef SK_DEBUG
316 // assert that the final offset value points to a save verb
317 uint32_t drawOp = *fWriter.peek32(-offset);
318 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
319#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000320}
321
reed@google.comd86e7ab2012-09-27 20:31:31 +0000322void SkPictureRecord::beginRecording() {
323 // we have to call this *after* our constructor, to ensure that it gets
324 // recorded. This is balanced by restoreToCount() call from endRecording,
325 // which in-turn calls our overridden restore(), so those get recorded too.
326 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
327}
328
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000329void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000330 SkASSERT(kNoInitialSave != fInitialSaveCount);
331 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000332}
333
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000334void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com45482d12011-08-29 19:02:39 +0000335 if (regionOpExpands(op)) {
336 // Run back through any previous clip ops, and mark their offset to
337 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
338 // they could hide this clips ability to expand the clip (i.e. go from
339 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000340 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
reed@google.com45482d12011-08-29 19:02:39 +0000341 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000342
reed@google.com45482d12011-08-29 19:02:39 +0000343 size_t offset = fWriter.size();
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000344 // The RestoreOffset field is initially filled with a placeholder
345 // value that points to the offset of the previous RestoreOffset
346 // in the current stack level, thus forming a linked list so that
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000347 // the restore offsets can be filled in when the corresponding
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000348 // restore command is recorded.
reed@google.com45482d12011-08-29 19:02:39 +0000349 addInt(fRestoreOffsetStack.top());
350 fRestoreOffsetStack.top() = offset;
351}
352
reed@google.com071eef92011-10-12 11:52:53 +0000353bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354 addDraw(CLIP_RECT);
355 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000356 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000357 recordRestoreOffsetPlaceholder(op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358
359 validate();
reed@google.com071eef92011-10-12 11:52:53 +0000360 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361}
362
reed@google.com071eef92011-10-12 11:52:53 +0000363bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 addDraw(CLIP_PATH);
365 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000366 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000367 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000368
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 validate();
reed@google.com82065d62011-02-07 15:30:46 +0000370
reed@android.comae814c82009-02-13 14:56:09 +0000371 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
reed@google.com071eef92011-10-12 11:52:53 +0000372 return this->INHERITED::clipRect(path.getBounds(), op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000373 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000374 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000375 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376}
377
378bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
reed@google.com82065d62011-02-07 15:30:46 +0000379 addDraw(CLIP_REGION);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000381 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000382 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000383
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384 validate();
385 return this->INHERITED::clipRegion(region, op);
386}
387
reed@google.com2a981812011-04-14 18:59:28 +0000388void SkPictureRecord::clear(SkColor color) {
389 addDraw(DRAW_CLEAR);
390 addInt(color);
391 validate();
392}
393
reed@android.com8a1c16f2008-12-17 15:59:43 +0000394void SkPictureRecord::drawPaint(const SkPaint& paint) {
395 addDraw(DRAW_PAINT);
396 addPaint(paint);
397 validate();
398}
399
400void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
401 const SkPaint& paint) {
402 addDraw(DRAW_POINTS);
403 addPaint(paint);
404 addInt(mode);
405 addInt(count);
406 fWriter.writeMul4(pts, count * sizeof(SkPoint));
407 validate();
408}
409
410void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
411 addDraw(DRAW_RECT);
412 addPaint(paint);
413 addRect(rect);
414 validate();
415}
416
417void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
418 addDraw(DRAW_PATH);
419 addPaint(paint);
420 addPath(path);
421 validate();
422}
423
424void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
425 const SkPaint* paint = NULL) {
426 addDraw(DRAW_BITMAP);
427 addPaintPtr(paint);
428 addBitmap(bitmap);
429 addScalar(left);
430 addScalar(top);
431 validate();
432}
433
reed@google.com71121732012-09-18 15:14:33 +0000434void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435 const SkRect& dst, const SkPaint* paint) {
reed@google.com71121732012-09-18 15:14:33 +0000436 addDraw(DRAW_BITMAP_RECT_TO_RECT);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437 addPaintPtr(paint);
438 addBitmap(bitmap);
reed@google.com71121732012-09-18 15:14:33 +0000439 addRectPtr(src); // may be null
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440 addRect(dst);
441 validate();
442}
443
444void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000445 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446 addDraw(DRAW_BITMAP_MATRIX);
447 addPaintPtr(paint);
448 addBitmap(bitmap);
449 addMatrix(matrix);
450 validate();
451}
452
reed@google.comf0b5e112011-09-07 11:57:34 +0000453void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
454 const SkRect& dst, const SkPaint* paint) {
455 addDraw(DRAW_BITMAP_NINE);
456 addPaintPtr(paint);
457 addBitmap(bitmap);
458 addIRect(center);
459 addRect(dst);
460 validate();
461}
462
reed@android.com8a1c16f2008-12-17 15:59:43 +0000463void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
464 const SkPaint* paint = NULL) {
465 addDraw(DRAW_SPRITE);
466 addPaintPtr(paint);
467 addBitmap(bitmap);
468 addInt(left);
469 addInt(top);
470 validate();
471}
472
473void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint,
reed@google.com9efd9a02012-01-30 15:41:43 +0000474 SkScalar minY, SkScalar maxY) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000475 SkPaint::FontMetrics metrics;
476 paint.getFontMetrics(&metrics);
477 SkRect bounds;
478 // construct a rect so we can see any adjustments from the paint.
479 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com9efd9a02012-01-30 15:41:43 +0000480 bounds.set(0, metrics.fTop + minY,
481 SK_Scalar1, metrics.fBottom + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000482 (void)paint.computeFastBounds(bounds, &bounds);
483 // now record the top and bottom
484 addScalar(bounds.fTop);
485 addScalar(bounds.fBottom);
486}
487
reed@google.com82065d62011-02-07 15:30:46 +0000488void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000489 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +0000490 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +0000491
reed@android.com8a1c16f2008-12-17 15:59:43 +0000492 addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT);
493 addPaint(paint);
494 addText(text, byteLength);
495 addScalar(x);
496 addScalar(y);
497 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000498 addFontMetricsTopBottom(paint, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000499 }
500 validate();
501}
502
reed@google.com82065d62011-02-07 15:30:46 +0000503void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000504 const SkPoint pos[], const SkPaint& paint) {
505 size_t points = paint.countText(text, byteLength);
506 if (0 == points)
507 return;
508
509 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +0000510 SkScalar minY = pos[0].fY;
511 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000512 // check if the caller really should have used drawPosTextH()
513 {
514 const SkScalar firstY = pos[0].fY;
515 for (size_t index = 1; index < points; index++) {
516 if (pos[index].fY != firstY) {
517 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +0000518 if (pos[index].fY < minY) {
519 minY = pos[index].fY;
520 } else if (pos[index].fY > maxY) {
521 maxY = pos[index].fY;
522 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523 }
524 }
525 }
reed@google.com82065d62011-02-07 15:30:46 +0000526
reed@google.com2eb5bb12012-04-12 14:27:42 +0000527 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +0000528 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000529
530 if (fast) {
531 addDraw(DRAW_POS_TEXT_H_TOP_BOTTOM);
reed@google.com9efd9a02012-01-30 15:41:43 +0000532 } else if (canUseDrawH) {
533 addDraw(DRAW_POS_TEXT_H);
534 } else if (fastBounds) {
535 addDraw(DRAW_POS_TEXT_TOP_BOTTOM);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000536 } else {
reed@google.com9efd9a02012-01-30 15:41:43 +0000537 addDraw(DRAW_POS_TEXT);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000538 }
539 addPaint(paint);
540 addText(text, byteLength);
541 addInt(points);
542
543#ifdef SK_DEBUG_SIZE
544 size_t start = fWriter.size();
545#endif
546 if (canUseDrawH) {
547 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000548 addFontMetricsTopBottom(paint, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549 }
550 addScalar(pos[0].fY);
551 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +0000552 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553 *xptr++ = pos[index].fX;
554 }
555 else {
556 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +0000557 if (fastBounds) {
558 addFontMetricsTopBottom(paint, minY, maxY);
559 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000560 }
561#ifdef SK_DEBUG_SIZE
562 fPointBytes += fWriter.size() - start;
563 fPointWrites += points;
564#endif
565 validate();
566}
567
568void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
569 const SkScalar xpos[], SkScalar constY,
570 const SkPaint& paint) {
571 size_t points = paint.countText(text, byteLength);
572 if (0 == points)
573 return;
reed@google.com82065d62011-02-07 15:30:46 +0000574
reed@google.com2eb5bb12012-04-12 14:27:42 +0000575 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576
577 addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H);
578 addPaint(paint);
579 addText(text, byteLength);
580 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +0000581
reed@android.com8a1c16f2008-12-17 15:59:43 +0000582#ifdef SK_DEBUG_SIZE
583 size_t start = fWriter.size();
584#endif
585 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000586 addFontMetricsTopBottom(paint, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000587 }
588 addScalar(constY);
589 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
590#ifdef SK_DEBUG_SIZE
591 fPointBytes += fWriter.size() - start;
592 fPointWrites += points;
593#endif
594 validate();
595}
596
reed@google.com82065d62011-02-07 15:30:46 +0000597void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
598 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000599 const SkPaint& paint) {
600 addDraw(DRAW_TEXT_ON_PATH);
601 addPaint(paint);
602 addText(text, byteLength);
603 addPath(path);
604 addMatrixPtr(matrix);
605 validate();
606}
607
608void SkPictureRecord::drawPicture(SkPicture& picture) {
609 addDraw(DRAW_PICTURE);
610 addPicture(picture);
611 validate();
612}
613
614void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
615 const SkPoint vertices[], const SkPoint texs[],
616 const SkColor colors[], SkXfermode*,
617 const uint16_t indices[], int indexCount,
618 const SkPaint& paint) {
619 uint32_t flags = 0;
620 if (texs) {
621 flags |= DRAW_VERTICES_HAS_TEXS;
622 }
623 if (colors) {
624 flags |= DRAW_VERTICES_HAS_COLORS;
625 }
626 if (indexCount > 0) {
627 flags |= DRAW_VERTICES_HAS_INDICES;
628 }
629
630 addDraw(DRAW_VERTICES);
631 addPaint(paint);
632 addInt(flags);
633 addInt(vmode);
634 addInt(vertexCount);
635 addPoints(vertices, vertexCount);
636 if (flags & DRAW_VERTICES_HAS_TEXS) {
637 addPoints(texs, vertexCount);
638 }
639 if (flags & DRAW_VERTICES_HAS_COLORS) {
640 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
641 }
642 if (flags & DRAW_VERTICES_HAS_INDICES) {
643 addInt(indexCount);
644 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
645 }
646}
647
reed@android.comcb608442009-12-04 21:32:27 +0000648void SkPictureRecord::drawData(const void* data, size_t length) {
649 addDraw(DRAW_DATA);
650 addInt(length);
651 fWriter.writePad(data, length);
652}
653
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000655
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000657 addInt(fBitmapHeap->insert(bitmap));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658}
659
660void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
661 addMatrixPtr(&matrix);
662}
663
664void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
reed@google.com83ca3372012-07-12 15:27:54 +0000665 this->addInt(matrix ? fMatrices.find(*matrix) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666}
667
668void SkPictureRecord::addPaint(const SkPaint& paint) {
669 addPaintPtr(&paint);
670}
671
672void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
scroggo@google.com4dffc592012-07-17 16:49:40 +0000673 this->addInt(paint ? fPaints.find(*paint) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674}
675
676void SkPictureRecord::addPath(const SkPath& path) {
677 if (NULL == fPathHeap) {
678 fPathHeap = SkNEW(SkPathHeap);
679 }
680 addInt(fPathHeap->append(path));
681}
682
683void SkPictureRecord::addPicture(SkPicture& picture) {
684 int index = fPictureRefs.find(&picture);
685 if (index < 0) { // not found
686 index = fPictureRefs.count();
687 *fPictureRefs.append() = &picture;
688 picture.ref();
689 }
690 // follow the convention of recording a 1-based index
691 addInt(index + 1);
692}
693
694void SkPictureRecord::addPoint(const SkPoint& point) {
695#ifdef SK_DEBUG_SIZE
696 size_t start = fWriter.size();
697#endif
698 fWriter.writePoint(point);
699#ifdef SK_DEBUG_SIZE
700 fPointBytes += fWriter.size() - start;
701 fPointWrites++;
702#endif
703}
reed@google.com82065d62011-02-07 15:30:46 +0000704
reed@android.com8a1c16f2008-12-17 15:59:43 +0000705void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
706 fWriter.writeMul4(pts, count * sizeof(SkPoint));
707#ifdef SK_DEBUG_SIZE
708 fPointBytes += count * sizeof(SkPoint);
709 fPointWrites++;
710#endif
711}
712
713void SkPictureRecord::addRect(const SkRect& rect) {
714#ifdef SK_DEBUG_SIZE
715 size_t start = fWriter.size();
716#endif
717 fWriter.writeRect(rect);
718#ifdef SK_DEBUG_SIZE
719 fRectBytes += fWriter.size() - start;
720 fRectWrites++;
721#endif
722}
723
724void SkPictureRecord::addRectPtr(const SkRect* rect) {
725 if (fWriter.writeBool(rect != NULL)) {
726 fWriter.writeRect(*rect);
727 }
728}
729
reed@google.comf0b5e112011-09-07 11:57:34 +0000730void SkPictureRecord::addIRect(const SkIRect& rect) {
731 fWriter.write(&rect, sizeof(rect));
732}
733
reed@android.com8a1c16f2008-12-17 15:59:43 +0000734void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
735 if (fWriter.writeBool(rect != NULL)) {
736 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
737 }
738}
739
740void SkPictureRecord::addRegion(const SkRegion& region) {
reed@google.com83ca3372012-07-12 15:27:54 +0000741 addInt(fRegions.find(region));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742}
743
744void SkPictureRecord::addText(const void* text, size_t byteLength) {
745#ifdef SK_DEBUG_SIZE
746 size_t start = fWriter.size();
747#endif
748 addInt(byteLength);
749 fWriter.writePad(text, byteLength);
750#ifdef SK_DEBUG_SIZE
751 fTextBytes += fWriter.size() - start;
752 fTextWrites++;
753#endif
754}
755
756///////////////////////////////////////////////////////////////////////////////
757
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758#ifdef SK_DEBUG_SIZE
759size_t SkPictureRecord::size() const {
760 size_t result = 0;
761 size_t sizeData;
762 bitmaps(&sizeData);
763 result += sizeData;
764 matrices(&sizeData);
765 result += sizeData;
766 paints(&sizeData);
767 result += sizeData;
768 paths(&sizeData);
769 result += sizeData;
770 pictures(&sizeData);
771 result += sizeData;
772 regions(&sizeData);
773 result += sizeData;
774 result += streamlen();
775 return result;
776}
777
778int SkPictureRecord::bitmaps(size_t* size) const {
779 size_t result = 0;
780 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +0000781 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
783 *size = result;
784 return count;
785}
786
787int SkPictureRecord::matrices(size_t* size) const {
788 int count = fMatrices.count();
789 *size = sizeof(fMatrices[0]) * count;
790 return count;
791}
792
793int SkPictureRecord::paints(size_t* size) const {
794 size_t result = 0;
795 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +0000796 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000797 result += sizeof(fPaints[index]) + fPaints[index]->size();
798 *size = result;
799 return count;
800}
801
802int SkPictureRecord::paths(size_t* size) const {
803 size_t result = 0;
804 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +0000805 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806 result += sizeof(fPaths[index]) + fPaths[index]->size();
807 *size = result;
808 return count;
809}
810
811int SkPictureRecord::regions(size_t* size) const {
812 size_t result = 0;
813 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +0000814 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000815 result += sizeof(fRegions[index]) + fRegions[index]->size();
816 *size = result;
817 return count;
818}
819
820size_t SkPictureRecord::streamlen() const {
821 return fWriter.size();
822}
823#endif
824
825#ifdef SK_DEBUG_VALIDATE
826void SkPictureRecord::validate() const {
827 validateBitmaps();
828 validateMatrices();
829 validatePaints();
830 validatePaths();
831 validatePictures();
832 validateRegions();
833}
834
835void SkPictureRecord::validateBitmaps() const {
836 int count = fBitmaps.count();
837 SkASSERT((unsigned) count < 0x1000);
838 for (int index = 0; index < count; index++) {
839 const SkFlatBitmap* bitPtr = fBitmaps[index];
840 SkASSERT(bitPtr);
841 bitPtr->validate();
842 }
843}
844
845void SkPictureRecord::validateMatrices() const {
846 int count = fMatrices.count();
847 SkASSERT((unsigned) count < 0x1000);
848 for (int index = 0; index < count; index++) {
849 const SkFlatMatrix* matrix = fMatrices[index];
850 SkASSERT(matrix);
reed@google.com82065d62011-02-07 15:30:46 +0000851 matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000852 }
853}
854
855void SkPictureRecord::validatePaints() const {
856 int count = fPaints.count();
857 SkASSERT((unsigned) count < 0x1000);
858 for (int index = 0; index < count; index++) {
859 const SkFlatPaint* paint = fPaints[index];
860 SkASSERT(paint);
861// paint->validate();
862 }
863}
864
865void SkPictureRecord::validatePaths() const {
866 int count = fPaths.count();
867 SkASSERT((unsigned) count < 0x1000);
868 for (int index = 0; index < count; index++) {
869 const SkFlatPath* path = fPaths[index];
870 SkASSERT(path);
871 path->validate();
872 }
873}
874
875void SkPictureRecord::validateRegions() const {
876 int count = fRegions.count();
877 SkASSERT((unsigned) count < 0x1000);
878 for (int index = 0; index < count; index++) {
879 const SkFlatRegion* region = fRegions[index];
880 SkASSERT(region);
881 region->validate();
882 }
883}
884#endif
885