SkPicture.cpp revision 466310dbd3073add2ec934e336c30deaaf702eae
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 "SkBitmapDevice.h" 15#include "SkCanvas.h" 16#include "SkChunkAlloc.h" 17#include "SkPicture.h" 18#include "SkRegion.h" 19#include "SkStream.h" 20#include "SkTDArray.h" 21#include "SkTSearch.h" 22#include "SkTime.h" 23 24#include "SkReader32.h" 25#include "SkWriter32.h" 26#include "SkRTree.h" 27#include "SkBBoxHierarchyRecord.h" 28 29SK_DEFINE_INST_COUNT(SkPicture) 30 31#define DUMP_BUFFER_SIZE 65536 32 33//#define ENABLE_TIME_DRAW // dumps milliseconds for each draw 34 35 36#ifdef SK_DEBUG 37// enable SK_DEBUG_TRACE to trace DrawType elements when 38// recorded and played back 39// #define SK_DEBUG_TRACE 40// enable SK_DEBUG_SIZE to see the size of picture components 41// #define SK_DEBUG_SIZE 42// enable SK_DEBUG_DUMP to see the contents of recorded elements 43// #define SK_DEBUG_DUMP 44// enable SK_DEBUG_VALIDATE to check internal structures for consistency 45// #define SK_DEBUG_VALIDATE 46#endif 47 48#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP 49const char* DrawTypeToString(DrawType drawType) { 50 switch (drawType) { 51 case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break; 52 case CLIP_PATH: return "CLIP_PATH"; 53 case CLIP_REGION: return "CLIP_REGION"; 54 case CLIP_RECT: return "CLIP_RECT"; 55 case CLIP_RRECT: return "CLIP_RRECT"; 56 case CONCAT: return "CONCAT"; 57 case DRAW_BITMAP: return "DRAW_BITMAP"; 58 case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX"; 59 case DRAW_BITMAP_NINE: return "DRAW_BITMAP_NINE"; 60 case DRAW_BITMAP_RECT_TO_RECT: return "DRAW_BITMAP_RECT_TO_RECT"; 61 case DRAW_CLEAR: return "DRAW_CLEAR"; 62 case DRAW_DATA: return "DRAW_DATA"; 63 case DRAW_OVAL: return "DRAW_OVAL"; 64 case DRAW_PAINT: return "DRAW_PAINT"; 65 case DRAW_PATH: return "DRAW_PATH"; 66 case DRAW_PICTURE: return "DRAW_PICTURE"; 67 case DRAW_POINTS: return "DRAW_POINTS"; 68 case DRAW_POS_TEXT: return "DRAW_POS_TEXT"; 69 case DRAW_POS_TEXT_TOP_BOTTOM: return "DRAW_POS_TEXT_TOP_BOTTOM"; 70 case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H"; 71 case DRAW_POS_TEXT_H_TOP_BOTTOM: return "DRAW_POS_TEXT_H_TOP_BOTTOM"; 72 case DRAW_RECT: return "DRAW_RECT"; 73 case DRAW_RRECT: return "DRAW_RRECT"; 74 case DRAW_SPRITE: return "DRAW_SPRITE"; 75 case DRAW_TEXT: return "DRAW_TEXT"; 76 case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH"; 77 case DRAW_TEXT_TOP_BOTTOM: return "DRAW_TEXT_TOP_BOTTOM"; 78 case DRAW_VERTICES: return "DRAW_VERTICES"; 79 case RESTORE: return "RESTORE"; 80 case ROTATE: return "ROTATE"; 81 case SAVE: return "SAVE"; 82 case SAVE_LAYER: return "SAVE_LAYER"; 83 case SCALE: return "SCALE"; 84 case SET_MATRIX: return "SET_MATRIX"; 85 case SKEW: return "SKEW"; 86 case TRANSLATE: return "TRANSLATE"; 87 case NOOP: return "NOOP"; 88 default: 89 SkDebugf("DrawType error 0x%08x\n", drawType); 90 SkASSERT(0); 91 break; 92 } 93 SkASSERT(0); 94 return NULL; 95} 96#endif 97 98#ifdef SK_DEBUG_VALIDATE 99static void validateMatrix(const SkMatrix* matrix) { 100 SkScalar scaleX = matrix->getScaleX(); 101 SkScalar scaleY = matrix->getScaleY(); 102 SkScalar skewX = matrix->getSkewX(); 103 SkScalar skewY = matrix->getSkewY(); 104 SkScalar perspX = matrix->getPerspX(); 105 SkScalar perspY = matrix->getPerspY(); 106 if (scaleX != 0 && skewX != 0) 107 SkDebugf("scaleX != 0 && skewX != 0\n"); 108 SkASSERT(scaleX == 0 || skewX == 0); 109 SkASSERT(scaleY == 0 || skewY == 0); 110 SkASSERT(perspX == 0); 111 SkASSERT(perspY == 0); 112} 113#endif 114 115 116/////////////////////////////////////////////////////////////////////////////// 117 118SkPicture::SkPicture() { 119 fRecord = NULL; 120 fPlayback = NULL; 121 fWidth = fHeight = 0; 122} 123 124SkPicture::SkPicture(const SkPicture& src) : INHERITED() { 125 fWidth = src.fWidth; 126 fHeight = src.fHeight; 127 fRecord = NULL; 128 129 /* We want to copy the src's playback. However, if that hasn't been built 130 yet, we need to fake a call to endRecording() without actually calling 131 it (since it is destructive, and we don't want to change src). 132 */ 133 if (src.fPlayback) { 134 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback)); 135 } else if (src.fRecord) { 136 // here we do a fake src.endRecording() 137 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord)); 138 } else { 139 fPlayback = NULL; 140 } 141} 142 143SkPicture::~SkPicture() { 144 SkSafeUnref(fRecord); 145 SkDELETE(fPlayback); 146} 147 148void SkPicture::swap(SkPicture& other) { 149 SkTSwap(fRecord, other.fRecord); 150 SkTSwap(fPlayback, other.fPlayback); 151 SkTSwap(fWidth, other.fWidth); 152 SkTSwap(fHeight, other.fHeight); 153} 154 155SkPicture* SkPicture::clone() const { 156 SkPicture* clonedPicture = SkNEW(SkPicture); 157 clone(clonedPicture, 1); 158 return clonedPicture; 159} 160 161void SkPicture::clone(SkPicture* pictures, int count) const { 162 SkPictCopyInfo copyInfo; 163 164 for (int i = 0; i < count; i++) { 165 SkPicture* clone = &pictures[i]; 166 167 clone->fWidth = fWidth; 168 clone->fHeight = fHeight; 169 clone->fRecord = NULL; 170 171 if (NULL != clone->fRecord) { 172 clone->fRecord->unref(); 173 clone->fRecord = NULL; 174 } 175 SkDELETE(clone->fPlayback); 176 177 /* We want to copy the src's playback. However, if that hasn't been built 178 yet, we need to fake a call to endRecording() without actually calling 179 it (since it is destructive, and we don't want to change src). 180 */ 181 if (fPlayback) { 182 clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fPlayback, ©Info)); 183 } else if (fRecord) { 184 // here we do a fake src.endRecording() 185 clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, true)); 186 } else { 187 clone->fPlayback = NULL; 188 } 189 } 190} 191 192/////////////////////////////////////////////////////////////////////////////// 193 194SkCanvas* SkPicture::beginRecording(int width, int height, 195 uint32_t recordingFlags) { 196 if (fPlayback) { 197 SkDELETE(fPlayback); 198 fPlayback = NULL; 199 } 200 201 if (NULL != fRecord) { 202 fRecord->unref(); 203 fRecord = NULL; 204 } 205 206 SkBitmap bm; 207 bm.setConfig(SkBitmap::kNo_Config, width, height); 208 SkAutoTUnref<SkBaseDevice> dev(SkNEW_ARGS(SkBitmapDevice, (bm))); 209 210 // Must be set before calling createBBoxHierarchy 211 fWidth = width; 212 fHeight = height; 213 214 if (recordingFlags & kOptimizeForClippedPlayback_RecordingFlag) { 215 SkBBoxHierarchy* tree = this->createBBoxHierarchy(); 216 SkASSERT(NULL != tree); 217 fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (recordingFlags, tree, dev)); 218 tree->unref(); 219 } else { 220 fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags, dev)); 221 } 222 fRecord->beginRecording(); 223 224 return fRecord; 225} 226 227SkBBoxHierarchy* SkPicture::createBBoxHierarchy() const { 228 // These values were empirically determined to produce reasonable 229 // performance in most cases. 230 static const int kRTreeMinChildren = 6; 231 static const int kRTreeMaxChildren = 11; 232 233 SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth), 234 SkIntToScalar(fHeight)); 235 bool sortDraws = false; // Do not sort draw calls when bulk loading. 236 237 return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren, 238 aspectRatio, sortDraws); 239} 240 241SkCanvas* SkPicture::getRecordingCanvas() const { 242 // will be null if we are not recording 243 return fRecord; 244} 245 246void SkPicture::endRecording() { 247 if (NULL == fPlayback) { 248 if (NULL != fRecord) { 249 fRecord->endRecording(); 250 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); 251 fRecord->unref(); 252 fRecord = NULL; 253 } 254 } 255 SkASSERT(NULL == fRecord); 256} 257 258void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) { 259 this->endRecording(); 260 if (fPlayback) { 261 fPlayback->draw(*surface, callback); 262 } 263} 264 265/////////////////////////////////////////////////////////////////////////////// 266 267#include "SkStream.h" 268 269static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' }; 270 271bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { 272 if (NULL == stream) { 273 return false; 274 } 275 276 // Check magic bytes. 277 char magic[sizeof(kMagic)]; 278 stream->read(magic, sizeof(kMagic)); 279 if (0 != memcmp(magic, kMagic, sizeof(kMagic))) { 280 return false; 281 } 282 283 SkPictInfo info; 284 if (!stream->read(&info, sizeof(SkPictInfo))) { 285 return false; 286 } 287 if (PICTURE_VERSION != info.fVersion 288#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO 289 // V13 is backwards compatible with V12 290 && PRIOR_PRIOR_PICTURE_VERSION != info.fVersion // TODO: remove when .skps regenerated 291#endif 292#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TOO 293 // V14 is backwards compatible with V13 294 && PRIOR_PICTURE_VERSION2 != info.fVersion // TODO: remove when .skps regenerated 295#endif 296#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO 297 // V16 is backwards compatible with V15 298 && PRIOR_PICTURE_VERSION3 != info.fVersion // TODO: remove when .skps regenerated 299#endif 300 ) { 301 return false; 302 } 303 304 if (pInfo != NULL) { 305 *pInfo = info; 306 } 307 return true; 308} 309 310SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height) 311 : fPlayback(playback) 312 , fRecord(NULL) 313 , fWidth(width) 314 , fHeight(height) {} 315 316SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) { 317 SkPictInfo info; 318 319 if (!StreamIsSKP(stream, &info)) { 320 return NULL; 321 } 322 323 SkPicturePlayback* playback; 324 // Check to see if there is a playback to recreate. 325 if (stream->readBool()) { 326 playback = SkPicturePlayback::CreateFromStream(stream, info, proc); 327 if (NULL == playback) { 328 return NULL; 329 } 330 } else { 331 playback = NULL; 332 } 333 334 return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight)); 335} 336 337void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const { 338 SkPicturePlayback* playback = fPlayback; 339 340 if (NULL == playback && fRecord) { 341 playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); 342 } 343 344 SkPictInfo info; 345 346 info.fVersion = PICTURE_VERSION; 347 info.fWidth = fWidth; 348 info.fHeight = fHeight; 349 info.fFlags = SkPictInfo::kCrossProcess_Flag; 350#ifdef SK_SCALAR_IS_FLOAT 351 info.fFlags |= SkPictInfo::kScalarIsFloat_Flag; 352#endif 353 if (8 == sizeof(void*)) { 354 info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag; 355 } 356 357 // Write 8 magic bytes to ID this file format. 358 SkASSERT(sizeof(kMagic) == 8); 359 stream->write(kMagic, sizeof(kMagic)); 360 361 stream->write(&info, sizeof(info)); 362 if (playback) { 363 stream->writeBool(true); 364 playback->serialize(stream, encoder); 365 // delete playback if it is a local version (i.e. cons'd up just now) 366 if (playback != fPlayback) { 367 SkDELETE(playback); 368 } 369 } else { 370 stream->writeBool(false); 371 } 372} 373 374bool SkPicture::willPlayBackBitmaps() const { 375 if (!fPlayback) return false; 376 return fPlayback->containsBitmaps(); 377} 378 379#ifdef SK_BUILD_FOR_ANDROID 380void SkPicture::abortPlayback() { 381 if (NULL == fPlayback) { 382 return; 383 } 384 fPlayback->abort(); 385} 386#endif 387