| 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 |