blob: b4c4bbc98bb2ac912db1b7ca471c6c19834796f7 [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@android.com8a1c16f2008-12-17 15:59:43 +000011
12#define MIN_WRITER_SIZE 16384
13#define HEAP_BLOCK_SIZE 4096
14
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000015enum {
16 kNoInitialSave = -1,
17};
18
reed@android.comae814c82009-02-13 14:56:09 +000019SkPictureRecord::SkPictureRecord(uint32_t flags) :
djsollen@google.com21830d92012-08-07 19:49:41 +000020 fFlattenableHeap(HEAP_BLOCK_SIZE),
21 fMatrices(&fFlattenableHeap),
22 fPaints(&fFlattenableHeap),
23 fRegions(&fFlattenableHeap),
djsollen@google.comd2700ee2012-05-30 16:54:13 +000024 fWriter(MIN_WRITER_SIZE),
25 fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000026#ifdef SK_DEBUG_SIZE
27 fPointBytes = fRectBytes = fTextBytes = 0;
28 fPointWrites = fRectWrites = fTextWrites = 0;
29#endif
30
31 fRestoreOffsetStack.setReserve(32);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000032 fInitialSaveCount = kNoInitialSave;
reed@google.com82065d62011-02-07 15:30:46 +000033
djsollen@google.comc9ab9872012-08-29 18:52:07 +000034 fBitmapHeap = SkNEW(SkBitmapHeap);
35 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000036 fPathHeap = NULL; // lazy allocate
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000037 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@android.com8a1c16f2008-12-17 15:59:43 +000038}
39
40SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000041 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000042 SkSafeUnref(fPathHeap);
43 fFlattenableHeap.setBitmapStorage(NULL);
44 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000045}
46
47///////////////////////////////////////////////////////////////////////////////
48
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000049SkDevice* SkPictureRecord::setDevice(SkDevice* device) {
50 SkASSERT(kNoInitialSave == fInitialSaveCount);
51 this->INHERITED::setDevice(device);
52
53 // The bracketting save() call needs to be recorded after setting the
54 // device otherwise the clip stack will get messed-up
55 fInitialSaveCount = this->save(SkCanvas::kMatrixClip_SaveFlag);
56 return device;
57}
58
reed@android.com8a1c16f2008-12-17 15:59:43 +000059int SkPictureRecord::save(SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +000060 // record the offset to us, making it non-positive to distinguish a save
61 // from a clip entry.
62 fRestoreOffsetStack.push(-(int32_t)fWriter.size());
63
reed@android.com8a1c16f2008-12-17 15:59:43 +000064 addDraw(SAVE);
65 addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +000066
reed@android.com8a1c16f2008-12-17 15:59:43 +000067 validate();
68 return this->INHERITED::save(flags);
69}
70
71int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
72 SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +000073 // record the offset to us, making it non-positive to distinguish a save
74 // from a clip entry.
75 fRestoreOffsetStack.push(-(int32_t)fWriter.size());
76
reed@android.com8a1c16f2008-12-17 15:59:43 +000077 addDraw(SAVE_LAYER);
78 addRectPtr(bounds);
79 addPaintPtr(paint);
80 addInt(flags);
81
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000082 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
83 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
84 }
85
reed@android.com8a1c16f2008-12-17 15:59:43 +000086 validate();
reed@android.com261ae4d2009-10-02 16:37:46 +000087 /* Don't actually call saveLayer, because that will try to allocate an
88 offscreen device (potentially very big) which we don't actually need
89 at this time (and may not be able to afford since during record our
90 clip starts out the size of the picture, which is often much larger
91 than the size of the actual device we'll use during playback).
92 */
junov@chromium.orga907ac32012-02-24 21:54:07 +000093 int count = this->INHERITED::save(flags);
94 this->clipRectBounds(bounds, flags, NULL);
95 return count;
reed@android.com8a1c16f2008-12-17 15:59:43 +000096}
97
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000098bool SkPictureRecord::isDrawingToLayer() const {
99 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
100}
101
reed@google.comffacd3c2012-08-30 15:31:23 +0000102// Return the size of the specified drawType's recorded block, or 0 if this verb
103// is variable sized, and therefore not known.
104static inline uint32_t getSkipableSize(unsigned drawType) {
105 static const uint8_t gSizes[LAST_DRAWTYPE_ENUM + 1] = {
106 0, // UNUSED,
107 4, // CLIP_PATH,
108 4, // CLIP_REGION,
109 7, // CLIP_RECT,
110 2, // CONCAT,
111 0, // DRAW_BITMAP,
112 0, // DRAW_BITMAP_MATRIX,
113 0, // DRAW_BITMAP_NINE,
114 0, // DRAW_BITMAP_RECT,
115 0, // DRAW_CLEAR,
116 0, // DRAW_DATA,
117 0, // DRAW_PAINT,
118 0, // DRAW_PATH,
119 0, // DRAW_PICTURE,
120 0, // DRAW_POINTS,
121 0, // DRAW_POS_TEXT,
122 0, // DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
123 0, // DRAW_POS_TEXT_H,
124 0, // DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
125 0, // DRAW_RECT,
126 0, // DRAW_SPRITE,
127 0, // DRAW_TEXT,
128 0, // DRAW_TEXT_ON_PATH,
129 0, // DRAW_TEXT_TOP_BOTTOM, // fast variant of DRAW_TEXT
130 0, // DRAW_VERTICES,
131 0, // RESTORE,
132 2, // ROTATE,
133 2, // SAVE,
134 0, // SAVE_LAYER,
135 3, // SCALE,
136 2, // SET_MATRIX,
137 3, // SKEW,
138 3, // TRANSLATE,
139 };
140
141 SkASSERT(sizeof(gSizes) == LAST_DRAWTYPE_ENUM + 1);
142 SkASSERT((unsigned)drawType <= (unsigned)LAST_DRAWTYPE_ENUM);
143 return gSizes[drawType] * sizeof(uint32_t);
144}
145
146#ifdef TRACK_COLLAPSE_STATS
147 static int gCollapseCount, gCollapseCalls;
148#endif
149
150/*
151 * Restore has just been called (but not recoreded), so look back at the
152 * matching save(), and see if we can eliminate the pair of them, due to no
153 * intervening matrix/clip calls.
154 *
155 * If so, update the writer and return true, in which case we won't even record
156 * the restore() call. If we still need the restore(), return false.
157 */
158static bool collapseSaveClipRestore(SkWriter32* writer, int32_t offset) {
159#ifdef TRACK_COLLAPSE_STATS
160 gCollapseCalls += 1;
161#endif
162
163 int32_t restoreOffset = (int32_t)writer->size();
164
165 // back up to the save block
166 while (offset > 0) {
167 offset = *writer->peek32(offset);
168 }
169
170 // now offset points to a save
171 offset = -offset;
172 if (SAVE_LAYER == *writer->peek32(offset)) {
173 // not ready to cull these out yet (mrr)
174 return false;
175 }
176 SkASSERT(SAVE == *writer->peek32(offset));
177
178 // Walk forward until we get back to either a draw-verb (abort) or we hit
179 // our restore (success).
180 int32_t saveOffset = offset;
181
182 offset += getSkipableSize(SAVE);
183 while (offset < restoreOffset) {
184 uint32_t* block = writer->peek32(offset);
185 uint32_t op = *block;
186 uint32_t opSize = getSkipableSize(op);
187 if (0 == opSize) {
188 // drawing verb, abort
189 return false;
190 }
191 offset += opSize;
192 }
193
194#ifdef TRACK_COLLAPSE_STATS
195 gCollapseCount += 1;
196 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
197 (double)gCollapseCount / gCollapseCalls, "%");
198#endif
199
200 writer->rewindToOffset(saveOffset);
201 return true;
202}
203
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000205 // FIXME: SkDeferredCanvas needs to be refactored to respect
206 // save/restore balancing so that the following test can be
207 // turned on permanently.
208#if 0
209 SkASSERT(fRestoreOffsetStack.count() > 1);
210#endif
211
reed@android.comb4e22d62009-07-09 15:20:25 +0000212 // check for underflow
213 if (fRestoreOffsetStack.count() == 0) {
214 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000216
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000217 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
218 fFirstSavedLayerIndex = kNoSavedLayerIndex;
219 }
220
reed@google.comffacd3c2012-08-30 15:31:23 +0000221 if (!collapseSaveClipRestore(&fWriter, fRestoreOffsetStack.top())) {
222 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size());
223 this->addDraw(RESTORE);
224 }
225
reed@android.comb4e22d62009-07-09 15:20:25 +0000226 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000227
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228 validate();
229 return this->INHERITED::restore();
230}
231
232bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
233 addDraw(TRANSLATE);
234 addScalar(dx);
235 addScalar(dy);
236 validate();
237 return this->INHERITED::translate(dx, dy);
238}
239
240bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
reed@google.com82065d62011-02-07 15:30:46 +0000241 addDraw(SCALE);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 addScalar(sx);
243 addScalar(sy);
244 validate();
245 return this->INHERITED::scale(sx, sy);
246}
247
248bool SkPictureRecord::rotate(SkScalar degrees) {
reed@google.com82065d62011-02-07 15:30:46 +0000249 addDraw(ROTATE);
250 addScalar(degrees);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 validate();
252 return this->INHERITED::rotate(degrees);
253}
254
255bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
reed@google.com82065d62011-02-07 15:30:46 +0000256 addDraw(SKEW);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 addScalar(sx);
258 addScalar(sy);
259 validate();
260 return this->INHERITED::skew(sx, sy);
261}
262
263bool SkPictureRecord::concat(const SkMatrix& matrix) {
264 validate();
265 addDraw(CONCAT);
266 addMatrix(matrix);
267 validate();
268 return this->INHERITED::concat(matrix);
269}
270
reed@android.com6e073b92009-01-06 15:03:30 +0000271void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
272 validate();
273 addDraw(SET_MATRIX);
274 addMatrix(matrix);
275 validate();
276 this->INHERITED::setMatrix(matrix);
277}
278
reed@google.com45482d12011-08-29 19:02:39 +0000279static bool regionOpExpands(SkRegion::Op op) {
280 switch (op) {
281 case SkRegion::kUnion_Op:
282 case SkRegion::kXOR_Op:
283 case SkRegion::kReverseDifference_Op:
284 case SkRegion::kReplace_Op:
285 return true;
286 case SkRegion::kIntersect_Op:
287 case SkRegion::kDifference_Op:
288 return false;
289 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000290 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000291 return false;
292 }
293}
294
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000295void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(
296 uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000297 int32_t offset = fRestoreOffsetStack.top();
298 while (offset > 0) {
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000299 uint32_t* peek = fWriter.peek32(offset);
300 offset = *peek;
301 *peek = restoreOffset;
302 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000303
304#ifdef SK_DEBUG
305 // assert that the final offset value points to a save verb
306 uint32_t drawOp = *fWriter.peek32(-offset);
307 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
308#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000309}
310
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000311void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000312 SkASSERT(kNoInitialSave != fInitialSaveCount);
313 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000314}
315
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000316void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com45482d12011-08-29 19:02:39 +0000317 if (regionOpExpands(op)) {
318 // Run back through any previous clip ops, and mark their offset to
319 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
320 // they could hide this clips ability to expand the clip (i.e. go from
321 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000322 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
reed@google.com45482d12011-08-29 19:02:39 +0000323 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000324
reed@google.com45482d12011-08-29 19:02:39 +0000325 size_t offset = fWriter.size();
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000326 // The RestoreOffset field is initially filled with a placeholder
327 // value that points to the offset of the previous RestoreOffset
328 // in the current stack level, thus forming a linked list so that
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000329 // the restore offsets can be filled in when the corresponding
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000330 // restore command is recorded.
reed@google.com45482d12011-08-29 19:02:39 +0000331 addInt(fRestoreOffsetStack.top());
332 fRestoreOffsetStack.top() = offset;
333}
334
reed@google.com071eef92011-10-12 11:52:53 +0000335bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336 addDraw(CLIP_RECT);
337 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000338 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000339 recordRestoreOffsetPlaceholder(op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340
341 validate();
reed@google.com071eef92011-10-12 11:52:53 +0000342 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343}
344
reed@google.com071eef92011-10-12 11:52:53 +0000345bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346 addDraw(CLIP_PATH);
347 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000348 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000349 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000350
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 validate();
reed@google.com82065d62011-02-07 15:30:46 +0000352
reed@android.comae814c82009-02-13 14:56:09 +0000353 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
reed@google.com071eef92011-10-12 11:52:53 +0000354 return this->INHERITED::clipRect(path.getBounds(), op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000355 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000356 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000357 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358}
359
360bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
reed@google.com82065d62011-02-07 15:30:46 +0000361 addDraw(CLIP_REGION);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000363 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000364 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000365
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366 validate();
367 return this->INHERITED::clipRegion(region, op);
368}
369
reed@google.com2a981812011-04-14 18:59:28 +0000370void SkPictureRecord::clear(SkColor color) {
371 addDraw(DRAW_CLEAR);
372 addInt(color);
373 validate();
374}
375
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376void SkPictureRecord::drawPaint(const SkPaint& paint) {
377 addDraw(DRAW_PAINT);
378 addPaint(paint);
379 validate();
380}
381
382void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
383 const SkPaint& paint) {
384 addDraw(DRAW_POINTS);
385 addPaint(paint);
386 addInt(mode);
387 addInt(count);
388 fWriter.writeMul4(pts, count * sizeof(SkPoint));
389 validate();
390}
391
392void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
393 addDraw(DRAW_RECT);
394 addPaint(paint);
395 addRect(rect);
396 validate();
397}
398
399void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
400 addDraw(DRAW_PATH);
401 addPaint(paint);
402 addPath(path);
403 validate();
404}
405
406void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
407 const SkPaint* paint = NULL) {
408 addDraw(DRAW_BITMAP);
409 addPaintPtr(paint);
410 addBitmap(bitmap);
411 addScalar(left);
412 addScalar(top);
413 validate();
414}
415
416void SkPictureRecord::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
417 const SkRect& dst, const SkPaint* paint) {
418 addDraw(DRAW_BITMAP_RECT);
419 addPaintPtr(paint);
420 addBitmap(bitmap);
421 addIRectPtr(src); // may be null
422 addRect(dst);
423 validate();
424}
425
426void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000427 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000428 addDraw(DRAW_BITMAP_MATRIX);
429 addPaintPtr(paint);
430 addBitmap(bitmap);
431 addMatrix(matrix);
432 validate();
433}
434
reed@google.comf0b5e112011-09-07 11:57:34 +0000435void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
436 const SkRect& dst, const SkPaint* paint) {
437 addDraw(DRAW_BITMAP_NINE);
438 addPaintPtr(paint);
439 addBitmap(bitmap);
440 addIRect(center);
441 addRect(dst);
442 validate();
443}
444
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
446 const SkPaint* paint = NULL) {
447 addDraw(DRAW_SPRITE);
448 addPaintPtr(paint);
449 addBitmap(bitmap);
450 addInt(left);
451 addInt(top);
452 validate();
453}
454
455void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint,
reed@google.com9efd9a02012-01-30 15:41:43 +0000456 SkScalar minY, SkScalar maxY) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000457 SkPaint::FontMetrics metrics;
458 paint.getFontMetrics(&metrics);
459 SkRect bounds;
460 // construct a rect so we can see any adjustments from the paint.
461 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com9efd9a02012-01-30 15:41:43 +0000462 bounds.set(0, metrics.fTop + minY,
463 SK_Scalar1, metrics.fBottom + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000464 (void)paint.computeFastBounds(bounds, &bounds);
465 // now record the top and bottom
466 addScalar(bounds.fTop);
467 addScalar(bounds.fBottom);
468}
469
reed@google.com82065d62011-02-07 15:30:46 +0000470void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000471 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +0000472 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +0000473
reed@android.com8a1c16f2008-12-17 15:59:43 +0000474 addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT);
475 addPaint(paint);
476 addText(text, byteLength);
477 addScalar(x);
478 addScalar(y);
479 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000480 addFontMetricsTopBottom(paint, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000481 }
482 validate();
483}
484
reed@google.com82065d62011-02-07 15:30:46 +0000485void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000486 const SkPoint pos[], const SkPaint& paint) {
487 size_t points = paint.countText(text, byteLength);
488 if (0 == points)
489 return;
490
491 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +0000492 SkScalar minY = pos[0].fY;
493 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000494 // check if the caller really should have used drawPosTextH()
495 {
496 const SkScalar firstY = pos[0].fY;
497 for (size_t index = 1; index < points; index++) {
498 if (pos[index].fY != firstY) {
499 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +0000500 if (pos[index].fY < minY) {
501 minY = pos[index].fY;
502 } else if (pos[index].fY > maxY) {
503 maxY = pos[index].fY;
504 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000505 }
506 }
507 }
reed@google.com82065d62011-02-07 15:30:46 +0000508
reed@google.com2eb5bb12012-04-12 14:27:42 +0000509 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +0000510 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000511
512 if (fast) {
513 addDraw(DRAW_POS_TEXT_H_TOP_BOTTOM);
reed@google.com9efd9a02012-01-30 15:41:43 +0000514 } else if (canUseDrawH) {
515 addDraw(DRAW_POS_TEXT_H);
516 } else if (fastBounds) {
517 addDraw(DRAW_POS_TEXT_TOP_BOTTOM);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000518 } else {
reed@google.com9efd9a02012-01-30 15:41:43 +0000519 addDraw(DRAW_POS_TEXT);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000520 }
521 addPaint(paint);
522 addText(text, byteLength);
523 addInt(points);
524
525#ifdef SK_DEBUG_SIZE
526 size_t start = fWriter.size();
527#endif
528 if (canUseDrawH) {
529 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000530 addFontMetricsTopBottom(paint, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000531 }
532 addScalar(pos[0].fY);
533 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +0000534 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000535 *xptr++ = pos[index].fX;
536 }
537 else {
538 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +0000539 if (fastBounds) {
540 addFontMetricsTopBottom(paint, minY, maxY);
541 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000542 }
543#ifdef SK_DEBUG_SIZE
544 fPointBytes += fWriter.size() - start;
545 fPointWrites += points;
546#endif
547 validate();
548}
549
550void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
551 const SkScalar xpos[], SkScalar constY,
552 const SkPaint& paint) {
553 size_t points = paint.countText(text, byteLength);
554 if (0 == points)
555 return;
reed@google.com82065d62011-02-07 15:30:46 +0000556
reed@google.com2eb5bb12012-04-12 14:27:42 +0000557 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000558
559 addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H);
560 addPaint(paint);
561 addText(text, byteLength);
562 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +0000563
reed@android.com8a1c16f2008-12-17 15:59:43 +0000564#ifdef SK_DEBUG_SIZE
565 size_t start = fWriter.size();
566#endif
567 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000568 addFontMetricsTopBottom(paint, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000569 }
570 addScalar(constY);
571 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
572#ifdef SK_DEBUG_SIZE
573 fPointBytes += fWriter.size() - start;
574 fPointWrites += points;
575#endif
576 validate();
577}
578
reed@google.com82065d62011-02-07 15:30:46 +0000579void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
580 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000581 const SkPaint& paint) {
582 addDraw(DRAW_TEXT_ON_PATH);
583 addPaint(paint);
584 addText(text, byteLength);
585 addPath(path);
586 addMatrixPtr(matrix);
587 validate();
588}
589
590void SkPictureRecord::drawPicture(SkPicture& picture) {
591 addDraw(DRAW_PICTURE);
592 addPicture(picture);
593 validate();
594}
595
596void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
597 const SkPoint vertices[], const SkPoint texs[],
598 const SkColor colors[], SkXfermode*,
599 const uint16_t indices[], int indexCount,
600 const SkPaint& paint) {
601 uint32_t flags = 0;
602 if (texs) {
603 flags |= DRAW_VERTICES_HAS_TEXS;
604 }
605 if (colors) {
606 flags |= DRAW_VERTICES_HAS_COLORS;
607 }
608 if (indexCount > 0) {
609 flags |= DRAW_VERTICES_HAS_INDICES;
610 }
611
612 addDraw(DRAW_VERTICES);
613 addPaint(paint);
614 addInt(flags);
615 addInt(vmode);
616 addInt(vertexCount);
617 addPoints(vertices, vertexCount);
618 if (flags & DRAW_VERTICES_HAS_TEXS) {
619 addPoints(texs, vertexCount);
620 }
621 if (flags & DRAW_VERTICES_HAS_COLORS) {
622 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
623 }
624 if (flags & DRAW_VERTICES_HAS_INDICES) {
625 addInt(indexCount);
626 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
627 }
628}
629
reed@android.comcb608442009-12-04 21:32:27 +0000630void SkPictureRecord::drawData(const void* data, size_t length) {
631 addDraw(DRAW_DATA);
632 addInt(length);
633 fWriter.writePad(data, length);
634}
635
reed@android.com8a1c16f2008-12-17 15:59:43 +0000636///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000637
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000639 addInt(fBitmapHeap->insert(bitmap));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000640}
641
642void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
643 addMatrixPtr(&matrix);
644}
645
646void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
reed@google.com83ca3372012-07-12 15:27:54 +0000647 this->addInt(matrix ? fMatrices.find(*matrix) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648}
649
650void SkPictureRecord::addPaint(const SkPaint& paint) {
651 addPaintPtr(&paint);
652}
653
654void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
scroggo@google.com4dffc592012-07-17 16:49:40 +0000655 this->addInt(paint ? fPaints.find(*paint) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656}
657
658void SkPictureRecord::addPath(const SkPath& path) {
659 if (NULL == fPathHeap) {
660 fPathHeap = SkNEW(SkPathHeap);
661 }
662 addInt(fPathHeap->append(path));
663}
664
665void SkPictureRecord::addPicture(SkPicture& picture) {
666 int index = fPictureRefs.find(&picture);
667 if (index < 0) { // not found
668 index = fPictureRefs.count();
669 *fPictureRefs.append() = &picture;
670 picture.ref();
671 }
672 // follow the convention of recording a 1-based index
673 addInt(index + 1);
674}
675
676void SkPictureRecord::addPoint(const SkPoint& point) {
677#ifdef SK_DEBUG_SIZE
678 size_t start = fWriter.size();
679#endif
680 fWriter.writePoint(point);
681#ifdef SK_DEBUG_SIZE
682 fPointBytes += fWriter.size() - start;
683 fPointWrites++;
684#endif
685}
reed@google.com82065d62011-02-07 15:30:46 +0000686
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
688 fWriter.writeMul4(pts, count * sizeof(SkPoint));
689#ifdef SK_DEBUG_SIZE
690 fPointBytes += count * sizeof(SkPoint);
691 fPointWrites++;
692#endif
693}
694
695void SkPictureRecord::addRect(const SkRect& rect) {
696#ifdef SK_DEBUG_SIZE
697 size_t start = fWriter.size();
698#endif
699 fWriter.writeRect(rect);
700#ifdef SK_DEBUG_SIZE
701 fRectBytes += fWriter.size() - start;
702 fRectWrites++;
703#endif
704}
705
706void SkPictureRecord::addRectPtr(const SkRect* rect) {
707 if (fWriter.writeBool(rect != NULL)) {
708 fWriter.writeRect(*rect);
709 }
710}
711
reed@google.comf0b5e112011-09-07 11:57:34 +0000712void SkPictureRecord::addIRect(const SkIRect& rect) {
713 fWriter.write(&rect, sizeof(rect));
714}
715
reed@android.com8a1c16f2008-12-17 15:59:43 +0000716void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
717 if (fWriter.writeBool(rect != NULL)) {
718 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
719 }
720}
721
722void SkPictureRecord::addRegion(const SkRegion& region) {
reed@google.com83ca3372012-07-12 15:27:54 +0000723 addInt(fRegions.find(region));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000724}
725
726void SkPictureRecord::addText(const void* text, size_t byteLength) {
727#ifdef SK_DEBUG_SIZE
728 size_t start = fWriter.size();
729#endif
730 addInt(byteLength);
731 fWriter.writePad(text, byteLength);
732#ifdef SK_DEBUG_SIZE
733 fTextBytes += fWriter.size() - start;
734 fTextWrites++;
735#endif
736}
737
738///////////////////////////////////////////////////////////////////////////////
739
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740#ifdef SK_DEBUG_SIZE
741size_t SkPictureRecord::size() const {
742 size_t result = 0;
743 size_t sizeData;
744 bitmaps(&sizeData);
745 result += sizeData;
746 matrices(&sizeData);
747 result += sizeData;
748 paints(&sizeData);
749 result += sizeData;
750 paths(&sizeData);
751 result += sizeData;
752 pictures(&sizeData);
753 result += sizeData;
754 regions(&sizeData);
755 result += sizeData;
756 result += streamlen();
757 return result;
758}
759
760int SkPictureRecord::bitmaps(size_t* size) const {
761 size_t result = 0;
762 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +0000763 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000764 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
765 *size = result;
766 return count;
767}
768
769int SkPictureRecord::matrices(size_t* size) const {
770 int count = fMatrices.count();
771 *size = sizeof(fMatrices[0]) * count;
772 return count;
773}
774
775int SkPictureRecord::paints(size_t* size) const {
776 size_t result = 0;
777 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +0000778 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000779 result += sizeof(fPaints[index]) + fPaints[index]->size();
780 *size = result;
781 return count;
782}
783
784int SkPictureRecord::paths(size_t* size) const {
785 size_t result = 0;
786 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +0000787 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000788 result += sizeof(fPaths[index]) + fPaths[index]->size();
789 *size = result;
790 return count;
791}
792
793int SkPictureRecord::regions(size_t* size) const {
794 size_t result = 0;
795 int count = fRegions.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(fRegions[index]) + fRegions[index]->size();
798 *size = result;
799 return count;
800}
801
802size_t SkPictureRecord::streamlen() const {
803 return fWriter.size();
804}
805#endif
806
807#ifdef SK_DEBUG_VALIDATE
808void SkPictureRecord::validate() const {
809 validateBitmaps();
810 validateMatrices();
811 validatePaints();
812 validatePaths();
813 validatePictures();
814 validateRegions();
815}
816
817void SkPictureRecord::validateBitmaps() const {
818 int count = fBitmaps.count();
819 SkASSERT((unsigned) count < 0x1000);
820 for (int index = 0; index < count; index++) {
821 const SkFlatBitmap* bitPtr = fBitmaps[index];
822 SkASSERT(bitPtr);
823 bitPtr->validate();
824 }
825}
826
827void SkPictureRecord::validateMatrices() const {
828 int count = fMatrices.count();
829 SkASSERT((unsigned) count < 0x1000);
830 for (int index = 0; index < count; index++) {
831 const SkFlatMatrix* matrix = fMatrices[index];
832 SkASSERT(matrix);
reed@google.com82065d62011-02-07 15:30:46 +0000833 matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000834 }
835}
836
837void SkPictureRecord::validatePaints() const {
838 int count = fPaints.count();
839 SkASSERT((unsigned) count < 0x1000);
840 for (int index = 0; index < count; index++) {
841 const SkFlatPaint* paint = fPaints[index];
842 SkASSERT(paint);
843// paint->validate();
844 }
845}
846
847void SkPictureRecord::validatePaths() const {
848 int count = fPaths.count();
849 SkASSERT((unsigned) count < 0x1000);
850 for (int index = 0; index < count; index++) {
851 const SkFlatPath* path = fPaths[index];
852 SkASSERT(path);
853 path->validate();
854 }
855}
856
857void SkPictureRecord::validateRegions() const {
858 int count = fRegions.count();
859 SkASSERT((unsigned) count < 0x1000);
860 for (int index = 0; index < count; index++) {
861 const SkFlatRegion* region = fRegions[index];
862 SkASSERT(region);
863 region->validate();
864 }
865}
866#endif
867