SkPicture.cpp revision 6142609b22814283210f79d698182b651a93136c
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 "SkPictureData.h" 12#include "SkPicturePlayback.h" 13#include "SkPictureRecord.h" 14#include "SkPictureRecorder.h" 15#include "SkPictureStateTree.h" 16 17#include "SkBBHFactory.h" 18#include "SkBitmapDevice.h" 19#include "SkCanvas.h" 20#include "SkChunkAlloc.h" 21#include "SkDrawPictureCallback.h" 22#include "SkPaintPriv.h" 23#include "SkPicture.h" 24#include "SkRecordAnalysis.h" 25#include "SkRegion.h" 26#include "SkStream.h" 27#include "SkTDArray.h" 28#include "SkTSearch.h" 29#include "SkTime.h" 30 31#include "SkReader32.h" 32#include "SkWriter32.h" 33#include "SkRTree.h" 34#include "SkBBoxHierarchyRecord.h" 35 36#if SK_SUPPORT_GPU 37#include "GrContext.h" 38#endif 39 40#include "SkRecord.h" 41#include "SkRecordDraw.h" 42#include "SkRecorder.h" 43 44template <typename T> int SafeCount(const T* obj) { 45 return obj ? obj->count() : 0; 46} 47 48#define DUMP_BUFFER_SIZE 65536 49 50#ifdef SK_DEBUG 51// enable SK_DEBUG_TRACE to trace DrawType elements when 52// recorded and played back 53// #define SK_DEBUG_TRACE 54// enable SK_DEBUG_SIZE to see the size of picture components 55// #define SK_DEBUG_SIZE 56// enable SK_DEBUG_DUMP to see the contents of recorded elements 57// #define SK_DEBUG_DUMP 58// enable SK_DEBUG_VALIDATE to check internal structures for consistency 59// #define SK_DEBUG_VALIDATE 60#endif 61 62#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP 63const char* DrawTypeToString(DrawType drawType) { 64 switch (drawType) { 65 case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break; 66 case CLIP_PATH: return "CLIP_PATH"; 67 case CLIP_REGION: return "CLIP_REGION"; 68 case CLIP_RECT: return "CLIP_RECT"; 69 case CLIP_RRECT: return "CLIP_RRECT"; 70 case CONCAT: return "CONCAT"; 71 case DRAW_BITMAP: return "DRAW_BITMAP"; 72 case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX"; 73 case DRAW_BITMAP_NINE: return "DRAW_BITMAP_NINE"; 74 case DRAW_BITMAP_RECT_TO_RECT: return "DRAW_BITMAP_RECT_TO_RECT"; 75 case DRAW_CLEAR: return "DRAW_CLEAR"; 76 case DRAW_DATA: return "DRAW_DATA"; 77 case DRAW_OVAL: return "DRAW_OVAL"; 78 case DRAW_PAINT: return "DRAW_PAINT"; 79 case DRAW_PATH: return "DRAW_PATH"; 80 case DRAW_PICTURE: return "DRAW_PICTURE"; 81 case DRAW_POINTS: return "DRAW_POINTS"; 82 case DRAW_POS_TEXT: return "DRAW_POS_TEXT"; 83 case DRAW_POS_TEXT_TOP_BOTTOM: return "DRAW_POS_TEXT_TOP_BOTTOM"; 84 case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H"; 85 case DRAW_POS_TEXT_H_TOP_BOTTOM: return "DRAW_POS_TEXT_H_TOP_BOTTOM"; 86 case DRAW_RECT: return "DRAW_RECT"; 87 case DRAW_RRECT: return "DRAW_RRECT"; 88 case DRAW_SPRITE: return "DRAW_SPRITE"; 89 case DRAW_TEXT: return "DRAW_TEXT"; 90 case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH"; 91 case DRAW_TEXT_TOP_BOTTOM: return "DRAW_TEXT_TOP_BOTTOM"; 92 case DRAW_VERTICES: return "DRAW_VERTICES"; 93 case RESTORE: return "RESTORE"; 94 case ROTATE: return "ROTATE"; 95 case SAVE: return "SAVE"; 96 case SAVE_LAYER: return "SAVE_LAYER"; 97 case SCALE: return "SCALE"; 98 case SET_MATRIX: return "SET_MATRIX"; 99 case SKEW: return "SKEW"; 100 case TRANSLATE: return "TRANSLATE"; 101 case NOOP: return "NOOP"; 102 default: 103 SkDebugf("DrawType error 0x%08x\n", drawType); 104 SkASSERT(0); 105 break; 106 } 107 SkASSERT(0); 108 return NULL; 109} 110#endif 111 112#ifdef SK_DEBUG_VALIDATE 113static void validateMatrix(const SkMatrix* matrix) { 114 SkScalar scaleX = matrix->getScaleX(); 115 SkScalar scaleY = matrix->getScaleY(); 116 SkScalar skewX = matrix->getSkewX(); 117 SkScalar skewY = matrix->getSkewY(); 118 SkScalar perspX = matrix->getPerspX(); 119 SkScalar perspY = matrix->getPerspY(); 120 if (scaleX != 0 && skewX != 0) 121 SkDebugf("scaleX != 0 && skewX != 0\n"); 122 SkASSERT(scaleX == 0 || skewX == 0); 123 SkASSERT(scaleY == 0 || skewY == 0); 124 SkASSERT(perspX == 0); 125 SkASSERT(perspY == 0); 126} 127#endif 128 129 130/////////////////////////////////////////////////////////////////////////////// 131 132// fRecord OK 133SkPicture::SkPicture() 134 : fWidth(0) 135 , fHeight(0) 136 , fRecordWillPlayBackBitmaps(false) { 137 this->needsNewGenID(); 138} 139 140// fRecord OK 141SkPicture::SkPicture(int width, int height, 142 const SkPictureRecord& record, 143 bool deepCopyOps) 144 : fWidth(width) 145 , fHeight(height) 146 , fRecordWillPlayBackBitmaps(false) { 147 this->needsNewGenID(); 148 149 SkPictInfo info; 150 this->createHeader(&info); 151 fData.reset(SkNEW_ARGS(SkPictureData, (record, info, deepCopyOps))); 152} 153 154// The simplest / safest way to copy an SkRecord is to replay it into a new one. 155static SkRecord* copy(const SkRecord& src, int width, int height) { 156 SkRecord* dst = SkNEW(SkRecord); 157 SkRecorder recorder(dst, width, height); 158 SkRecordDraw(src, &recorder); 159 return dst; 160} 161 162// Create an SkPictureData-backed SkPicture from an SkRecord. 163// This for compatibility with serialization code only. This is not cheap. 164static SkPicture* backport(const SkRecord& src, int width, int height) { 165 SkPictureRecorder recorder; 166 SkRecordDraw(src, recorder.beginRecording(width, height)); 167 return recorder.endRecording(); 168} 169 170// fRecord OK 171SkPicture::SkPicture(const SkPicture& src) : INHERITED() { 172 this->needsNewGenID(); 173 fWidth = src.fWidth; 174 fHeight = src.fHeight; 175 fRecordWillPlayBackBitmaps = src.fRecordWillPlayBackBitmaps; 176 177 if (NULL != src.fData.get()) { 178 fData.reset(SkNEW_ARGS(SkPictureData, (*src.fData))); 179 fUniqueID = src.uniqueID(); // need to call method to ensure != 0 180 } 181 182 if (NULL != src.fRecord.get()) { 183 fRecord.reset(copy(*src.fRecord, fWidth, fHeight)); 184 fUniqueID = src.uniqueID(); // need to call method to ensure != 0 185 } 186} 187 188// fRecord OK 189SkPicture::~SkPicture() {} 190 191#ifdef SK_SUPPORT_LEGACY_PICTURE_CLONE 192// fRecord TODO, fix by deleting this method 193SkPicture* SkPicture::clone() const { 194 SkPicture* clonedPicture = SkNEW(SkPicture); 195 this->clone(clonedPicture, 1); 196 return clonedPicture; 197} 198 199// fRecord TODO, fix by deleting this method 200void SkPicture::clone(SkPicture* pictures, int count) const { 201 SkPictCopyInfo copyInfo; 202 203 for (int i = 0; i < count; i++) { 204 SkPicture* clone = &pictures[i]; 205 206 clone->needsNewGenID(); 207 clone->fWidth = fWidth; 208 clone->fHeight = fHeight; 209 clone->fData.reset(NULL); 210 clone->fRecordWillPlayBackBitmaps = fRecordWillPlayBackBitmaps; 211 212 /* We want to copy the src's playback. However, if that hasn't been built 213 yet, we need to fake a call to endRecording() without actually calling 214 it (since it is destructive, and we don't want to change src). 215 */ 216 if (fData.get()) { 217 if (!copyInfo.initialized) { 218 int paintCount = SafeCount(fData->fPaints); 219 220 /* The alternative to doing this is to have a clone method on the paint and have it 221 * make the deep copy of its internal structures as needed. The holdup to doing 222 * that is at this point we would need to pass the SkBitmapHeap so that we don't 223 * unnecessarily flatten the pixels in a bitmap shader. 224 */ 225 copyInfo.paintData.setCount(paintCount); 226 227 /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is 228 * one, use it. If this SkPictureData was created from a stream, fBitmapHeap 229 * will be NULL, so create a new one. 230 */ 231 if (fData->fBitmapHeap.get() == NULL) { 232 // FIXME: Put this on the stack inside SkPicture::clone. 233 SkBitmapHeap* heap = SkNEW(SkBitmapHeap); 234 copyInfo.controller.setBitmapStorage(heap); 235 heap->unref(); 236 } else { 237 copyInfo.controller.setBitmapStorage(fData->fBitmapHeap); 238 } 239 240 SkDEBUGCODE(int heapSize = SafeCount(fData->fBitmapHeap.get());) 241 for (int i = 0; i < paintCount; i++) { 242 if (NeedsDeepCopy(fData->fPaints->at(i))) { 243 copyInfo.paintData[i] = 244 SkFlatData::Create<SkPaint::FlatteningTraits>(©Info.controller, 245 fData->fPaints->at(i), 0); 246 247 } else { 248 // this is our sentinel, which we use in the unflatten loop 249 copyInfo.paintData[i] = NULL; 250 } 251 } 252 SkASSERT(SafeCount(fData->fBitmapHeap.get()) == heapSize); 253 254 // needed to create typeface playback 255 copyInfo.controller.setupPlaybacks(); 256 copyInfo.initialized = true; 257 } 258 259 clone->fData.reset(SkNEW_ARGS(SkPictureData, (*fData, ©Info))); 260 clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0 261 } 262 } 263} 264#endif//SK_SUPPORT_LEGACY_PICTURE_CLONE 265 266// fRecord OK 267void SkPicture::EXPERIMENTAL_addAccelData(const SkPicture::AccelData* data) const { 268 fAccelData.reset(SkRef(data)); 269} 270 271// fRecord OK 272const SkPicture::AccelData* SkPicture::EXPERIMENTAL_getAccelData( 273 SkPicture::AccelData::Key key) const { 274 if (NULL != fAccelData.get() && fAccelData->getKey() == key) { 275 return fAccelData.get(); 276 } 277 return NULL; 278} 279 280// fRecord OK 281SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() { 282 static int32_t gNextID = 0; 283 284 int32_t id = sk_atomic_inc(&gNextID); 285 if (id >= 1 << (8 * sizeof(Domain))) { 286 SK_CRASH(); 287 } 288 289 return static_cast<Domain>(id); 290} 291 292/////////////////////////////////////////////////////////////////////////////// 293 294uint32_t SkPicture::OperationList::offset(int index) const { 295 SkASSERT(index < fOps.count()); 296 return ((SkPictureStateTree::Draw*)fOps[index])->fOffset; 297} 298 299const SkMatrix& SkPicture::OperationList::matrix(int index) const { 300 SkASSERT(index < fOps.count()); 301 return *((SkPictureStateTree::Draw*)fOps[index])->fMatrix; 302} 303 304// fRecord TODO 305const SkPicture::OperationList* SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const { 306 SkASSERT(NULL != fData.get()); 307 if (NULL != fData.get()) { 308 return fData->getActiveOps(queryRect); 309 } 310 return NULL; 311} 312 313// fRecord OK 314void SkPicture::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) const { 315 SkASSERT(NULL != canvas); 316 SkASSERT(NULL != fData.get() || NULL != fRecord.get()); 317 318 if (NULL != fData.get()) { 319 SkPicturePlayback playback(this); 320 playback.draw(canvas, callback); 321 } 322 if (NULL != fRecord.get()) { 323 SkRecordDraw(*fRecord, canvas, callback); 324 } 325} 326 327/////////////////////////////////////////////////////////////////////////////// 328 329#include "SkStream.h" 330 331static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' }; 332 333// fRecord OK 334bool SkPicture::IsValidPictInfo(const SkPictInfo& info) { 335 if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) { 336 return false; 337 } 338 339 if (info.fVersion < MIN_PICTURE_VERSION || 340 info.fVersion > CURRENT_PICTURE_VERSION) { 341 return false; 342 } 343 344 return true; 345} 346 347// fRecord OK 348bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { 349 if (NULL == stream) { 350 return false; 351 } 352 353 // Check magic bytes. 354 SkPictInfo info; 355 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); 356 if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) { 357 return false; 358 } 359 360 if (pInfo != NULL) { 361 *pInfo = info; 362 } 363 return true; 364} 365 366// fRecord OK 367bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) { 368 // Check magic bytes. 369 SkPictInfo info; 370 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); 371 if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) { 372 return false; 373 } 374 375 if (pInfo != NULL) { 376 *pInfo = info; 377 } 378 return true; 379} 380 381// fRecord OK 382SkPicture::SkPicture(SkPictureData* data, int width, int height) 383 : fData(data) 384 , fWidth(width) 385 , fHeight(height) 386 , fRecordWillPlayBackBitmaps(false) { 387 this->needsNewGenID(); 388} 389 390// fRecord OK 391SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) { 392 SkPictInfo info; 393 394 if (!InternalOnly_StreamIsSKP(stream, &info)) { 395 return NULL; 396 } 397 398 // Check to see if there is a playback to recreate. 399 if (stream->readBool()) { 400 SkPictureData* data = SkPictureData::CreateFromStream(stream, info, proc); 401 if (NULL == data) { 402 return NULL; 403 } 404 405 return SkNEW_ARGS(SkPicture, (data, info.fWidth, info.fHeight)); 406 } 407 408 return NULL; 409} 410 411// fRecord OK 412SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) { 413 SkPictInfo info; 414 415 if (!InternalOnly_BufferIsSKP(buffer, &info)) { 416 return NULL; 417 } 418 419 // Check to see if there is a playback to recreate. 420 if (buffer.readBool()) { 421 SkPictureData* data = SkPictureData::CreateFromBuffer(buffer, info); 422 if (NULL == data) { 423 return NULL; 424 } 425 426 return SkNEW_ARGS(SkPicture, (data, info.fWidth, info.fHeight)); 427 } 428 429 return NULL; 430} 431 432// fRecord OK 433void SkPicture::createHeader(SkPictInfo* info) const { 434 // Copy magic bytes at the beginning of the header 435 SkASSERT(sizeof(kMagic) == 8); 436 SkASSERT(sizeof(kMagic) == sizeof(info->fMagic)); 437 memcpy(info->fMagic, kMagic, sizeof(kMagic)); 438 439 // Set picture info after magic bytes in the header 440 info->fVersion = CURRENT_PICTURE_VERSION; 441 info->fWidth = fWidth; 442 info->fHeight = fHeight; 443 info->fFlags = SkPictInfo::kCrossProcess_Flag; 444 // TODO: remove this flag, since we're always float (now) 445 info->fFlags |= SkPictInfo::kScalarIsFloat_Flag; 446 447 if (8 == sizeof(void*)) { 448 info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag; 449 } 450} 451 452// fRecord OK 453void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const { 454 const SkPictureData* data = fData.get(); 455 456 // If we're a new-format picture, backport to old format for serialization. 457 SkAutoTDelete<SkPicture> oldFormat; 458 if (NULL == data && NULL != fRecord.get()) { 459 oldFormat.reset(backport(*fRecord, fWidth, fHeight)); 460 data = oldFormat->fData.get(); 461 SkASSERT(NULL != data); 462 } 463 464 SkPictInfo info; 465 this->createHeader(&info); 466 stream->write(&info, sizeof(info)); 467 468 if (NULL != data) { 469 stream->writeBool(true); 470 data->serialize(stream, encoder); 471 } else { 472 stream->writeBool(false); 473 } 474} 475 476// fRecord OK 477void SkPicture::flatten(SkWriteBuffer& buffer) const { 478 const SkPictureData* data = fData.get(); 479 480 // If we're a new-format picture, backport to old format for serialization. 481 SkAutoTDelete<SkPicture> oldFormat; 482 if (NULL == data && NULL != fRecord.get()) { 483 oldFormat.reset(backport(*fRecord, fWidth, fHeight)); 484 data = oldFormat->fData.get(); 485 SkASSERT(NULL != data); 486 } 487 488 SkPictInfo info; 489 this->createHeader(&info); 490 buffer.writeByteArray(&info, sizeof(info)); 491 492 if (NULL != data) { 493 buffer.writeBool(true); 494 data->flatten(buffer); 495 } else { 496 buffer.writeBool(false); 497 } 498} 499 500#if SK_SUPPORT_GPU 501// fRecord TODO 502bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const { 503 if (NULL == fData.get()) { 504 if (NULL != reason) { 505 *reason = "Missing internal data."; 506 } 507 return false; 508 } 509 510 return fData->suitableForGpuRasterization(context, reason); 511} 512#endif 513 514// fRecord OK 515bool SkPicture::willPlayBackBitmaps() const { 516 if (fRecord.get()) { 517 return fRecordWillPlayBackBitmaps; 518 } 519 if (!fData.get()) { 520 return false; 521 } 522 return fData->containsBitmaps(); 523} 524 525// fRecord OK 526static int32_t next_picture_generation_id() { 527 static int32_t gPictureGenerationID = 0; 528 // do a loop in case our global wraps around, as we never want to 529 // return a 0 530 int32_t genID; 531 do { 532 genID = sk_atomic_inc(&gPictureGenerationID) + 1; 533 } while (SK_InvalidGenID == genID); 534 return genID; 535} 536 537// fRecord OK 538uint32_t SkPicture::uniqueID() const { 539 if (SK_InvalidGenID == fUniqueID) { 540 fUniqueID = next_picture_generation_id(); 541 } 542 return fUniqueID; 543} 544 545// fRecord OK 546SkPicture::SkPicture(int width, int height, SkRecord* record) 547 : fWidth(width) 548 , fHeight(height) 549 , fRecord(record) 550 , fRecordWillPlayBackBitmaps(SkRecordWillPlaybackBitmaps(*record)) { 551 this->needsNewGenID(); 552} 553