blob: fb4f991f513f4ff5b53d0b050c90bdaca3c5d0e3 [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.com21830d92012-08-07 19:49:41 +000034 fFlattenableHeap.setBitmapStorage(&fBitmapHeap);
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() {
djsollen@google.com21830d92012-08-07 19:49:41 +000040 SkSafeUnref(fPathHeap);
41 fFlattenableHeap.setBitmapStorage(NULL);
42 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000043}
44
45///////////////////////////////////////////////////////////////////////////////
46
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000047SkDevice* SkPictureRecord::setDevice(SkDevice* device) {
48 SkASSERT(kNoInitialSave == fInitialSaveCount);
49 this->INHERITED::setDevice(device);
50
51 // The bracketting save() call needs to be recorded after setting the
52 // device otherwise the clip stack will get messed-up
53 fInitialSaveCount = this->save(SkCanvas::kMatrixClip_SaveFlag);
54 return device;
55}
56
reed@android.com8a1c16f2008-12-17 15:59:43 +000057int SkPictureRecord::save(SaveFlags flags) {
58 addDraw(SAVE);
59 addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +000060
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 fRestoreOffsetStack.push(0);
reed@google.com82065d62011-02-07 15:30:46 +000062
reed@android.com8a1c16f2008-12-17 15:59:43 +000063 validate();
64 return this->INHERITED::save(flags);
65}
66
67int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
68 SaveFlags flags) {
69 addDraw(SAVE_LAYER);
70 addRectPtr(bounds);
71 addPaintPtr(paint);
72 addInt(flags);
73
74 fRestoreOffsetStack.push(0);
75
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000076 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
77 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
78 }
79
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 validate();
reed@android.com261ae4d2009-10-02 16:37:46 +000081 /* Don't actually call saveLayer, because that will try to allocate an
82 offscreen device (potentially very big) which we don't actually need
83 at this time (and may not be able to afford since during record our
84 clip starts out the size of the picture, which is often much larger
85 than the size of the actual device we'll use during playback).
86 */
junov@chromium.orga907ac32012-02-24 21:54:07 +000087 int count = this->INHERITED::save(flags);
88 this->clipRectBounds(bounds, flags, NULL);
89 return count;
reed@android.com8a1c16f2008-12-17 15:59:43 +000090}
91
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000092bool SkPictureRecord::isDrawingToLayer() const {
93 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
94}
95
reed@android.com8a1c16f2008-12-17 15:59:43 +000096void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000097 // FIXME: SkDeferredCanvas needs to be refactored to respect
98 // save/restore balancing so that the following test can be
99 // turned on permanently.
100#if 0
101 SkASSERT(fRestoreOffsetStack.count() > 1);
102#endif
103
reed@android.comb4e22d62009-07-09 15:20:25 +0000104 // check for underflow
105 if (fRestoreOffsetStack.count() == 0) {
106 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000108
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000109 fillRestoreOffsetPlaceholdersForCurrentStackLevel(
110 (uint32_t)fWriter.size());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000111
112 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
113 fFirstSavedLayerIndex = kNoSavedLayerIndex;
114 }
115
reed@android.comb4e22d62009-07-09 15:20:25 +0000116 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000117
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 addDraw(RESTORE);
119 validate();
120 return this->INHERITED::restore();
121}
122
123bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
124 addDraw(TRANSLATE);
125 addScalar(dx);
126 addScalar(dy);
127 validate();
128 return this->INHERITED::translate(dx, dy);
129}
130
131bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
reed@google.com82065d62011-02-07 15:30:46 +0000132 addDraw(SCALE);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 addScalar(sx);
134 addScalar(sy);
135 validate();
136 return this->INHERITED::scale(sx, sy);
137}
138
139bool SkPictureRecord::rotate(SkScalar degrees) {
reed@google.com82065d62011-02-07 15:30:46 +0000140 addDraw(ROTATE);
141 addScalar(degrees);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 validate();
143 return this->INHERITED::rotate(degrees);
144}
145
146bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
reed@google.com82065d62011-02-07 15:30:46 +0000147 addDraw(SKEW);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148 addScalar(sx);
149 addScalar(sy);
150 validate();
151 return this->INHERITED::skew(sx, sy);
152}
153
154bool SkPictureRecord::concat(const SkMatrix& matrix) {
155 validate();
156 addDraw(CONCAT);
157 addMatrix(matrix);
158 validate();
159 return this->INHERITED::concat(matrix);
160}
161
reed@android.com6e073b92009-01-06 15:03:30 +0000162void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
163 validate();
164 addDraw(SET_MATRIX);
165 addMatrix(matrix);
166 validate();
167 this->INHERITED::setMatrix(matrix);
168}
169
reed@google.com45482d12011-08-29 19:02:39 +0000170static bool regionOpExpands(SkRegion::Op op) {
171 switch (op) {
172 case SkRegion::kUnion_Op:
173 case SkRegion::kXOR_Op:
174 case SkRegion::kReverseDifference_Op:
175 case SkRegion::kReplace_Op:
176 return true;
177 case SkRegion::kIntersect_Op:
178 case SkRegion::kDifference_Op:
179 return false;
180 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000181 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000182 return false;
183 }
184}
185
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000186void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(
187 uint32_t restoreOffset) {
188 uint32_t offset = fRestoreOffsetStack.top();
189 while (offset) {
190 uint32_t* peek = fWriter.peek32(offset);
191 offset = *peek;
192 *peek = restoreOffset;
193 }
194}
195
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000196void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000197 SkASSERT(kNoInitialSave != fInitialSaveCount);
198 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000199}
200
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000201void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com45482d12011-08-29 19:02:39 +0000202 if (regionOpExpands(op)) {
203 // Run back through any previous clip ops, and mark their offset to
204 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
205 // they could hide this clips ability to expand the clip (i.e. go from
206 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000207 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
reed@google.com45482d12011-08-29 19:02:39 +0000208 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000209
reed@google.com45482d12011-08-29 19:02:39 +0000210 size_t offset = fWriter.size();
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000211 // The RestoreOffset field is initially filled with a placeholder
212 // value that points to the offset of the previous RestoreOffset
213 // in the current stack level, thus forming a linked list so that
214 // the restore offsets can be filled in when the corresponding
215 // restore command is recorded.
reed@google.com45482d12011-08-29 19:02:39 +0000216 addInt(fRestoreOffsetStack.top());
217 fRestoreOffsetStack.top() = offset;
218}
219
reed@google.com071eef92011-10-12 11:52:53 +0000220bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 addDraw(CLIP_RECT);
222 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000223 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000224 recordRestoreOffsetPlaceholder(op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225
226 validate();
reed@google.com071eef92011-10-12 11:52:53 +0000227 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228}
229
reed@google.com071eef92011-10-12 11:52:53 +0000230bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 addDraw(CLIP_PATH);
232 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000233 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000234 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000235
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 validate();
reed@google.com82065d62011-02-07 15:30:46 +0000237
reed@android.comae814c82009-02-13 14:56:09 +0000238 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
reed@google.com071eef92011-10-12 11:52:53 +0000239 return this->INHERITED::clipRect(path.getBounds(), op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000240 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000241 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000242 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243}
244
245bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
reed@google.com82065d62011-02-07 15:30:46 +0000246 addDraw(CLIP_REGION);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000248 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000249 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000250
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 validate();
252 return this->INHERITED::clipRegion(region, op);
253}
254
reed@google.com2a981812011-04-14 18:59:28 +0000255void SkPictureRecord::clear(SkColor color) {
256 addDraw(DRAW_CLEAR);
257 addInt(color);
258 validate();
259}
260
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261void SkPictureRecord::drawPaint(const SkPaint& paint) {
262 addDraw(DRAW_PAINT);
263 addPaint(paint);
264 validate();
265}
266
267void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
268 const SkPaint& paint) {
269 addDraw(DRAW_POINTS);
270 addPaint(paint);
271 addInt(mode);
272 addInt(count);
273 fWriter.writeMul4(pts, count * sizeof(SkPoint));
274 validate();
275}
276
277void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
278 addDraw(DRAW_RECT);
279 addPaint(paint);
280 addRect(rect);
281 validate();
282}
283
284void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
285 addDraw(DRAW_PATH);
286 addPaint(paint);
287 addPath(path);
288 validate();
289}
290
291void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
292 const SkPaint* paint = NULL) {
293 addDraw(DRAW_BITMAP);
294 addPaintPtr(paint);
295 addBitmap(bitmap);
296 addScalar(left);
297 addScalar(top);
298 validate();
299}
300
301void SkPictureRecord::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
302 const SkRect& dst, const SkPaint* paint) {
303 addDraw(DRAW_BITMAP_RECT);
304 addPaintPtr(paint);
305 addBitmap(bitmap);
306 addIRectPtr(src); // may be null
307 addRect(dst);
308 validate();
309}
310
311void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000312 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 addDraw(DRAW_BITMAP_MATRIX);
314 addPaintPtr(paint);
315 addBitmap(bitmap);
316 addMatrix(matrix);
317 validate();
318}
319
reed@google.comf0b5e112011-09-07 11:57:34 +0000320void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
321 const SkRect& dst, const SkPaint* paint) {
322 addDraw(DRAW_BITMAP_NINE);
323 addPaintPtr(paint);
324 addBitmap(bitmap);
325 addIRect(center);
326 addRect(dst);
327 validate();
328}
329
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
331 const SkPaint* paint = NULL) {
332 addDraw(DRAW_SPRITE);
333 addPaintPtr(paint);
334 addBitmap(bitmap);
335 addInt(left);
336 addInt(top);
337 validate();
338}
339
340void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint,
reed@google.com9efd9a02012-01-30 15:41:43 +0000341 SkScalar minY, SkScalar maxY) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 SkPaint::FontMetrics metrics;
343 paint.getFontMetrics(&metrics);
344 SkRect bounds;
345 // construct a rect so we can see any adjustments from the paint.
346 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com9efd9a02012-01-30 15:41:43 +0000347 bounds.set(0, metrics.fTop + minY,
348 SK_Scalar1, metrics.fBottom + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 (void)paint.computeFastBounds(bounds, &bounds);
350 // now record the top and bottom
351 addScalar(bounds.fTop);
352 addScalar(bounds.fBottom);
353}
354
reed@google.com82065d62011-02-07 15:30:46 +0000355void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +0000357 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +0000358
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359 addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT);
360 addPaint(paint);
361 addText(text, byteLength);
362 addScalar(x);
363 addScalar(y);
364 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000365 addFontMetricsTopBottom(paint, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366 }
367 validate();
368}
369
reed@google.com82065d62011-02-07 15:30:46 +0000370void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371 const SkPoint pos[], const SkPaint& paint) {
372 size_t points = paint.countText(text, byteLength);
373 if (0 == points)
374 return;
375
376 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +0000377 SkScalar minY = pos[0].fY;
378 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 // check if the caller really should have used drawPosTextH()
380 {
381 const SkScalar firstY = pos[0].fY;
382 for (size_t index = 1; index < points; index++) {
383 if (pos[index].fY != firstY) {
384 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +0000385 if (pos[index].fY < minY) {
386 minY = pos[index].fY;
387 } else if (pos[index].fY > maxY) {
388 maxY = pos[index].fY;
389 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000390 }
391 }
392 }
reed@google.com82065d62011-02-07 15:30:46 +0000393
reed@google.com2eb5bb12012-04-12 14:27:42 +0000394 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +0000395 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000396
397 if (fast) {
398 addDraw(DRAW_POS_TEXT_H_TOP_BOTTOM);
reed@google.com9efd9a02012-01-30 15:41:43 +0000399 } else if (canUseDrawH) {
400 addDraw(DRAW_POS_TEXT_H);
401 } else if (fastBounds) {
402 addDraw(DRAW_POS_TEXT_TOP_BOTTOM);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403 } else {
reed@google.com9efd9a02012-01-30 15:41:43 +0000404 addDraw(DRAW_POS_TEXT);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000405 }
406 addPaint(paint);
407 addText(text, byteLength);
408 addInt(points);
409
410#ifdef SK_DEBUG_SIZE
411 size_t start = fWriter.size();
412#endif
413 if (canUseDrawH) {
414 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000415 addFontMetricsTopBottom(paint, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000416 }
417 addScalar(pos[0].fY);
418 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +0000419 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000420 *xptr++ = pos[index].fX;
421 }
422 else {
423 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +0000424 if (fastBounds) {
425 addFontMetricsTopBottom(paint, minY, maxY);
426 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 }
428#ifdef SK_DEBUG_SIZE
429 fPointBytes += fWriter.size() - start;
430 fPointWrites += points;
431#endif
432 validate();
433}
434
435void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
436 const SkScalar xpos[], SkScalar constY,
437 const SkPaint& paint) {
438 size_t points = paint.countText(text, byteLength);
439 if (0 == points)
440 return;
reed@google.com82065d62011-02-07 15:30:46 +0000441
reed@google.com2eb5bb12012-04-12 14:27:42 +0000442 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443
444 addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H);
445 addPaint(paint);
446 addText(text, byteLength);
447 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +0000448
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449#ifdef SK_DEBUG_SIZE
450 size_t start = fWriter.size();
451#endif
452 if (fast) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000453 addFontMetricsTopBottom(paint, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454 }
455 addScalar(constY);
456 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
457#ifdef SK_DEBUG_SIZE
458 fPointBytes += fWriter.size() - start;
459 fPointWrites += points;
460#endif
461 validate();
462}
463
reed@google.com82065d62011-02-07 15:30:46 +0000464void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
465 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466 const SkPaint& paint) {
467 addDraw(DRAW_TEXT_ON_PATH);
468 addPaint(paint);
469 addText(text, byteLength);
470 addPath(path);
471 addMatrixPtr(matrix);
472 validate();
473}
474
475void SkPictureRecord::drawPicture(SkPicture& picture) {
476 addDraw(DRAW_PICTURE);
477 addPicture(picture);
478 validate();
479}
480
481void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
482 const SkPoint vertices[], const SkPoint texs[],
483 const SkColor colors[], SkXfermode*,
484 const uint16_t indices[], int indexCount,
485 const SkPaint& paint) {
486 uint32_t flags = 0;
487 if (texs) {
488 flags |= DRAW_VERTICES_HAS_TEXS;
489 }
490 if (colors) {
491 flags |= DRAW_VERTICES_HAS_COLORS;
492 }
493 if (indexCount > 0) {
494 flags |= DRAW_VERTICES_HAS_INDICES;
495 }
496
497 addDraw(DRAW_VERTICES);
498 addPaint(paint);
499 addInt(flags);
500 addInt(vmode);
501 addInt(vertexCount);
502 addPoints(vertices, vertexCount);
503 if (flags & DRAW_VERTICES_HAS_TEXS) {
504 addPoints(texs, vertexCount);
505 }
506 if (flags & DRAW_VERTICES_HAS_COLORS) {
507 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
508 }
509 if (flags & DRAW_VERTICES_HAS_INDICES) {
510 addInt(indexCount);
511 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
512 }
513}
514
reed@android.comcb608442009-12-04 21:32:27 +0000515void SkPictureRecord::drawData(const void* data, size_t length) {
516 addDraw(DRAW_DATA);
517 addInt(length);
518 fWriter.writePad(data, length);
519}
520
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000522
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
djsollen@google.com21830d92012-08-07 19:49:41 +0000524 addInt(fBitmapHeap.insert(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) {
scroggo@google.com4dffc592012-07-17 16:49:40 +0000540 this->addInt(paint ? fPaints.find(*paint) : 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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625#ifdef SK_DEBUG_SIZE
626size_t SkPictureRecord::size() const {
627 size_t result = 0;
628 size_t sizeData;
629 bitmaps(&sizeData);
630 result += sizeData;
631 matrices(&sizeData);
632 result += sizeData;
633 paints(&sizeData);
634 result += sizeData;
635 paths(&sizeData);
636 result += sizeData;
637 pictures(&sizeData);
638 result += sizeData;
639 regions(&sizeData);
640 result += sizeData;
641 result += streamlen();
642 return result;
643}
644
645int SkPictureRecord::bitmaps(size_t* size) const {
646 size_t result = 0;
647 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +0000648 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
650 *size = result;
651 return count;
652}
653
654int SkPictureRecord::matrices(size_t* size) const {
655 int count = fMatrices.count();
656 *size = sizeof(fMatrices[0]) * count;
657 return count;
658}
659
660int SkPictureRecord::paints(size_t* size) const {
661 size_t result = 0;
662 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +0000663 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664 result += sizeof(fPaints[index]) + fPaints[index]->size();
665 *size = result;
666 return count;
667}
668
669int SkPictureRecord::paths(size_t* size) const {
670 size_t result = 0;
671 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +0000672 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000673 result += sizeof(fPaths[index]) + fPaths[index]->size();
674 *size = result;
675 return count;
676}
677
678int SkPictureRecord::regions(size_t* size) const {
679 size_t result = 0;
680 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +0000681 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000682 result += sizeof(fRegions[index]) + fRegions[index]->size();
683 *size = result;
684 return count;
685}
686
687size_t SkPictureRecord::streamlen() const {
688 return fWriter.size();
689}
690#endif
691
692#ifdef SK_DEBUG_VALIDATE
693void SkPictureRecord::validate() const {
694 validateBitmaps();
695 validateMatrices();
696 validatePaints();
697 validatePaths();
698 validatePictures();
699 validateRegions();
700}
701
702void SkPictureRecord::validateBitmaps() const {
703 int count = fBitmaps.count();
704 SkASSERT((unsigned) count < 0x1000);
705 for (int index = 0; index < count; index++) {
706 const SkFlatBitmap* bitPtr = fBitmaps[index];
707 SkASSERT(bitPtr);
708 bitPtr->validate();
709 }
710}
711
712void SkPictureRecord::validateMatrices() const {
713 int count = fMatrices.count();
714 SkASSERT((unsigned) count < 0x1000);
715 for (int index = 0; index < count; index++) {
716 const SkFlatMatrix* matrix = fMatrices[index];
717 SkASSERT(matrix);
reed@google.com82065d62011-02-07 15:30:46 +0000718 matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000719 }
720}
721
722void SkPictureRecord::validatePaints() const {
723 int count = fPaints.count();
724 SkASSERT((unsigned) count < 0x1000);
725 for (int index = 0; index < count; index++) {
726 const SkFlatPaint* paint = fPaints[index];
727 SkASSERT(paint);
728// paint->validate();
729 }
730}
731
732void SkPictureRecord::validatePaths() const {
733 int count = fPaths.count();
734 SkASSERT((unsigned) count < 0x1000);
735 for (int index = 0; index < count; index++) {
736 const SkFlatPath* path = fPaths[index];
737 SkASSERT(path);
738 path->validate();
739 }
740}
741
742void SkPictureRecord::validateRegions() const {
743 int count = fRegions.count();
744 SkASSERT((unsigned) count < 0x1000);
745 for (int index = 0; index < count; index++) {
746 const SkFlatRegion* region = fRegions[index];
747 SkASSERT(region);
748 region->validate();
749 }
750}
751#endif
752