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 "SkCanvas.h" 15#include "SkChunkAlloc.h" 16#include "SkDevice.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 CONCAT: return "CONCAT"; 56 case DRAW_BITMAP: return "DRAW_BITMAP"; 57 case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX"; 58 case DRAW_BITMAP_RECT: return "DRAW_BITMAP_RECT"; 59 case DRAW_PAINT: return "DRAW_PAINT"; 60 case DRAW_PATH: return "DRAW_PATH"; 61 case DRAW_PICTURE: return "DRAW_PICTURE"; 62 case DRAW_POINTS: return "DRAW_POINTS"; 63 case DRAW_POS_TEXT: return "DRAW_POS_TEXT"; 64 case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H"; 65 case DRAW_RECT_GENERAL: return "DRAW_RECT_GENERAL"; 66 case DRAW_RECT_SIMPLE: return "DRAW_RECT_SIMPLE"; 67 case DRAW_SPRITE: return "DRAW_SPRITE"; 68 case DRAW_TEXT: return "DRAW_TEXT"; 69 case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH"; 70 case RESTORE: return "RESTORE"; 71 case ROTATE: return "ROTATE"; 72 case SAVE: return "SAVE"; 73 case SAVE_LAYER: return "SAVE_LAYER"; 74 case SCALE: return "SCALE"; 75 case SKEW: return "SKEW"; 76 case TRANSLATE: return "TRANSLATE"; 77 default: 78 SkDebugf("DrawType error 0x%08x\n", drawType); 79 SkASSERT(0); 80 break; 81 } 82 SkASSERT(0); 83 return NULL; 84} 85#endif 86 87#ifdef SK_DEBUG_VALIDATE 88static void validateMatrix(const SkMatrix* matrix) { 89 SkScalar scaleX = matrix->getScaleX(); 90 SkScalar scaleY = matrix->getScaleY(); 91 SkScalar skewX = matrix->getSkewX(); 92 SkScalar skewY = matrix->getSkewY(); 93 SkScalar perspX = matrix->getPerspX(); 94 SkScalar perspY = matrix->getPerspY(); 95 if (scaleX != 0 && skewX != 0) 96 SkDebugf("scaleX != 0 && skewX != 0\n"); 97 SkASSERT(scaleX == 0 || skewX == 0); 98 SkASSERT(scaleY == 0 || skewY == 0); 99 SkASSERT(perspX == 0); 100 SkASSERT(perspY == 0); 101} 102#endif 103 104 105/////////////////////////////////////////////////////////////////////////////// 106 107SkPicture::SkPicture() { 108 fRecord = NULL; 109 fPlayback = NULL; 110 fWidth = fHeight = 0; 111} 112 113SkPicture::SkPicture(const SkPicture& src) : SkRefCnt() { 114 fWidth = src.fWidth; 115 fHeight = src.fHeight; 116 fRecord = NULL; 117 118 /* We want to copy the src's playback. However, if that hasn't been built 119 yet, we need to fake a call to endRecording() without actually calling 120 it (since it is destructive, and we don't want to change src). 121 */ 122 if (src.fPlayback) { 123 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback)); 124 } else if (src.fRecord) { 125 // here we do a fake src.endRecording() 126 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord)); 127 } else { 128 fPlayback = NULL; 129 } 130} 131 132SkPicture::~SkPicture() { 133 SkSafeUnref(fRecord); 134 SkDELETE(fPlayback); 135} 136 137void SkPicture::swap(SkPicture& other) { 138 SkTSwap(fRecord, other.fRecord); 139 SkTSwap(fPlayback, other.fPlayback); 140 SkTSwap(fWidth, other.fWidth); 141 SkTSwap(fHeight, other.fHeight); 142} 143 144SkPicture* SkPicture::clone() const { 145 SkPicture* clonedPicture = SkNEW(SkPicture); 146 clone(clonedPicture, 1); 147 return clonedPicture; 148} 149 150void SkPicture::clone(SkPicture* pictures, int count) const { 151 SkPictCopyInfo copyInfo; 152 153 for (int i = 0; i < count; i++) { 154 SkPicture* clone = &pictures[i]; 155 156 clone->fWidth = fWidth; 157 clone->fHeight = fHeight; 158 clone->fRecord = NULL; 159 160 if (NULL != clone->fRecord) { 161 clone->fRecord->unref(); 162 clone->fRecord = NULL; 163 } 164 SkDELETE(clone->fPlayback); 165 166 /* We want to copy the src's playback. However, if that hasn't been built 167 yet, we need to fake a call to endRecording() without actually calling 168 it (since it is destructive, and we don't want to change src). 169 */ 170 if (fPlayback) { 171 clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fPlayback, ©Info)); 172 } else if (fRecord) { 173 // here we do a fake src.endRecording() 174 clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, true)); 175 } else { 176 clone->fPlayback = NULL; 177 } 178 } 179} 180 181/////////////////////////////////////////////////////////////////////////////// 182 183SkCanvas* SkPicture::beginRecording(int width, int height, 184 uint32_t recordingFlags) { 185 if (fPlayback) { 186 SkDELETE(fPlayback); 187 fPlayback = NULL; 188 } 189 190 if (NULL != fRecord) { 191 fRecord->unref(); 192 fRecord = NULL; 193 } 194 195 SkBitmap bm; 196 bm.setConfig(SkBitmap::kNo_Config, width, height); 197 SkAutoTUnref<SkDevice> dev(SkNEW_ARGS(SkDevice, (bm))); 198 199 // Must be set before calling createBBoxHierarchy 200 fWidth = width; 201 fHeight = height; 202 203 if (recordingFlags & kOptimizeForClippedPlayback_RecordingFlag) { 204 SkBBoxHierarchy* tree = this->createBBoxHierarchy(); 205 SkASSERT(NULL != tree); 206 fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (recordingFlags, tree, dev)); 207 tree->unref(); 208 } else { 209 fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags, dev)); 210 } 211 fRecord->beginRecording(); 212 213 return fRecord; 214} 215 216SkBBoxHierarchy* SkPicture::createBBoxHierarchy() const { 217 // These values were empirically determined to produce reasonable 218 // performance in most cases. 219 static const int kRTreeMinChildren = 6; 220 static const int kRTreeMaxChildren = 11; 221 222 SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth), 223 SkIntToScalar(fHeight)); 224 return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren, 225 aspectRatio); 226} 227 228SkCanvas* SkPicture::getRecordingCanvas() const { 229 // will be null if we are not recording 230 return fRecord; 231} 232 233void SkPicture::endRecording() { 234 if (NULL == fPlayback) { 235 if (NULL != fRecord) { 236 fRecord->endRecording(); 237 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); 238 fRecord->unref(); 239 fRecord = NULL; 240 } 241 } 242 SkASSERT(NULL == fRecord); 243} 244 245void SkPicture::draw(SkCanvas* surface) { 246 this->endRecording(); 247 if (fPlayback) { 248 fPlayback->draw(*surface); 249 } 250} 251 252/////////////////////////////////////////////////////////////////////////////// 253 254#include "SkStream.h" 255 256SkPicture::SkPicture(SkStream* stream, bool* success, SkSerializationHelpers::DecodeBitmap decoder) : SkRefCnt() { 257 if (success) { 258 *success = false; 259 } 260 fRecord = NULL; 261 fPlayback = NULL; 262 fWidth = fHeight = 0; 263 264 SkPictInfo info; 265 266 if (!stream->read(&info, sizeof(info))) { 267 return; 268 } 269 if (PICTURE_VERSION != info.fVersion) { 270 return; 271 } 272 273 if (stream->readBool()) { 274 bool isValid = false; 275 fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream, info, &isValid, decoder)); 276 if (!isValid) { 277 SkDELETE(fPlayback); 278 fPlayback = NULL; 279 return; 280 } 281 } 282 283 // do this at the end, so that they will be zero if we hit an error. 284 fWidth = info.fWidth; 285 fHeight = info.fHeight; 286 if (success) { 287 *success = true; 288 } 289} 290 291void SkPicture::serialize(SkWStream* stream, SkSerializationHelpers::EncodeBitmap encoder) const { 292 SkPicturePlayback* playback = fPlayback; 293 294 if (NULL == playback && fRecord) { 295 playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); 296 } 297 298 SkPictInfo info; 299 300 info.fVersion = PICTURE_VERSION; 301 info.fWidth = fWidth; 302 info.fHeight = fHeight; 303 info.fFlags = SkPictInfo::kCrossProcess_Flag; 304#ifdef SK_SCALAR_IS_FLOAT 305 info.fFlags |= SkPictInfo::kScalarIsFloat_Flag; 306#endif 307 if (8 == sizeof(void*)) { 308 info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag; 309 } 310 311 stream->write(&info, sizeof(info)); 312 if (playback) { 313 stream->writeBool(true); 314 playback->serialize(stream, encoder); 315 // delete playback if it is a local version (i.e. cons'd up just now) 316 if (playback != fPlayback) { 317 SkDELETE(playback); 318 } 319 } else { 320 stream->writeBool(false); 321 } 322} 323 324#ifdef SK_BUILD_FOR_ANDROID 325void SkPicture::abortPlayback() { 326 if (NULL == fPlayback) { 327 return; 328 } 329 fPlayback->abort(); 330} 331#endif 332