SkPicture.cpp revision 01ec2eb42e9c64f8d06afd51f80c055710147141
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 "SkPicture.h" 17#include "SkRegion.h" 18#include "SkStream.h" 19#include "SkTDArray.h" 20#include "SkTSearch.h" 21#include "SkTime.h" 22 23#include "SkReader32.h" 24#include "SkWriter32.h" 25 26SK_DEFINE_INST_COUNT(SkPicture) 27 28#define DUMP_BUFFER_SIZE 65536 29 30//#define ENABLE_TIME_DRAW // dumps milliseconds for each draw 31 32 33#ifdef SK_DEBUG 34// enable SK_DEBUG_TRACE to trace DrawType elements when 35// recorded and played back 36// #define SK_DEBUG_TRACE 37// enable SK_DEBUG_SIZE to see the size of picture components 38// #define SK_DEBUG_SIZE 39// enable SK_DEBUG_DUMP to see the contents of recorded elements 40// #define SK_DEBUG_DUMP 41// enable SK_DEBUG_VALIDATE to check internal structures for consistency 42// #define SK_DEBUG_VALIDATE 43#endif 44 45#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP 46const char* DrawTypeToString(DrawType drawType) { 47 switch (drawType) { 48 case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break; 49 case CLIP_PATH: return "CLIP_PATH"; 50 case CLIP_REGION: return "CLIP_REGION"; 51 case CLIP_RECT: return "CLIP_RECT"; 52 case CONCAT: return "CONCAT"; 53 case DRAW_BITMAP: return "DRAW_BITMAP"; 54 case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX"; 55 case DRAW_BITMAP_RECT: return "DRAW_BITMAP_RECT"; 56 case DRAW_PAINT: return "DRAW_PAINT"; 57 case DRAW_PATH: return "DRAW_PATH"; 58 case DRAW_PICTURE: return "DRAW_PICTURE"; 59 case DRAW_POINTS: return "DRAW_POINTS"; 60 case DRAW_POS_TEXT: return "DRAW_POS_TEXT"; 61 case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H"; 62 case DRAW_RECT_GENERAL: return "DRAW_RECT_GENERAL"; 63 case DRAW_RECT_SIMPLE: return "DRAW_RECT_SIMPLE"; 64 case DRAW_SPRITE: return "DRAW_SPRITE"; 65 case DRAW_TEXT: return "DRAW_TEXT"; 66 case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH"; 67 case RESTORE: return "RESTORE"; 68 case ROTATE: return "ROTATE"; 69 case SAVE: return "SAVE"; 70 case SAVE_LAYER: return "SAVE_LAYER"; 71 case SCALE: return "SCALE"; 72 case SKEW: return "SKEW"; 73 case TRANSLATE: return "TRANSLATE"; 74 default: 75 SkDebugf("DrawType error 0x%08x\n", drawType); 76 SkASSERT(0); 77 break; 78 } 79 SkASSERT(0); 80 return NULL; 81} 82#endif 83 84#ifdef SK_DEBUG_VALIDATE 85static void validateMatrix(const SkMatrix* matrix) { 86 SkScalar scaleX = matrix->getScaleX(); 87 SkScalar scaleY = matrix->getScaleY(); 88 SkScalar skewX = matrix->getSkewX(); 89 SkScalar skewY = matrix->getSkewY(); 90 SkScalar perspX = matrix->getPerspX(); 91 SkScalar perspY = matrix->getPerspY(); 92 if (scaleX != 0 && skewX != 0) 93 SkDebugf("scaleX != 0 && skewX != 0\n"); 94 SkASSERT(scaleX == 0 || skewX == 0); 95 SkASSERT(scaleY == 0 || skewY == 0); 96 SkASSERT(perspX == 0); 97 SkASSERT(perspY == 0); 98} 99#endif 100 101 102/////////////////////////////////////////////////////////////////////////////// 103 104SkPicture::SkPicture() { 105 fRecord = NULL; 106 fPlayback = NULL; 107 fWidth = fHeight = 0; 108} 109 110SkPicture::SkPicture(const SkPicture& src) : SkRefCnt() { 111 fWidth = src.fWidth; 112 fHeight = src.fHeight; 113 fRecord = NULL; 114 115 /* We want to copy the src's playback. However, if that hasn't been built 116 yet, we need to fake a call to endRecording() without actually calling 117 it (since it is destructive, and we don't want to change src). 118 */ 119 if (src.fPlayback) { 120 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback)); 121 } else if (src.fRecord) { 122 // here we do a fake src.endRecording() 123 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord)); 124 } else { 125 fPlayback = NULL; 126 } 127} 128 129SkPicture::~SkPicture() { 130 SkSafeUnref(fRecord); 131 SkDELETE(fPlayback); 132} 133 134void SkPicture::swap(SkPicture& other) { 135 SkTSwap(fRecord, other.fRecord); 136 SkTSwap(fPlayback, other.fPlayback); 137 SkTSwap(fWidth, other.fWidth); 138 SkTSwap(fHeight, other.fHeight); 139} 140 141/////////////////////////////////////////////////////////////////////////////// 142 143SkCanvas* SkPicture::beginRecording(int width, int height, 144 uint32_t recordingFlags) { 145 if (fPlayback) { 146 SkDELETE(fPlayback); 147 fPlayback = NULL; 148 } 149 150 if (NULL != fRecord) { 151 fRecord->unref(); 152 fRecord = NULL; 153 } 154 155 fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags)); 156 157 fWidth = width; 158 fHeight = height; 159 160 SkBitmap bm; 161 bm.setConfig(SkBitmap::kNo_Config, width, height); 162 fRecord->setBitmapDevice(bm); 163 164 return fRecord; 165} 166 167bool SkPicture::hasRecorded() const { 168 return NULL != fRecord && fRecord->writeStream().size() > 0; 169} 170 171SkCanvas* SkPicture::getRecordingCanvas() const { 172 // will be null if we are not recording 173 return fRecord; 174} 175 176void SkPicture::endRecording() { 177 if (NULL == fPlayback) { 178 if (NULL != fRecord) { 179 fRecord->endRecording(); 180 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); 181 fRecord->unref(); 182 fRecord = NULL; 183 } 184 } 185 SkASSERT(NULL == fRecord); 186} 187 188void SkPicture::draw(SkCanvas* surface) { 189 this->endRecording(); 190 if (fPlayback) { 191 fPlayback->draw(*surface); 192 } 193} 194 195/////////////////////////////////////////////////////////////////////////////// 196 197#include "SkStream.h" 198 199// V2 : adds SkPixelRef's generation ID. 200// V3 : PictInfo tag at beginning, and EOF tag at the end 201// V4 : move SkPictInfo to be the header 202// V5 : don't read/write FunctionPtr on cross-process (we can detect that) 203// V6 : added serialization of SkPath's bounds (and packed its flags tighter) 204#define PICTURE_VERSION 6 205 206SkPicture::SkPicture(SkStream* stream) : SkRefCnt() { 207 fRecord = NULL; 208 fPlayback = NULL; 209 fWidth = fHeight = 0; 210 211 SkPictInfo info; 212 213 if (!stream->read(&info, sizeof(info))) { 214 return; 215 } 216 if (PICTURE_VERSION != info.fVersion) { 217 return; 218 } 219 220 if (stream->readBool()) { 221 bool isValid = false; 222 fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream, info, &isValid)); 223 if (!isValid) { 224 SkDELETE(fPlayback); 225 fPlayback = NULL; 226 return; 227 } 228 } 229 230 // do this at the end, so that they will be zero if we hit an error. 231 fWidth = info.fWidth; 232 fHeight = info.fHeight; 233} 234 235void SkPicture::serialize(SkWStream* stream) const { 236 SkPicturePlayback* playback = fPlayback; 237 238 if (NULL == playback && fRecord) { 239 playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); 240 } 241 242 SkPictInfo info; 243 244 info.fVersion = PICTURE_VERSION; 245 info.fWidth = fWidth; 246 info.fHeight = fHeight; 247 info.fFlags = SkPictInfo::kCrossProcess_Flag; 248#ifdef SK_SCALAR_IS_FLOAT 249 info.fFlags |= SkPictInfo::kScalarIsFloat_Flag; 250#endif 251 if (8 == sizeof(void*)) { 252 info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag; 253 } 254 255 stream->write(&info, sizeof(info)); 256 if (playback) { 257 stream->writeBool(true); 258 playback->serialize(stream); 259 // delete playback if it is a local version (i.e. cons'd up just now) 260 if (playback != fPlayback) { 261 SkDELETE(playback); 262 } 263 } else { 264 stream->writeBool(false); 265 } 266} 267 268void SkPicture::abortPlayback() { 269 if (NULL == fPlayback) { 270 return; 271 } 272 fPlayback->abort(); 273} 274 275 276