1 /*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkPictureRecord.h"
9 #include "SkDevice.h"
10 #include "SkImage_Base.h"
11 #include "SkPatchUtils.h"
12 #include "SkPixelRef.h"
13 #include "SkRRect.h"
14 #include "SkTextBlob.h"
15 #include "SkTSearch.h"
16
17 #define HEAP_BLOCK_SIZE 4096
18
19 enum {
20 // just need a value that save or getSaveCount would never return
21 kNoInitialSave = -1,
22 };
23
24 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
25 static int const kUInt32Size = 4;
26
27 static const uint32_t kSaveSize = kUInt32Size;
28 #ifdef SK_DEBUG
29 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
30 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
31 #endif//SK_DEBUG
32
SkPictureRecord(const SkISize & dimensions,uint32_t flags)33 SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
34 : INHERITED(dimensions.width(), dimensions.height())
35 , fRecordFlags(flags)
36 , fInitialSaveCount(kNoInitialSave) {
37 }
38
~SkPictureRecord()39 SkPictureRecord::~SkPictureRecord() {
40 fPictureRefs.unrefAll();
41 fTextBlobRefs.unrefAll();
42 }
43
44 ///////////////////////////////////////////////////////////////////////////////
45
46 #ifdef SK_DEBUG
47 // Return the offset of the paint inside a given op's byte stream. A zero
48 // return value means there is no paint (and you really shouldn't be calling
49 // this method)
get_paint_offset(DrawType op,size_t opSize)50 static inline size_t get_paint_offset(DrawType op, size_t opSize) {
51 // These offsets are where the paint would be if the op size doesn't overflow
52 static const uint8_t gPaintOffsets[] = {
53 0, // UNUSED - no paint
54 0, // CLIP_PATH - no paint
55 0, // CLIP_REGION - no paint
56 0, // CLIP_RECT - no paint
57 0, // CLIP_RRECT - no paint
58 0, // CONCAT - no paint
59 1, // DRAW_BITMAP - right after op code
60 1, // DRAW_BITMAP_MATRIX - right after op code, deprecated
61 1, // DRAW_BITMAP_NINE - right after op code
62 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
63 0, // DRAW_CLEAR - no paint
64 0, // DRAW_DATA - no paint
65 1, // DRAW_OVAL - right after op code
66 1, // DRAW_PAINT - right after op code
67 1, // DRAW_PATH - right after op code
68 0, // DRAW_PICTURE - no paint
69 1, // DRAW_POINTS - right after op code
70 1, // DRAW_POS_TEXT - right after op code
71 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
72 1, // DRAW_POS_TEXT_H - right after op code
73 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
74 1, // DRAW_RECT - right after op code
75 1, // DRAW_RRECT - right after op code
76 1, // DRAW_SPRITE - right after op code
77 1, // DRAW_TEXT - right after op code
78 1, // DRAW_TEXT_ON_PATH - right after op code
79 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
80 1, // DRAW_VERTICES - right after op code
81 0, // RESTORE - no paint
82 0, // ROTATE - no paint
83 0, // SAVE - no paint
84 0, // SAVE_LAYER - see below - this paint's location varies
85 0, // SCALE - no paint
86 0, // SET_MATRIX - no paint
87 0, // SKEW - no paint
88 0, // TRANSLATE - no paint
89 0, // NOOP - no paint
90 0, // BEGIN_GROUP - no paint
91 0, // COMMENT - no paint
92 0, // END_GROUP - no paint
93 1, // DRAWDRRECT - right after op code
94 0, // PUSH_CULL - no paint
95 0, // POP_CULL - no paint
96 1, // DRAW_PATCH - right after op code
97 1, // DRAW_PICTURE_MATRIX_PAINT - right after op code
98 1, // DRAW_TEXT_BLOB- right after op code
99 };
100
101 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
102 need_to_be_in_sync);
103 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
104
105 int overflow = 0;
106 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
107 // This op's size overflows so an extra uint32_t will be written
108 // after the op code
109 overflow = sizeof(uint32_t);
110 }
111
112 if (SAVE_LAYER == op) {
113 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
114 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
115
116 if (kSaveLayerNoBoundsSize == opSize) {
117 return kSaveLayerNoBoundsPaintOffset + overflow;
118 } else {
119 SkASSERT(kSaveLayerWithBoundsSize == opSize);
120 return kSaveLayerWithBoundsPaintOffset + overflow;
121 }
122 }
123
124 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
125 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
126 }
127 #endif//SK_DEBUG
128
willSave()129 void SkPictureRecord::willSave() {
130 // record the offset to us, making it non-positive to distinguish a save
131 // from a clip entry.
132 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
133 this->recordSave();
134
135 this->INHERITED::willSave();
136 }
137
recordSave()138 void SkPictureRecord::recordSave() {
139 fContentInfo.onSave();
140
141 // op only
142 size_t size = kSaveSize;
143 size_t initialOffset = this->addDraw(SAVE, &size);
144
145 this->validate(initialOffset, size);
146 }
147
willSaveLayer(const SkRect * bounds,const SkPaint * paint,SaveFlags flags)148 SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
149 const SkPaint* paint, SaveFlags flags) {
150 // record the offset to us, making it non-positive to distinguish a save
151 // from a clip entry.
152 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
153 this->recordSaveLayer(bounds, paint, flags);
154
155 this->INHERITED::willSaveLayer(bounds, paint, flags);
156 /* No need for a (potentially very big) layer which we don't actually need
157 at this time (and may not be able to afford since during record our
158 clip starts out the size of the picture, which is often much larger
159 than the size of the actual device we'll use during playback).
160 */
161 return kNoLayer_SaveLayerStrategy;
162 }
163
recordSaveLayer(const SkRect * bounds,const SkPaint * paint,SaveFlags flags)164 void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
165 SaveFlags flags) {
166 fContentInfo.onSaveLayer();
167
168 // op + bool for 'bounds'
169 size_t size = 2 * kUInt32Size;
170 if (bounds) {
171 size += sizeof(*bounds); // + rect
172 }
173 // + paint index + flags
174 size += 2 * kUInt32Size;
175
176 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
177
178 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
179 this->addRectPtr(bounds);
180 SkASSERT(initialOffset+get_paint_offset(SAVE_LAYER, size) == fWriter.bytesWritten());
181 this->addPaintPtr(paint);
182 this->addInt(flags);
183
184 this->validate(initialOffset, size);
185 }
186
187 #ifdef SK_DEBUG
188 /*
189 * Read the op code from 'offset' in 'writer' and extract the size too.
190 */
peek_op_and_size(SkWriter32 * writer,size_t offset,uint32_t * size)191 static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
192 uint32_t peek = writer->readTAt<uint32_t>(offset);
193
194 uint32_t op;
195 UNPACK_8_24(peek, op, *size);
196 if (MASK_24 == *size) {
197 // size required its own slot right after the op code
198 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
199 }
200 return (DrawType) op;
201 }
202 #endif//SK_DEBUG
203
willRestore()204 void SkPictureRecord::willRestore() {
205 // FIXME: SkDeferredCanvas needs to be refactored to respect
206 // save/restore balancing so that the following test can be
207 // turned on permanently.
208 #if 0
209 SkASSERT(fRestoreOffsetStack.count() > 1);
210 #endif
211
212 // check for underflow
213 if (fRestoreOffsetStack.count() == 0) {
214 return;
215 }
216
217 this->recordRestore();
218
219 fRestoreOffsetStack.pop();
220
221 this->INHERITED::willRestore();
222 }
223
recordRestore(bool fillInSkips)224 void SkPictureRecord::recordRestore(bool fillInSkips) {
225 fContentInfo.onRestore();
226
227 if (fillInSkips) {
228 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
229 }
230 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
231 size_t initialOffset = this->addDraw(RESTORE, &size);
232 this->validate(initialOffset, size);
233 }
234
recordTranslate(const SkMatrix & m)235 void SkPictureRecord::recordTranslate(const SkMatrix& m) {
236 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
237
238 // op + dx + dy
239 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
240 size_t initialOffset = this->addDraw(TRANSLATE, &size);
241 this->addScalar(m.getTranslateX());
242 this->addScalar(m.getTranslateY());
243 this->validate(initialOffset, size);
244 }
245
recordScale(const SkMatrix & m)246 void SkPictureRecord::recordScale(const SkMatrix& m) {
247 SkASSERT(SkMatrix::kScale_Mask == m.getType());
248
249 // op + sx + sy
250 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
251 size_t initialOffset = this->addDraw(SCALE, &size);
252 this->addScalar(m.getScaleX());
253 this->addScalar(m.getScaleY());
254 this->validate(initialOffset, size);
255 }
256
didConcat(const SkMatrix & matrix)257 void SkPictureRecord::didConcat(const SkMatrix& matrix) {
258 switch (matrix.getType()) {
259 case SkMatrix::kTranslate_Mask:
260 this->recordTranslate(matrix);
261 break;
262 case SkMatrix::kScale_Mask:
263 this->recordScale(matrix);
264 break;
265 default:
266 this->recordConcat(matrix);
267 break;
268 }
269 this->INHERITED::didConcat(matrix);
270 }
271
recordConcat(const SkMatrix & matrix)272 void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
273 this->validate(fWriter.bytesWritten(), 0);
274 // op + matrix
275 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
276 size_t initialOffset = this->addDraw(CONCAT, &size);
277 this->addMatrix(matrix);
278 this->validate(initialOffset, size);
279 }
280
didSetMatrix(const SkMatrix & matrix)281 void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
282 this->validate(fWriter.bytesWritten(), 0);
283 // op + matrix
284 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
285 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
286 this->addMatrix(matrix);
287 this->validate(initialOffset, size);
288 this->INHERITED::didSetMatrix(matrix);
289 }
290
regionOpExpands(SkRegion::Op op)291 static bool regionOpExpands(SkRegion::Op op) {
292 switch (op) {
293 case SkRegion::kUnion_Op:
294 case SkRegion::kXOR_Op:
295 case SkRegion::kReverseDifference_Op:
296 case SkRegion::kReplace_Op:
297 return true;
298 case SkRegion::kIntersect_Op:
299 case SkRegion::kDifference_Op:
300 return false;
301 default:
302 SkDEBUGFAIL("unknown region op");
303 return false;
304 }
305 }
306
fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset)307 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
308 int32_t offset = fRestoreOffsetStack.top();
309 while (offset > 0) {
310 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
311 fWriter.overwriteTAt(offset, restoreOffset);
312 offset = peek;
313 }
314
315 #ifdef SK_DEBUG
316 // offset of 0 has been disabled, so we skip it
317 if (offset > 0) {
318 // assert that the final offset value points to a save verb
319 uint32_t opSize;
320 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
321 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
322 }
323 #endif
324 }
325
beginRecording()326 void SkPictureRecord::beginRecording() {
327 // we have to call this *after* our constructor, to ensure that it gets
328 // recorded. This is balanced by restoreToCount() call from endRecording,
329 // which in-turn calls our overridden restore(), so those get recorded too.
330 fInitialSaveCount = this->save();
331 }
332
endRecording()333 void SkPictureRecord::endRecording() {
334 SkASSERT(kNoInitialSave != fInitialSaveCount);
335 this->restoreToCount(fInitialSaveCount);
336 }
337
recordRestoreOffsetPlaceholder(SkRegion::Op op)338 size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
339 if (fRestoreOffsetStack.isEmpty()) {
340 return -1;
341 }
342
343 // The RestoreOffset field is initially filled with a placeholder
344 // value that points to the offset of the previous RestoreOffset
345 // in the current stack level, thus forming a linked list so that
346 // the restore offsets can be filled in when the corresponding
347 // restore command is recorded.
348 int32_t prevOffset = fRestoreOffsetStack.top();
349
350 if (regionOpExpands(op)) {
351 // Run back through any previous clip ops, and mark their offset to
352 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
353 // they could hide this clips ability to expand the clip (i.e. go from
354 // empty to non-empty).
355 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
356
357 // Reset the pointer back to the previous clip so that subsequent
358 // restores don't overwrite the offsets we just cleared.
359 prevOffset = 0;
360 }
361
362 size_t offset = fWriter.bytesWritten();
363 this->addInt(prevOffset);
364 fRestoreOffsetStack.top() = SkToU32(offset);
365 return offset;
366 }
367
onClipRect(const SkRect & rect,SkRegion::Op op,ClipEdgeStyle edgeStyle)368 void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
369 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
370 this->INHERITED::onClipRect(rect, op, edgeStyle);
371 }
372
recordClipRect(const SkRect & rect,SkRegion::Op op,bool doAA)373 size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
374 // id + rect + clip params
375 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
376 // recordRestoreOffsetPlaceholder doesn't always write an offset
377 if (!fRestoreOffsetStack.isEmpty()) {
378 // + restore offset
379 size += kUInt32Size;
380 }
381 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
382 this->addRect(rect);
383 this->addInt(ClipParams_pack(op, doAA));
384 size_t offset = this->recordRestoreOffsetPlaceholder(op);
385
386 this->validate(initialOffset, size);
387 return offset;
388 }
389
onClipRRect(const SkRRect & rrect,SkRegion::Op op,ClipEdgeStyle edgeStyle)390 void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
391 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
392 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
393 }
394
recordClipRRect(const SkRRect & rrect,SkRegion::Op op,bool doAA)395 size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
396 // op + rrect + clip params
397 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
398 // recordRestoreOffsetPlaceholder doesn't always write an offset
399 if (!fRestoreOffsetStack.isEmpty()) {
400 // + restore offset
401 size += kUInt32Size;
402 }
403 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
404 this->addRRect(rrect);
405 this->addInt(ClipParams_pack(op, doAA));
406 size_t offset = recordRestoreOffsetPlaceholder(op);
407 this->validate(initialOffset, size);
408 return offset;
409 }
410
onClipPath(const SkPath & path,SkRegion::Op op,ClipEdgeStyle edgeStyle)411 void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
412 int pathID = this->addPathToHeap(path);
413 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
414 this->INHERITED::onClipPath(path, op, edgeStyle);
415 }
416
recordClipPath(int pathID,SkRegion::Op op,bool doAA)417 size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
418 // op + path index + clip params
419 size_t size = 3 * kUInt32Size;
420 // recordRestoreOffsetPlaceholder doesn't always write an offset
421 if (!fRestoreOffsetStack.isEmpty()) {
422 // + restore offset
423 size += kUInt32Size;
424 }
425 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
426 this->addInt(pathID);
427 this->addInt(ClipParams_pack(op, doAA));
428 size_t offset = recordRestoreOffsetPlaceholder(op);
429 this->validate(initialOffset, size);
430 return offset;
431 }
432
onClipRegion(const SkRegion & region,SkRegion::Op op)433 void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
434 this->recordClipRegion(region, op);
435 this->INHERITED::onClipRegion(region, op);
436 }
437
recordClipRegion(const SkRegion & region,SkRegion::Op op)438 size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
439 // op + clip params + region
440 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
441 // recordRestoreOffsetPlaceholder doesn't always write an offset
442 if (!fRestoreOffsetStack.isEmpty()) {
443 // + restore offset
444 size += kUInt32Size;
445 }
446 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
447 this->addRegion(region);
448 this->addInt(ClipParams_pack(op, false));
449 size_t offset = this->recordRestoreOffsetPlaceholder(op);
450
451 this->validate(initialOffset, size);
452 return offset;
453 }
454
onDrawPaint(const SkPaint & paint)455 void SkPictureRecord::onDrawPaint(const SkPaint& paint) {
456 // op + paint index
457 size_t size = 2 * kUInt32Size;
458 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
459 SkASSERT(initialOffset+get_paint_offset(DRAW_PAINT, size) == fWriter.bytesWritten());
460 this->addPaint(paint);
461 this->validate(initialOffset, size);
462 }
463
onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)464 void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
465 const SkPaint& paint) {
466 fContentInfo.onDrawPoints(count, paint);
467
468 // op + paint index + mode + count + point data
469 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
470 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
471 SkASSERT(initialOffset+get_paint_offset(DRAW_POINTS, size) == fWriter.bytesWritten());
472 this->addPaint(paint);
473
474 this->addInt(mode);
475 this->addInt(SkToInt(count));
476 fWriter.writeMul4(pts, count * sizeof(SkPoint));
477 this->validate(initialOffset, size);
478 }
479
onDrawOval(const SkRect & oval,const SkPaint & paint)480 void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) {
481 // op + paint index + rect
482 size_t size = 2 * kUInt32Size + sizeof(oval);
483 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
484 SkASSERT(initialOffset+get_paint_offset(DRAW_OVAL, size) == fWriter.bytesWritten());
485 this->addPaint(paint);
486 this->addRect(oval);
487 this->validate(initialOffset, size);
488 }
489
onDrawRect(const SkRect & rect,const SkPaint & paint)490 void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) {
491 // op + paint index + rect
492 size_t size = 2 * kUInt32Size + sizeof(rect);
493 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
494 SkASSERT(initialOffset+get_paint_offset(DRAW_RECT, size) == fWriter.bytesWritten());
495 this->addPaint(paint);
496 this->addRect(rect);
497 this->validate(initialOffset, size);
498 }
499
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)500 void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
501 // op + paint index + rrect
502 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
503 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
504 SkASSERT(initialOffset+get_paint_offset(DRAW_RRECT, size) == fWriter.bytesWritten());
505 this->addPaint(paint);
506 this->addRRect(rrect);
507 this->validate(initialOffset, size);
508 }
509
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)510 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
511 const SkPaint& paint) {
512 // op + paint index + rrects
513 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
514 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
515 SkASSERT(initialOffset+get_paint_offset(DRAW_DRRECT, size) == fWriter.bytesWritten());
516 this->addPaint(paint);
517 this->addRRect(outer);
518 this->addRRect(inner);
519 this->validate(initialOffset, size);
520 }
521
onDrawPath(const SkPath & path,const SkPaint & paint)522 void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) {
523 fContentInfo.onDrawPath(path, paint);
524
525 // op + paint index + path index
526 size_t size = 3 * kUInt32Size;
527 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
528 SkASSERT(initialOffset+get_paint_offset(DRAW_PATH, size) == fWriter.bytesWritten());
529 this->addPaint(paint);
530 this->addPath(path);
531 this->validate(initialOffset, size);
532 }
533
onDrawBitmap(const SkBitmap & bitmap,SkScalar left,SkScalar top,const SkPaint * paint)534 void SkPictureRecord::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
535 const SkPaint* paint) {
536 // op + paint index + bitmap index + left + top
537 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
538 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
539 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP, size) == fWriter.bytesWritten());
540 this->addPaintPtr(paint);
541 this->addBitmap(bitmap);
542 this->addScalar(left);
543 this->addScalar(top);
544 this->validate(initialOffset, size);
545 }
546
onDrawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,DrawBitmapRectFlags flags)547 void SkPictureRecord::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
548 const SkPaint* paint, DrawBitmapRectFlags flags) {
549 // id + paint index + bitmap index + bool for 'src' + flags
550 size_t size = 5 * kUInt32Size;
551 if (src) {
552 size += sizeof(*src); // + rect
553 }
554 size += sizeof(dst); // + rect
555
556 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
557 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_RECT_TO_RECT, size)
558 == fWriter.bytesWritten());
559 this->addPaintPtr(paint);
560 this->addBitmap(bitmap);
561 this->addRectPtr(src); // may be null
562 this->addRect(dst);
563 this->addInt(flags);
564 this->validate(initialOffset, size);
565 }
566
onDrawImage(const SkImage * image,SkScalar x,SkScalar y,const SkPaint * paint)567 void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
568 const SkPaint* paint) {
569 SkBitmap bm;
570 if (as_IB(image)->getROPixels(&bm)) {
571 this->SkPictureRecord::onDrawBitmap(bm, x, y, paint);
572 }
573 }
574
onDrawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint * paint)575 void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
576 const SkPaint* paint) {
577 SkBitmap bm;
578 if (as_IB(image)->getROPixels(&bm)) {
579 this->SkPictureRecord::onDrawBitmapRect(bm, src, dst, paint, kNone_DrawBitmapRectFlag);
580 }
581 }
582
onDrawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)583 void SkPictureRecord::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
584 const SkRect& dst, const SkPaint* paint) {
585 // op + paint index + bitmap id + center + dst rect
586 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
587 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
588 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
589 this->addPaintPtr(paint);
590 this->addBitmap(bitmap);
591 this->addIRect(center);
592 this->addRect(dst);
593 this->validate(initialOffset, size);
594 }
595
onDrawSprite(const SkBitmap & bitmap,int left,int top,const SkPaint * paint)596 void SkPictureRecord::onDrawSprite(const SkBitmap& bitmap, int left, int top,
597 const SkPaint* paint) {
598 // op + paint index + bitmap index + left + top
599 size_t size = 5 * kUInt32Size;
600 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
601 SkASSERT(initialOffset+get_paint_offset(DRAW_SPRITE, size) == fWriter.bytesWritten());
602 this->addPaintPtr(paint);
603 this->addBitmap(bitmap);
604 this->addInt(left);
605 this->addInt(top);
606 this->validate(initialOffset, size);
607 }
608
onDrawText(const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)609 void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
610 const SkPaint& paint) {
611 // op + paint index + length + 'length' worth of chars + x + y
612 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
613
614 DrawType op = DRAW_TEXT;
615 size_t initialOffset = this->addDraw(op, &size);
616 SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
617 this->addPaint(paint);
618 this->addText(text, byteLength);
619 this->addScalar(x);
620 this->addScalar(y);
621 this->validate(initialOffset, size);
622 }
623
onDrawPosText(const void * text,size_t byteLength,const SkPoint pos[],const SkPaint & paint)624 void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
625 const SkPaint& paint) {
626 int points = paint.countText(text, byteLength);
627
628 // op + paint index + length + 'length' worth of data + num points + x&y point data
629 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint);
630
631 DrawType op = DRAW_POS_TEXT;
632
633 size_t initialOffset = this->addDraw(op, &size);
634 SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
635 this->addPaint(paint);
636 this->addText(text, byteLength);
637 this->addInt(points);
638 fWriter.writeMul4(pos, points * sizeof(SkPoint));
639 this->validate(initialOffset, size);
640 }
641
onDrawPosTextH(const void * text,size_t byteLength,const SkScalar xpos[],SkScalar constY,const SkPaint & paint)642 void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
643 SkScalar constY, const SkPaint& paint) {
644 int points = paint.countText(text, byteLength);
645
646 // op + paint index + length + 'length' worth of data + num points
647 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
648 // + y + the actual points
649 size += 1 * kUInt32Size + points * sizeof(SkScalar);
650
651 size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size);
652 this->addPaint(paint);
653 this->addText(text, byteLength);
654 this->addInt(points);
655 this->addScalar(constY);
656 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
657 this->validate(initialOffset, size);
658 }
659
onDrawTextOnPath(const void * text,size_t byteLength,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)660 void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
661 const SkMatrix* matrix, const SkPaint& paint) {
662 // op + paint index + length + 'length' worth of data + path index + matrix
663 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
664 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
665 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
666 SkASSERT(initialOffset+get_paint_offset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
667 this->addPaint(paint);
668 this->addText(text, byteLength);
669 this->addPath(path);
670 this->addMatrix(m);
671 this->validate(initialOffset, size);
672 }
673
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)674 void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
675 const SkPaint& paint) {
676
677 // op + paint index + blob index + x/y
678 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
679 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
680 SkASSERT(initialOffset + get_paint_offset(DRAW_TEXT_BLOB, size) == fWriter.bytesWritten());
681
682 this->addPaint(paint);
683 this->addTextBlob(blob);
684 this->addScalar(x);
685 this->addScalar(y);
686
687 this->validate(initialOffset, size);
688 }
689
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)690 void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
691 const SkPaint* paint) {
692 // op + picture index
693 size_t size = 2 * kUInt32Size;
694 size_t initialOffset;
695
696 if (NULL == matrix && NULL == paint) {
697 initialOffset = this->addDraw(DRAW_PICTURE, &size);
698 this->addPicture(picture);
699 } else {
700 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
701 size += m.writeToMemory(NULL) + kUInt32Size; // matrix + paint
702 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
703 SkASSERT(initialOffset + get_paint_offset(DRAW_PICTURE_MATRIX_PAINT, size)
704 == fWriter.bytesWritten());
705 this->addPaintPtr(paint);
706 this->addMatrix(m);
707 this->addPicture(picture);
708 }
709 this->validate(initialOffset, size);
710 }
711
onDrawVertices(VertexMode vmode,int vertexCount,const SkPoint vertices[],const SkPoint texs[],const SkColor colors[],SkXfermode * xfer,const uint16_t indices[],int indexCount,const SkPaint & paint)712 void SkPictureRecord::onDrawVertices(VertexMode vmode, int vertexCount,
713 const SkPoint vertices[], const SkPoint texs[],
714 const SkColor colors[], SkXfermode* xfer,
715 const uint16_t indices[], int indexCount,
716 const SkPaint& paint) {
717 uint32_t flags = 0;
718 if (texs) {
719 flags |= DRAW_VERTICES_HAS_TEXS;
720 }
721 if (colors) {
722 flags |= DRAW_VERTICES_HAS_COLORS;
723 }
724 if (indexCount > 0) {
725 flags |= DRAW_VERTICES_HAS_INDICES;
726 }
727 if (xfer) {
728 SkXfermode::Mode mode;
729 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
730 flags |= DRAW_VERTICES_HAS_XFER;
731 }
732 }
733
734 // op + paint index + flags + vmode + vCount + vertices
735 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
736 if (flags & DRAW_VERTICES_HAS_TEXS) {
737 size += vertexCount * sizeof(SkPoint); // + uvs
738 }
739 if (flags & DRAW_VERTICES_HAS_COLORS) {
740 size += vertexCount * sizeof(SkColor); // + vert colors
741 }
742 if (flags & DRAW_VERTICES_HAS_INDICES) {
743 // + num indices + indices
744 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
745 }
746 if (flags & DRAW_VERTICES_HAS_XFER) {
747 size += kUInt32Size; // mode enum
748 }
749
750 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
751 SkASSERT(initialOffset+get_paint_offset(DRAW_VERTICES, size) == fWriter.bytesWritten());
752 this->addPaint(paint);
753 this->addInt(flags);
754 this->addInt(vmode);
755 this->addInt(vertexCount);
756 this->addPoints(vertices, vertexCount);
757 if (flags & DRAW_VERTICES_HAS_TEXS) {
758 this->addPoints(texs, vertexCount);
759 }
760 if (flags & DRAW_VERTICES_HAS_COLORS) {
761 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
762 }
763 if (flags & DRAW_VERTICES_HAS_INDICES) {
764 this->addInt(indexCount);
765 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
766 }
767 if (flags & DRAW_VERTICES_HAS_XFER) {
768 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
769 (void)xfer->asMode(&mode);
770 this->addInt(mode);
771 }
772 this->validate(initialOffset, size);
773 }
774
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkXfermode * xmode,const SkPaint & paint)775 void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
776 const SkPoint texCoords[4], SkXfermode* xmode,
777 const SkPaint& paint) {
778 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
779 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
780 uint32_t flag = 0;
781 if (colors) {
782 flag |= DRAW_VERTICES_HAS_COLORS;
783 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
784 }
785 if (texCoords) {
786 flag |= DRAW_VERTICES_HAS_TEXS;
787 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
788 }
789 if (xmode) {
790 SkXfermode::Mode mode;
791 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
792 flag |= DRAW_VERTICES_HAS_XFER;
793 size += kUInt32Size;
794 }
795 }
796
797 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
798 SkASSERT(initialOffset+get_paint_offset(DRAW_PATCH, size) == fWriter.bytesWritten());
799 this->addPaint(paint);
800 this->addPatch(cubics);
801 this->addInt(flag);
802
803 // write optional parameters
804 if (colors) {
805 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
806 }
807 if (texCoords) {
808 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
809 }
810 if (flag & DRAW_VERTICES_HAS_XFER) {
811 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
812 xmode->asMode(&mode);
813 this->addInt(mode);
814 }
815 this->validate(initialOffset, size);
816 }
817
beginCommentGroup(const char * description)818 void SkPictureRecord::beginCommentGroup(const char* description) {
819 // op/size + length of string + \0 terminated chars
820 size_t length = strlen(description);
821 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
822 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
823 fWriter.writeString(description, length);
824 this->validate(initialOffset, size);
825 }
826
addComment(const char * kywd,const char * value)827 void SkPictureRecord::addComment(const char* kywd, const char* value) {
828 // op/size + 2x length of string + 2x \0 terminated chars
829 size_t kywdLen = strlen(kywd);
830 size_t valueLen = strlen(value);
831 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
832 size_t initialOffset = this->addDraw(COMMENT, &size);
833 fWriter.writeString(kywd, kywdLen);
834 fWriter.writeString(value, valueLen);
835 this->validate(initialOffset, size);
836 }
837
endCommentGroup()838 void SkPictureRecord::endCommentGroup() {
839 // op/size
840 size_t size = 1 * kUInt32Size;
841 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
842 this->validate(initialOffset, size);
843 }
844
845 ///////////////////////////////////////////////////////////////////////////////
846
onNewSurface(const SkImageInfo & info,const SkSurfaceProps &)847 SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
848 return NULL;
849 }
850
851 // If we already have a stored, can we reuse it instead of also storing b?
equivalent(const SkBitmap & a,const SkBitmap & b)852 static bool equivalent(const SkBitmap& a, const SkBitmap& b) {
853 if (a.info() != b.info() || a.pixelRefOrigin() != b.pixelRefOrigin()) {
854 // Requiring a.info() == b.info() may be overkill in some cases (alphatype mismatch),
855 // but it sure makes things easier to reason about below.
856 return false;
857 }
858 if (a.pixelRef() == b.pixelRef()) {
859 return true; // Same shape and same pixels -> same bitmap.
860 }
861
862 // From here down we're going to have to look at the bitmap data, so we require pixelRefs().
863 if (!a.pixelRef() || !b.pixelRef()) {
864 return false;
865 }
866
867 // If the bitmaps have encoded data, check first before locking pixels so they don't decode.
868 SkAutoTUnref<SkData> encA(a.pixelRef()->refEncodedData()),
869 encB(b.pixelRef()->refEncodedData());
870 if (encA && encB) {
871 return encA->equals(encB);
872 } else if (encA || encB) {
873 return false; // One has encoded data but the other does not.
874 }
875
876 // As a last resort, we have to look at the pixels. This will read back textures.
877 SkAutoLockPixels al(a), bl(b);
878 const char* ap = (const char*)a.getPixels();
879 const char* bp = (const char*)b.getPixels();
880 if (ap && bp) {
881 // We check row by row; row bytes might differ.
882 SkASSERT(a.info() == b.info()); // We checked this above.
883 SkASSERT(a.info().bytesPerPixel() > 0); // If we have pixelRefs, this better be true.
884 const SkImageInfo info = a.info();
885 const size_t bytesToCompare = info.width() * info.bytesPerPixel();
886 for (int row = 0; row < info.height(); row++) {
887 if (0 != memcmp(ap, bp, bytesToCompare)) {
888 return false;
889 }
890 ap += a.rowBytes();
891 bp += b.rowBytes();
892 }
893 return true;
894 }
895 return false; // Couldn't get pixels for both bitmaps.
896 }
897
addBitmap(const SkBitmap & bitmap)898 void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
899 // First see if we already have this bitmap. This deduplication should really
900 // only be important for our tests, where bitmaps tend not to be tagged immutable.
901 // In Chrome (and hopefully Android?) they're typically immutable.
902 for (int i = 0; i < fBitmaps.count(); i++) {
903 if (equivalent(fBitmaps[i], bitmap)) {
904 this->addInt(i); // Unlike the rest, bitmap indices are 0-based.
905 return;
906 }
907 }
908 // Don't have it. We'll add it to our list, making sure it's tagged as immutable.
909 if (bitmap.isImmutable()) {
910 // Shallow copies of bitmaps are cheap, so immutable == fast.
911 fBitmaps.push_back(bitmap);
912 } else {
913 // If you see this block on a memory profile, it's a good opportunity to reduce RAM usage.
914 SkBitmap copy;
915 bitmap.copyTo(©);
916 copy.setImmutable();
917 fBitmaps.push_back(copy);
918 }
919 this->addInt(fBitmaps.count()-1); // Remember, 0-based.
920 }
921
addMatrix(const SkMatrix & matrix)922 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
923 fWriter.writeMatrix(matrix);
924 }
925
addPaintPtr(const SkPaint * paint)926 void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
927 fContentInfo.onAddPaintPtr(paint);
928
929 if (paint) {
930 fPaints.push_back(*paint);
931 this->addInt(fPaints.count());
932 } else {
933 this->addInt(0);
934 }
935 }
936
addPathToHeap(const SkPath & path)937 int SkPictureRecord::addPathToHeap(const SkPath& path) {
938 fPaths.push_back(path);
939 return fPaths.count();
940 }
941
addPath(const SkPath & path)942 void SkPictureRecord::addPath(const SkPath& path) {
943 this->addInt(this->addPathToHeap(path));
944 }
945
addPatch(const SkPoint cubics[12])946 void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
947 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
948 }
949
addPicture(const SkPicture * picture)950 void SkPictureRecord::addPicture(const SkPicture* picture) {
951 int index = fPictureRefs.find(picture);
952 if (index < 0) { // not found
953 index = fPictureRefs.count();
954 *fPictureRefs.append() = picture;
955 picture->ref();
956 }
957 // follow the convention of recording a 1-based index
958 this->addInt(index + 1);
959 }
960
addPoint(const SkPoint & point)961 void SkPictureRecord::addPoint(const SkPoint& point) {
962 fWriter.writePoint(point);
963 }
964
addPoints(const SkPoint pts[],int count)965 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
966 fWriter.writeMul4(pts, count * sizeof(SkPoint));
967 }
968
addNoOp()969 void SkPictureRecord::addNoOp() {
970 size_t size = kUInt32Size; // op
971 this->addDraw(NOOP, &size);
972 }
973
addRect(const SkRect & rect)974 void SkPictureRecord::addRect(const SkRect& rect) {
975 fWriter.writeRect(rect);
976 }
977
addRectPtr(const SkRect * rect)978 void SkPictureRecord::addRectPtr(const SkRect* rect) {
979 if (fWriter.writeBool(rect != NULL)) {
980 fWriter.writeRect(*rect);
981 }
982 }
983
addIRect(const SkIRect & rect)984 void SkPictureRecord::addIRect(const SkIRect& rect) {
985 fWriter.write(&rect, sizeof(rect));
986 }
987
addIRectPtr(const SkIRect * rect)988 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
989 if (fWriter.writeBool(rect != NULL)) {
990 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
991 }
992 }
993
addRRect(const SkRRect & rrect)994 void SkPictureRecord::addRRect(const SkRRect& rrect) {
995 fWriter.writeRRect(rrect);
996 }
997
addRegion(const SkRegion & region)998 void SkPictureRecord::addRegion(const SkRegion& region) {
999 fWriter.writeRegion(region);
1000 }
1001
addText(const void * text,size_t byteLength)1002 void SkPictureRecord::addText(const void* text, size_t byteLength) {
1003 fContentInfo.onDrawText();
1004 addInt(SkToInt(byteLength));
1005 fWriter.writePad(text, byteLength);
1006 }
1007
addTextBlob(const SkTextBlob * blob)1008 void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
1009 int index = fTextBlobRefs.count();
1010 *fTextBlobRefs.append() = blob;
1011 blob->ref();
1012 // follow the convention of recording a 1-based index
1013 this->addInt(index + 1);
1014 }
1015
1016 ///////////////////////////////////////////////////////////////////////////////
1017
1018