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