OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkPictureRecord.h" | 8 #include "SkPictureRecord.h" |
9 #include "SkBBoxHierarchy.h" | |
10 #include "SkDevice.h" | 9 #include "SkDevice.h" |
11 #include "SkPatchUtils.h" | 10 #include "SkPatchUtils.h" |
12 #include "SkPictureStateTree.h" | |
13 #include "SkPixelRef.h" | 11 #include "SkPixelRef.h" |
14 #include "SkRRect.h" | 12 #include "SkRRect.h" |
15 #include "SkTextBlob.h" | 13 #include "SkTextBlob.h" |
16 #include "SkTSearch.h" | 14 #include "SkTSearch.h" |
17 | 15 |
18 #define HEAP_BLOCK_SIZE 4096 | 16 #define HEAP_BLOCK_SIZE 4096 |
19 | 17 |
20 // If SK_RECORD_LITERAL_PICTURES is defined, record our inputs as literally as p
ossible. | |
21 // Otherwise, we can be clever and record faster equivalents. kBeClever is norm
ally true. | |
22 static const bool kBeClever = | |
23 #ifdef SK_RECORD_LITERAL_PICTURES | |
24 false; | |
25 #else | |
26 true; | |
27 #endif | |
28 | |
29 enum { | 18 enum { |
30 // just need a value that save or getSaveCount would never return | 19 // just need a value that save or getSaveCount would never return |
31 kNoInitialSave = -1, | 20 kNoInitialSave = -1, |
32 }; | 21 }; |
33 | 22 |
34 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, et
c. | 23 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, et
c. |
35 static int const kUInt32Size = 4; | 24 static int const kUInt32Size = 4; |
36 | 25 |
37 static const uint32_t kSaveSize = kUInt32Size; | 26 static const uint32_t kSaveSize = kUInt32Size; |
38 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size; | 27 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size; |
39 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect
); | 28 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect
); |
40 | 29 |
41 SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags) | 30 SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags) |
42 : INHERITED(dimensions.width(), dimensions.height()) | 31 : INHERITED(dimensions.width(), dimensions.height()) |
43 , fBoundingHierarchy(NULL) | |
44 , fStateTree(NULL) | |
45 , fFlattenableHeap(HEAP_BLOCK_SIZE) | 32 , fFlattenableHeap(HEAP_BLOCK_SIZE) |
46 , fPaints(&fFlattenableHeap) | 33 , fPaints(&fFlattenableHeap) |
47 , fRecordFlags(flags) | 34 , fRecordFlags(flags) { |
48 , fOptsEnabled(kBeClever) { | |
49 | 35 |
50 fBitmapHeap = SkNEW(SkBitmapHeap); | 36 fBitmapHeap = SkNEW(SkBitmapHeap); |
51 fFlattenableHeap.setBitmapStorage(fBitmapHeap); | 37 fFlattenableHeap.setBitmapStorage(fBitmapHeap); |
52 | 38 |
53 fFirstSavedLayerIndex = kNoSavedLayerIndex; | 39 fFirstSavedLayerIndex = kNoSavedLayerIndex; |
54 fInitialSaveCount = kNoInitialSave; | 40 fInitialSaveCount = kNoInitialSave; |
55 } | 41 } |
56 | 42 |
57 SkPictureRecord::~SkPictureRecord() { | 43 SkPictureRecord::~SkPictureRecord() { |
58 SkSafeUnref(fBitmapHeap); | 44 SkSafeUnref(fBitmapHeap); |
59 SkSafeUnref(fBoundingHierarchy); | |
60 SkSafeUnref(fStateTree); | |
61 fFlattenableHeap.setBitmapStorage(NULL); | 45 fFlattenableHeap.setBitmapStorage(NULL); |
62 fPictureRefs.unrefAll(); | 46 fPictureRefs.unrefAll(); |
63 fTextBlobRefs.unrefAll(); | 47 fTextBlobRefs.unrefAll(); |
64 } | 48 } |
65 | 49 |
66 /////////////////////////////////////////////////////////////////////////////// | 50 /////////////////////////////////////////////////////////////////////////////// |
67 | 51 |
68 // Return the offset of the paint inside a given op's byte stream. A zero | 52 // Return the offset of the paint inside a given op's byte stream. A zero |
69 // return value means there is no paint (and you really shouldn't be calling | 53 // return value means there is no paint (and you really shouldn't be calling |
70 // this method) | 54 // this method) |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 this->addPaintPtr(paint); | 188 this->addPaintPtr(paint); |
205 this->addInt(flags); | 189 this->addInt(flags); |
206 | 190 |
207 this->validate(initialOffset, size); | 191 this->validate(initialOffset, size); |
208 } | 192 } |
209 | 193 |
210 bool SkPictureRecord::isDrawingToLayer() const { | 194 bool SkPictureRecord::isDrawingToLayer() const { |
211 return fFirstSavedLayerIndex != kNoSavedLayerIndex; | 195 return fFirstSavedLayerIndex != kNoSavedLayerIndex; |
212 } | 196 } |
213 | 197 |
214 /* | |
215 * Read the op code from 'offset' in 'writer'. | |
216 */ | |
217 #ifdef SK_DEBUG | 198 #ifdef SK_DEBUG |
218 static DrawType peek_op(SkWriter32* writer, size_t offset) { | |
219 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24); | |
220 } | |
221 #endif | |
222 | |
223 /* | 199 /* |
224 * Read the op code from 'offset' in 'writer' and extract the size too. | 200 * Read the op code from 'offset' in 'writer' and extract the size too. |
225 */ | 201 */ |
226 static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* si
ze) { | 202 static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* si
ze) { |
227 uint32_t peek = writer->readTAt<uint32_t>(offset); | 203 uint32_t peek = writer->readTAt<uint32_t>(offset); |
228 | 204 |
229 uint32_t op; | 205 uint32_t op; |
230 UNPACK_8_24(peek, op, *size); | 206 UNPACK_8_24(peek, op, *size); |
231 if (MASK_24 == *size) { | 207 if (MASK_24 == *size) { |
232 // size required its own slot right after the op code | 208 // size required its own slot right after the op code |
233 *size = writer->readTAt<uint32_t>(offset + kUInt32Size); | 209 *size = writer->readTAt<uint32_t>(offset + kUInt32Size); |
234 } | 210 } |
235 return (DrawType) op; | 211 return (DrawType) op; |
236 } | 212 } |
237 | 213 #endif//SK_DEBUG |
238 // Is the supplied paint simply a color? | |
239 static bool is_simple(const SkPaint& p) { | |
240 intptr_t orAccum = (intptr_t)p.getPathEffect() | | |
241 (intptr_t)p.getShader() | | |
242 (intptr_t)p.getXfermode() | | |
243 (intptr_t)p.getMaskFilter() | | |
244 (intptr_t)p.getColorFilter() | | |
245 (intptr_t)p.getRasterizer() | | |
246 (intptr_t)p.getLooper() | | |
247 (intptr_t)p.getImageFilter(); | |
248 return 0 == orAccum; | |
249 } | |
250 | |
251 // CommandInfos are fed to the 'match' method and filled in with command | |
252 // information. | |
253 struct CommandInfo { | |
254 DrawType fActualOp; | |
255 uint32_t fOffset; | |
256 uint32_t fSize; | |
257 }; | |
258 | |
259 /* | |
260 * Attempt to match the provided pattern of commands starting at 'offset' | |
261 * in the byte stream and stopping at the end of the stream. Upon success, | |
262 * return true with all the pattern information filled out in the result | |
263 * array (i.e., actual ops, offsets and sizes). | |
264 * Note this method skips any NOOPs seen in the stream | |
265 */ | |
266 static bool match(SkWriter32* writer, uint32_t offset, | |
267 int* pattern, CommandInfo* result, int numCommands) { | |
268 SkASSERT(offset < writer->bytesWritten()); | |
269 | |
270 uint32_t curOffset = offset; | |
271 uint32_t curSize = 0; | |
272 int numMatched; | |
273 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWr
itten(); ++numMatched) { | |
274 DrawType op = peek_op_and_size(writer, curOffset, &curSize); | |
275 while (NOOP == op) { | |
276 curOffset += curSize; | |
277 if (curOffset >= writer->bytesWritten()) { | |
278 return false; | |
279 } | |
280 op = peek_op_and_size(writer, curOffset, &curSize); | |
281 } | |
282 | |
283 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) { | |
284 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op && | |
285 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) { | |
286 return false; | |
287 } | |
288 } else if (op != pattern[numMatched]) { | |
289 return false; | |
290 } | |
291 | |
292 result[numMatched].fActualOp = op; | |
293 result[numMatched].fOffset = curOffset; | |
294 result[numMatched].fSize = curSize; | |
295 | |
296 curOffset += curSize; | |
297 } | |
298 | |
299 if (numMatched != numCommands) { | |
300 return false; | |
301 } | |
302 | |
303 if (curOffset < writer->bytesWritten()) { | |
304 // Something else between the last command and the end of the stream | |
305 return false; | |
306 } | |
307 | |
308 return true; | |
309 } | |
310 | |
311 // temporarily here to make code review easier | |
312 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer, | |
313 SkPaintDictionary* paintDict, | |
314 const CommandInfo& saveLayerInf
o, | |
315 const CommandInfo& dbmInfo); | |
316 | |
317 /* | |
318 * Restore has just been called (but not recorded), look back at the | |
319 * matching save* and see if we are in the configuration: | |
320 * SAVE_LAYER | |
321 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_REC
T | |
322 * RESTORE | |
323 * where the saveLayer's color can be moved into the drawBitmap*'s paint | |
324 */ | |
325 static bool remove_save_layer1(SkWriter32* writer, int32_t offset, | |
326 SkPaintDictionary* paintDict) { | |
327 // back up to the save block | |
328 // TODO: add a stack to track save*/restore offsets rather than searching ba
ckwards | |
329 while (offset > 0) { | |
330 offset = writer->readTAt<uint32_t>(offset); | |
331 } | |
332 | |
333 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ }; | |
334 CommandInfo result[SK_ARRAY_COUNT(pattern)]; | |
335 | |
336 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) { | |
337 return false; | |
338 } | |
339 | |
340 if (kSaveLayerWithBoundsSize == result[0].fSize) { | |
341 // The saveLayer's bound can offset where the dbm is drawn | |
342 return false; | |
343 } | |
344 | |
345 return merge_savelayer_paint_into_drawbitmp(writer, paintDict, | |
346 result[0], result[1]); | |
347 } | |
348 | |
349 /* | |
350 * Convert the command code located at 'offset' to a NOOP. Leave the size | |
351 * field alone so the NOOP can be skipped later. | |
352 */ | |
353 static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) { | |
354 uint32_t command = writer->readTAt<uint32_t>(offset); | |
355 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24)); | |
356 } | |
357 | |
358 /* | |
359 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint. | |
360 * Return true on success; false otherwise. | |
361 */ | |
362 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer, | |
363 SkPaintDictionary* paintDict, | |
364 const CommandInfo& saveLayerInf
o, | |
365 const CommandInfo& dbmInfo) { | |
366 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp); | |
367 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp || | |
368 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp || | |
369 DRAW_BITMAP_NINE == dbmInfo.fActualOp || | |
370 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp); | |
371 | |
372 size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize); | |
373 size_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize); | |
374 | |
375 // we have a match, now we need to get the paints involved | |
376 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOf
fset); | |
377 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset
+ slPaintOffset); | |
378 | |
379 if (0 == saveLayerPaintId) { | |
380 // In this case the saveLayer/restore isn't needed at all - just kill th
e saveLayer | |
381 // and signal the caller (by returning true) to not add the RESTORE op | |
382 convert_command_to_noop(writer, saveLayerInfo.fOffset); | |
383 return true; | |
384 } | |
385 | |
386 if (0 == dbmPaintId) { | |
387 // In this case just make the DBM* use the saveLayer's paint, kill the s
aveLayer | |
388 // and signal the caller (by returning true) to not add the RESTORE op | |
389 convert_command_to_noop(writer, saveLayerInfo.fOffset); | |
390 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId)
; | |
391 return true; | |
392 } | |
393 | |
394 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId)
); | |
395 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) { | |
396 return false; | |
397 } | |
398 | |
399 // For this optimization we only fold the saveLayer and drawBitmapRect | |
400 // together if the saveLayer's draw is simple (i.e., no fancy effects) and | |
401 // and the only difference in the colors is that the saveLayer's can have | |
402 // an alpha while the drawBitmapRect's is opaque. | |
403 // TODO: it should be possible to fold them together even if they both | |
404 // have different non-255 alphas | |
405 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaqu
e | |
406 | |
407 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId)); | |
408 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor || !is_simp
le(*dbmPaint)) { | |
409 return false; | |
410 } | |
411 | |
412 SkColor newColor = SkColorSetA(dbmPaint->getColor(), | |
413 SkColorGetA(saveLayerPaint->getColor())); | |
414 dbmPaint->setColor(newColor); | |
415 | |
416 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint); | |
417 if (NULL == data) { | |
418 return false; | |
419 } | |
420 | |
421 // kill the saveLayer and alter the DBMR2R's paint to be the modified one | |
422 convert_command_to_noop(writer, saveLayerInfo.fOffset); | |
423 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index()); | |
424 return true; | |
425 } | |
426 | |
427 /* | |
428 * Restore has just been called (but not recorded), look back at the | |
429 * matching save* and see if we are in the configuration: | |
430 * SAVE_LAYER (with NULL == bounds) | |
431 * SAVE | |
432 * CLIP_RECT | |
433 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_R
ECT | |
434 * RESTORE | |
435 * RESTORE | |
436 * where the saveLayer's color can be moved into the drawBitmap*'s paint | |
437 */ | |
438 static bool remove_save_layer2(SkWriter32* writer, int32_t offset, | |
439 SkPaintDictionary* paintDict) { | |
440 // back up to the save block | |
441 // TODO: add a stack to track save*/restore offsets rather than searching ba
ckwards | |
442 while (offset > 0) { | |
443 offset = writer->readTAt<uint32_t>(offset); | |
444 } | |
445 | |
446 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE,
/* RESTORE */ }; | |
447 CommandInfo result[SK_ARRAY_COUNT(pattern)]; | |
448 | |
449 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) { | |
450 return false; | |
451 } | |
452 | |
453 if (kSaveLayerWithBoundsSize == result[0].fSize) { | |
454 // The saveLayer's bound can offset where the dbm is drawn | |
455 return false; | |
456 } | |
457 | |
458 return merge_savelayer_paint_into_drawbitmp(writer, paintDict, | |
459 result[0], result[3]); | |
460 } | |
461 | |
462 static bool is_drawing_op(DrawType op) { | |
463 | |
464 // FIXME: yuck. convert to a lookup table? | |
465 return (op > CONCAT && op < ROTATE) | |
466 || DRAW_DRRECT == op | |
467 || DRAW_PATCH == op | |
468 || DRAW_PICTURE_MATRIX_PAINT == op | |
469 || DRAW_TEXT_BLOB == op; | |
470 } | |
471 | |
472 /* | |
473 * Restore has just been called (but not recorded), so look back at the | |
474 * matching save(), and see if we can eliminate the pair of them, due to no | |
475 * intervening matrix/clip calls. | |
476 * | |
477 * If so, update the writer and return true, in which case we won't even record | |
478 * the restore() call. If we still need the restore(), return false. | |
479 */ | |
480 static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset, | |
481 SkPaintDictionary* paintDict) { | |
482 int32_t restoreOffset = (int32_t)writer->bytesWritten(); | |
483 | |
484 // back up to the save block | |
485 while (offset > 0) { | |
486 offset = writer->readTAt<uint32_t>(offset); | |
487 } | |
488 | |
489 // now offset points to a save | |
490 offset = -offset; | |
491 uint32_t opSize; | |
492 DrawType op = peek_op_and_size(writer, offset, &opSize); | |
493 if (SAVE_LAYER == op) { | |
494 // not ready to cull these out yet (mrr) | |
495 return false; | |
496 } | |
497 SkASSERT(SAVE == op); | |
498 SkASSERT(kSaveSize == opSize); | |
499 | |
500 // Walk forward until we get back to either a draw-verb (abort) or we hit | |
501 // our restore (success). | |
502 int32_t saveOffset = offset; | |
503 | |
504 offset += opSize; | |
505 while (offset < restoreOffset) { | |
506 op = peek_op_and_size(writer, offset, &opSize); | |
507 if (is_drawing_op(op) || (SAVE_LAYER == op)) { | |
508 // drawing verb, abort | |
509 return false; | |
510 } | |
511 offset += opSize; | |
512 } | |
513 | |
514 writer->rewindToOffset(saveOffset); | |
515 return true; | |
516 } | |
517 | |
518 typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset, | |
519 SkPaintDictionary* paintDict); | |
520 enum PictureRecordOptType { | |
521 kRewind_OptType, // Optimization rewinds the command stream | |
522 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair | |
523 }; | |
524 | |
525 enum PictureRecordOptFlags { | |
526 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the | |
527 // SkPicture has a bounding box hierarchy
. | |
528 kRescindLastSave_Flag = 0x2, | |
529 kRescindLastSaveLayer_Flag = 0x4, | |
530 }; | |
531 | |
532 struct PictureRecordOpt { | |
533 PictureRecordOptProc fProc; | |
534 PictureRecordOptType fType; | |
535 unsigned fFlags; | |
536 }; | |
537 /* | |
538 * A list of the optimizations that are tried upon seeing a restore | |
539 * TODO: add a real API for such optimizations | |
540 * Add the ability to fire optimizations on any op (not just RESTORE) | |
541 */ | |
542 static const PictureRecordOpt gPictureRecordOpts[] = { | |
543 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy | |
544 // because it is redundant with the state traversal optimization in | |
545 // SkPictureStateTree, and applying the optimization introduces significant | |
546 // record time overhead because it requires rewinding contents that were | |
547 // recorded into the BBoxHierarchy. | |
548 { collapse_save_clip_restore, kRewind_OptType, | |
549 kSkipIfBBoxHierarchy_Flag|kResci
ndLastSave_Flag }, | |
550 { remove_save_layer1, kCollapseSaveLayer_OptType, kRescindLastSaveLa
yer_Flag }, | |
551 { remove_save_layer2, kCollapseSaveLayer_OptType, kRescindLastSaveLa
yer_Flag } | |
552 }; | |
553 | |
554 // This is called after an optimization has been applied to the command stream | |
555 // in order to adjust the contents and state of the bounding box hierarchy and | |
556 // state tree to reflect the optimization. | |
557 static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTr
ee* stateTree, | |
558 SkBBoxHierarchy* boundingHierarchy) { | |
559 switch (opt) { | |
560 case kCollapseSaveLayer_OptType: | |
561 if (stateTree) { | |
562 stateTree->saveCollapsed(); | |
563 } | |
564 break; | |
565 case kRewind_OptType: | |
566 if (boundingHierarchy) { | |
567 boundingHierarchy->rewindInserts(); | |
568 } | |
569 // Note: No need to touch the state tree for this to work correctly. | |
570 // Unused branches do not burden the playback, and pruning the tree | |
571 // would be O(N^2), so it is best to leave it alone. | |
572 break; | |
573 default: | |
574 SkASSERT(0); | |
575 } | |
576 } | |
577 | 214 |
578 void SkPictureRecord::willRestore() { | 215 void SkPictureRecord::willRestore() { |
579 // FIXME: SkDeferredCanvas needs to be refactored to respect | 216 // FIXME: SkDeferredCanvas needs to be refactored to respect |
580 // save/restore balancing so that the following test can be | 217 // save/restore balancing so that the following test can be |
581 // turned on permanently. | 218 // turned on permanently. |
582 #if 0 | 219 #if 0 |
583 SkASSERT(fRestoreOffsetStack.count() > 1); | 220 SkASSERT(fRestoreOffsetStack.count() > 1); |
584 #endif | 221 #endif |
585 | 222 |
586 // check for underflow | 223 // check for underflow |
587 if (fRestoreOffsetStack.count() == 0) { | 224 if (fRestoreOffsetStack.count() == 0) { |
588 return; | 225 return; |
589 } | 226 } |
590 | 227 |
591 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) { | 228 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) { |
592 fFirstSavedLayerIndex = kNoSavedLayerIndex; | 229 fFirstSavedLayerIndex = kNoSavedLayerIndex; |
593 } | 230 } |
594 | 231 |
595 size_t opt = 0; | 232 this->recordRestore(); |
596 if (fOptsEnabled) { | |
597 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) { | |
598 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag
) | |
599 && fBoundingHierarchy) { | |
600 continue; | |
601 } | |
602 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.t
op(), &fPaints)) { | |
603 // Some optimization fired so don't add the RESTORE | |
604 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType, | |
605 fStateTree, fBoundingHierarchy); | |
606 if (gPictureRecordOpts[opt].fFlags & kRescindLastSave_Flag) { | |
607 fContentInfo.rescindLastSave(); | |
608 } else if (gPictureRecordOpts[opt].fFlags & kRescindLastSaveLaye
r_Flag) { | |
609 fContentInfo.rescindLastSaveLayer(); | |
610 } | |
611 break; | |
612 } | |
613 } | |
614 } | |
615 | |
616 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) { | |
617 // No optimization fired so add the RESTORE | |
618 this->recordRestore(); | |
619 } | |
620 | 233 |
621 fRestoreOffsetStack.pop(); | 234 fRestoreOffsetStack.pop(); |
622 | 235 |
623 this->INHERITED::willRestore(); | 236 this->INHERITED::willRestore(); |
624 } | 237 } |
625 | 238 |
626 void SkPictureRecord::recordRestore(bool fillInSkips) { | 239 void SkPictureRecord::recordRestore(bool fillInSkips) { |
627 fContentInfo.onRestore(); | 240 fContentInfo.onRestore(); |
628 | 241 |
629 if (fillInSkips) { | 242 if (fillInSkips) { |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
898 // op + paint index + rect | 511 // op + paint index + rect |
899 size_t size = 2 * kUInt32Size + sizeof(rect); | 512 size_t size = 2 * kUInt32Size + sizeof(rect); |
900 size_t initialOffset = this->addDraw(DRAW_RECT, &size); | 513 size_t initialOffset = this->addDraw(DRAW_RECT, &size); |
901 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritt
en()); | 514 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritt
en()); |
902 this->addPaint(paint); | 515 this->addPaint(paint); |
903 this->addRect(rect); | 516 this->addRect(rect); |
904 this->validate(initialOffset, size); | 517 this->validate(initialOffset, size); |
905 } | 518 } |
906 | 519 |
907 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { | 520 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { |
908 if (rrect.isRect() && kBeClever) { | 521 // op + paint index + rrect |
909 this->SkPictureRecord::drawRect(rrect.getBounds(), paint); | 522 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory; |
910 } else if (rrect.isOval() && kBeClever) { | 523 size_t initialOffset = this->addDraw(DRAW_RRECT, &size); |
911 this->SkPictureRecord::drawOval(rrect.getBounds(), paint); | 524 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWrit
ten()); |
912 } else { | 525 this->addPaint(paint); |
913 // op + paint index + rrect | 526 this->addRRect(rrect); |
914 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory; | 527 this->validate(initialOffset, size); |
915 size_t initialOffset = this->addDraw(DRAW_RRECT, &size); | |
916 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytes
Written()); | |
917 this->addPaint(paint); | |
918 this->addRRect(rrect); | |
919 this->validate(initialOffset, size); | |
920 } | |
921 } | 528 } |
922 | 529 |
923 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, | 530 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, |
924 const SkPaint& paint) { | 531 const SkPaint& paint) { |
925 // op + paint index + rrects | 532 // op + paint index + rrects |
926 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2; | 533 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2; |
927 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size); | 534 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size); |
928 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWri
tten()); | 535 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWri
tten()); |
929 this->addPaint(paint); | 536 this->addPaint(paint); |
930 this->addRRect(outer); | 537 this->addRRect(outer); |
931 this->addRRect(inner); | 538 this->addRRect(inner); |
932 this->validate(initialOffset, size); | 539 this->validate(initialOffset, size); |
933 } | 540 } |
934 | 541 |
935 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { | 542 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { |
936 fContentInfo.onDrawPath(path, paint); | 543 fContentInfo.onDrawPath(path, paint); |
937 | 544 |
938 // op + paint index + path index | 545 // op + paint index + path index |
939 size_t size = 3 * kUInt32Size; | 546 size_t size = 3 * kUInt32Size; |
940 size_t initialOffset = this->addDraw(DRAW_PATH, &size); | 547 size_t initialOffset = this->addDraw(DRAW_PATH, &size); |
941 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritt
en()); | 548 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritt
en()); |
942 this->addPaint(paint); | 549 this->addPaint(paint); |
943 this->addPath(path); | 550 this->addPath(path); |
944 this->validate(initialOffset, size); | 551 this->validate(initialOffset, size); |
945 } | 552 } |
946 | 553 |
947 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar
top, | 554 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar
top, |
948 const SkPaint* paint = NULL) { | 555 const SkPaint* paint = NULL) { |
949 if (bitmap.drawsNothing() && kBeClever) { | |
950 return; | |
951 } | |
952 | |
953 // op + paint index + bitmap index + left + top | 556 // op + paint index + bitmap index + left + top |
954 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); | 557 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); |
955 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size); | 558 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size); |
956 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWri
tten()); | 559 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWri
tten()); |
957 this->addPaintPtr(paint); | 560 this->addPaintPtr(paint); |
958 this->addBitmap(bitmap); | 561 this->addBitmap(bitmap); |
959 this->addScalar(left); | 562 this->addScalar(left); |
960 this->addScalar(top); | 563 this->addScalar(top); |
961 this->validate(initialOffset, size); | 564 this->validate(initialOffset, size); |
962 } | 565 } |
963 | 566 |
964 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect*
src, | 567 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect*
src, |
965 const SkRect& dst, const SkPaint* pai
nt, | 568 const SkRect& dst, const SkPaint* pai
nt, |
966 DrawBitmapRectFlags flags) { | 569 DrawBitmapRectFlags flags) { |
967 if (bitmap.drawsNothing() && kBeClever) { | |
968 return; | |
969 } | |
970 | |
971 // id + paint index + bitmap index + bool for 'src' + flags | 570 // id + paint index + bitmap index + bool for 'src' + flags |
972 size_t size = 5 * kUInt32Size; | 571 size_t size = 5 * kUInt32Size; |
973 if (src) { | 572 if (src) { |
974 size += sizeof(*src); // + rect | 573 size += sizeof(*src); // + rect |
975 } | 574 } |
976 size += sizeof(dst); // + rect | 575 size += sizeof(dst); // + rect |
977 | 576 |
978 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size); | 577 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size); |
979 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) | 578 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) |
980 == fWriter.bytesWritten()); | 579 == fWriter.bytesWritten()); |
981 this->addPaintPtr(paint); | 580 this->addPaintPtr(paint); |
982 this->addBitmap(bitmap); | 581 this->addBitmap(bitmap); |
983 this->addRectPtr(src); // may be null | 582 this->addRectPtr(src); // may be null |
984 this->addRect(dst); | 583 this->addRect(dst); |
985 this->addInt(flags); | 584 this->addInt(flags); |
986 this->validate(initialOffset, size); | 585 this->validate(initialOffset, size); |
987 } | 586 } |
988 | 587 |
989 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m
atrix, | 588 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m
atrix, |
990 const SkPaint* paint) { | 589 const SkPaint* paint) { |
991 if (bitmap.drawsNothing() && kBeClever) { | |
992 return; | |
993 } | |
994 | |
995 // id + paint index + bitmap index + matrix | 590 // id + paint index + bitmap index + matrix |
996 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL); | 591 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL); |
997 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size); | 592 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size); |
998 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.b
ytesWritten()); | 593 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.b
ytesWritten()); |
999 this->addPaintPtr(paint); | 594 this->addPaintPtr(paint); |
1000 this->addBitmap(bitmap); | 595 this->addBitmap(bitmap); |
1001 this->addMatrix(matrix); | 596 this->addMatrix(matrix); |
1002 this->validate(initialOffset, size); | 597 this->validate(initialOffset, size); |
1003 } | 598 } |
1004 | 599 |
1005 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& cent
er, | 600 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& cent
er, |
1006 const SkRect& dst, const SkPaint* paint) { | 601 const SkRect& dst, const SkPaint* paint) { |
1007 if (bitmap.drawsNothing() && kBeClever) { | |
1008 return; | |
1009 } | |
1010 | |
1011 // op + paint index + bitmap id + center + dst rect | 602 // op + paint index + bitmap id + center + dst rect |
1012 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); | 603 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); |
1013 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); | 604 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); |
1014 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.byt
esWritten()); | 605 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.byt
esWritten()); |
1015 this->addPaintPtr(paint); | 606 this->addPaintPtr(paint); |
1016 this->addBitmap(bitmap); | 607 this->addBitmap(bitmap); |
1017 this->addIRect(center); | 608 this->addIRect(center); |
1018 this->addRect(dst); | 609 this->addRect(dst); |
1019 this->validate(initialOffset, size); | 610 this->validate(initialOffset, size); |
1020 } | 611 } |
1021 | 612 |
1022 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top, | 613 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top, |
1023 const SkPaint* paint = NULL) { | 614 const SkPaint* paint = NULL) { |
1024 if (bitmap.drawsNothing() && kBeClever) { | |
1025 return; | |
1026 } | |
1027 | |
1028 // op + paint index + bitmap index + left + top | 615 // op + paint index + bitmap index + left + top |
1029 size_t size = 5 * kUInt32Size; | 616 size_t size = 5 * kUInt32Size; |
1030 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size); | 617 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size); |
1031 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWri
tten()); | 618 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWri
tten()); |
1032 this->addPaintPtr(paint); | 619 this->addPaintPtr(paint); |
1033 this->addBitmap(bitmap); | 620 this->addBitmap(bitmap); |
1034 this->addInt(left); | 621 this->addInt(left); |
1035 this->addInt(top); | 622 this->addInt(top); |
1036 this->validate(initialOffset, size); | 623 this->validate(initialOffset, size); |
1037 } | 624 } |
1038 | 625 |
1039 void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar
topbot[2]) { | |
1040 SkPaint::FontMetrics metrics; | |
1041 paint.getFontMetrics(&metrics); | |
1042 SkRect bounds; | |
1043 // construct a rect so we can see any adjustments from the paint. | |
1044 // we use 0,1 for left,right, just so the rect isn't empty | |
1045 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom); | |
1046 (void)paint.computeFastBounds(bounds, &bounds); | |
1047 topbot[0] = bounds.fTop; | |
1048 topbot[1] = bounds.fBottom; | |
1049 } | |
1050 | |
1051 void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlat
Data& flat, | |
1052 SkScalar minY, SkScalar maxY) { | |
1053 WriteTopBot(paint, flat); | |
1054 this->addScalar(flat.topBot()[0] + minY); | |
1055 this->addScalar(flat.topBot()[1] + maxY); | |
1056 } | |
1057 | |
1058 void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x
, SkScalar y, | 626 void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x
, SkScalar y, |
1059 const SkPaint& paint) { | 627 const SkPaint& paint) { |
1060 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeCl
ever; | |
1061 | |
1062 // op + paint index + length + 'length' worth of chars + x + y | 628 // op + paint index + length + 'length' worth of chars + x + y |
1063 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar); | 629 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar); |
1064 if (fast) { | |
1065 size += 2 * sizeof(SkScalar); // + top & bottom | |
1066 } | |
1067 | 630 |
1068 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT; | 631 DrawType op = DRAW_TEXT; |
1069 size_t initialOffset = this->addDraw(op, &size); | 632 size_t initialOffset = this->addDraw(op, &size); |
1070 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten()); | 633 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten()); |
1071 const SkFlatData* flatPaintData = addPaint(paint); | 634 this->addPaint(paint); |
1072 SkASSERT(flatPaintData); | |
1073 this->addText(text, byteLength); | 635 this->addText(text, byteLength); |
1074 this->addScalar(x); | 636 this->addScalar(x); |
1075 this->addScalar(y); | 637 this->addScalar(y); |
1076 if (fast) { | |
1077 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y); | |
1078 } | |
1079 this->validate(initialOffset, size); | 638 this->validate(initialOffset, size); |
1080 } | 639 } |
1081 | 640 |
1082 void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const S
kPoint pos[], | 641 void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const S
kPoint pos[], |
1083 const SkPaint& paint) { | 642 const SkPaint& paint) { |
1084 int points = paint.countText(text, byteLength); | 643 int points = paint.countText(text, byteLength); |
1085 if (0 == points) | |
1086 return; | |
1087 | 644 |
1088 bool canUseDrawH = true; | 645 // op + paint index + length + 'length' worth of data + num points + x&y poi
nt data |
1089 SkScalar minY = pos[0].fY; | 646 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points
* sizeof(SkPoint); |
1090 SkScalar maxY = pos[0].fY; | |
1091 // check if the caller really should have used drawPosTextH() | |
1092 { | |
1093 const SkScalar firstY = pos[0].fY; | |
1094 for (int index = 1; index < points; index++) { | |
1095 if (pos[index].fY != firstY) { | |
1096 canUseDrawH = false; | |
1097 if (pos[index].fY < minY) { | |
1098 minY = pos[index].fY; | |
1099 } else if (pos[index].fY > maxY) { | |
1100 maxY = pos[index].fY; | |
1101 } | |
1102 } | |
1103 } | |
1104 } | |
1105 | 647 |
1106 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() &&
kBeClever; | 648 DrawType op = DRAW_POS_TEXT; |
1107 bool fast = canUseDrawH && fastBounds && kBeClever; | |
1108 | 649 |
1109 // op + paint index + length + 'length' worth of data + num points | |
1110 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; | |
1111 if (canUseDrawH) { | |
1112 if (fast) { | |
1113 size += 2 * sizeof(SkScalar); // + top & bottom | |
1114 } | |
1115 // + y-pos + actual x-point data | |
1116 size += sizeof(SkScalar) + points * sizeof(SkScalar); | |
1117 } else { | |
1118 // + x&y point data | |
1119 size += points * sizeof(SkPoint); | |
1120 if (fastBounds) { | |
1121 size += 2 * sizeof(SkScalar); // + top & bottom | |
1122 } | |
1123 } | |
1124 | |
1125 DrawType op; | |
1126 if (fast) { | |
1127 op = DRAW_POS_TEXT_H_TOP_BOTTOM; | |
1128 } else if (canUseDrawH) { | |
1129 op = DRAW_POS_TEXT_H; | |
1130 } else if (fastBounds) { | |
1131 op = DRAW_POS_TEXT_TOP_BOTTOM; | |
1132 } else { | |
1133 op = DRAW_POS_TEXT; | |
1134 } | |
1135 size_t initialOffset = this->addDraw(op, &size); | 650 size_t initialOffset = this->addDraw(op, &size); |
1136 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten()); | 651 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten()); |
1137 const SkFlatData* flatPaintData = this->addPaint(paint); | 652 this->addPaint(paint); |
1138 SkASSERT(flatPaintData); | |
1139 this->addText(text, byteLength); | 653 this->addText(text, byteLength); |
1140 this->addInt(points); | 654 this->addInt(points); |
1141 | 655 fWriter.writeMul4(pos, points * sizeof(SkPoint)); |
1142 if (canUseDrawH) { | |
1143 if (fast) { | |
1144 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[
0].fY); | |
1145 } | |
1146 this->addScalar(pos[0].fY); | |
1147 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar)); | |
1148 for (int index = 0; index < points; index++) | |
1149 *xptr++ = pos[index].fX; | |
1150 } else { | |
1151 fWriter.writeMul4(pos, points * sizeof(SkPoint)); | |
1152 if (fastBounds) { | |
1153 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY); | |
1154 } | |
1155 } | |
1156 this->validate(initialOffset, size); | 656 this->validate(initialOffset, size); |
1157 } | 657 } |
1158 | 658 |
1159 void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const
SkScalar xpos[], | 659 void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const
SkScalar xpos[], |
1160 SkScalar constY, const SkPaint& paint) { | 660 SkScalar constY, const SkPaint& paint) { |
1161 const SkFlatData* flatPaintData = this->getFlatPaintData(paint); | |
1162 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData)
; | |
1163 } | |
1164 | |
1165 void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength, | |
1166 const SkScalar xpos[], SkScalar constY, | |
1167 const SkPaint& paint, const SkFlatData* flatPaintData)
{ | |
1168 int points = paint.countText(text, byteLength); | 661 int points = paint.countText(text, byteLength); |
1169 if (0 == points && kBeClever) { | |
1170 return; | |
1171 } | |
1172 | |
1173 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeCl
ever; | |
1174 | 662 |
1175 // op + paint index + length + 'length' worth of data + num points | 663 // op + paint index + length + 'length' worth of data + num points |
1176 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; | 664 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; |
1177 if (fast) { | |
1178 size += 2 * sizeof(SkScalar); // + top & bottom | |
1179 } | |
1180 // + y + the actual points | 665 // + y + the actual points |
1181 size += 1 * kUInt32Size + points * sizeof(SkScalar); | 666 size += 1 * kUInt32Size + points * sizeof(SkScalar); |
1182 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRA
W_POS_TEXT_H, | |
1183 &size); | |
1184 SkASSERT(flatPaintData); | |
1185 this->addFlatPaint(flatPaintData); | |
1186 | 667 |
| 668 size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size); |
| 669 this->addPaint(paint); |
1187 this->addText(text, byteLength); | 670 this->addText(text, byteLength); |
1188 this->addInt(points); | 671 this->addInt(points); |
1189 | |
1190 if (fast) { | |
1191 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY); | |
1192 } | |
1193 this->addScalar(constY); | 672 this->addScalar(constY); |
1194 fWriter.writeMul4(xpos, points * sizeof(SkScalar)); | 673 fWriter.writeMul4(xpos, points * sizeof(SkScalar)); |
1195 this->validate(initialOffset, size); | 674 this->validate(initialOffset, size); |
1196 } | 675 } |
1197 | 676 |
1198 void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, cons
t SkPath& path, | 677 void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, cons
t SkPath& path, |
1199 const SkMatrix* matrix, const SkPaint& pa
int) { | 678 const SkMatrix* matrix, const SkPaint& pa
int) { |
1200 // op + paint index + length + 'length' worth of data + path index + matrix | 679 // op + paint index + length + 'length' worth of data + path index + matrix |
1201 const SkMatrix& m = matrix ? *matrix : SkMatrix::I(); | 680 const SkMatrix& m = matrix ? *matrix : SkMatrix::I(); |
1202 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.write
ToMemory(NULL); | 681 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.write
ToMemory(NULL); |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1324 flag |= DRAW_VERTICES_HAS_TEXS; | 803 flag |= DRAW_VERTICES_HAS_TEXS; |
1325 size += SkPatchUtils::kNumCorners * sizeof(SkPoint); | 804 size += SkPatchUtils::kNumCorners * sizeof(SkPoint); |
1326 } | 805 } |
1327 if (xmode) { | 806 if (xmode) { |
1328 SkXfermode::Mode mode; | 807 SkXfermode::Mode mode; |
1329 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) { | 808 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) { |
1330 flag |= DRAW_VERTICES_HAS_XFER; | 809 flag |= DRAW_VERTICES_HAS_XFER; |
1331 size += kUInt32Size; | 810 size += kUInt32Size; |
1332 } | 811 } |
1333 } | 812 } |
1334 | 813 |
1335 size_t initialOffset = this->addDraw(DRAW_PATCH, &size); | 814 size_t initialOffset = this->addDraw(DRAW_PATCH, &size); |
1336 SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWrit
ten()); | 815 SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWrit
ten()); |
1337 this->addPaint(paint); | 816 this->addPaint(paint); |
1338 this->addPatch(cubics); | 817 this->addPatch(cubics); |
1339 this->addInt(flag); | 818 this->addInt(flag); |
1340 | 819 |
1341 // write optional parameters | 820 // write optional parameters |
1342 if (colors) { | 821 if (colors) { |
1343 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor)); | 822 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor)); |
1344 } | 823 } |
1345 if (texCoords) { | 824 if (texCoords) { |
1346 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint)); | 825 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint)); |
1347 } | 826 } |
1348 if (flag & DRAW_VERTICES_HAS_XFER) { | 827 if (flag & DRAW_VERTICES_HAS_XFER) { |
1349 SkXfermode::Mode mode = SkXfermode::kModulate_Mode; | 828 SkXfermode::Mode mode = SkXfermode::kModulate_Mode; |
1350 xmode->asMode(&mode); | 829 xmode->asMode(&mode); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1402 this->addInt(0); | 881 this->addInt(0); |
1403 this->validate(initialOffset, size); | 882 this->validate(initialOffset, size); |
1404 } | 883 } |
1405 | 884 |
1406 void SkPictureRecord::onPopCull() { | 885 void SkPictureRecord::onPopCull() { |
1407 SkASSERT(!fCullOffsetStack.isEmpty()); | 886 SkASSERT(!fCullOffsetStack.isEmpty()); |
1408 | 887 |
1409 uint32_t cullSkipOffset = fCullOffsetStack.top(); | 888 uint32_t cullSkipOffset = fCullOffsetStack.top(); |
1410 fCullOffsetStack.pop(); | 889 fCullOffsetStack.pop(); |
1411 | 890 |
1412 // Collapse empty push/pop pairs. | |
1413 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeC
lever) { | |
1414 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize); | |
1415 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCu
llOpSize)); | |
1416 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize); | |
1417 return; | |
1418 } | |
1419 | |
1420 // op only | 891 // op only |
1421 size_t size = kUInt32Size; | 892 size_t size = kUInt32Size; |
1422 size_t initialOffset = this->addDraw(POP_CULL, &size); | 893 size_t initialOffset = this->addDraw(POP_CULL, &size); |
1423 | 894 |
1424 // update the cull skip offset to point past this op. | 895 // update the cull skip offset to point past this op. |
1425 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten(
))); | 896 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten(
))); |
1426 | 897 |
1427 this->validate(initialOffset, size); | 898 this->validate(initialOffset, size); |
1428 } | 899 } |
1429 | 900 |
(...skipping 10 matching lines...) Expand all Loading... |
1440 // was a problem. | 911 // was a problem. |
1441 SkASSERT(index != SkBitmapHeap::INVALID_SLOT); | 912 SkASSERT(index != SkBitmapHeap::INVALID_SLOT); |
1442 this->addInt(index); | 913 this->addInt(index); |
1443 return index; | 914 return index; |
1444 } | 915 } |
1445 | 916 |
1446 void SkPictureRecord::addMatrix(const SkMatrix& matrix) { | 917 void SkPictureRecord::addMatrix(const SkMatrix& matrix) { |
1447 fWriter.writeMatrix(matrix); | 918 fWriter.writeMatrix(matrix); |
1448 } | 919 } |
1449 | 920 |
1450 const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) { | 921 void SkPictureRecord::addPaintPtr(const SkPaint* paint) { |
1451 return fPaints.findAndReturnFlat(paint); | |
1452 } | |
1453 | |
1454 const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) { | |
1455 fContentInfo.onAddPaintPtr(paint); | 922 fContentInfo.onAddPaintPtr(paint); |
1456 | 923 |
1457 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL; | 924 if (paint) { |
1458 this->addFlatPaint(data); | 925 const SkFlatData* flat = fPaints.findAndReturnFlat(*paint); |
1459 return data; | 926 SkASSERT(flat && flat->index() != 0); |
1460 } | 927 this->addInt(flat->index()); |
1461 | 928 } else { |
1462 void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) { | 929 this->addInt(0); |
1463 int index = flatPaint ? flatPaint->index() : 0; | 930 } |
1464 this->addInt(index); | |
1465 } | 931 } |
1466 | 932 |
1467 int SkPictureRecord::addPathToHeap(const SkPath& path) { | 933 int SkPictureRecord::addPathToHeap(const SkPath& path) { |
1468 if (NULL == fPathHeap) { | 934 if (NULL == fPathHeap) { |
1469 fPathHeap.reset(SkNEW(SkPathHeap)); | 935 fPathHeap.reset(SkNEW(SkPathHeap)); |
1470 } | 936 } |
1471 #ifdef SK_DEDUP_PICTURE_PATHS | 937 #ifdef SK_DEDUP_PICTURE_PATHS |
1472 return fPathHeap->insert(path); | 938 return fPathHeap->insert(path); |
1473 #else | 939 #else |
1474 return fPathHeap->append(path); | 940 return fPathHeap->append(path); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1544 void SkPictureRecord::addTextBlob(const SkTextBlob *blob) { | 1010 void SkPictureRecord::addTextBlob(const SkTextBlob *blob) { |
1545 int index = fTextBlobRefs.count(); | 1011 int index = fTextBlobRefs.count(); |
1546 *fTextBlobRefs.append() = blob; | 1012 *fTextBlobRefs.append() = blob; |
1547 blob->ref(); | 1013 blob->ref(); |
1548 // follow the convention of recording a 1-based index | 1014 // follow the convention of recording a 1-based index |
1549 this->addInt(index + 1); | 1015 this->addInt(index + 1); |
1550 } | 1016 } |
1551 | 1017 |
1552 /////////////////////////////////////////////////////////////////////////////// | 1018 /////////////////////////////////////////////////////////////////////////////// |
1553 | 1019 |
OLD | NEW |