blob: ed528f293c443e56129536115fe734dca225a709 [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.comd2700ee2012-05-30 16:54:13 +000020 fHeap(HEAP_BLOCK_SIZE),
21 fBitmaps(&fHeap),
22 fMatrices(&fHeap),
23 fPaints(&fHeap),
24 fRegions(&fHeap),
25 fWriter(MIN_WRITER_SIZE),
26 fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000027#ifdef SK_DEBUG_SIZE
28 fPointBytes = fRectBytes = fTextBytes = 0;
29 fPointWrites = fRectWrites = fTextWrites = 0;
30#endif
31
32 fRestoreOffsetStack.setReserve(32);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000033 fInitialSaveCount = kNoInitialSave;
reed@google.com82065d62011-02-07 15:30:46 +000034
reed@android.com8a1c16f2008-12-17 15:59:43 +000035 fPathHeap = NULL; // lazy allocate
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000036 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@android.com8a1c16f2008-12-17 15:59:43 +000037}
38
39SkPictureRecord::~SkPictureRecord() {
40 reset();
41}
42
43///////////////////////////////////////////////////////////////////////////////
44
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000045SkDevice* SkPictureRecord::setDevice(SkDevice* device) {
46 SkASSERT(kNoInitialSave == fInitialSaveCount);
47 this->INHERITED::setDevice(device);
48
49 // The bracketting save() call needs to be recorded after setting the
50 // device otherwise the clip stack will get messed-up
51 fInitialSaveCount = this->save(SkCanvas::kMatrixClip_SaveFlag);
52 return device;
53}
54
reed@android.com8a1c16f2008-12-17 15:59:43 +000055int SkPictureRecord::save(SaveFlags flags) {
56 addDraw(SAVE);
57 addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +000058
reed@android.com8a1c16f2008-12-17 15:59:43 +000059 fRestoreOffsetStack.push(0);
reed@google.com82065d62011-02-07 15:30:46 +000060
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 validate();
62 return this->INHERITED::save(flags);
63}
64
65int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
66 SaveFlags flags) {
67 addDraw(SAVE_LAYER);
68 addRectPtr(bounds);
69 addPaintPtr(paint);
70 addInt(flags);
71
72 fRestoreOffsetStack.push(0);
73
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000074 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
75 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
76 }
77
reed@android.com8a1c16f2008-12-17 15:59:43 +000078 validate();
reed@android.com261ae4d2009-10-02 16:37:46 +000079 /* Don't actually call saveLayer, because that will try to allocate an
80 offscreen device (potentially very big) which we don't actually need
81 at this time (and may not be able to afford since during record our
82 clip starts out the size of the picture, which is often much larger
83 than the size of the actual device we'll use during playback).
84 */
junov@chromium.orga907ac32012-02-24 21:54:07 +000085 int count = this->INHERITED::save(flags);
86 this->clipRectBounds(bounds, flags, NULL);
87 return count;
reed@android.com8a1c16f2008-12-17 15:59:43 +000088}
89
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000090bool SkPictureRecord::isDrawingToLayer() const {
91 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
92}
93
reed@android.com8a1c16f2008-12-17 15:59:43 +000094void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000095 // FIXME: SkDeferredCanvas needs to be refactored to respect
96 // save/restore balancing so that the following test can be
97 // turned on permanently.
98#if 0
99 SkASSERT(fRestoreOffsetStack.count() > 1);
100#endif
101
reed@android.comb4e22d62009-07-09 15:20:25 +0000102 // check for underflow
103 if (fRestoreOffsetStack.count() == 0) {
104 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000106
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000107 fillRestoreOffsetPlaceholdersForCurrentStackLevel(
108 (uint32_t)fWriter.size());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000109
110 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
111 fFirstSavedLayerIndex = kNoSavedLayerIndex;
112 }
113
reed@android.comb4e22d62009-07-09 15:20:25 +0000114 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000115
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116 addDraw(RESTORE);
117 validate();
118 return this->INHERITED::restore();
119}
120
121bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
122 addDraw(TRANSLATE);
123 addScalar(dx);
124 addScalar(dy);
125 validate();
126 return this->INHERITED::translate(dx, dy);
127}
128
129bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
reed@google.com82065d62011-02-07 15:30:46 +0000130 addDraw(SCALE);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131 addScalar(sx);
132 addScalar(sy);
133 validate();
134 return this->INHERITED::scale(sx, sy);
135}
136
137bool SkPictureRecord::rotate(SkScalar degrees) {
reed@google.com82065d62011-02-07 15:30:46 +0000138 addDraw(ROTATE);
139 addScalar(degrees);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140 validate();
141 return this->INHERITED::rotate(degrees);
142}
143
144bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
reed@google.com82065d62011-02-07 15:30:46 +0000145 addDraw(SKEW);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 addScalar(sx);
147 addScalar(sy);
148 validate();
149 return this->INHERITED::skew(sx, sy);
150}
151
152bool SkPictureRecord::concat(const SkMatrix& matrix) {
153 validate();
154 addDraw(CONCAT);
155 addMatrix(matrix);
156 validate();
157 return this->INHERITED::concat(matrix);
158}
159
reed@android.com6e073b92009-01-06 15:03:30 +0000160void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
161 validate();
162 addDraw(SET_MATRIX);
163 addMatrix(matrix);
164 validate();
165 this->INHERITED::setMatrix(matrix);
166}
167
reed@google.com45482d12011-08-29 19:02:39 +0000168static bool regionOpExpands(SkRegion::Op op) {
169 switch (op) {
170 case SkRegion::kUnion_Op:
171 case SkRegion::kXOR_Op:
172 case SkRegion::kReverseDifference_Op:
173 case SkRegion::kReplace_Op:
174 return true;
175 case SkRegion::kIntersect_Op:
176 case SkRegion::kDifference_Op:
177 return false;
178 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000179 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000180 return false;
181 }
182}
183
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000184void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(
185 uint32_t restoreOffset) {
186 uint32_t offset = fRestoreOffsetStack.top();
187 while (offset) {
188 uint32_t* peek = fWriter.peek32(offset);
189 offset = *peek;
190 *peek = restoreOffset;
191 }
192}
193
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000194void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000195 SkASSERT(kNoInitialSave != fInitialSaveCount);
196 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000197}
198
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000199void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com45482d12011-08-29 19:02:39 +0000200 if (regionOpExpands(op)) {
201 // Run back through any previous clip ops, and mark their offset to
202 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
203 // they could hide this clips ability to expand the clip (i.e. go from
204 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000205 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
reed@google.com45482d12011-08-29 19:02:39 +0000206 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000207
reed@google.com45482d12011-08-29 19:02:39 +0000208 size_t offset = fWriter.size();
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000209 // The RestoreOffset field is initially filled with a placeholder
210 // value that points to the offset of the previous RestoreOffset
211 // in the current stack level, thus forming a linked list so that
212 // the restore offsets can be filled in when the corresponding
213 // restore command is recorded.
reed@google.com45482d12011-08-29 19:02:39 +0000214 addInt(fRestoreOffsetStack.top());
215 fRestoreOffsetStack.top() = offset;
216}
217
reed@google.com071eef92011-10-12 11:52:53 +0000218bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 addDraw(CLIP_RECT);
220 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000221 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000222 recordRestoreOffsetPlaceholder(op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223
224 validate();
reed@google.com071eef92011-10-12 11:52:53 +0000225 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226}
227
reed@google.com071eef92011-10-12 11:52:53 +0000228bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229 addDraw(CLIP_PATH);
230 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000231 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000232 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000233
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 validate();
reed@google.com82065d62011-02-07 15:30:46 +0000235
reed@android.comae814c82009-02-13 14:56:09 +0000236 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
reed@google.com071eef92011-10-12 11:52:53 +0000237 return this->INHERITED::clipRect(path.getBounds(), op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000238 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000239 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000240 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241}
242
243bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
reed@google.com82065d62011-02-07 15:30:46 +0000244 addDraw(CLIP_REGION);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000246 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000247 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000248
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249 validate();
250 return this->INHERITED::clipRegion(region, op);
251}
252
reed@google.com2a981812011-04-14 18:59:28 +0000253void SkPictureRecord::clear(SkColor color) {
254 addDraw(DRAW_CLEAR);
255 addInt(color);
256 validate();
257}
258
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259void SkPictureRecord::drawPaint(const SkPaint& paint) {
260 addDraw(DRAW_PAINT);
261 addPaint(paint);
262 validate();
263}
264
265void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
266 const SkPaint& paint) {
267 addDraw(DRAW_POINTS);
268 addPaint(paint);
269 addInt(mode);
270 addInt(count);
271 fWriter.writeMul4(pts, count * sizeof(SkPoint));
272 validate();
273}
274
275void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
276 addDraw(DRAW_RECT);
277 addPaint(paint);
278 addRect(rect);
279 validate();
280}
281
282void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
283 addDraw(DRAW_PATH);
284 addPaint(paint);
285 addPath(path);
286 validate();
287}
288
289void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
290 const SkPaint* paint = NULL) {
291 addDraw(DRAW_BITMAP);
292 addPaintPtr(paint);
293 addBitmap(bitmap);
294 addScalar(left);
295 addScalar(top);
296 validate();
297}
298
299void SkPictureRecord::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
300 const SkRect& dst, const SkPaint* paint) {
301 addDraw(DRAW_BITMAP_RECT);
302 addPaintPtr(paint);
303 addBitmap(bitmap);
304 addIRectPtr(src); // may be null
305 addRect(dst);
306 validate();
307}
308
309void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000310 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000311 addDraw(DRAW_BITMAP_MATRIX);
312 addPaintPtr(paint);
313 addBitmap(bitmap);
314 addMatrix(matrix);
315 validate();
316}
317
reed@google.comf0b5e112011-09-07 11:57:34 +0000318void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
319 const SkRect& dst, const SkPaint* paint) {
320 addDraw(DRAW_BITMAP_NINE);
321 addPaintPtr(paint);
322 addBitmap(bitmap);
323 addIRect(center);
324 addRect(dst);
325 validate();
326}
327
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
329 const SkPaint* paint = NULL) {
330 addDraw(DRAW_SPRITE);
331 addPaintPtr(paint);
332 addBitmap(bitmap);
333 addInt(left);
334 addInt(top);
335 validate();
336}
337
338void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint,
reed@google.com9efd9a02012-01-30 15:41:43 +0000339 SkScalar minY, SkScalar maxY) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 SkPaint::FontMetrics metrics;
341 paint.getFontMetrics(&metrics);
342 SkRect bounds;
343 // construct a rect so we can see any adjustments from the paint.
344 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com9efd9a02012-01-30 15:41:43 +0000345 bounds.set(0, metrics.fTop + minY,
346 SK_Scalar1, metrics.fBottom + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347 (void)paint.computeFastBounds(bounds, &bounds);
348 // now record the top and bottom
349 addScalar(bounds.fTop);
350 addScalar(bounds.fBottom);
351}
352
reed@google.com82065d62011-02-07 15:30:46 +0000353void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +0000355 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +0000356
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357 addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT);
358 addPaint(paint);
359 addText(text, byteLength);
360 addScalar(x);
361 addScalar(y);
362 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000363 addFontMetricsTopBottom(paint, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 }
365 validate();
366}
367
reed@google.com82065d62011-02-07 15:30:46 +0000368void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 const SkPoint pos[], const SkPaint& paint) {
370 size_t points = paint.countText(text, byteLength);
371 if (0 == points)
372 return;
373
374 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +0000375 SkScalar minY = pos[0].fY;
376 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377 // check if the caller really should have used drawPosTextH()
378 {
379 const SkScalar firstY = pos[0].fY;
380 for (size_t index = 1; index < points; index++) {
381 if (pos[index].fY != firstY) {
382 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +0000383 if (pos[index].fY < minY) {
384 minY = pos[index].fY;
385 } else if (pos[index].fY > maxY) {
386 maxY = pos[index].fY;
387 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388 }
389 }
390 }
reed@google.com82065d62011-02-07 15:30:46 +0000391
reed@google.com2eb5bb12012-04-12 14:27:42 +0000392 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +0000393 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000394
395 if (fast) {
396 addDraw(DRAW_POS_TEXT_H_TOP_BOTTOM);
reed@google.com9efd9a02012-01-30 15:41:43 +0000397 } else if (canUseDrawH) {
398 addDraw(DRAW_POS_TEXT_H);
399 } else if (fastBounds) {
400 addDraw(DRAW_POS_TEXT_TOP_BOTTOM);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401 } else {
reed@google.com9efd9a02012-01-30 15:41:43 +0000402 addDraw(DRAW_POS_TEXT);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403 }
404 addPaint(paint);
405 addText(text, byteLength);
406 addInt(points);
407
408#ifdef SK_DEBUG_SIZE
409 size_t start = fWriter.size();
410#endif
411 if (canUseDrawH) {
412 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000413 addFontMetricsTopBottom(paint, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000414 }
415 addScalar(pos[0].fY);
416 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +0000417 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000418 *xptr++ = pos[index].fX;
419 }
420 else {
421 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +0000422 if (fastBounds) {
423 addFontMetricsTopBottom(paint, minY, maxY);
424 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000425 }
426#ifdef SK_DEBUG_SIZE
427 fPointBytes += fWriter.size() - start;
428 fPointWrites += points;
429#endif
430 validate();
431}
432
433void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
434 const SkScalar xpos[], SkScalar constY,
435 const SkPaint& paint) {
436 size_t points = paint.countText(text, byteLength);
437 if (0 == points)
438 return;
reed@google.com82065d62011-02-07 15:30:46 +0000439
reed@google.com2eb5bb12012-04-12 14:27:42 +0000440 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441
442 addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H);
443 addPaint(paint);
444 addText(text, byteLength);
445 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +0000446
reed@android.com8a1c16f2008-12-17 15:59:43 +0000447#ifdef SK_DEBUG_SIZE
448 size_t start = fWriter.size();
449#endif
450 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000451 addFontMetricsTopBottom(paint, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452 }
453 addScalar(constY);
454 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
455#ifdef SK_DEBUG_SIZE
456 fPointBytes += fWriter.size() - start;
457 fPointWrites += points;
458#endif
459 validate();
460}
461
reed@google.com82065d62011-02-07 15:30:46 +0000462void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
463 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000464 const SkPaint& paint) {
465 addDraw(DRAW_TEXT_ON_PATH);
466 addPaint(paint);
467 addText(text, byteLength);
468 addPath(path);
469 addMatrixPtr(matrix);
470 validate();
471}
472
473void SkPictureRecord::drawPicture(SkPicture& picture) {
474 addDraw(DRAW_PICTURE);
475 addPicture(picture);
476 validate();
477}
478
479void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
480 const SkPoint vertices[], const SkPoint texs[],
481 const SkColor colors[], SkXfermode*,
482 const uint16_t indices[], int indexCount,
483 const SkPaint& paint) {
484 uint32_t flags = 0;
485 if (texs) {
486 flags |= DRAW_VERTICES_HAS_TEXS;
487 }
488 if (colors) {
489 flags |= DRAW_VERTICES_HAS_COLORS;
490 }
491 if (indexCount > 0) {
492 flags |= DRAW_VERTICES_HAS_INDICES;
493 }
494
495 addDraw(DRAW_VERTICES);
496 addPaint(paint);
497 addInt(flags);
498 addInt(vmode);
499 addInt(vertexCount);
500 addPoints(vertices, vertexCount);
501 if (flags & DRAW_VERTICES_HAS_TEXS) {
502 addPoints(texs, vertexCount);
503 }
504 if (flags & DRAW_VERTICES_HAS_COLORS) {
505 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
506 }
507 if (flags & DRAW_VERTICES_HAS_INDICES) {
508 addInt(indexCount);
509 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
510 }
511}
512
reed@android.comcb608442009-12-04 21:32:27 +0000513void SkPictureRecord::drawData(const void* data, size_t length) {
514 addDraw(DRAW_DATA);
515 addInt(length);
516 fWriter.writePad(data, length);
517}
518
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000520
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521void SkPictureRecord::reset() {
reed@google.com82065d62011-02-07 15:30:46 +0000522 SkSafeUnref(fPathHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523 fPathHeap = NULL;
524
525 fBitmaps.reset();
junov@chromium.org4866cc02012-06-01 21:23:07 +0000526 fPixelRefDictionary.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000527 fMatrices.reset();
528 fPaints.reset();
529 fPictureRefs.unrefAll();
530 fRegions.reset();
531 fWriter.reset();
532 fHeap.reset();
reed@google.com82065d62011-02-07 15:30:46 +0000533
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534 fRestoreOffsetStack.setCount(1);
535 fRestoreOffsetStack.top() = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000536
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000537 fRCSet.reset();
538 fTFSet.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000539}
540
541void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
junov@chromium.org4866cc02012-06-01 21:23:07 +0000542 addInt(find(bitmap));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000543}
544
545void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
546 addMatrixPtr(&matrix);
547}
548
549void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
reed@google.com83ca3372012-07-12 15:27:54 +0000550 this->addInt(matrix ? fMatrices.find(*matrix) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000551}
552
553void SkPictureRecord::addPaint(const SkPaint& paint) {
554 addPaintPtr(&paint);
555}
556
557void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
reed@google.com83ca3372012-07-12 15:27:54 +0000558 this->addInt(paint ? fPaints.find(*paint, &fRCSet, &fTFSet) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000559}
560
561void SkPictureRecord::addPath(const SkPath& path) {
562 if (NULL == fPathHeap) {
563 fPathHeap = SkNEW(SkPathHeap);
564 }
565 addInt(fPathHeap->append(path));
566}
567
568void SkPictureRecord::addPicture(SkPicture& picture) {
569 int index = fPictureRefs.find(&picture);
570 if (index < 0) { // not found
571 index = fPictureRefs.count();
572 *fPictureRefs.append() = &picture;
573 picture.ref();
574 }
575 // follow the convention of recording a 1-based index
576 addInt(index + 1);
577}
578
579void SkPictureRecord::addPoint(const SkPoint& point) {
580#ifdef SK_DEBUG_SIZE
581 size_t start = fWriter.size();
582#endif
583 fWriter.writePoint(point);
584#ifdef SK_DEBUG_SIZE
585 fPointBytes += fWriter.size() - start;
586 fPointWrites++;
587#endif
588}
reed@google.com82065d62011-02-07 15:30:46 +0000589
reed@android.com8a1c16f2008-12-17 15:59:43 +0000590void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
591 fWriter.writeMul4(pts, count * sizeof(SkPoint));
592#ifdef SK_DEBUG_SIZE
593 fPointBytes += count * sizeof(SkPoint);
594 fPointWrites++;
595#endif
596}
597
598void SkPictureRecord::addRect(const SkRect& rect) {
599#ifdef SK_DEBUG_SIZE
600 size_t start = fWriter.size();
601#endif
602 fWriter.writeRect(rect);
603#ifdef SK_DEBUG_SIZE
604 fRectBytes += fWriter.size() - start;
605 fRectWrites++;
606#endif
607}
608
609void SkPictureRecord::addRectPtr(const SkRect* rect) {
610 if (fWriter.writeBool(rect != NULL)) {
611 fWriter.writeRect(*rect);
612 }
613}
614
reed@google.comf0b5e112011-09-07 11:57:34 +0000615void SkPictureRecord::addIRect(const SkIRect& rect) {
616 fWriter.write(&rect, sizeof(rect));
617}
618
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
620 if (fWriter.writeBool(rect != NULL)) {
621 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
622 }
623}
624
625void SkPictureRecord::addRegion(const SkRegion& region) {
reed@google.com83ca3372012-07-12 15:27:54 +0000626 addInt(fRegions.find(region));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000627}
628
629void SkPictureRecord::addText(const void* text, size_t byteLength) {
630#ifdef SK_DEBUG_SIZE
631 size_t start = fWriter.size();
632#endif
633 addInt(byteLength);
634 fWriter.writePad(text, byteLength);
635#ifdef SK_DEBUG_SIZE
636 fTextBytes += fWriter.size() - start;
637 fTextWrites++;
638#endif
639}
640
641///////////////////////////////////////////////////////////////////////////////
642
junov@chromium.org4866cc02012-06-01 21:23:07 +0000643bool SkPictureRecord::shouldFlattenPixels(const SkBitmap& bitmap) const {
644 return (fRecordFlags &
645 SkPicture::kFlattenMutableNonTexturePixelRefs_RecordingFlag)
646 && !bitmap.isImmutable() && bitmap.pixelRef()
647 && NULL == bitmap.getTexture();
648}
649
650int SkPictureRecord::find(const SkBitmap& bitmap) {
651 int dictionaryIndex = 0;
652 PixelRefDictionaryEntry entry;
653 bool flattenPixels = shouldFlattenPixels(bitmap);
654 if (flattenPixels) {
655 // Flattened bitmap may be very large. First attempt a fast lookup
656 // based on generation ID to avoid unnecessary flattening in
657 // fBitmaps.find()
658 entry.fKey = bitmap.pixelRef()->getGenerationID();
659 dictionaryIndex =
660 SkTSearch<const PixelRefDictionaryEntry>(fPixelRefDictionary.begin(),
661 fPixelRefDictionary.count(), entry, sizeof(entry));
662 if (dictionaryIndex >= 0) {
663 return fPixelRefDictionary[dictionaryIndex].fIndex;
664 }
665 }
666
667 uint32_t writeFlags = flattenPixels ?
668 SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag : 0;
reed@google.com83ca3372012-07-12 15:27:54 +0000669 int index = fBitmaps.find(bitmap, &fRCSet, NULL, writeFlags);
junov@chromium.org4866cc02012-06-01 21:23:07 +0000670
671 if (flattenPixels) {
672 entry.fIndex = index;
673 dictionaryIndex = ~dictionaryIndex;
674 *fPixelRefDictionary.insert(dictionaryIndex) = entry;
675 }
676 return index;
677}
678
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679#ifdef SK_DEBUG_SIZE
680size_t SkPictureRecord::size() const {
681 size_t result = 0;
682 size_t sizeData;
683 bitmaps(&sizeData);
684 result += sizeData;
685 matrices(&sizeData);
686 result += sizeData;
687 paints(&sizeData);
688 result += sizeData;
689 paths(&sizeData);
690 result += sizeData;
691 pictures(&sizeData);
692 result += sizeData;
693 regions(&sizeData);
694 result += sizeData;
695 result += streamlen();
696 return result;
697}
698
699int SkPictureRecord::bitmaps(size_t* size) const {
700 size_t result = 0;
701 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +0000702 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000703 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
704 *size = result;
705 return count;
706}
707
708int SkPictureRecord::matrices(size_t* size) const {
709 int count = fMatrices.count();
710 *size = sizeof(fMatrices[0]) * count;
711 return count;
712}
713
714int SkPictureRecord::paints(size_t* size) const {
715 size_t result = 0;
716 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +0000717 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000718 result += sizeof(fPaints[index]) + fPaints[index]->size();
719 *size = result;
720 return count;
721}
722
723int SkPictureRecord::paths(size_t* size) const {
724 size_t result = 0;
725 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +0000726 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000727 result += sizeof(fPaths[index]) + fPaths[index]->size();
728 *size = result;
729 return count;
730}
731
732int SkPictureRecord::regions(size_t* size) const {
733 size_t result = 0;
734 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +0000735 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000736 result += sizeof(fRegions[index]) + fRegions[index]->size();
737 *size = result;
738 return count;
739}
740
741size_t SkPictureRecord::streamlen() const {
742 return fWriter.size();
743}
744#endif
745
746#ifdef SK_DEBUG_VALIDATE
747void SkPictureRecord::validate() const {
748 validateBitmaps();
749 validateMatrices();
750 validatePaints();
751 validatePaths();
752 validatePictures();
753 validateRegions();
754}
755
756void SkPictureRecord::validateBitmaps() const {
757 int count = fBitmaps.count();
758 SkASSERT((unsigned) count < 0x1000);
759 for (int index = 0; index < count; index++) {
760 const SkFlatBitmap* bitPtr = fBitmaps[index];
761 SkASSERT(bitPtr);
762 bitPtr->validate();
763 }
764}
765
766void SkPictureRecord::validateMatrices() const {
767 int count = fMatrices.count();
768 SkASSERT((unsigned) count < 0x1000);
769 for (int index = 0; index < count; index++) {
770 const SkFlatMatrix* matrix = fMatrices[index];
771 SkASSERT(matrix);
reed@google.com82065d62011-02-07 15:30:46 +0000772 matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773 }
774}
775
776void SkPictureRecord::validatePaints() const {
777 int count = fPaints.count();
778 SkASSERT((unsigned) count < 0x1000);
779 for (int index = 0; index < count; index++) {
780 const SkFlatPaint* paint = fPaints[index];
781 SkASSERT(paint);
782// paint->validate();
783 }
784}
785
786void SkPictureRecord::validatePaths() const {
787 int count = fPaths.count();
788 SkASSERT((unsigned) count < 0x1000);
789 for (int index = 0; index < count; index++) {
790 const SkFlatPath* path = fPaths[index];
791 SkASSERT(path);
792 path->validate();
793 }
794}
795
796void SkPictureRecord::validateRegions() const {
797 int count = fRegions.count();
798 SkASSERT((unsigned) count < 0x1000);
799 for (int index = 0; index < count; index++) {
800 const SkFlatRegion* region = fRegions[index];
801 SkASSERT(region);
802 region->validate();
803 }
804}
805#endif
806