blob: a55c9afe9a84db7303cfce1f794cd060a3f190ee [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
173void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com45482d12011-08-29 19:02:39 +0000174 if (regionOpExpands(op)) {
175 // Run back through any previous clip ops, and mark their offset to
176 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
177 // they could hide this clips ability to expand the clip (i.e. go from
178 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000179 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
reed@google.com45482d12011-08-29 19:02:39 +0000180 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000181
reed@google.com45482d12011-08-29 19:02:39 +0000182 size_t offset = fWriter.size();
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000183 // The RestoreOffset field is initially filled with a placeholder
184 // value that points to the offset of the previous RestoreOffset
185 // in the current stack level, thus forming a linked list so that
186 // the restore offsets can be filled in when the corresponding
187 // restore command is recorded.
reed@google.com45482d12011-08-29 19:02:39 +0000188 addInt(fRestoreOffsetStack.top());
189 fRestoreOffsetStack.top() = offset;
190}
191
reed@google.com071eef92011-10-12 11:52:53 +0000192bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193 addDraw(CLIP_RECT);
194 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000195 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000196 recordRestoreOffsetPlaceholder(op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197
198 validate();
reed@google.com071eef92011-10-12 11:52:53 +0000199 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200}
201
reed@google.com071eef92011-10-12 11:52:53 +0000202bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 addDraw(CLIP_PATH);
204 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000205 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000206 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000207
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 validate();
reed@google.com82065d62011-02-07 15:30:46 +0000209
reed@android.comae814c82009-02-13 14:56:09 +0000210 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
reed@google.com071eef92011-10-12 11:52:53 +0000211 return this->INHERITED::clipRect(path.getBounds(), op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000212 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000213 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000214 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215}
216
217bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
reed@google.com82065d62011-02-07 15:30:46 +0000218 addDraw(CLIP_REGION);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000220 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000221 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000222
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 validate();
224 return this->INHERITED::clipRegion(region, op);
225}
226
reed@google.com2a981812011-04-14 18:59:28 +0000227void SkPictureRecord::clear(SkColor color) {
228 addDraw(DRAW_CLEAR);
229 addInt(color);
230 validate();
231}
232
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233void SkPictureRecord::drawPaint(const SkPaint& paint) {
234 addDraw(DRAW_PAINT);
235 addPaint(paint);
236 validate();
237}
238
239void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
240 const SkPaint& paint) {
241 addDraw(DRAW_POINTS);
242 addPaint(paint);
243 addInt(mode);
244 addInt(count);
245 fWriter.writeMul4(pts, count * sizeof(SkPoint));
246 validate();
247}
248
249void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
250 addDraw(DRAW_RECT);
251 addPaint(paint);
252 addRect(rect);
253 validate();
254}
255
256void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
257 addDraw(DRAW_PATH);
258 addPaint(paint);
259 addPath(path);
260 validate();
261}
262
263void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
264 const SkPaint* paint = NULL) {
265 addDraw(DRAW_BITMAP);
266 addPaintPtr(paint);
267 addBitmap(bitmap);
268 addScalar(left);
269 addScalar(top);
270 validate();
271}
272
273void SkPictureRecord::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
274 const SkRect& dst, const SkPaint* paint) {
275 addDraw(DRAW_BITMAP_RECT);
276 addPaintPtr(paint);
277 addBitmap(bitmap);
278 addIRectPtr(src); // may be null
279 addRect(dst);
280 validate();
281}
282
283void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000284 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 addDraw(DRAW_BITMAP_MATRIX);
286 addPaintPtr(paint);
287 addBitmap(bitmap);
288 addMatrix(matrix);
289 validate();
290}
291
reed@google.comf0b5e112011-09-07 11:57:34 +0000292void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
293 const SkRect& dst, const SkPaint* paint) {
294 addDraw(DRAW_BITMAP_NINE);
295 addPaintPtr(paint);
296 addBitmap(bitmap);
297 addIRect(center);
298 addRect(dst);
299 validate();
300}
301
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
303 const SkPaint* paint = NULL) {
304 addDraw(DRAW_SPRITE);
305 addPaintPtr(paint);
306 addBitmap(bitmap);
307 addInt(left);
308 addInt(top);
309 validate();
310}
311
312void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint,
reed@google.com9efd9a02012-01-30 15:41:43 +0000313 SkScalar minY, SkScalar maxY) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314 SkPaint::FontMetrics metrics;
315 paint.getFontMetrics(&metrics);
316 SkRect bounds;
317 // construct a rect so we can see any adjustments from the paint.
318 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com9efd9a02012-01-30 15:41:43 +0000319 bounds.set(0, metrics.fTop + minY,
320 SK_Scalar1, metrics.fBottom + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321 (void)paint.computeFastBounds(bounds, &bounds);
322 // now record the top and bottom
323 addScalar(bounds.fTop);
324 addScalar(bounds.fBottom);
325}
326
reed@google.com82065d62011-02-07 15:30:46 +0000327void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +0000329 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +0000330
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT);
332 addPaint(paint);
333 addText(text, byteLength);
334 addScalar(x);
335 addScalar(y);
336 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000337 addFontMetricsTopBottom(paint, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 }
339 validate();
340}
341
reed@google.com82065d62011-02-07 15:30:46 +0000342void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343 const SkPoint pos[], const SkPaint& paint) {
344 size_t points = paint.countText(text, byteLength);
345 if (0 == points)
346 return;
347
348 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +0000349 SkScalar minY = pos[0].fY;
350 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 // check if the caller really should have used drawPosTextH()
352 {
353 const SkScalar firstY = pos[0].fY;
354 for (size_t index = 1; index < points; index++) {
355 if (pos[index].fY != firstY) {
356 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +0000357 if (pos[index].fY < minY) {
358 minY = pos[index].fY;
359 } else if (pos[index].fY > maxY) {
360 maxY = pos[index].fY;
361 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 }
363 }
364 }
reed@google.com82065d62011-02-07 15:30:46 +0000365
reed@google.com2eb5bb12012-04-12 14:27:42 +0000366 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +0000367 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368
369 if (fast) {
370 addDraw(DRAW_POS_TEXT_H_TOP_BOTTOM);
reed@google.com9efd9a02012-01-30 15:41:43 +0000371 } else if (canUseDrawH) {
372 addDraw(DRAW_POS_TEXT_H);
373 } else if (fastBounds) {
374 addDraw(DRAW_POS_TEXT_TOP_BOTTOM);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375 } else {
reed@google.com9efd9a02012-01-30 15:41:43 +0000376 addDraw(DRAW_POS_TEXT);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377 }
378 addPaint(paint);
379 addText(text, byteLength);
380 addInt(points);
381
382#ifdef SK_DEBUG_SIZE
383 size_t start = fWriter.size();
384#endif
385 if (canUseDrawH) {
386 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000387 addFontMetricsTopBottom(paint, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388 }
389 addScalar(pos[0].fY);
390 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +0000391 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392 *xptr++ = pos[index].fX;
393 }
394 else {
395 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +0000396 if (fastBounds) {
397 addFontMetricsTopBottom(paint, minY, maxY);
398 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000399 }
400#ifdef SK_DEBUG_SIZE
401 fPointBytes += fWriter.size() - start;
402 fPointWrites += points;
403#endif
404 validate();
405}
406
407void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
408 const SkScalar xpos[], SkScalar constY,
409 const SkPaint& paint) {
410 size_t points = paint.countText(text, byteLength);
411 if (0 == points)
412 return;
reed@google.com82065d62011-02-07 15:30:46 +0000413
reed@google.com2eb5bb12012-04-12 14:27:42 +0000414 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000415
416 addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H);
417 addPaint(paint);
418 addText(text, byteLength);
419 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +0000420
reed@android.com8a1c16f2008-12-17 15:59:43 +0000421#ifdef SK_DEBUG_SIZE
422 size_t start = fWriter.size();
423#endif
424 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000425 addFontMetricsTopBottom(paint, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426 }
427 addScalar(constY);
428 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
429#ifdef SK_DEBUG_SIZE
430 fPointBytes += fWriter.size() - start;
431 fPointWrites += points;
432#endif
433 validate();
434}
435
reed@google.com82065d62011-02-07 15:30:46 +0000436void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
437 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438 const SkPaint& paint) {
439 addDraw(DRAW_TEXT_ON_PATH);
440 addPaint(paint);
441 addText(text, byteLength);
442 addPath(path);
443 addMatrixPtr(matrix);
444 validate();
445}
446
447void SkPictureRecord::drawPicture(SkPicture& picture) {
448 addDraw(DRAW_PICTURE);
449 addPicture(picture);
450 validate();
451}
452
453void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
454 const SkPoint vertices[], const SkPoint texs[],
455 const SkColor colors[], SkXfermode*,
456 const uint16_t indices[], int indexCount,
457 const SkPaint& paint) {
458 uint32_t flags = 0;
459 if (texs) {
460 flags |= DRAW_VERTICES_HAS_TEXS;
461 }
462 if (colors) {
463 flags |= DRAW_VERTICES_HAS_COLORS;
464 }
465 if (indexCount > 0) {
466 flags |= DRAW_VERTICES_HAS_INDICES;
467 }
468
469 addDraw(DRAW_VERTICES);
470 addPaint(paint);
471 addInt(flags);
472 addInt(vmode);
473 addInt(vertexCount);
474 addPoints(vertices, vertexCount);
475 if (flags & DRAW_VERTICES_HAS_TEXS) {
476 addPoints(texs, vertexCount);
477 }
478 if (flags & DRAW_VERTICES_HAS_COLORS) {
479 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
480 }
481 if (flags & DRAW_VERTICES_HAS_INDICES) {
482 addInt(indexCount);
483 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
484 }
485}
486
reed@android.comcb608442009-12-04 21:32:27 +0000487void SkPictureRecord::drawData(const void* data, size_t length) {
488 addDraw(DRAW_DATA);
489 addInt(length);
490 fWriter.writePad(data, length);
491}
492
reed@android.com8a1c16f2008-12-17 15:59:43 +0000493///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000494
reed@android.com8a1c16f2008-12-17 15:59:43 +0000495void SkPictureRecord::reset() {
reed@google.com82065d62011-02-07 15:30:46 +0000496 SkSafeUnref(fPathHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497 fPathHeap = NULL;
498
499 fBitmaps.reset();
junov@chromium.org4866cc02012-06-01 21:23:07 +0000500 fPixelRefDictionary.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000501 fMatrices.reset();
502 fPaints.reset();
503 fPictureRefs.unrefAll();
504 fRegions.reset();
505 fWriter.reset();
506 fHeap.reset();
reed@google.com82065d62011-02-07 15:30:46 +0000507
reed@android.com8a1c16f2008-12-17 15:59:43 +0000508 fRestoreOffsetStack.setCount(1);
509 fRestoreOffsetStack.top() = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000510
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000511 fRCSet.reset();
512 fTFSet.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000513}
514
515void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
junov@chromium.org4866cc02012-06-01 21:23:07 +0000516 addInt(find(bitmap));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517}
518
519void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
520 addMatrixPtr(&matrix);
521}
522
523void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000524 addInt(fMatrices.find(matrix));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525}
526
527void SkPictureRecord::addPaint(const SkPaint& paint) {
528 addPaintPtr(&paint);
529}
530
531void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000532 addInt(fPaints.find(paint, &fRCSet, &fTFSet));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000533}
534
535void SkPictureRecord::addPath(const SkPath& path) {
536 if (NULL == fPathHeap) {
537 fPathHeap = SkNEW(SkPathHeap);
538 }
539 addInt(fPathHeap->append(path));
540}
541
542void SkPictureRecord::addPicture(SkPicture& picture) {
543 int index = fPictureRefs.find(&picture);
544 if (index < 0) { // not found
545 index = fPictureRefs.count();
546 *fPictureRefs.append() = &picture;
547 picture.ref();
548 }
549 // follow the convention of recording a 1-based index
550 addInt(index + 1);
551}
552
553void SkPictureRecord::addPoint(const SkPoint& point) {
554#ifdef SK_DEBUG_SIZE
555 size_t start = fWriter.size();
556#endif
557 fWriter.writePoint(point);
558#ifdef SK_DEBUG_SIZE
559 fPointBytes += fWriter.size() - start;
560 fPointWrites++;
561#endif
562}
reed@google.com82065d62011-02-07 15:30:46 +0000563
reed@android.com8a1c16f2008-12-17 15:59:43 +0000564void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
565 fWriter.writeMul4(pts, count * sizeof(SkPoint));
566#ifdef SK_DEBUG_SIZE
567 fPointBytes += count * sizeof(SkPoint);
568 fPointWrites++;
569#endif
570}
571
572void SkPictureRecord::addRect(const SkRect& rect) {
573#ifdef SK_DEBUG_SIZE
574 size_t start = fWriter.size();
575#endif
576 fWriter.writeRect(rect);
577#ifdef SK_DEBUG_SIZE
578 fRectBytes += fWriter.size() - start;
579 fRectWrites++;
580#endif
581}
582
583void SkPictureRecord::addRectPtr(const SkRect* rect) {
584 if (fWriter.writeBool(rect != NULL)) {
585 fWriter.writeRect(*rect);
586 }
587}
588
reed@google.comf0b5e112011-09-07 11:57:34 +0000589void SkPictureRecord::addIRect(const SkIRect& rect) {
590 fWriter.write(&rect, sizeof(rect));
591}
592
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
594 if (fWriter.writeBool(rect != NULL)) {
595 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
596 }
597}
598
599void SkPictureRecord::addRegion(const SkRegion& region) {
djsollen@google.comd2700ee2012-05-30 16:54:13 +0000600 addInt(fRegions.find(&region));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601}
602
603void SkPictureRecord::addText(const void* text, size_t byteLength) {
604#ifdef SK_DEBUG_SIZE
605 size_t start = fWriter.size();
606#endif
607 addInt(byteLength);
608 fWriter.writePad(text, byteLength);
609#ifdef SK_DEBUG_SIZE
610 fTextBytes += fWriter.size() - start;
611 fTextWrites++;
612#endif
613}
614
615///////////////////////////////////////////////////////////////////////////////
616
junov@chromium.org4866cc02012-06-01 21:23:07 +0000617bool SkPictureRecord::shouldFlattenPixels(const SkBitmap& bitmap) const {
618 return (fRecordFlags &
619 SkPicture::kFlattenMutableNonTexturePixelRefs_RecordingFlag)
620 && !bitmap.isImmutable() && bitmap.pixelRef()
621 && NULL == bitmap.getTexture();
622}
623
624int SkPictureRecord::find(const SkBitmap& bitmap) {
625 int dictionaryIndex = 0;
626 PixelRefDictionaryEntry entry;
627 bool flattenPixels = shouldFlattenPixels(bitmap);
628 if (flattenPixels) {
629 // Flattened bitmap may be very large. First attempt a fast lookup
630 // based on generation ID to avoid unnecessary flattening in
631 // fBitmaps.find()
632 entry.fKey = bitmap.pixelRef()->getGenerationID();
633 dictionaryIndex =
634 SkTSearch<const PixelRefDictionaryEntry>(fPixelRefDictionary.begin(),
635 fPixelRefDictionary.count(), entry, sizeof(entry));
636 if (dictionaryIndex >= 0) {
637 return fPixelRefDictionary[dictionaryIndex].fIndex;
638 }
639 }
640
641 uint32_t writeFlags = flattenPixels ?
642 SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag : 0;
643 int index = fBitmaps.find(&bitmap, &fRCSet, NULL, writeFlags);
644
645 if (flattenPixels) {
646 entry.fIndex = index;
647 dictionaryIndex = ~dictionaryIndex;
648 *fPixelRefDictionary.insert(dictionaryIndex) = entry;
649 }
650 return index;
651}
652
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653#ifdef SK_DEBUG_SIZE
654size_t SkPictureRecord::size() const {
655 size_t result = 0;
656 size_t sizeData;
657 bitmaps(&sizeData);
658 result += sizeData;
659 matrices(&sizeData);
660 result += sizeData;
661 paints(&sizeData);
662 result += sizeData;
663 paths(&sizeData);
664 result += sizeData;
665 pictures(&sizeData);
666 result += sizeData;
667 regions(&sizeData);
668 result += sizeData;
669 result += streamlen();
670 return result;
671}
672
673int SkPictureRecord::bitmaps(size_t* size) const {
674 size_t result = 0;
675 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +0000676 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
678 *size = result;
679 return count;
680}
681
682int SkPictureRecord::matrices(size_t* size) const {
683 int count = fMatrices.count();
684 *size = sizeof(fMatrices[0]) * count;
685 return count;
686}
687
688int SkPictureRecord::paints(size_t* size) const {
689 size_t result = 0;
690 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +0000691 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692 result += sizeof(fPaints[index]) + fPaints[index]->size();
693 *size = result;
694 return count;
695}
696
697int SkPictureRecord::paths(size_t* size) const {
698 size_t result = 0;
699 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +0000700 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000701 result += sizeof(fPaths[index]) + fPaths[index]->size();
702 *size = result;
703 return count;
704}
705
706int SkPictureRecord::regions(size_t* size) const {
707 size_t result = 0;
708 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +0000709 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000710 result += sizeof(fRegions[index]) + fRegions[index]->size();
711 *size = result;
712 return count;
713}
714
715size_t SkPictureRecord::streamlen() const {
716 return fWriter.size();
717}
718#endif
719
720#ifdef SK_DEBUG_VALIDATE
721void SkPictureRecord::validate() const {
722 validateBitmaps();
723 validateMatrices();
724 validatePaints();
725 validatePaths();
726 validatePictures();
727 validateRegions();
728}
729
730void SkPictureRecord::validateBitmaps() const {
731 int count = fBitmaps.count();
732 SkASSERT((unsigned) count < 0x1000);
733 for (int index = 0; index < count; index++) {
734 const SkFlatBitmap* bitPtr = fBitmaps[index];
735 SkASSERT(bitPtr);
736 bitPtr->validate();
737 }
738}
739
740void SkPictureRecord::validateMatrices() const {
741 int count = fMatrices.count();
742 SkASSERT((unsigned) count < 0x1000);
743 for (int index = 0; index < count; index++) {
744 const SkFlatMatrix* matrix = fMatrices[index];
745 SkASSERT(matrix);
reed@google.com82065d62011-02-07 15:30:46 +0000746 matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000747 }
748}
749
750void SkPictureRecord::validatePaints() const {
751 int count = fPaints.count();
752 SkASSERT((unsigned) count < 0x1000);
753 for (int index = 0; index < count; index++) {
754 const SkFlatPaint* paint = fPaints[index];
755 SkASSERT(paint);
756// paint->validate();
757 }
758}
759
760void SkPictureRecord::validatePaths() const {
761 int count = fPaths.count();
762 SkASSERT((unsigned) count < 0x1000);
763 for (int index = 0; index < count; index++) {
764 const SkFlatPath* path = fPaths[index];
765 SkASSERT(path);
766 path->validate();
767 }
768}
769
770void SkPictureRecord::validateRegions() const {
771 int count = fRegions.count();
772 SkASSERT((unsigned) count < 0x1000);
773 for (int index = 0; index < count; index++) {
774 const SkFlatRegion* region = fRegions[index];
775 SkASSERT(region);
776 region->validate();
777 }
778}
779#endif
780