1
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 */
8 #include "SkPictureRecord.h"
9 #include "SkTSearch.h"
10 #include "SkPixelRef.h"
11 #include "SkRRect.h"
12 #include "SkBBoxHierarchy.h"
13 #include "SkPictureStateTree.h"
14
15 #define MIN_WRITER_SIZE 16384
16 #define HEAP_BLOCK_SIZE 4096
17
18 enum {
19 // just need a value that save or getSaveCount would never return
20 kNoInitialSave = -1,
21 };
22
SkPictureRecord(uint32_t flags,SkDevice * device)23 SkPictureRecord::SkPictureRecord(uint32_t flags, SkDevice* device) :
24 INHERITED(device),
25 fBoundingHierarchy(NULL),
26 fStateTree(NULL),
27 fFlattenableHeap(HEAP_BLOCK_SIZE),
28 fMatrices(&fFlattenableHeap),
29 fPaints(&fFlattenableHeap),
30 fRegions(&fFlattenableHeap),
31 fWriter(MIN_WRITER_SIZE),
32 fRecordFlags(flags) {
33 #ifdef SK_DEBUG_SIZE
34 fPointBytes = fRectBytes = fTextBytes = 0;
35 fPointWrites = fRectWrites = fTextWrites = 0;
36 #endif
37
38 fRestoreOffsetStack.setReserve(32);
39
40 fBitmapHeap = SkNEW(SkBitmapHeap);
41 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
42 fPathHeap = NULL; // lazy allocate
43 fFirstSavedLayerIndex = kNoSavedLayerIndex;
44
45 fInitialSaveCount = kNoInitialSave;
46 }
47
~SkPictureRecord()48 SkPictureRecord::~SkPictureRecord() {
49 SkSafeUnref(fBitmapHeap);
50 SkSafeUnref(fPathHeap);
51 SkSafeUnref(fBoundingHierarchy);
52 SkSafeUnref(fStateTree);
53 fFlattenableHeap.setBitmapStorage(NULL);
54 fPictureRefs.unrefAll();
55 }
56
57 ///////////////////////////////////////////////////////////////////////////////
58
setDevice(SkDevice * device)59 SkDevice* SkPictureRecord::setDevice(SkDevice* device) {
60 SkASSERT(!"eeek, don't try to change the device on a recording canvas");
61 return this->INHERITED::setDevice(device);
62 }
63
save(SaveFlags flags)64 int SkPictureRecord::save(SaveFlags flags) {
65 // record the offset to us, making it non-positive to distinguish a save
66 // from a clip entry.
67 fRestoreOffsetStack.push(-(int32_t)fWriter.size());
68
69 addDraw(SAVE);
70 addInt(flags);
71
72 validate();
73 return this->INHERITED::save(flags);
74 }
75
saveLayer(const SkRect * bounds,const SkPaint * paint,SaveFlags flags)76 int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
77 SaveFlags flags) {
78 // record the offset to us, making it non-positive to distinguish a save
79 // from a clip entry.
80 fRestoreOffsetStack.push(-(int32_t)fWriter.size());
81
82 addDraw(SAVE_LAYER);
83 addRectPtr(bounds);
84 addPaintPtr(paint);
85 addInt(flags);
86
87 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
88 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
89 }
90
91 validate();
92 /* Don't actually call saveLayer, because that will try to allocate an
93 offscreen device (potentially very big) which we don't actually need
94 at this time (and may not be able to afford since during record our
95 clip starts out the size of the picture, which is often much larger
96 than the size of the actual device we'll use during playback).
97 */
98 int count = this->INHERITED::save(flags);
99 this->clipRectBounds(bounds, flags, NULL);
100 return count;
101 }
102
isDrawingToLayer() const103 bool SkPictureRecord::isDrawingToLayer() const {
104 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
105 }
106
107 // Return the size of the specified drawType's recorded block, or 0 if this verb
108 // is variable sized, and therefore not known.
getSkipableSize(unsigned drawType)109 static inline uint32_t getSkipableSize(unsigned drawType) {
110 static const uint8_t gSizes[LAST_DRAWTYPE_ENUM + 1] = {
111 0, // UNUSED,
112 4, // CLIP_PATH,
113 4, // CLIP_REGION,
114 7, // CLIP_RECT,
115 15, // CLIP_RRECT,
116 2, // CONCAT,
117 0, // DRAW_BITMAP,
118 0, // DRAW_BITMAP_MATRIX,
119 0, // DRAW_BITMAP_NINE,
120 0, // DRAW_BITMAP_RECT,
121 0, // DRAW_CLEAR,
122 0, // DRAW_DATA,
123 0, // DRAW_OVAL,
124 0, // DRAW_PAINT,
125 0, // DRAW_PATH,
126 0, // DRAW_PICTURE,
127 0, // DRAW_POINTS,
128 0, // DRAW_POS_TEXT,
129 0, // DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
130 0, // DRAW_POS_TEXT_H,
131 0, // DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
132 0, // DRAW_RECT,
133 0, // DRAW_RRECT,
134 0, // DRAW_SPRITE,
135 0, // DRAW_TEXT,
136 0, // DRAW_TEXT_ON_PATH,
137 0, // DRAW_TEXT_TOP_BOTTOM, // fast variant of DRAW_TEXT
138 0, // DRAW_VERTICES,
139 0, // RESTORE,
140 2, // ROTATE,
141 2, // SAVE,
142 0, // SAVE_LAYER,
143 3, // SCALE,
144 2, // SET_MATRIX,
145 3, // SKEW,
146 3, // TRANSLATE,
147 };
148
149 SkASSERT(sizeof(gSizes) == LAST_DRAWTYPE_ENUM + 1);
150 SkASSERT((unsigned)drawType <= (unsigned)LAST_DRAWTYPE_ENUM);
151 return gSizes[drawType] * sizeof(uint32_t);
152 }
153
154 #ifdef TRACK_COLLAPSE_STATS
155 static int gCollapseCount, gCollapseCalls;
156 #endif
157
158 /*
159 * Restore has just been called (but not recoreded), so look back at the
160 * matching save(), and see if we can eliminate the pair of them, due to no
161 * intervening matrix/clip calls.
162 *
163 * If so, update the writer and return true, in which case we won't even record
164 * the restore() call. If we still need the restore(), return false.
165 */
collapseSaveClipRestore(SkWriter32 * writer,int32_t offset)166 static bool collapseSaveClipRestore(SkWriter32* writer, int32_t offset) {
167 #ifdef TRACK_COLLAPSE_STATS
168 gCollapseCalls += 1;
169 #endif
170
171 int32_t restoreOffset = (int32_t)writer->size();
172
173 // back up to the save block
174 while (offset > 0) {
175 offset = *writer->peek32(offset);
176 }
177
178 // now offset points to a save
179 offset = -offset;
180 if (SAVE_LAYER == *writer->peek32(offset)) {
181 // not ready to cull these out yet (mrr)
182 return false;
183 }
184 SkASSERT(SAVE == *writer->peek32(offset));
185
186 // Walk forward until we get back to either a draw-verb (abort) or we hit
187 // our restore (success).
188 int32_t saveOffset = offset;
189
190 offset += getSkipableSize(SAVE);
191 while (offset < restoreOffset) {
192 uint32_t* block = writer->peek32(offset);
193 uint32_t op = *block;
194 uint32_t opSize = getSkipableSize(op);
195 if (0 == opSize) {
196 // drawing verb, abort
197 return false;
198 }
199 offset += opSize;
200 }
201
202 #ifdef TRACK_COLLAPSE_STATS
203 gCollapseCount += 1;
204 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
205 (double)gCollapseCount / gCollapseCalls, "%");
206 #endif
207
208 writer->rewindToOffset(saveOffset);
209 return true;
210 }
211
restore()212 void SkPictureRecord::restore() {
213 // FIXME: SkDeferredCanvas needs to be refactored to respect
214 // save/restore balancing so that the following test can be
215 // turned on permanently.
216 #if 0
217 SkASSERT(fRestoreOffsetStack.count() > 1);
218 #endif
219
220 // check for underflow
221 if (fRestoreOffsetStack.count() == 0) {
222 return;
223 }
224
225 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
226 fFirstSavedLayerIndex = kNoSavedLayerIndex;
227 }
228
229 if (!collapseSaveClipRestore(&fWriter, fRestoreOffsetStack.top())) {
230 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size());
231 this->addDraw(RESTORE);
232 }
233
234 fRestoreOffsetStack.pop();
235
236 validate();
237 return this->INHERITED::restore();
238 }
239
translate(SkScalar dx,SkScalar dy)240 bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
241 addDraw(TRANSLATE);
242 addScalar(dx);
243 addScalar(dy);
244 validate();
245 return this->INHERITED::translate(dx, dy);
246 }
247
scale(SkScalar sx,SkScalar sy)248 bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
249 addDraw(SCALE);
250 addScalar(sx);
251 addScalar(sy);
252 validate();
253 return this->INHERITED::scale(sx, sy);
254 }
255
rotate(SkScalar degrees)256 bool SkPictureRecord::rotate(SkScalar degrees) {
257 addDraw(ROTATE);
258 addScalar(degrees);
259 validate();
260 return this->INHERITED::rotate(degrees);
261 }
262
skew(SkScalar sx,SkScalar sy)263 bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
264 addDraw(SKEW);
265 addScalar(sx);
266 addScalar(sy);
267 validate();
268 return this->INHERITED::skew(sx, sy);
269 }
270
concat(const SkMatrix & matrix)271 bool SkPictureRecord::concat(const SkMatrix& matrix) {
272 validate();
273 addDraw(CONCAT);
274 addMatrix(matrix);
275 validate();
276 return this->INHERITED::concat(matrix);
277 }
278
setMatrix(const SkMatrix & matrix)279 void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
280 validate();
281 addDraw(SET_MATRIX);
282 addMatrix(matrix);
283 validate();
284 this->INHERITED::setMatrix(matrix);
285 }
286
regionOpExpands(SkRegion::Op op)287 static bool regionOpExpands(SkRegion::Op op) {
288 switch (op) {
289 case SkRegion::kUnion_Op:
290 case SkRegion::kXOR_Op:
291 case SkRegion::kReverseDifference_Op:
292 case SkRegion::kReplace_Op:
293 return true;
294 case SkRegion::kIntersect_Op:
295 case SkRegion::kDifference_Op:
296 return false;
297 default:
298 SkDEBUGFAIL("unknown region op");
299 return false;
300 }
301 }
302
fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset)303 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(
304 uint32_t restoreOffset) {
305 int32_t offset = fRestoreOffsetStack.top();
306 while (offset > 0) {
307 uint32_t* peek = fWriter.peek32(offset);
308 offset = *peek;
309 *peek = restoreOffset;
310 }
311
312 #ifdef SK_DEBUG
313 // assert that the final offset value points to a save verb
314 uint32_t drawOp = *fWriter.peek32(-offset);
315 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
316 #endif
317 }
318
beginRecording()319 void SkPictureRecord::beginRecording() {
320 // we have to call this *after* our constructor, to ensure that it gets
321 // recorded. This is balanced by restoreToCount() call from endRecording,
322 // which in-turn calls our overridden restore(), so those get recorded too.
323 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
324 }
325
endRecording()326 void SkPictureRecord::endRecording() {
327 SkASSERT(kNoInitialSave != fInitialSaveCount);
328 this->restoreToCount(fInitialSaveCount);
329 }
330
recordRestoreOffsetPlaceholder(SkRegion::Op op)331 void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
332 if (fRestoreOffsetStack.isEmpty()) {
333 return;
334 }
335
336 if (regionOpExpands(op)) {
337 // Run back through any previous clip ops, and mark their offset to
338 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
339 // they could hide this clips ability to expand the clip (i.e. go from
340 // empty to non-empty).
341 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
342 }
343
344 size_t offset = fWriter.size();
345 // The RestoreOffset field is initially filled with a placeholder
346 // value that points to the offset of the previous RestoreOffset
347 // in the current stack level, thus forming a linked list so that
348 // the restore offsets can be filled in when the corresponding
349 // restore command is recorded.
350 addInt(fRestoreOffsetStack.top());
351 fRestoreOffsetStack.top() = offset;
352 }
353
clipRect(const SkRect & rect,SkRegion::Op op,bool doAA)354 bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
355 addDraw(CLIP_RECT);
356 addRect(rect);
357 addInt(ClipParams_pack(op, doAA));
358 recordRestoreOffsetPlaceholder(op);
359
360 validate();
361 return this->INHERITED::clipRect(rect, op, doAA);
362 }
363
clipRRect(const SkRRect & rrect,SkRegion::Op op,bool doAA)364 bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
365 if (rrect.isRect()) {
366 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
367 }
368
369 addDraw(CLIP_RRECT);
370 addRRect(rrect);
371 addInt(ClipParams_pack(op, doAA));
372 recordRestoreOffsetPlaceholder(op);
373
374 validate();
375
376 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
377 return this->INHERITED::clipRect(rrect.getBounds(), op, doAA);
378 } else {
379 return this->INHERITED::clipRRect(rrect, op, doAA);
380 }
381 }
382
clipPath(const SkPath & path,SkRegion::Op op,bool doAA)383 bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
384
385 SkRect r;
386 if (!path.isInverseFillType() && path.isRect(&r)) {
387 return this->clipRect(r, op, doAA);
388 }
389
390 addDraw(CLIP_PATH);
391 addPath(path);
392 addInt(ClipParams_pack(op, doAA));
393 recordRestoreOffsetPlaceholder(op);
394
395 validate();
396
397 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
398 return this->INHERITED::clipRect(path.getBounds(), op, doAA);
399 } else {
400 return this->INHERITED::clipPath(path, op, doAA);
401 }
402 }
403
clipRegion(const SkRegion & region,SkRegion::Op op)404 bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
405 addDraw(CLIP_REGION);
406 addRegion(region);
407 addInt(ClipParams_pack(op, false));
408 recordRestoreOffsetPlaceholder(op);
409
410 validate();
411 return this->INHERITED::clipRegion(region, op);
412 }
413
clear(SkColor color)414 void SkPictureRecord::clear(SkColor color) {
415 addDraw(DRAW_CLEAR);
416 addInt(color);
417 validate();
418 }
419
drawPaint(const SkPaint & paint)420 void SkPictureRecord::drawPaint(const SkPaint& paint) {
421 addDraw(DRAW_PAINT);
422 addPaint(paint);
423 validate();
424 }
425
drawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)426 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
427 const SkPaint& paint) {
428 addDraw(DRAW_POINTS);
429 addPaint(paint);
430 addInt(mode);
431 addInt(count);
432 fWriter.writeMul4(pts, count * sizeof(SkPoint));
433 validate();
434 }
435
drawOval(const SkRect & oval,const SkPaint & paint)436 void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
437 addDraw(DRAW_OVAL);
438 addPaint(paint);
439 addRect(oval);
440 validate();
441 }
442
drawRect(const SkRect & rect,const SkPaint & paint)443 void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
444 addDraw(DRAW_RECT);
445 addPaint(paint);
446 addRect(rect);
447 validate();
448 }
449
drawRRect(const SkRRect & rrect,const SkPaint & paint)450 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
451 if (rrect.isRect()) {
452 addDraw(DRAW_RECT);
453 addPaint(paint);
454 addRect(rrect.getBounds());
455 } else if (rrect.isOval()) {
456 addDraw(DRAW_OVAL);
457 addPaint(paint);
458 addRect(rrect.getBounds());
459 } else {
460 addDraw(DRAW_RRECT);
461 addPaint(paint);
462 addRRect(rrect);
463 }
464 validate();
465 }
466
drawPath(const SkPath & path,const SkPaint & paint)467 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
468 addDraw(DRAW_PATH);
469 addPaint(paint);
470 addPath(path);
471 validate();
472 }
473
drawBitmap(const SkBitmap & bitmap,SkScalar left,SkScalar top,const SkPaint * paint=NULL)474 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
475 const SkPaint* paint = NULL) {
476 addDraw(DRAW_BITMAP);
477 addPaintPtr(paint);
478 addBitmap(bitmap);
479 addScalar(left);
480 addScalar(top);
481 validate();
482 }
483
drawBitmapRectToRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint)484 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
485 const SkRect& dst, const SkPaint* paint) {
486 addDraw(DRAW_BITMAP_RECT_TO_RECT);
487 addPaintPtr(paint);
488 addBitmap(bitmap);
489 addRectPtr(src); // may be null
490 addRect(dst);
491 validate();
492 }
493
drawBitmapMatrix(const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint * paint)494 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
495 const SkPaint* paint) {
496 addDraw(DRAW_BITMAP_MATRIX);
497 addPaintPtr(paint);
498 addBitmap(bitmap);
499 addMatrix(matrix);
500 validate();
501 }
502
drawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)503 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
504 const SkRect& dst, const SkPaint* paint) {
505 addDraw(DRAW_BITMAP_NINE);
506 addPaintPtr(paint);
507 addBitmap(bitmap);
508 addIRect(center);
509 addRect(dst);
510 validate();
511 }
512
drawSprite(const SkBitmap & bitmap,int left,int top,const SkPaint * paint=NULL)513 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
514 const SkPaint* paint = NULL) {
515 addDraw(DRAW_SPRITE);
516 addPaintPtr(paint);
517 addBitmap(bitmap);
518 addInt(left);
519 addInt(top);
520 validate();
521 }
522
523 // Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been
524 // tweaked by paint.computeFastBounds().
525 //
computeFontMetricsTopBottom(const SkPaint & paint,SkScalar topbot[2])526 static void computeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
527 SkPaint::FontMetrics metrics;
528 paint.getFontMetrics(&metrics);
529 SkRect bounds;
530 // construct a rect so we can see any adjustments from the paint.
531 // we use 0,1 for left,right, just so the rect isn't empty
532 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
533 (void)paint.computeFastBounds(bounds, &bounds);
534 topbot[0] = bounds.fTop;
535 topbot[1] = bounds.fBottom;
536 }
537
addFontMetricsTopBottom(const SkPaint & paint,const SkFlatData & flat,SkScalar minY,SkScalar maxY)538 void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
539 SkScalar minY, SkScalar maxY) {
540 if (!flat.isTopBotWritten()) {
541 computeFontMetricsTopBottom(paint, flat.writableTopBot());
542 SkASSERT(flat.isTopBotWritten());
543 }
544 addScalar(flat.topBot()[0] + minY);
545 addScalar(flat.topBot()[1] + maxY);
546 }
547
drawText(const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)548 void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
549 SkScalar y, const SkPaint& paint) {
550 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
551
552 addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT);
553 const SkFlatData* flatPaintData = addPaint(paint);
554 SkASSERT(flatPaintData);
555 addText(text, byteLength);
556 addScalar(x);
557 addScalar(y);
558 if (fast) {
559 addFontMetricsTopBottom(paint, *flatPaintData, y, y);
560 }
561 validate();
562 }
563
drawPosText(const void * text,size_t byteLength,const SkPoint pos[],const SkPaint & paint)564 void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
565 const SkPoint pos[], const SkPaint& paint) {
566 size_t points = paint.countText(text, byteLength);
567 if (0 == points)
568 return;
569
570 bool canUseDrawH = true;
571 SkScalar minY = pos[0].fY;
572 SkScalar maxY = pos[0].fY;
573 // check if the caller really should have used drawPosTextH()
574 {
575 const SkScalar firstY = pos[0].fY;
576 for (size_t index = 1; index < points; index++) {
577 if (pos[index].fY != firstY) {
578 canUseDrawH = false;
579 if (pos[index].fY < minY) {
580 minY = pos[index].fY;
581 } else if (pos[index].fY > maxY) {
582 maxY = pos[index].fY;
583 }
584 }
585 }
586 }
587
588 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
589 bool fast = canUseDrawH && fastBounds;
590
591 if (fast) {
592 addDraw(DRAW_POS_TEXT_H_TOP_BOTTOM);
593 } else if (canUseDrawH) {
594 addDraw(DRAW_POS_TEXT_H);
595 } else if (fastBounds) {
596 addDraw(DRAW_POS_TEXT_TOP_BOTTOM);
597 } else {
598 addDraw(DRAW_POS_TEXT);
599 }
600 const SkFlatData* flatPaintData = addPaint(paint);
601 SkASSERT(flatPaintData);
602 addText(text, byteLength);
603 addInt(points);
604
605 #ifdef SK_DEBUG_SIZE
606 size_t start = fWriter.size();
607 #endif
608 if (canUseDrawH) {
609 if (fast) {
610 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
611 }
612 addScalar(pos[0].fY);
613 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
614 for (size_t index = 0; index < points; index++)
615 *xptr++ = pos[index].fX;
616 }
617 else {
618 fWriter.writeMul4(pos, points * sizeof(SkPoint));
619 if (fastBounds) {
620 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
621 }
622 }
623 #ifdef SK_DEBUG_SIZE
624 fPointBytes += fWriter.size() - start;
625 fPointWrites += points;
626 #endif
627 validate();
628 }
629
drawPosTextH(const void * text,size_t byteLength,const SkScalar xpos[],SkScalar constY,const SkPaint & paint)630 void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
631 const SkScalar xpos[], SkScalar constY,
632 const SkPaint& paint) {
633 size_t points = paint.countText(text, byteLength);
634 if (0 == points)
635 return;
636
637 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
638
639 addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H);
640 const SkFlatData* flatPaintData = addPaint(paint);
641 SkASSERT(flatPaintData);
642 addText(text, byteLength);
643 addInt(points);
644
645 #ifdef SK_DEBUG_SIZE
646 size_t start = fWriter.size();
647 #endif
648 if (fast) {
649 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
650 }
651 addScalar(constY);
652 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
653 #ifdef SK_DEBUG_SIZE
654 fPointBytes += fWriter.size() - start;
655 fPointWrites += points;
656 #endif
657 validate();
658 }
659
drawTextOnPath(const void * text,size_t byteLength,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)660 void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
661 const SkPath& path, const SkMatrix* matrix,
662 const SkPaint& paint) {
663 addDraw(DRAW_TEXT_ON_PATH);
664 addPaint(paint);
665 addText(text, byteLength);
666 addPath(path);
667 addMatrixPtr(matrix);
668 validate();
669 }
670
drawPicture(SkPicture & picture)671 void SkPictureRecord::drawPicture(SkPicture& picture) {
672 addDraw(DRAW_PICTURE);
673 addPicture(picture);
674 validate();
675 }
676
drawVertices(VertexMode vmode,int vertexCount,const SkPoint vertices[],const SkPoint texs[],const SkColor colors[],SkXfermode *,const uint16_t indices[],int indexCount,const SkPaint & paint)677 void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
678 const SkPoint vertices[], const SkPoint texs[],
679 const SkColor colors[], SkXfermode*,
680 const uint16_t indices[], int indexCount,
681 const SkPaint& paint) {
682 uint32_t flags = 0;
683 if (texs) {
684 flags |= DRAW_VERTICES_HAS_TEXS;
685 }
686 if (colors) {
687 flags |= DRAW_VERTICES_HAS_COLORS;
688 }
689 if (indexCount > 0) {
690 flags |= DRAW_VERTICES_HAS_INDICES;
691 }
692
693 addDraw(DRAW_VERTICES);
694 addPaint(paint);
695 addInt(flags);
696 addInt(vmode);
697 addInt(vertexCount);
698 addPoints(vertices, vertexCount);
699 if (flags & DRAW_VERTICES_HAS_TEXS) {
700 addPoints(texs, vertexCount);
701 }
702 if (flags & DRAW_VERTICES_HAS_COLORS) {
703 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
704 }
705 if (flags & DRAW_VERTICES_HAS_INDICES) {
706 addInt(indexCount);
707 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
708 }
709 }
710
drawData(const void * data,size_t length)711 void SkPictureRecord::drawData(const void* data, size_t length) {
712 addDraw(DRAW_DATA);
713 addInt(length);
714 fWriter.writePad(data, length);
715 }
716
717 ///////////////////////////////////////////////////////////////////////////////
718
addBitmap(const SkBitmap & bitmap)719 void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
720 const int index = fBitmapHeap->insert(bitmap);
721 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
722 // release builds, the invalid value will be recorded so that the reader will know that there
723 // was a problem.
724 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
725 addInt(index);
726 }
727
addMatrix(const SkMatrix & matrix)728 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
729 addMatrixPtr(&matrix);
730 }
731
addMatrixPtr(const SkMatrix * matrix)732 void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
733 this->addInt(matrix ? fMatrices.find(*matrix) : 0);
734 }
735
addPaintPtr(const SkPaint * paint)736 const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
737 const SkFlatData* data = paint ? fPaints.findAndReturnFlat(*paint) : NULL;
738 int index = data ? data->index() : 0;
739 this->addInt(index);
740 return data;
741 }
742
addPath(const SkPath & path)743 void SkPictureRecord::addPath(const SkPath& path) {
744 if (NULL == fPathHeap) {
745 fPathHeap = SkNEW(SkPathHeap);
746 }
747 addInt(fPathHeap->append(path));
748 }
749
addPicture(SkPicture & picture)750 void SkPictureRecord::addPicture(SkPicture& picture) {
751 int index = fPictureRefs.find(&picture);
752 if (index < 0) { // not found
753 index = fPictureRefs.count();
754 *fPictureRefs.append() = &picture;
755 picture.ref();
756 }
757 // follow the convention of recording a 1-based index
758 addInt(index + 1);
759 }
760
addPoint(const SkPoint & point)761 void SkPictureRecord::addPoint(const SkPoint& point) {
762 #ifdef SK_DEBUG_SIZE
763 size_t start = fWriter.size();
764 #endif
765 fWriter.writePoint(point);
766 #ifdef SK_DEBUG_SIZE
767 fPointBytes += fWriter.size() - start;
768 fPointWrites++;
769 #endif
770 }
771
addPoints(const SkPoint pts[],int count)772 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
773 fWriter.writeMul4(pts, count * sizeof(SkPoint));
774 #ifdef SK_DEBUG_SIZE
775 fPointBytes += count * sizeof(SkPoint);
776 fPointWrites++;
777 #endif
778 }
779
addRect(const SkRect & rect)780 void SkPictureRecord::addRect(const SkRect& rect) {
781 #ifdef SK_DEBUG_SIZE
782 size_t start = fWriter.size();
783 #endif
784 fWriter.writeRect(rect);
785 #ifdef SK_DEBUG_SIZE
786 fRectBytes += fWriter.size() - start;
787 fRectWrites++;
788 #endif
789 }
790
addRectPtr(const SkRect * rect)791 void SkPictureRecord::addRectPtr(const SkRect* rect) {
792 if (fWriter.writeBool(rect != NULL)) {
793 fWriter.writeRect(*rect);
794 }
795 }
796
addIRect(const SkIRect & rect)797 void SkPictureRecord::addIRect(const SkIRect& rect) {
798 fWriter.write(&rect, sizeof(rect));
799 }
800
addIRectPtr(const SkIRect * rect)801 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
802 if (fWriter.writeBool(rect != NULL)) {
803 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
804 }
805 }
806
addRRect(const SkRRect & rrect)807 void SkPictureRecord::addRRect(const SkRRect& rrect) {
808 fWriter.writeRRect(rrect);
809 }
810
addRegion(const SkRegion & region)811 void SkPictureRecord::addRegion(const SkRegion& region) {
812 addInt(fRegions.find(region));
813 }
814
addText(const void * text,size_t byteLength)815 void SkPictureRecord::addText(const void* text, size_t byteLength) {
816 #ifdef SK_DEBUG_SIZE
817 size_t start = fWriter.size();
818 #endif
819 addInt(byteLength);
820 fWriter.writePad(text, byteLength);
821 #ifdef SK_DEBUG_SIZE
822 fTextBytes += fWriter.size() - start;
823 fTextWrites++;
824 #endif
825 }
826
827 ///////////////////////////////////////////////////////////////////////////////
828
829 #ifdef SK_DEBUG_SIZE
size() const830 size_t SkPictureRecord::size() const {
831 size_t result = 0;
832 size_t sizeData;
833 bitmaps(&sizeData);
834 result += sizeData;
835 matrices(&sizeData);
836 result += sizeData;
837 paints(&sizeData);
838 result += sizeData;
839 paths(&sizeData);
840 result += sizeData;
841 pictures(&sizeData);
842 result += sizeData;
843 regions(&sizeData);
844 result += sizeData;
845 result += streamlen();
846 return result;
847 }
848
bitmaps(size_t * size) const849 int SkPictureRecord::bitmaps(size_t* size) const {
850 size_t result = 0;
851 int count = fBitmaps.count();
852 for (int index = 0; index < count; index++)
853 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
854 *size = result;
855 return count;
856 }
857
matrices(size_t * size) const858 int SkPictureRecord::matrices(size_t* size) const {
859 int count = fMatrices.count();
860 *size = sizeof(fMatrices[0]) * count;
861 return count;
862 }
863
paints(size_t * size) const864 int SkPictureRecord::paints(size_t* size) const {
865 size_t result = 0;
866 int count = fPaints.count();
867 for (int index = 0; index < count; index++)
868 result += sizeof(fPaints[index]) + fPaints[index]->size();
869 *size = result;
870 return count;
871 }
872
paths(size_t * size) const873 int SkPictureRecord::paths(size_t* size) const {
874 size_t result = 0;
875 int count = fPaths.count();
876 for (int index = 0; index < count; index++)
877 result += sizeof(fPaths[index]) + fPaths[index]->size();
878 *size = result;
879 return count;
880 }
881
regions(size_t * size) const882 int SkPictureRecord::regions(size_t* size) const {
883 size_t result = 0;
884 int count = fRegions.count();
885 for (int index = 0; index < count; index++)
886 result += sizeof(fRegions[index]) + fRegions[index]->size();
887 *size = result;
888 return count;
889 }
890
streamlen() const891 size_t SkPictureRecord::streamlen() const {
892 return fWriter.size();
893 }
894 #endif
895
896 #ifdef SK_DEBUG_VALIDATE
validate() const897 void SkPictureRecord::validate() const {
898 validateBitmaps();
899 validateMatrices();
900 validatePaints();
901 validatePaths();
902 validatePictures();
903 validateRegions();
904 }
905
validateBitmaps() const906 void SkPictureRecord::validateBitmaps() const {
907 int count = fBitmaps.count();
908 SkASSERT((unsigned) count < 0x1000);
909 for (int index = 0; index < count; index++) {
910 const SkFlatBitmap* bitPtr = fBitmaps[index];
911 SkASSERT(bitPtr);
912 bitPtr->validate();
913 }
914 }
915
validateMatrices() const916 void SkPictureRecord::validateMatrices() const {
917 int count = fMatrices.count();
918 SkASSERT((unsigned) count < 0x1000);
919 for (int index = 0; index < count; index++) {
920 const SkFlatMatrix* matrix = fMatrices[index];
921 SkASSERT(matrix);
922 matrix->validate();
923 }
924 }
925
validatePaints() const926 void SkPictureRecord::validatePaints() const {
927 int count = fPaints.count();
928 SkASSERT((unsigned) count < 0x1000);
929 for (int index = 0; index < count; index++) {
930 const SkFlatPaint* paint = fPaints[index];
931 SkASSERT(paint);
932 // paint->validate();
933 }
934 }
935
validatePaths() const936 void SkPictureRecord::validatePaths() const {
937 int count = fPaths.count();
938 SkASSERT((unsigned) count < 0x1000);
939 for (int index = 0; index < count; index++) {
940 const SkFlatPath* path = fPaths[index];
941 SkASSERT(path);
942 path->validate();
943 }
944 }
945
validateRegions() const946 void SkPictureRecord::validateRegions() const {
947 int count = fRegions.count();
948 SkASSERT((unsigned) count < 0x1000);
949 for (int index = 0; index < count; index++) {
950 const SkFlatRegion* region = fRegions[index];
951 SkASSERT(region);
952 region->validate();
953 }
954 }
955 #endif
956