SkPicture.cpp revision 3ba15ae3e13a6da0a9735fcc04166ed4d3ddcd67
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/////////////////////////////////////////////////////////////////////////////// 113 114#ifdef SK_SUPPORT_LEGACY_DEFAULT_PICTURE_CTOR 115// fRecord OK 116SkPicture::SkPicture() 117 : fWidth(0) 118 , fHeight(0) 119 , fRecordWillPlayBackBitmaps(false) { 120 this->needsNewGenID(); 121} 122#endif 123 124// fRecord OK 125SkPicture::SkPicture(int width, int height, 126 const SkPictureRecord& record, 127 bool deepCopyOps) 128 : fWidth(width) 129 , fHeight(height) 130 , fRecordWillPlayBackBitmaps(false) { 131 this->needsNewGenID(); 132 133 SkPictInfo info; 134 this->createHeader(&info); 135 fData.reset(SkNEW_ARGS(SkPictureData, (record, info, deepCopyOps))); 136} 137 138// Create an SkPictureData-backed SkPicture from an SkRecord. 139// This for compatibility with serialization code only. This is not cheap. 140static SkPicture* backport(const SkRecord& src, int width, int height) { 141 SkPictureRecorder recorder; 142 SkRecordDraw(src, recorder.beginRecording(width, height)); 143 return recorder.endRecording(); 144} 145 146// fRecord OK 147SkPicture::~SkPicture() { 148 this->callDeletionListeners(); 149} 150 151#ifdef SK_SUPPORT_LEGACY_PICTURE_CLONE 152// fRecord TODO, fix by deleting this method 153SkPicture* SkPicture::clone() const { 154#ifdef SK_PICTURE_CLONE_NOOP 155 return SkRef(const_cast<SkPicture*>(this)); 156#else 157 SkAutoTDelete<SkPictureData> newData; 158 159 if (fData.get()) { 160 SkPictCopyInfo copyInfo; 161 162 int paintCount = SafeCount(fData->fPaints); 163 164 /* The alternative to doing this is to have a clone method on the paint and have it 165 * make the deep copy of its internal structures as needed. The holdup to doing 166 * that is at this point we would need to pass the SkBitmapHeap so that we don't 167 * unnecessarily flatten the pixels in a bitmap shader. 168 */ 169 copyInfo.paintData.setCount(paintCount); 170 171 /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is 172 * one, use it. If this SkPictureData was created from a stream, fBitmapHeap 173 * will be NULL, so create a new one. 174 */ 175 if (fData->fBitmapHeap.get() == NULL) { 176 // FIXME: Put this on the stack inside SkPicture::clone. 177 SkBitmapHeap* heap = SkNEW(SkBitmapHeap); 178 copyInfo.controller.setBitmapStorage(heap); 179 heap->unref(); 180 } else { 181 copyInfo.controller.setBitmapStorage(fData->fBitmapHeap); 182 } 183 184 SkDEBUGCODE(int heapSize = SafeCount(fData->fBitmapHeap.get());) 185 for (int i = 0; i < paintCount; i++) { 186 if (NeedsDeepCopy(fData->fPaints->at(i))) { 187 copyInfo.paintData[i] = 188 SkFlatData::Create<SkPaint::FlatteningTraits>(©Info.controller, 189 fData->fPaints->at(i), 0); 190 191 } else { 192 // this is our sentinel, which we use in the unflatten loop 193 copyInfo.paintData[i] = NULL; 194 } 195 } 196 SkASSERT(SafeCount(fData->fBitmapHeap.get()) == heapSize); 197 198 // needed to create typeface playback 199 copyInfo.controller.setupPlaybacks(); 200 201 newData.reset(SkNEW_ARGS(SkPictureData, (*fData, ©Info))); 202 } 203 204 SkPicture* clone = SkNEW_ARGS(SkPicture, (newData.detach(), fWidth, fHeight)); 205 clone->fRecordWillPlayBackBitmaps = fRecordWillPlayBackBitmaps; 206 clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0 207 208 return clone; 209#endif 210} 211#endif//SK_SUPPORT_LEGACY_PICTURE_CLONE 212 213// fRecord OK 214void SkPicture::EXPERIMENTAL_addAccelData(const SkPicture::AccelData* data) const { 215 fAccelData.reset(SkRef(data)); 216} 217 218// fRecord OK 219const SkPicture::AccelData* SkPicture::EXPERIMENTAL_getAccelData( 220 SkPicture::AccelData::Key key) const { 221 if (NULL != fAccelData.get() && fAccelData->getKey() == key) { 222 return fAccelData.get(); 223 } 224 return NULL; 225} 226 227// fRecord OK 228SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() { 229 static int32_t gNextID = 0; 230 231 int32_t id = sk_atomic_inc(&gNextID); 232 if (id >= 1 << (8 * sizeof(Domain))) { 233 SK_CRASH(); 234 } 235 236 return static_cast<Domain>(id); 237} 238 239/////////////////////////////////////////////////////////////////////////////// 240 241uint32_t SkPicture::OperationList::offset(int index) const { 242 SkASSERT(index < fOps.count()); 243 return ((SkPictureStateTree::Draw*)fOps[index])->fOffset; 244} 245 246const SkMatrix& SkPicture::OperationList::matrix(int index) const { 247 SkASSERT(index < fOps.count()); 248 return *((SkPictureStateTree::Draw*)fOps[index])->fMatrix; 249} 250 251// fRecord TODO 252const SkPicture::OperationList* SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const { 253 SkASSERT(NULL != fData.get()); 254 if (NULL != fData.get()) { 255 return fData->getActiveOps(queryRect); 256 } 257 return NULL; 258} 259 260// fRecord OK 261void SkPicture::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) const { 262 SkASSERT(NULL != canvas); 263 SkASSERT(NULL != fData.get() || NULL != fRecord.get()); 264 265 if (NULL != fData.get()) { 266 SkPicturePlayback playback(this); 267 playback.draw(canvas, callback); 268 } 269 if (NULL != fRecord.get()) { 270 SkRecordDraw(*fRecord, canvas, callback); 271 } 272} 273 274/////////////////////////////////////////////////////////////////////////////// 275 276#include "SkStream.h" 277 278static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' }; 279 280// fRecord OK 281bool SkPicture::IsValidPictInfo(const SkPictInfo& info) { 282 if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) { 283 return false; 284 } 285 286 if (info.fVersion < MIN_PICTURE_VERSION || 287 info.fVersion > CURRENT_PICTURE_VERSION) { 288 return false; 289 } 290 291 return true; 292} 293 294// fRecord OK 295bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { 296 if (NULL == stream) { 297 return false; 298 } 299 300 // Check magic bytes. 301 SkPictInfo info; 302 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); 303 if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) { 304 return false; 305 } 306 307 if (pInfo != NULL) { 308 *pInfo = info; 309 } 310 return true; 311} 312 313// fRecord OK 314bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) { 315 // Check magic bytes. 316 SkPictInfo info; 317 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); 318 if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) { 319 return false; 320 } 321 322 if (pInfo != NULL) { 323 *pInfo = info; 324 } 325 return true; 326} 327 328// fRecord OK 329SkPicture::SkPicture(SkPictureData* data, int width, int height) 330 : fData(data) 331 , fWidth(width) 332 , fHeight(height) 333 , fRecordWillPlayBackBitmaps(false) { 334 this->needsNewGenID(); 335} 336 337// fRecord OK 338SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) { 339 SkPictInfo info; 340 341 if (!InternalOnly_StreamIsSKP(stream, &info)) { 342 return NULL; 343 } 344 345 // Check to see if there is a playback to recreate. 346 if (stream->readBool()) { 347 SkPictureData* data = SkPictureData::CreateFromStream(stream, info, proc); 348 if (NULL == data) { 349 return NULL; 350 } 351 352 return SkNEW_ARGS(SkPicture, (data, info.fWidth, info.fHeight)); 353 } 354 355 return NULL; 356} 357 358// fRecord OK 359SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) { 360 SkPictInfo info; 361 362 if (!InternalOnly_BufferIsSKP(buffer, &info)) { 363 return NULL; 364 } 365 366 // Check to see if there is a playback to recreate. 367 if (buffer.readBool()) { 368 SkPictureData* data = SkPictureData::CreateFromBuffer(buffer, info); 369 if (NULL == data) { 370 return NULL; 371 } 372 373 return SkNEW_ARGS(SkPicture, (data, info.fWidth, info.fHeight)); 374 } 375 376 return NULL; 377} 378 379// fRecord OK 380void SkPicture::createHeader(SkPictInfo* info) const { 381 // Copy magic bytes at the beginning of the header 382 SkASSERT(sizeof(kMagic) == 8); 383 SkASSERT(sizeof(kMagic) == sizeof(info->fMagic)); 384 memcpy(info->fMagic, kMagic, sizeof(kMagic)); 385 386 // Set picture info after magic bytes in the header 387 info->fVersion = CURRENT_PICTURE_VERSION; 388 info->fWidth = fWidth; 389 info->fHeight = fHeight; 390 info->fFlags = SkPictInfo::kCrossProcess_Flag; 391 // TODO: remove this flag, since we're always float (now) 392 info->fFlags |= SkPictInfo::kScalarIsFloat_Flag; 393 394 if (8 == sizeof(void*)) { 395 info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag; 396 } 397} 398 399// fRecord OK 400void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const { 401 const SkPictureData* data = fData.get(); 402 403 // If we're a new-format picture, backport to old format for serialization. 404 SkAutoTDelete<SkPicture> oldFormat; 405 if (NULL == data && NULL != fRecord.get()) { 406 oldFormat.reset(backport(*fRecord, fWidth, fHeight)); 407 data = oldFormat->fData.get(); 408 SkASSERT(NULL != data); 409 } 410 411 SkPictInfo info; 412 this->createHeader(&info); 413 stream->write(&info, sizeof(info)); 414 415 if (NULL != data) { 416 stream->writeBool(true); 417 data->serialize(stream, encoder); 418 } else { 419 stream->writeBool(false); 420 } 421} 422 423// fRecord OK 424void SkPicture::flatten(SkWriteBuffer& buffer) const { 425 const SkPictureData* data = fData.get(); 426 427 // If we're a new-format picture, backport to old format for serialization. 428 SkAutoTDelete<SkPicture> oldFormat; 429 if (NULL == data && NULL != fRecord.get()) { 430 oldFormat.reset(backport(*fRecord, fWidth, fHeight)); 431 data = oldFormat->fData.get(); 432 SkASSERT(NULL != data); 433 } 434 435 SkPictInfo info; 436 this->createHeader(&info); 437 buffer.writeByteArray(&info, sizeof(info)); 438 439 if (NULL != data) { 440 buffer.writeBool(true); 441 data->flatten(buffer); 442 } else { 443 buffer.writeBool(false); 444 } 445} 446 447#if SK_SUPPORT_GPU 448// fRecord TODO 449bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const { 450 if (NULL == fData.get()) { 451 if (NULL != reason) { 452 *reason = "Missing internal data."; 453 } 454 return false; 455 } 456 457 return fData->suitableForGpuRasterization(context, reason); 458} 459#endif 460 461// fRecord OK 462bool SkPicture::willPlayBackBitmaps() const { 463 if (fRecord.get()) { 464 return fRecordWillPlayBackBitmaps; 465 } 466 if (!fData.get()) { 467 return false; 468 } 469 return fData->containsBitmaps(); 470} 471 472// fRecord OK 473static int32_t next_picture_generation_id() { 474 static int32_t gPictureGenerationID = 0; 475 // do a loop in case our global wraps around, as we never want to 476 // return a 0 477 int32_t genID; 478 do { 479 genID = sk_atomic_inc(&gPictureGenerationID) + 1; 480 } while (SK_InvalidGenID == genID); 481 return genID; 482} 483 484// fRecord OK 485uint32_t SkPicture::uniqueID() const { 486 if (SK_InvalidGenID == fUniqueID) { 487 fUniqueID = next_picture_generation_id(); 488 } 489 return fUniqueID; 490} 491 492// fRecord OK 493SkPicture::SkPicture(int width, int height, SkRecord* record) 494 : fWidth(width) 495 , fHeight(height) 496 , fRecord(record) 497 , fRecordWillPlayBackBitmaps(SkRecordWillPlaybackBitmaps(*record)) { 498 this->needsNewGenID(); 499} 500 501// Note that we are assuming that this entry point will only be called from 502// one thread. Currently the only client of this method is 503// SkGpuDevice::EXPERIMENTAL_optimize which should be only called from a single 504// thread. 505void SkPicture::addDeletionListener(DeletionListener* listener) const { 506 SkASSERT(NULL != listener); 507 508 *fDeletionListeners.append() = SkRef(listener); 509} 510 511void SkPicture::callDeletionListeners() { 512 for (int i = 0; i < fDeletionListeners.count(); ++i) { 513 fDeletionListeners[i]->onDeletion(this->uniqueID()); 514 } 515 516 fDeletionListeners.unrefAll(); 517} 518