1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkPicture.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,451 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2007 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#include "SkPictureFlat.h" 1.14 +#include "SkPicturePlayback.h" 1.15 +#include "SkPictureRecord.h" 1.16 + 1.17 +#include "SkBitmapDevice.h" 1.18 +#include "SkCanvas.h" 1.19 +#include "SkChunkAlloc.h" 1.20 +#include "SkPicture.h" 1.21 +#include "SkRegion.h" 1.22 +#include "SkStream.h" 1.23 +#include "SkTDArray.h" 1.24 +#include "SkTSearch.h" 1.25 +#include "SkTime.h" 1.26 + 1.27 +#include "SkReader32.h" 1.28 +#include "SkWriter32.h" 1.29 +#include "SkRTree.h" 1.30 +#include "SkBBoxHierarchyRecord.h" 1.31 + 1.32 +#define DUMP_BUFFER_SIZE 65536 1.33 + 1.34 +//#define ENABLE_TIME_DRAW // dumps milliseconds for each draw 1.35 + 1.36 + 1.37 +#ifdef SK_DEBUG 1.38 +// enable SK_DEBUG_TRACE to trace DrawType elements when 1.39 +// recorded and played back 1.40 +// #define SK_DEBUG_TRACE 1.41 +// enable SK_DEBUG_SIZE to see the size of picture components 1.42 +// #define SK_DEBUG_SIZE 1.43 +// enable SK_DEBUG_DUMP to see the contents of recorded elements 1.44 +// #define SK_DEBUG_DUMP 1.45 +// enable SK_DEBUG_VALIDATE to check internal structures for consistency 1.46 +// #define SK_DEBUG_VALIDATE 1.47 +#endif 1.48 + 1.49 +#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP 1.50 +const char* DrawTypeToString(DrawType drawType) { 1.51 + switch (drawType) { 1.52 + case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break; 1.53 + case CLIP_PATH: return "CLIP_PATH"; 1.54 + case CLIP_REGION: return "CLIP_REGION"; 1.55 + case CLIP_RECT: return "CLIP_RECT"; 1.56 + case CLIP_RRECT: return "CLIP_RRECT"; 1.57 + case CONCAT: return "CONCAT"; 1.58 + case DRAW_BITMAP: return "DRAW_BITMAP"; 1.59 + case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX"; 1.60 + case DRAW_BITMAP_NINE: return "DRAW_BITMAP_NINE"; 1.61 + case DRAW_BITMAP_RECT_TO_RECT: return "DRAW_BITMAP_RECT_TO_RECT"; 1.62 + case DRAW_CLEAR: return "DRAW_CLEAR"; 1.63 + case DRAW_DATA: return "DRAW_DATA"; 1.64 + case DRAW_OVAL: return "DRAW_OVAL"; 1.65 + case DRAW_PAINT: return "DRAW_PAINT"; 1.66 + case DRAW_PATH: return "DRAW_PATH"; 1.67 + case DRAW_PICTURE: return "DRAW_PICTURE"; 1.68 + case DRAW_POINTS: return "DRAW_POINTS"; 1.69 + case DRAW_POS_TEXT: return "DRAW_POS_TEXT"; 1.70 + case DRAW_POS_TEXT_TOP_BOTTOM: return "DRAW_POS_TEXT_TOP_BOTTOM"; 1.71 + case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H"; 1.72 + case DRAW_POS_TEXT_H_TOP_BOTTOM: return "DRAW_POS_TEXT_H_TOP_BOTTOM"; 1.73 + case DRAW_RECT: return "DRAW_RECT"; 1.74 + case DRAW_RRECT: return "DRAW_RRECT"; 1.75 + case DRAW_SPRITE: return "DRAW_SPRITE"; 1.76 + case DRAW_TEXT: return "DRAW_TEXT"; 1.77 + case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH"; 1.78 + case DRAW_TEXT_TOP_BOTTOM: return "DRAW_TEXT_TOP_BOTTOM"; 1.79 + case DRAW_VERTICES: return "DRAW_VERTICES"; 1.80 + case RESTORE: return "RESTORE"; 1.81 + case ROTATE: return "ROTATE"; 1.82 + case SAVE: return "SAVE"; 1.83 + case SAVE_LAYER: return "SAVE_LAYER"; 1.84 + case SCALE: return "SCALE"; 1.85 + case SET_MATRIX: return "SET_MATRIX"; 1.86 + case SKEW: return "SKEW"; 1.87 + case TRANSLATE: return "TRANSLATE"; 1.88 + case NOOP: return "NOOP"; 1.89 + default: 1.90 + SkDebugf("DrawType error 0x%08x\n", drawType); 1.91 + SkASSERT(0); 1.92 + break; 1.93 + } 1.94 + SkASSERT(0); 1.95 + return NULL; 1.96 +} 1.97 +#endif 1.98 + 1.99 +#ifdef SK_DEBUG_VALIDATE 1.100 +static void validateMatrix(const SkMatrix* matrix) { 1.101 + SkScalar scaleX = matrix->getScaleX(); 1.102 + SkScalar scaleY = matrix->getScaleY(); 1.103 + SkScalar skewX = matrix->getSkewX(); 1.104 + SkScalar skewY = matrix->getSkewY(); 1.105 + SkScalar perspX = matrix->getPerspX(); 1.106 + SkScalar perspY = matrix->getPerspY(); 1.107 + if (scaleX != 0 && skewX != 0) 1.108 + SkDebugf("scaleX != 0 && skewX != 0\n"); 1.109 + SkASSERT(scaleX == 0 || skewX == 0); 1.110 + SkASSERT(scaleY == 0 || skewY == 0); 1.111 + SkASSERT(perspX == 0); 1.112 + SkASSERT(perspY == 0); 1.113 +} 1.114 +#endif 1.115 + 1.116 + 1.117 +/////////////////////////////////////////////////////////////////////////////// 1.118 + 1.119 +SkPicture::SkPicture() { 1.120 + fRecord = NULL; 1.121 + fPlayback = NULL; 1.122 + fWidth = fHeight = 0; 1.123 + fAccelData = NULL; 1.124 +} 1.125 + 1.126 +SkPicture::SkPicture(const SkPicture& src) 1.127 + : INHERITED() 1.128 + , fAccelData(NULL) { 1.129 + fWidth = src.fWidth; 1.130 + fHeight = src.fHeight; 1.131 + fRecord = NULL; 1.132 + 1.133 + /* We want to copy the src's playback. However, if that hasn't been built 1.134 + yet, we need to fake a call to endRecording() without actually calling 1.135 + it (since it is destructive, and we don't want to change src). 1.136 + */ 1.137 + if (src.fPlayback) { 1.138 + fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback)); 1.139 + } else if (src.fRecord) { 1.140 + // here we do a fake src.endRecording() 1.141 + fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord)); 1.142 + } else { 1.143 + fPlayback = NULL; 1.144 + } 1.145 +} 1.146 + 1.147 +SkPicture::~SkPicture() { 1.148 + SkSafeUnref(fRecord); 1.149 + SkDELETE(fPlayback); 1.150 + SkSafeUnref(fAccelData); 1.151 +} 1.152 + 1.153 +void SkPicture::internalOnly_EnableOpts(bool enableOpts) { 1.154 + if (NULL != fRecord) { 1.155 + fRecord->internalOnly_EnableOpts(enableOpts); 1.156 + } 1.157 +} 1.158 + 1.159 +void SkPicture::swap(SkPicture& other) { 1.160 + SkTSwap(fRecord, other.fRecord); 1.161 + SkTSwap(fPlayback, other.fPlayback); 1.162 + SkTSwap(fAccelData, other.fAccelData); 1.163 + SkTSwap(fWidth, other.fWidth); 1.164 + SkTSwap(fHeight, other.fHeight); 1.165 +} 1.166 + 1.167 +SkPicture* SkPicture::clone() const { 1.168 + SkPicture* clonedPicture = SkNEW(SkPicture); 1.169 + clone(clonedPicture, 1); 1.170 + return clonedPicture; 1.171 +} 1.172 + 1.173 +void SkPicture::clone(SkPicture* pictures, int count) const { 1.174 + SkPictCopyInfo copyInfo; 1.175 + 1.176 + for (int i = 0; i < count; i++) { 1.177 + SkPicture* clone = &pictures[i]; 1.178 + 1.179 + clone->fWidth = fWidth; 1.180 + clone->fHeight = fHeight; 1.181 + SkSafeSetNull(clone->fRecord); 1.182 + SkDELETE(clone->fPlayback); 1.183 + 1.184 + /* We want to copy the src's playback. However, if that hasn't been built 1.185 + yet, we need to fake a call to endRecording() without actually calling 1.186 + it (since it is destructive, and we don't want to change src). 1.187 + */ 1.188 + if (fPlayback) { 1.189 + clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fPlayback, ©Info)); 1.190 + } else if (fRecord) { 1.191 + // here we do a fake src.endRecording() 1.192 + clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, true)); 1.193 + } else { 1.194 + clone->fPlayback = NULL; 1.195 + } 1.196 + } 1.197 +} 1.198 + 1.199 +SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() { 1.200 + static int32_t gNextID = 0; 1.201 + 1.202 + int32_t id = sk_atomic_inc(&gNextID); 1.203 + if (id >= 1 << (8 * sizeof(Domain))) { 1.204 + SK_CRASH(); 1.205 + } 1.206 + 1.207 + return static_cast<Domain>(id); 1.208 +} 1.209 + 1.210 +/////////////////////////////////////////////////////////////////////////////// 1.211 + 1.212 +SkCanvas* SkPicture::beginRecording(int width, int height, 1.213 + uint32_t recordingFlags) { 1.214 + if (fPlayback) { 1.215 + SkDELETE(fPlayback); 1.216 + fPlayback = NULL; 1.217 + } 1.218 + SkSafeUnref(fAccelData); 1.219 + SkSafeSetNull(fRecord); 1.220 + 1.221 + // Must be set before calling createBBoxHierarchy 1.222 + fWidth = width; 1.223 + fHeight = height; 1.224 + 1.225 + const SkISize size = SkISize::Make(width, height); 1.226 + 1.227 + if (recordingFlags & kOptimizeForClippedPlayback_RecordingFlag) { 1.228 + SkBBoxHierarchy* tree = this->createBBoxHierarchy(); 1.229 + SkASSERT(NULL != tree); 1.230 + fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (size, recordingFlags, tree)); 1.231 + tree->unref(); 1.232 + } else { 1.233 + fRecord = SkNEW_ARGS(SkPictureRecord, (size, recordingFlags)); 1.234 + } 1.235 + fRecord->beginRecording(); 1.236 + 1.237 + return fRecord; 1.238 +} 1.239 + 1.240 +SkBBoxHierarchy* SkPicture::createBBoxHierarchy() const { 1.241 + // These values were empirically determined to produce reasonable 1.242 + // performance in most cases. 1.243 + static const int kRTreeMinChildren = 6; 1.244 + static const int kRTreeMaxChildren = 11; 1.245 + 1.246 + SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth), 1.247 + SkIntToScalar(fHeight)); 1.248 + bool sortDraws = false; // Do not sort draw calls when bulk loading. 1.249 + 1.250 + return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren, 1.251 + aspectRatio, sortDraws); 1.252 +} 1.253 + 1.254 +SkCanvas* SkPicture::getRecordingCanvas() const { 1.255 + // will be null if we are not recording 1.256 + return fRecord; 1.257 +} 1.258 + 1.259 +void SkPicture::endRecording() { 1.260 + if (NULL == fPlayback) { 1.261 + if (NULL != fRecord) { 1.262 + fRecord->endRecording(); 1.263 + fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); 1.264 + SkSafeSetNull(fRecord); 1.265 + } 1.266 + } 1.267 + SkASSERT(NULL == fRecord); 1.268 +} 1.269 + 1.270 +void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) { 1.271 + this->endRecording(); 1.272 + if (NULL != fPlayback) { 1.273 + fPlayback->draw(*surface, callback); 1.274 + } 1.275 +} 1.276 + 1.277 +/////////////////////////////////////////////////////////////////////////////// 1.278 + 1.279 +#include "SkStream.h" 1.280 + 1.281 +static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' }; 1.282 + 1.283 +bool SkPicture::IsValidPictInfo(const SkPictInfo& info) { 1.284 + if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) { 1.285 + return false; 1.286 + } 1.287 + 1.288 + if (info.fVersion < MIN_PICTURE_VERSION || 1.289 + info.fVersion > CURRENT_PICTURE_VERSION) { 1.290 + return false; 1.291 + } 1.292 + 1.293 + return true; 1.294 +} 1.295 + 1.296 +bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { 1.297 + if (NULL == stream) { 1.298 + return false; 1.299 + } 1.300 + 1.301 + // Check magic bytes. 1.302 + SkPictInfo info; 1.303 + SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); 1.304 + if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) { 1.305 + return false; 1.306 + } 1.307 + 1.308 + if (pInfo != NULL) { 1.309 + *pInfo = info; 1.310 + } 1.311 + return true; 1.312 +} 1.313 + 1.314 +bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) { 1.315 + // Check magic bytes. 1.316 + SkPictInfo info; 1.317 + SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); 1.318 + if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) { 1.319 + return false; 1.320 + } 1.321 + 1.322 + if (pInfo != NULL) { 1.323 + *pInfo = info; 1.324 + } 1.325 + return true; 1.326 +} 1.327 + 1.328 +SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height) 1.329 + : fPlayback(playback) 1.330 + , fRecord(NULL) 1.331 + , fWidth(width) 1.332 + , fHeight(height) 1.333 + , fAccelData(NULL) {} 1.334 + 1.335 +SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) { 1.336 + SkPictInfo info; 1.337 + 1.338 + if (!InternalOnly_StreamIsSKP(stream, &info)) { 1.339 + return NULL; 1.340 + } 1.341 + 1.342 + SkPicturePlayback* playback; 1.343 + // Check to see if there is a playback to recreate. 1.344 + if (stream->readBool()) { 1.345 + playback = SkPicturePlayback::CreateFromStream(stream, info, proc); 1.346 + if (NULL == playback) { 1.347 + return NULL; 1.348 + } 1.349 + } else { 1.350 + playback = NULL; 1.351 + } 1.352 + 1.353 + return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight)); 1.354 +} 1.355 + 1.356 +SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) { 1.357 + SkPictInfo info; 1.358 + 1.359 + if (!InternalOnly_BufferIsSKP(buffer, &info)) { 1.360 + return NULL; 1.361 + } 1.362 + 1.363 + SkPicturePlayback* playback; 1.364 + // Check to see if there is a playback to recreate. 1.365 + if (buffer.readBool()) { 1.366 + playback = SkPicturePlayback::CreateFromBuffer(buffer); 1.367 + if (NULL == playback) { 1.368 + return NULL; 1.369 + } 1.370 + } else { 1.371 + playback = NULL; 1.372 + } 1.373 + 1.374 + return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight)); 1.375 +} 1.376 + 1.377 +void SkPicture::createHeader(SkPictInfo* info) const { 1.378 + // Copy magic bytes at the beginning of the header 1.379 + SkASSERT(sizeof(kMagic) == 8); 1.380 + SkASSERT(sizeof(kMagic) == sizeof(info->fMagic)); 1.381 + memcpy(info->fMagic, kMagic, sizeof(kMagic)); 1.382 + 1.383 + // Set picture info after magic bytes in the header 1.384 + info->fVersion = CURRENT_PICTURE_VERSION; 1.385 + info->fWidth = fWidth; 1.386 + info->fHeight = fHeight; 1.387 + info->fFlags = SkPictInfo::kCrossProcess_Flag; 1.388 + // TODO: remove this flag, since we're always float (now) 1.389 + info->fFlags |= SkPictInfo::kScalarIsFloat_Flag; 1.390 + 1.391 + if (8 == sizeof(void*)) { 1.392 + info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag; 1.393 + } 1.394 +} 1.395 + 1.396 +void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const { 1.397 + SkPicturePlayback* playback = fPlayback; 1.398 + 1.399 + if (NULL == playback && fRecord) { 1.400 + playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); 1.401 + } 1.402 + 1.403 + SkPictInfo header; 1.404 + this->createHeader(&header); 1.405 + stream->write(&header, sizeof(header)); 1.406 + if (playback) { 1.407 + stream->writeBool(true); 1.408 + playback->serialize(stream, encoder); 1.409 + // delete playback if it is a local version (i.e. cons'd up just now) 1.410 + if (playback != fPlayback) { 1.411 + SkDELETE(playback); 1.412 + } 1.413 + } else { 1.414 + stream->writeBool(false); 1.415 + } 1.416 +} 1.417 + 1.418 +void SkPicture::flatten(SkWriteBuffer& buffer) const { 1.419 + SkPicturePlayback* playback = fPlayback; 1.420 + 1.421 + if (NULL == playback && fRecord) { 1.422 + playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); 1.423 + } 1.424 + 1.425 + SkPictInfo header; 1.426 + this->createHeader(&header); 1.427 + buffer.writeByteArray(&header, sizeof(header)); 1.428 + if (playback) { 1.429 + buffer.writeBool(true); 1.430 + playback->flatten(buffer); 1.431 + // delete playback if it is a local version (i.e. cons'd up just now) 1.432 + if (playback != fPlayback) { 1.433 + SkDELETE(playback); 1.434 + } 1.435 + } else { 1.436 + buffer.writeBool(false); 1.437 + } 1.438 +} 1.439 + 1.440 +bool SkPicture::willPlayBackBitmaps() const { 1.441 + if (!fPlayback) { 1.442 + return false; 1.443 + } 1.444 + return fPlayback->containsBitmaps(); 1.445 +} 1.446 + 1.447 +#ifdef SK_BUILD_FOR_ANDROID 1.448 +void SkPicture::abortPlayback() { 1.449 + if (NULL == fPlayback) { 1.450 + return; 1.451 + } 1.452 + fPlayback->abort(); 1.453 +} 1.454 +#endif