SkPicture.cpp revision 9b14f26d0f3a974f3dd626c8354e1db1cfcd322f
1 2/* 3 * Copyright 2007 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10#include "SkPictureFlat.h" 11#include "SkPicturePlayback.h" 12#include "SkPictureRecord.h" 13 14#include "SkBBHFactory.h" 15#include "SkBitmapDevice.h" 16#include "SkCanvas.h" 17#include "SkChunkAlloc.h" 18#include "SkPaintPriv.h" 19#include "SkPicture.h" 20#include "SkRegion.h" 21#include "SkStream.h" 22#include "SkTDArray.h" 23#include "SkTSearch.h" 24#include "SkTime.h" 25 26#include "SkReader32.h" 27#include "SkWriter32.h" 28#include "SkRTree.h" 29#include "SkBBoxHierarchyRecord.h" 30 31#if SK_SUPPORT_GPU 32#include "GrContext.h" 33#endif 34 35template <typename T> int SafeCount(const T* obj) { 36 return obj ? obj->count() : 0; 37} 38 39#define DUMP_BUFFER_SIZE 65536 40 41//#define ENABLE_TIME_DRAW // dumps milliseconds for each draw 42 43 44#ifdef SK_DEBUG 45// enable SK_DEBUG_TRACE to trace DrawType elements when 46// recorded and played back 47// #define SK_DEBUG_TRACE 48// enable SK_DEBUG_SIZE to see the size of picture components 49// #define SK_DEBUG_SIZE 50// enable SK_DEBUG_DUMP to see the contents of recorded elements 51// #define SK_DEBUG_DUMP 52// enable SK_DEBUG_VALIDATE to check internal structures for consistency 53// #define SK_DEBUG_VALIDATE 54#endif 55 56#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP 57const char* DrawTypeToString(DrawType drawType) { 58 switch (drawType) { 59 case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break; 60 case CLIP_PATH: return "CLIP_PATH"; 61 case CLIP_REGION: return "CLIP_REGION"; 62 case CLIP_RECT: return "CLIP_RECT"; 63 case CLIP_RRECT: return "CLIP_RRECT"; 64 case CONCAT: return "CONCAT"; 65 case DRAW_BITMAP: return "DRAW_BITMAP"; 66 case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX"; 67 case DRAW_BITMAP_NINE: return "DRAW_BITMAP_NINE"; 68 case DRAW_BITMAP_RECT_TO_RECT: return "DRAW_BITMAP_RECT_TO_RECT"; 69 case DRAW_CLEAR: return "DRAW_CLEAR"; 70 case DRAW_DATA: return "DRAW_DATA"; 71 case DRAW_OVAL: return "DRAW_OVAL"; 72 case DRAW_PAINT: return "DRAW_PAINT"; 73 case DRAW_PATH: return "DRAW_PATH"; 74 case DRAW_PICTURE: return "DRAW_PICTURE"; 75 case DRAW_POINTS: return "DRAW_POINTS"; 76 case DRAW_POS_TEXT: return "DRAW_POS_TEXT"; 77 case DRAW_POS_TEXT_TOP_BOTTOM: return "DRAW_POS_TEXT_TOP_BOTTOM"; 78 case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H"; 79 case DRAW_POS_TEXT_H_TOP_BOTTOM: return "DRAW_POS_TEXT_H_TOP_BOTTOM"; 80 case DRAW_RECT: return "DRAW_RECT"; 81 case DRAW_RRECT: return "DRAW_RRECT"; 82 case DRAW_SPRITE: return "DRAW_SPRITE"; 83 case DRAW_TEXT: return "DRAW_TEXT"; 84 case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH"; 85 case DRAW_TEXT_TOP_BOTTOM: return "DRAW_TEXT_TOP_BOTTOM"; 86 case DRAW_VERTICES: return "DRAW_VERTICES"; 87 case RESTORE: return "RESTORE"; 88 case ROTATE: return "ROTATE"; 89 case SAVE: return "SAVE"; 90 case SAVE_LAYER: return "SAVE_LAYER"; 91 case SCALE: return "SCALE"; 92 case SET_MATRIX: return "SET_MATRIX"; 93 case SKEW: return "SKEW"; 94 case TRANSLATE: return "TRANSLATE"; 95 case NOOP: return "NOOP"; 96 default: 97 SkDebugf("DrawType error 0x%08x\n", drawType); 98 SkASSERT(0); 99 break; 100 } 101 SkASSERT(0); 102 return NULL; 103} 104#endif 105 106#ifdef SK_DEBUG_VALIDATE 107static void validateMatrix(const SkMatrix* matrix) { 108 SkScalar scaleX = matrix->getScaleX(); 109 SkScalar scaleY = matrix->getScaleY(); 110 SkScalar skewX = matrix->getSkewX(); 111 SkScalar skewY = matrix->getSkewY(); 112 SkScalar perspX = matrix->getPerspX(); 113 SkScalar perspY = matrix->getPerspY(); 114 if (scaleX != 0 && skewX != 0) 115 SkDebugf("scaleX != 0 && skewX != 0\n"); 116 SkASSERT(scaleX == 0 || skewX == 0); 117 SkASSERT(scaleY == 0 || skewY == 0); 118 SkASSERT(perspX == 0); 119 SkASSERT(perspY == 0); 120} 121#endif 122 123 124/////////////////////////////////////////////////////////////////////////////// 125 126SkPicture::SkPicture() 127 : fAccelData(NULL) { 128 this->needsNewGenID(); 129 fRecord = NULL; 130 fPlayback = NULL; 131 fWidth = fHeight = 0; 132} 133 134// This method makes a SkPicturePlayback object from an in-progress recording. 135// Unfortunately, it does not include the restoreToCount of a real endRecording 136// call. 137SkPicturePlayback* SkPicture::FakeEndRecording(const SkPicture* resourceSrc, 138 const SkPictureRecord& record, 139 bool deepCopy) { 140 SkPictInfo info; 141 resourceSrc->createHeader(&info); 142 return SkNEW_ARGS(SkPicturePlayback, (resourceSrc, record, info, deepCopy)); 143} 144 145SkPicture::SkPicture(const SkPicture& src) 146 : INHERITED() 147 , fAccelData(NULL) 148 , fContentInfo(src.fContentInfo) { 149 this->needsNewGenID(); 150 fWidth = src.fWidth; 151 fHeight = src.fHeight; 152 fRecord = NULL; 153 154 /* We want to copy the src's playback. However, if that hasn't been built 155 yet, we need to fake a call to endRecording() without actually calling 156 it (since it is destructive, and we don't want to change src). 157 */ 158 if (src.fPlayback) { 159 fPlayback = SkNEW_ARGS(SkPicturePlayback, (this, *src.fPlayback)); 160 SkASSERT(NULL == src.fRecord); 161 fUniqueID = src.uniqueID(); // need to call method to ensure != 0 162 } else if (src.fRecord) { 163 fPlayback = FakeEndRecording(this, *src.fRecord, false); 164 } else { 165 fPlayback = NULL; 166 } 167 168 fPathHeap.reset(SkSafeRef(src.fPathHeap.get())); 169} 170 171const SkPath& SkPicture::getPath(int index) const { 172 return (*fPathHeap.get())[index]; 173} 174 175int SkPicture::addPathToHeap(const SkPath& path) { 176 if (NULL == fPathHeap) { 177 fPathHeap.reset(SkNEW(SkPathHeap)); 178 } 179#ifdef SK_DEDUP_PICTURE_PATHS 180 return fPathHeap->insert(path); 181#else 182 return fPathHeap->append(path); 183#endif 184} 185 186void SkPicture::initForPlayback() const { 187 // ensure that the paths bounds are pre-computed 188 if (NULL != fPathHeap.get()) { 189 for (int i = 0; i < fPathHeap->count(); i++) { 190 (*fPathHeap.get())[i].updateBoundsCache(); 191 } 192 } 193} 194 195void SkPicture::dumpSize() const { 196 SkDebugf("--- picture size: paths=%d\n", 197 SafeCount(fPathHeap.get())); 198} 199 200SkPicture::~SkPicture() { 201 SkSafeUnref(fRecord); 202 SkDELETE(fPlayback); 203 SkSafeUnref(fAccelData); 204} 205 206void SkPicture::internalOnly_EnableOpts(bool enableOpts) { 207 if (NULL != fRecord) { 208 fRecord->internalOnly_EnableOpts(enableOpts); 209 } 210} 211 212void SkPicture::swap(SkPicture& other) { 213 SkTSwap(fUniqueID, other.fUniqueID); 214 SkTSwap(fRecord, other.fRecord); 215 SkTSwap(fPlayback, other.fPlayback); 216 SkTSwap(fAccelData, other.fAccelData); 217 SkTSwap(fWidth, other.fWidth); 218 SkTSwap(fHeight, other.fHeight); 219 fPathHeap.swap(&other.fPathHeap); 220 fContentInfo.swap(&other.fContentInfo); 221} 222 223SkPicture* SkPicture::clone() const { 224 SkPicture* clonedPicture = SkNEW(SkPicture); 225 this->clone(clonedPicture, 1); 226 return clonedPicture; 227} 228 229void SkPicture::clone(SkPicture* pictures, int count) const { 230 SkPictCopyInfo copyInfo; 231 232 for (int i = 0; i < count; i++) { 233 SkPicture* clone = &pictures[i]; 234 235 clone->needsNewGenID(); 236 clone->fWidth = fWidth; 237 clone->fHeight = fHeight; 238 SkSafeSetNull(clone->fRecord); 239 SkDELETE(clone->fPlayback); 240 clone->fContentInfo.set(fContentInfo); 241 242 /* We want to copy the src's playback. However, if that hasn't been built 243 yet, we need to fake a call to endRecording() without actually calling 244 it (since it is destructive, and we don't want to change src). 245 */ 246 if (fPlayback) { 247 if (!copyInfo.initialized) { 248 int paintCount = SafeCount(fPlayback->fPaints); 249 250 /* The alternative to doing this is to have a clone method on the paint and have it 251 * make the deep copy of its internal structures as needed. The holdup to doing 252 * that is at this point we would need to pass the SkBitmapHeap so that we don't 253 * unnecessarily flatten the pixels in a bitmap shader. 254 */ 255 copyInfo.paintData.setCount(paintCount); 256 257 /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is 258 * one, use it. If this SkPicturePlayback was created from a stream, fBitmapHeap 259 * will be NULL, so create a new one. 260 */ 261 if (fPlayback->fBitmapHeap.get() == NULL) { 262 // FIXME: Put this on the stack inside SkPicture::clone. 263 SkBitmapHeap* heap = SkNEW(SkBitmapHeap); 264 copyInfo.controller.setBitmapStorage(heap); 265 heap->unref(); 266 } else { 267 copyInfo.controller.setBitmapStorage(fPlayback->fBitmapHeap); 268 } 269 270 SkDEBUGCODE(int heapSize = SafeCount(fPlayback->fBitmapHeap.get());) 271 for (int i = 0; i < paintCount; i++) { 272 if (NeedsDeepCopy(fPlayback->fPaints->at(i))) { 273 copyInfo.paintData[i] = 274 SkFlatData::Create<SkPaint::FlatteningTraits>(©Info.controller, 275 fPlayback->fPaints->at(i), 0); 276 277 } else { 278 // this is our sentinel, which we use in the unflatten loop 279 copyInfo.paintData[i] = NULL; 280 } 281 } 282 SkASSERT(SafeCount(fPlayback->fBitmapHeap.get()) == heapSize); 283 284 // needed to create typeface playback 285 copyInfo.controller.setupPlaybacks(); 286 copyInfo.initialized = true; 287 } 288 289 clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (clone, *fPlayback, ©Info)); 290 SkASSERT(NULL == fRecord); 291 clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0 292 } else if (fRecord) { 293 clone->fPlayback = FakeEndRecording(clone, *fRecord, true); 294 } else { 295 clone->fPlayback = NULL; 296 } 297 298 clone->fPathHeap.reset(SkSafeRef(fPathHeap.get())); 299 } 300} 301 302SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() { 303 static int32_t gNextID = 0; 304 305 int32_t id = sk_atomic_inc(&gNextID); 306 if (id >= 1 << (8 * sizeof(Domain))) { 307 SK_CRASH(); 308 } 309 310 return static_cast<Domain>(id); 311} 312 313/////////////////////////////////////////////////////////////////////////////// 314 315SkCanvas* SkPicture::beginRecording(int width, int height, 316 SkBBHFactory* bbhFactory, 317 uint32_t recordingFlags) { 318 if (fPlayback) { 319 SkDELETE(fPlayback); 320 fPlayback = NULL; 321 } 322 SkSafeUnref(fAccelData); 323 SkSafeSetNull(fRecord); 324 SkASSERT(NULL == fPathHeap); 325 fContentInfo.reset(); 326 327 this->needsNewGenID(); 328 329 fWidth = width; 330 fHeight = height; 331 332 const SkISize size = SkISize::Make(width, height); 333 334 if (NULL != bbhFactory) { 335 SkAutoTUnref<SkBBoxHierarchy> tree((*bbhFactory)(width, height)); 336 SkASSERT(NULL != tree); 337 fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (this, size, recordingFlags, tree.get())); 338 } else { 339 fRecord = SkNEW_ARGS(SkPictureRecord, (this, size, recordingFlags)); 340 } 341 fRecord->beginRecording(); 342 343 return fRecord; 344} 345 346SkCanvas* SkPicture::getRecordingCanvas() const { 347 // will be null if we are not recording 348 return fRecord; 349} 350 351void SkPicture::endRecording() { 352 if (NULL == fPlayback) { 353 if (NULL != fRecord) { 354 fRecord->endRecording(); 355 SkPictInfo info; 356 this->createHeader(&info); 357 fPlayback = SkNEW_ARGS(SkPicturePlayback, (this, *fRecord, info)); 358 SkSafeSetNull(fRecord); 359 } 360 } 361 SkASSERT(NULL == fRecord); 362} 363 364const SkPicture::OperationList& SkPicture::OperationList::InvalidList() { 365 static OperationList gInvalid; 366 return gInvalid; 367} 368 369const SkPicture::OperationList& SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const { 370 SkASSERT(NULL != fPlayback && NULL == fRecord); 371 if (NULL != fPlayback) { 372 return fPlayback->getActiveOps(queryRect); 373 } 374 return OperationList::InvalidList(); 375} 376 377size_t SkPicture::EXPERIMENTAL_curOpID() const { 378 if (NULL != fPlayback) { 379 return fPlayback->curOpID(); 380 } 381 return 0; 382} 383 384void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) const { 385 SkASSERT(NULL != fPlayback && NULL == fRecord); 386 if (NULL != fPlayback) { 387 fPlayback->draw(*surface, callback); 388 } 389} 390 391/////////////////////////////////////////////////////////////////////////////// 392 393#include "SkStream.h" 394 395static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' }; 396 397bool SkPicture::IsValidPictInfo(const SkPictInfo& info) { 398 if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) { 399 return false; 400 } 401 402 if (info.fVersion < MIN_PICTURE_VERSION || 403 info.fVersion > CURRENT_PICTURE_VERSION) { 404 return false; 405 } 406 407 return true; 408} 409 410bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { 411 if (NULL == stream) { 412 return false; 413 } 414 415 // Check magic bytes. 416 SkPictInfo info; 417 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); 418 if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) { 419 return false; 420 } 421 422 if (pInfo != NULL) { 423 *pInfo = info; 424 } 425 return true; 426} 427 428bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) { 429 // Check magic bytes. 430 SkPictInfo info; 431 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); 432 if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) { 433 return false; 434 } 435 436 if (pInfo != NULL) { 437 *pInfo = info; 438 } 439 return true; 440} 441 442SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height) 443 : fPlayback(playback) 444 , fRecord(NULL) 445 , fWidth(width) 446 , fHeight(height) 447 , fAccelData(NULL) { 448 this->needsNewGenID(); 449} 450 451SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) { 452 SkPictInfo info; 453 454 if (!InternalOnly_StreamIsSKP(stream, &info)) { 455 return NULL; 456 } 457 458 SkPicture* newPict = SkNEW_ARGS(SkPicture, (NULL, info.fWidth, info.fHeight)); 459 460 // Check to see if there is a playback to recreate. 461 if (stream->readBool()) { 462 SkPicturePlayback* playback = SkPicturePlayback::CreateFromStream(newPict, stream, 463 info, proc); 464 if (NULL == playback) { 465 SkDELETE(newPict); 466 return NULL; 467 } 468 newPict->fPlayback = playback; 469 } 470 471 return newPict; 472} 473 474SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) { 475 SkPictInfo info; 476 477 if (!InternalOnly_BufferIsSKP(buffer, &info)) { 478 return NULL; 479 } 480 481 SkPicture* newPict = SkNEW_ARGS(SkPicture, (NULL, info.fWidth, info.fHeight)); 482 483 // Check to see if there is a playback to recreate. 484 if (buffer.readBool()) { 485 SkPicturePlayback* playback = SkPicturePlayback::CreateFromBuffer(newPict, buffer, info); 486 if (NULL == playback) { 487 SkDELETE(newPict); 488 return NULL; 489 } 490 newPict->fPlayback = playback; 491 } 492 493 return newPict; 494} 495 496void SkPicture::createHeader(SkPictInfo* info) const { 497 // Copy magic bytes at the beginning of the header 498 SkASSERT(sizeof(kMagic) == 8); 499 SkASSERT(sizeof(kMagic) == sizeof(info->fMagic)); 500 memcpy(info->fMagic, kMagic, sizeof(kMagic)); 501 502 // Set picture info after magic bytes in the header 503 info->fVersion = CURRENT_PICTURE_VERSION; 504 info->fWidth = fWidth; 505 info->fHeight = fHeight; 506 info->fFlags = SkPictInfo::kCrossProcess_Flag; 507 // TODO: remove this flag, since we're always float (now) 508 info->fFlags |= SkPictInfo::kScalarIsFloat_Flag; 509 510 if (8 == sizeof(void*)) { 511 info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag; 512 } 513} 514 515void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const { 516 SkPicturePlayback* playback = fPlayback; 517 518 if (NULL == playback && fRecord) { 519 playback = FakeEndRecording(this, *fRecord, false); 520 } 521 522 SkPictInfo info; 523 this->createHeader(&info); 524 stream->write(&info, sizeof(info)); 525 if (playback) { 526 stream->writeBool(true); 527 playback->serialize(stream, encoder); 528 // delete playback if it is a local version (i.e. cons'd up just now) 529 if (playback != fPlayback) { 530 SkDELETE(playback); 531 } 532 } else { 533 stream->writeBool(false); 534 } 535} 536 537void SkPicture::WriteTagSize(SkWriteBuffer& buffer, uint32_t tag, size_t size) { 538 buffer.writeUInt(tag); 539 buffer.writeUInt(SkToU32(size)); 540} 541 542void SkPicture::WriteTagSize(SkWStream* stream, uint32_t tag, size_t size) { 543 stream->write32(tag); 544 stream->write32(SkToU32(size)); 545} 546 547bool SkPicture::parseBufferTag(SkReadBuffer& buffer, 548 uint32_t tag, 549 uint32_t size) { 550 switch (tag) { 551 case SK_PICT_PATH_BUFFER_TAG: 552 if (size > 0) { 553 fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer))); 554 } 555 break; 556 default: 557 // The tag was invalid. 558 return false; 559 } 560 561 return true; // success 562} 563 564void SkPicture::flattenToBuffer(SkWriteBuffer& buffer) const { 565 int n; 566 567 if ((n = SafeCount(fPathHeap.get())) > 0) { 568 WriteTagSize(buffer, SK_PICT_PATH_BUFFER_TAG, n); 569 fPathHeap->flatten(buffer); 570 } 571} 572 573void SkPicture::flatten(SkWriteBuffer& buffer) const { 574 SkPicturePlayback* playback = fPlayback; 575 576 if (NULL == playback && fRecord) { 577 playback = FakeEndRecording(this, *fRecord, false); 578 } 579 580 SkPictInfo info; 581 this->createHeader(&info); 582 buffer.writeByteArray(&info, sizeof(info)); 583 if (playback) { 584 buffer.writeBool(true); 585 playback->flatten(buffer); 586 // delete playback if it is a local version (i.e. cons'd up just now) 587 if (playback != fPlayback) { 588 SkDELETE(playback); 589 } 590 } else { 591 buffer.writeBool(false); 592 } 593} 594 595#if SK_SUPPORT_GPU 596bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const { 597 // TODO: the heuristic used here needs to be refined 598 static const int kNumPaintWithPathEffectUsesTol = 1; 599 static const int kNumAAConcavePaths = 5; 600 601 SkASSERT(this->numAAHairlineConcavePaths() <= this->numAAConcavePaths()); 602 603 bool ret = this->numPaintWithPathEffectUses() < kNumPaintWithPathEffectUsesTol && 604 (this->numAAConcavePaths()-this->numAAHairlineConcavePaths()) < kNumAAConcavePaths; 605 if (!ret && reason) { 606 if (this->numPaintWithPathEffectUses() >= kNumPaintWithPathEffectUsesTol) 607 *reason = "Too many path effects."; 608 else if ((this->numAAConcavePaths()-this->numAAHairlineConcavePaths()) >= kNumAAConcavePaths) 609 *reason = "Too many anti-aliased concave paths."; 610 else 611 *reason = "Unknown reason for GPU unsuitability."; 612 } 613 return ret; 614} 615#endif 616 617bool SkPicture::willPlayBackBitmaps() const { 618 if (!fPlayback) { 619 return false; 620 } 621 return fPlayback->containsBitmaps(); 622} 623 624#ifdef SK_BUILD_FOR_ANDROID 625void SkPicture::abortPlayback() { 626 if (NULL == fPlayback) { 627 return; 628 } 629 fPlayback->abort(); 630} 631#endif 632 633static int32_t next_picture_generation_id() { 634 static int32_t gPictureGenerationID = 0; 635 // do a loop in case our global wraps around, as we never want to 636 // return a 0 637 int32_t genID; 638 do { 639 genID = sk_atomic_inc(&gPictureGenerationID) + 1; 640 } while (SK_InvalidGenID == genID); 641 return genID; 642} 643 644uint32_t SkPicture::uniqueID() const { 645 if (NULL != fRecord) { 646 SkASSERT(NULL == fPlayback); 647 return SK_InvalidGenID; 648 } 649 650 if (SK_InvalidGenID == fUniqueID) { 651 fUniqueID = next_picture_generation_id(); 652 } 653 return fUniqueID; 654} 655