blob: 630a1bb64973834ae8311911d64a0284017b1b75 [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
reed@android.comae814c82009-02-13 14:56:09 +000015SkPictureRecord::SkPictureRecord(uint32_t flags) :
djsollen@google.comd2700ee2012-05-30 16:54:13 +000016 fHeap(HEAP_BLOCK_SIZE),
17 fBitmaps(&fHeap),
18 fMatrices(&fHeap),
19 fPaints(&fHeap),
20 fRegions(&fHeap),
21 fWriter(MIN_WRITER_SIZE),
22 fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000023#ifdef SK_DEBUG_SIZE
24 fPointBytes = fRectBytes = fTextBytes = 0;
25 fPointWrites = fRectWrites = fTextWrites = 0;
26#endif
27
28 fRestoreOffsetStack.setReserve(32);
29 fRestoreOffsetStack.push(0);
reed@google.com82065d62011-02-07 15:30:46 +000030
reed@android.com8a1c16f2008-12-17 15:59:43 +000031 fPathHeap = NULL; // lazy allocate
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000032 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@android.com8a1c16f2008-12-17 15:59:43 +000033}
34
35SkPictureRecord::~SkPictureRecord() {
36 reset();
37}
38
39///////////////////////////////////////////////////////////////////////////////
40
41int SkPictureRecord::save(SaveFlags flags) {
42 addDraw(SAVE);
43 addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +000044
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 fRestoreOffsetStack.push(0);
reed@google.com82065d62011-02-07 15:30:46 +000046
reed@android.com8a1c16f2008-12-17 15:59:43 +000047 validate();
48 return this->INHERITED::save(flags);
49}
50
51int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
52 SaveFlags flags) {
53 addDraw(SAVE_LAYER);
54 addRectPtr(bounds);
55 addPaintPtr(paint);
56 addInt(flags);
57
58 fRestoreOffsetStack.push(0);
59
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000060 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
61 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
62 }
63
reed@android.com8a1c16f2008-12-17 15:59:43 +000064 validate();
reed@android.com261ae4d2009-10-02 16:37:46 +000065 /* Don't actually call saveLayer, because that will try to allocate an
66 offscreen device (potentially very big) which we don't actually need
67 at this time (and may not be able to afford since during record our
68 clip starts out the size of the picture, which is often much larger
69 than the size of the actual device we'll use during playback).
70 */
junov@chromium.orga907ac32012-02-24 21:54:07 +000071 int count = this->INHERITED::save(flags);
72 this->clipRectBounds(bounds, flags, NULL);
73 return count;
reed@android.com8a1c16f2008-12-17 15:59:43 +000074}
75
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000076bool SkPictureRecord::isDrawingToLayer() const {
77 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
78}
79
reed@android.com8a1c16f2008-12-17 15:59:43 +000080void SkPictureRecord::restore() {
reed@android.comb4e22d62009-07-09 15:20:25 +000081 // check for underflow
82 if (fRestoreOffsetStack.count() == 0) {
83 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 }
reed@android.comb4e22d62009-07-09 15:20:25 +000085
junov@chromium.orge3dbedb2012-07-09 16:03:55 +000086 fillRestoreOffsetPlaceholdersForCurrentStackLevel(
87 (uint32_t)fWriter.size());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000088
89 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
90 fFirstSavedLayerIndex = kNoSavedLayerIndex;
91 }
92
reed@android.comb4e22d62009-07-09 15:20:25 +000093 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +000094
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 addDraw(RESTORE);
96 validate();
97 return this->INHERITED::restore();
98}
99
100bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
101 addDraw(TRANSLATE);
102 addScalar(dx);
103 addScalar(dy);
104 validate();
105 return this->INHERITED::translate(dx, dy);
106}
107
108bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
reed@google.com82065d62011-02-07 15:30:46 +0000109 addDraw(SCALE);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110 addScalar(sx);
111 addScalar(sy);
112 validate();
113 return this->INHERITED::scale(sx, sy);
114}
115
116bool SkPictureRecord::rotate(SkScalar degrees) {
reed@google.com82065d62011-02-07 15:30:46 +0000117 addDraw(ROTATE);
118 addScalar(degrees);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119 validate();
120 return this->INHERITED::rotate(degrees);
121}
122
123bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
reed@google.com82065d62011-02-07 15:30:46 +0000124 addDraw(SKEW);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125 addScalar(sx);
126 addScalar(sy);
127 validate();
128 return this->INHERITED::skew(sx, sy);
129}
130
131bool SkPictureRecord::concat(const SkMatrix& matrix) {
132 validate();
133 addDraw(CONCAT);
134 addMatrix(matrix);
135 validate();
136 return this->INHERITED::concat(matrix);
137}
138
reed@android.com6e073b92009-01-06 15:03:30 +0000139void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
140 validate();
141 addDraw(SET_MATRIX);
142 addMatrix(matrix);
143 validate();
144 this->INHERITED::setMatrix(matrix);
145}
146
reed@google.com45482d12011-08-29 19:02:39 +0000147static bool regionOpExpands(SkRegion::Op op) {
148 switch (op) {
149 case SkRegion::kUnion_Op:
150 case SkRegion::kXOR_Op:
151 case SkRegion::kReverseDifference_Op:
152 case SkRegion::kReplace_Op:
153 return true;
154 case SkRegion::kIntersect_Op:
155 case SkRegion::kDifference_Op:
156 return false;
157 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000158 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000159 return false;
160 }
161}
162
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000163void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(
164 uint32_t restoreOffset) {
165 uint32_t offset = fRestoreOffsetStack.top();
166 while (offset) {
167 uint32_t* peek = fWriter.peek32(offset);
168 offset = *peek;
169 *peek = restoreOffset;
170 }
171}
172
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000173void SkPictureRecord::endRecording() {
174 // clear any remaining unhandled restore offset placeholders
175 while (fRestoreOffsetStack.count()) {
176 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
177 fRestoreOffsetStack.pop();
178 }
179}
180
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000181void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com45482d12011-08-29 19:02:39 +0000182 if (regionOpExpands(op)) {
183 // Run back through any previous clip ops, and mark their offset to
184 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
185 // they could hide this clips ability to expand the clip (i.e. go from
186 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000187 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
reed@google.com45482d12011-08-29 19:02:39 +0000188 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000189
reed@google.com45482d12011-08-29 19:02:39 +0000190 size_t offset = fWriter.size();
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000191 // The RestoreOffset field is initially filled with a placeholder
192 // value that points to the offset of the previous RestoreOffset
193 // in the current stack level, thus forming a linked list so that
194 // the restore offsets can be filled in when the corresponding
195 // restore command is recorded.
reed@google.com45482d12011-08-29 19:02:39 +0000196 addInt(fRestoreOffsetStack.top());
197 fRestoreOffsetStack.top() = offset;
198}
199
reed@google.com071eef92011-10-12 11:52:53 +0000200bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 addDraw(CLIP_RECT);
202 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000203 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000204 recordRestoreOffsetPlaceholder(op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205
206 validate();
reed@google.com071eef92011-10-12 11:52:53 +0000207 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208}
209
reed@google.com071eef92011-10-12 11:52:53 +0000210bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211 addDraw(CLIP_PATH);
212 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000213 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000214 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000215
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 validate();
reed@google.com82065d62011-02-07 15:30:46 +0000217
reed@android.comae814c82009-02-13 14:56:09 +0000218 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
reed@google.com071eef92011-10-12 11:52:53 +0000219 return this->INHERITED::clipRect(path.getBounds(), op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000220 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000221 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000222 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223}
224
225bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
reed@google.com82065d62011-02-07 15:30:46 +0000226 addDraw(CLIP_REGION);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000228 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000229 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000230
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 validate();
232 return this->INHERITED::clipRegion(region, op);
233}
234
reed@google.com2a981812011-04-14 18:59:28 +0000235void SkPictureRecord::clear(SkColor color) {
236 addDraw(DRAW_CLEAR);
237 addInt(color);
238 validate();
239}
240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241void SkPictureRecord::drawPaint(const SkPaint& paint) {
242 addDraw(DRAW_PAINT);
243 addPaint(paint);
244 validate();
245}
246
247void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
248 const SkPaint& paint) {
249 addDraw(DRAW_POINTS);
250 addPaint(paint);
251 addInt(mode);
252 addInt(count);
253 fWriter.writeMul4(pts, count * sizeof(SkPoint));
254 validate();
255}
256
257void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
258 addDraw(DRAW_RECT);
259 addPaint(paint);
260 addRect(rect);
261 validate();
262}
263
264void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
265 addDraw(DRAW_PATH);
266 addPaint(paint);
267 addPath(path);
268 validate();
269}
270
271void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
272 const SkPaint* paint = NULL) {
273 addDraw(DRAW_BITMAP);
274 addPaintPtr(paint);
275 addBitmap(bitmap);
276 addScalar(left);
277 addScalar(top);
278 validate();
279}
280
281void SkPictureRecord::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
282 const SkRect& dst, const SkPaint* paint) {
283 addDraw(DRAW_BITMAP_RECT);
284 addPaintPtr(paint);
285 addBitmap(bitmap);
286 addIRectPtr(src); // may be null
287 addRect(dst);
288 validate();
289}
290
291void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000292 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293 addDraw(DRAW_BITMAP_MATRIX);
294 addPaintPtr(paint);
295 addBitmap(bitmap);
296 addMatrix(matrix);
297 validate();
298}
299
reed@google.comf0b5e112011-09-07 11:57:34 +0000300void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
301 const SkRect& dst, const SkPaint* paint) {
302 addDraw(DRAW_BITMAP_NINE);
303 addPaintPtr(paint);
304 addBitmap(bitmap);
305 addIRect(center);
306 addRect(dst);
307 validate();
308}
309
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
311 const SkPaint* paint = NULL) {
312 addDraw(DRAW_SPRITE);
313 addPaintPtr(paint);
314 addBitmap(bitmap);
315 addInt(left);
316 addInt(top);
317 validate();
318}
319
320void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint,
reed@google.com9efd9a02012-01-30 15:41:43 +0000321 SkScalar minY, SkScalar maxY) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322 SkPaint::FontMetrics metrics;
323 paint.getFontMetrics(&metrics);
324 SkRect bounds;
325 // construct a rect so we can see any adjustments from the paint.
326 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com9efd9a02012-01-30 15:41:43 +0000327 bounds.set(0, metrics.fTop + minY,
328 SK_Scalar1, metrics.fBottom + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 (void)paint.computeFastBounds(bounds, &bounds);
330 // now record the top and bottom
331 addScalar(bounds.fTop);
332 addScalar(bounds.fBottom);
333}
334
reed@google.com82065d62011-02-07 15:30:46 +0000335void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +0000337 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +0000338
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT);
340 addPaint(paint);
341 addText(text, byteLength);
342 addScalar(x);
343 addScalar(y);
344 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000345 addFontMetricsTopBottom(paint, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346 }
347 validate();
348}
349
reed@google.com82065d62011-02-07 15:30:46 +0000350void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 const SkPoint pos[], const SkPaint& paint) {
352 size_t points = paint.countText(text, byteLength);
353 if (0 == points)
354 return;
355
356 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +0000357 SkScalar minY = pos[0].fY;
358 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359 // check if the caller really should have used drawPosTextH()
360 {
361 const SkScalar firstY = pos[0].fY;
362 for (size_t index = 1; index < points; index++) {
363 if (pos[index].fY != firstY) {
364 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +0000365 if (pos[index].fY < minY) {
366 minY = pos[index].fY;
367 } else if (pos[index].fY > maxY) {
368 maxY = pos[index].fY;
369 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 }
371 }
372 }
reed@google.com82065d62011-02-07 15:30:46 +0000373
reed@google.com2eb5bb12012-04-12 14:27:42 +0000374 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +0000375 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376
377 if (fast) {
378 addDraw(DRAW_POS_TEXT_H_TOP_BOTTOM);
reed@google.com9efd9a02012-01-30 15:41:43 +0000379 } else if (canUseDrawH) {
380 addDraw(DRAW_POS_TEXT_H);
381 } else if (fastBounds) {
382 addDraw(DRAW_POS_TEXT_TOP_BOTTOM);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383 } else {
reed@google.com9efd9a02012-01-30 15:41:43 +0000384 addDraw(DRAW_POS_TEXT);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000385 }
386 addPaint(paint);
387 addText(text, byteLength);
388 addInt(points);
389
390#ifdef SK_DEBUG_SIZE
391 size_t start = fWriter.size();
392#endif
393 if (canUseDrawH) {
394 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000395 addFontMetricsTopBottom(paint, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000396 }
397 addScalar(pos[0].fY);
398 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +0000399 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400 *xptr++ = pos[index].fX;
401 }
402 else {
403 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +0000404 if (fastBounds) {
405 addFontMetricsTopBottom(paint, minY, maxY);
406 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000407 }
408#ifdef SK_DEBUG_SIZE
409 fPointBytes += fWriter.size() - start;
410 fPointWrites += points;
411#endif
412 validate();
413}
414
415void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
416 const SkScalar xpos[], SkScalar constY,
417 const SkPaint& paint) {
418 size_t points = paint.countText(text, byteLength);
419 if (0 == points)
420 return;
reed@google.com82065d62011-02-07 15:30:46 +0000421
reed@google.com2eb5bb12012-04-12 14:27:42 +0000422 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000423
424 addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H);
425 addPaint(paint);
426 addText(text, byteLength);
427 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +0000428
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429#ifdef SK_DEBUG_SIZE
430 size_t start = fWriter.size();
431#endif
432 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000433 addFontMetricsTopBottom(paint, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434 }
435 addScalar(constY);
436 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
437#ifdef SK_DEBUG_SIZE
438 fPointBytes += fWriter.size() - start;
439 fPointWrites += points;
440#endif
441 validate();
442}
443
reed@google.com82065d62011-02-07 15:30:46 +0000444void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
445 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446 const SkPaint& paint) {
447 addDraw(DRAW_TEXT_ON_PATH);
448 addPaint(paint);
449 addText(text, byteLength);
450 addPath(path);
451 addMatrixPtr(matrix);
452 validate();
453}
454
455void SkPictureRecord::drawPicture(SkPicture& picture) {
456 addDraw(DRAW_PICTURE);
457 addPicture(picture);
458 validate();
459}
460
461void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
462 const SkPoint vertices[], const SkPoint texs[],
463 const SkColor colors[], SkXfermode*,
464 const uint16_t indices[], int indexCount,
465 const SkPaint& paint) {
466 uint32_t flags = 0;
467 if (texs) {
468 flags |= DRAW_VERTICES_HAS_TEXS;
469 }
470 if (colors) {
471 flags |= DRAW_VERTICES_HAS_COLORS;
472 }
473 if (indexCount > 0) {
474 flags |= DRAW_VERTICES_HAS_INDICES;
475 }
476
477 addDraw(DRAW_VERTICES);
478 addPaint(paint);
479 addInt(flags);
480 addInt(vmode);
481 addInt(vertexCount);
482 addPoints(vertices, vertexCount);
483 if (flags & DRAW_VERTICES_HAS_TEXS) {
484 addPoints(texs, vertexCount);
485 }
486 if (flags & DRAW_VERTICES_HAS_COLORS) {
487 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
488 }
489 if (flags & DRAW_VERTICES_HAS_INDICES) {
490 addInt(indexCount);
491 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
492 }
493}
494
reed@android.comcb608442009-12-04 21:32:27 +0000495void SkPictureRecord::drawData(const void* data, size_t length) {
496 addDraw(DRAW_DATA);
497 addInt(length);
498 fWriter.writePad(data, length);
499}
500
reed@android.com8a1c16f2008-12-17 15:59:43 +0000501///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000502
reed@android.com8a1c16f2008-12-17 15:59:43 +0000503void SkPictureRecord::reset() {
reed@google.com82065d62011-02-07 15:30:46 +0000504 SkSafeUnref(fPathHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000505 fPathHeap = NULL;
506
507 fBitmaps.reset();
junov@chromium.org4866cc02012-06-01 21:23:07 +0000508 fPixelRefDictionary.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 fMatrices.reset();
510 fPaints.reset();
511 fPictureRefs.unrefAll();
512 fRegions.reset();
513 fWriter.reset();
514 fHeap.reset();
reed@google.com82065d62011-02-07 15:30:46 +0000515
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 fRestoreOffsetStack.setCount(1);
517 fRestoreOffsetStack.top() = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000518
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000519 fRCSet.reset();
520 fTFSet.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521}
522
523void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
junov@chromium.org4866cc02012-06-01 21:23:07 +0000524 addInt(find(bitmap));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525}
526
527void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
528 addMatrixPtr(&matrix);
529}
530
531void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
reed@google.com83ca3372012-07-12 15:27:54 +0000532 this->addInt(matrix ? fMatrices.find(*matrix) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000533}
534
535void SkPictureRecord::addPaint(const SkPaint& paint) {
536 addPaintPtr(&paint);
537}
538
539void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
reed@google.com83ca3372012-07-12 15:27:54 +0000540 this->addInt(paint ? fPaints.find(*paint, &fRCSet, &fTFSet) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000541}
542
543void SkPictureRecord::addPath(const SkPath& path) {
544 if (NULL == fPathHeap) {
545 fPathHeap = SkNEW(SkPathHeap);
546 }
547 addInt(fPathHeap->append(path));
548}
549
550void SkPictureRecord::addPicture(SkPicture& picture) {
551 int index = fPictureRefs.find(&picture);
552 if (index < 0) { // not found
553 index = fPictureRefs.count();
554 *fPictureRefs.append() = &picture;
555 picture.ref();
556 }
557 // follow the convention of recording a 1-based index
558 addInt(index + 1);
559}
560
561void SkPictureRecord::addPoint(const SkPoint& point) {
562#ifdef SK_DEBUG_SIZE
563 size_t start = fWriter.size();
564#endif
565 fWriter.writePoint(point);
566#ifdef SK_DEBUG_SIZE
567 fPointBytes += fWriter.size() - start;
568 fPointWrites++;
569#endif
570}
reed@google.com82065d62011-02-07 15:30:46 +0000571
reed@android.com8a1c16f2008-12-17 15:59:43 +0000572void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
573 fWriter.writeMul4(pts, count * sizeof(SkPoint));
574#ifdef SK_DEBUG_SIZE
575 fPointBytes += count * sizeof(SkPoint);
576 fPointWrites++;
577#endif
578}
579
580void SkPictureRecord::addRect(const SkRect& rect) {
581#ifdef SK_DEBUG_SIZE
582 size_t start = fWriter.size();
583#endif
584 fWriter.writeRect(rect);
585#ifdef SK_DEBUG_SIZE
586 fRectBytes += fWriter.size() - start;
587 fRectWrites++;
588#endif
589}
590
591void SkPictureRecord::addRectPtr(const SkRect* rect) {
592 if (fWriter.writeBool(rect != NULL)) {
593 fWriter.writeRect(*rect);
594 }
595}
596
reed@google.comf0b5e112011-09-07 11:57:34 +0000597void SkPictureRecord::addIRect(const SkIRect& rect) {
598 fWriter.write(&rect, sizeof(rect));
599}
600
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
602 if (fWriter.writeBool(rect != NULL)) {
603 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
604 }
605}
606
607void SkPictureRecord::addRegion(const SkRegion& region) {
reed@google.com83ca3372012-07-12 15:27:54 +0000608 addInt(fRegions.find(region));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000609}
610
611void SkPictureRecord::addText(const void* text, size_t byteLength) {
612#ifdef SK_DEBUG_SIZE
613 size_t start = fWriter.size();
614#endif
615 addInt(byteLength);
616 fWriter.writePad(text, byteLength);
617#ifdef SK_DEBUG_SIZE
618 fTextBytes += fWriter.size() - start;
619 fTextWrites++;
620#endif
621}
622
623///////////////////////////////////////////////////////////////////////////////
624
junov@chromium.org4866cc02012-06-01 21:23:07 +0000625bool SkPictureRecord::shouldFlattenPixels(const SkBitmap& bitmap) const {
626 return (fRecordFlags &
627 SkPicture::kFlattenMutableNonTexturePixelRefs_RecordingFlag)
628 && !bitmap.isImmutable() && bitmap.pixelRef()
629 && NULL == bitmap.getTexture();
630}
631
632int SkPictureRecord::find(const SkBitmap& bitmap) {
633 int dictionaryIndex = 0;
634 PixelRefDictionaryEntry entry;
635 bool flattenPixels = shouldFlattenPixels(bitmap);
636 if (flattenPixels) {
637 // Flattened bitmap may be very large. First attempt a fast lookup
638 // based on generation ID to avoid unnecessary flattening in
639 // fBitmaps.find()
640 entry.fKey = bitmap.pixelRef()->getGenerationID();
641 dictionaryIndex =
642 SkTSearch<const PixelRefDictionaryEntry>(fPixelRefDictionary.begin(),
643 fPixelRefDictionary.count(), entry, sizeof(entry));
644 if (dictionaryIndex >= 0) {
645 return fPixelRefDictionary[dictionaryIndex].fIndex;
646 }
647 }
648
649 uint32_t writeFlags = flattenPixels ?
650 SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag : 0;
reed@google.com83ca3372012-07-12 15:27:54 +0000651 int index = fBitmaps.find(bitmap, &fRCSet, NULL, writeFlags);
junov@chromium.org4866cc02012-06-01 21:23:07 +0000652
653 if (flattenPixels) {
654 entry.fIndex = index;
655 dictionaryIndex = ~dictionaryIndex;
656 *fPixelRefDictionary.insert(dictionaryIndex) = entry;
657 }
658 return index;
659}
660
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661#ifdef SK_DEBUG_SIZE
662size_t SkPictureRecord::size() const {
663 size_t result = 0;
664 size_t sizeData;
665 bitmaps(&sizeData);
666 result += sizeData;
667 matrices(&sizeData);
668 result += sizeData;
669 paints(&sizeData);
670 result += sizeData;
671 paths(&sizeData);
672 result += sizeData;
673 pictures(&sizeData);
674 result += sizeData;
675 regions(&sizeData);
676 result += sizeData;
677 result += streamlen();
678 return result;
679}
680
681int SkPictureRecord::bitmaps(size_t* size) const {
682 size_t result = 0;
683 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +0000684 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000685 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
686 *size = result;
687 return count;
688}
689
690int SkPictureRecord::matrices(size_t* size) const {
691 int count = fMatrices.count();
692 *size = sizeof(fMatrices[0]) * count;
693 return count;
694}
695
696int SkPictureRecord::paints(size_t* size) const {
697 size_t result = 0;
698 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +0000699 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000700 result += sizeof(fPaints[index]) + fPaints[index]->size();
701 *size = result;
702 return count;
703}
704
705int SkPictureRecord::paths(size_t* size) const {
706 size_t result = 0;
707 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +0000708 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000709 result += sizeof(fPaths[index]) + fPaths[index]->size();
710 *size = result;
711 return count;
712}
713
714int SkPictureRecord::regions(size_t* size) const {
715 size_t result = 0;
716 int count = fRegions.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(fRegions[index]) + fRegions[index]->size();
719 *size = result;
720 return count;
721}
722
723size_t SkPictureRecord::streamlen() const {
724 return fWriter.size();
725}
726#endif
727
728#ifdef SK_DEBUG_VALIDATE
729void SkPictureRecord::validate() const {
730 validateBitmaps();
731 validateMatrices();
732 validatePaints();
733 validatePaths();
734 validatePictures();
735 validateRegions();
736}
737
738void SkPictureRecord::validateBitmaps() const {
739 int count = fBitmaps.count();
740 SkASSERT((unsigned) count < 0x1000);
741 for (int index = 0; index < count; index++) {
742 const SkFlatBitmap* bitPtr = fBitmaps[index];
743 SkASSERT(bitPtr);
744 bitPtr->validate();
745 }
746}
747
748void SkPictureRecord::validateMatrices() const {
749 int count = fMatrices.count();
750 SkASSERT((unsigned) count < 0x1000);
751 for (int index = 0; index < count; index++) {
752 const SkFlatMatrix* matrix = fMatrices[index];
753 SkASSERT(matrix);
reed@google.com82065d62011-02-07 15:30:46 +0000754 matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000755 }
756}
757
758void SkPictureRecord::validatePaints() const {
759 int count = fPaints.count();
760 SkASSERT((unsigned) count < 0x1000);
761 for (int index = 0; index < count; index++) {
762 const SkFlatPaint* paint = fPaints[index];
763 SkASSERT(paint);
764// paint->validate();
765 }
766}
767
768void SkPictureRecord::validatePaths() const {
769 int count = fPaths.count();
770 SkASSERT((unsigned) count < 0x1000);
771 for (int index = 0; index < count; index++) {
772 const SkFlatPath* path = fPaths[index];
773 SkASSERT(path);
774 path->validate();
775 }
776}
777
778void SkPictureRecord::validateRegions() const {
779 int count = fRegions.count();
780 SkASSERT((unsigned) count < 0x1000);
781 for (int index = 0; index < count; index++) {
782 const SkFlatRegion* region = fRegions[index];
783 SkASSERT(region);
784 region->validate();
785 }
786}
787#endif
788