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 26 #define DUMP_BUFFER_SIZE 65536 27 28 //#define ENABLE_TIME_DRAW // dumps milliseconds for each draw 29 30 31 #ifdef SK_DEBUG 32 // enable SK_DEBUG_TRACE to trace DrawType elements when 33 // recorded and played back 34 // #define SK_DEBUG_TRACE 35 // enable SK_DEBUG_SIZE to see the size of picture components 36 // #define SK_DEBUG_SIZE 37 // enable SK_DEBUG_DUMP to see the contents of recorded elements 38 // #define SK_DEBUG_DUMP 39 // enable SK_DEBUG_VALIDATE to check internal structures for consistency 40 // #define SK_DEBUG_VALIDATE 41 #endif 42 43 #if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP 44 const char* DrawTypeToString(DrawType drawType) { 45 switch (drawType) { 46 case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break; 47 case CLIP_PATH: return "CLIP_PATH"; 48 case CLIP_REGION: return "CLIP_REGION"; 49 case CLIP_RECT: return "CLIP_RECT"; 50 case CONCAT: return "CONCAT"; 51 case DRAW_BITMAP: return "DRAW_BITMAP"; 52 case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX"; 53 case DRAW_BITMAP_RECT: return "DRAW_BITMAP_RECT"; 54 case DRAW_PAINT: return "DRAW_PAINT"; 55 case DRAW_PATH: return "DRAW_PATH"; 56 case DRAW_PICTURE: return "DRAW_PICTURE"; 57 case DRAW_POINTS: return "DRAW_POINTS"; 58 case DRAW_POS_TEXT: return "DRAW_POS_TEXT"; 59 case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H"; 60 case DRAW_RECT_GENERAL: return "DRAW_RECT_GENERAL"; 61 case DRAW_RECT_SIMPLE: return "DRAW_RECT_SIMPLE"; 62 case DRAW_SPRITE: return "DRAW_SPRITE"; 63 case DRAW_TEXT: return "DRAW_TEXT"; 64 case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH"; 65 case RESTORE: return "RESTORE"; 66 case ROTATE: return "ROTATE"; 67 case SAVE: return "SAVE"; 68 case SAVE_LAYER: return "SAVE_LAYER"; 69 case SCALE: return "SCALE"; 70 case SKEW: return "SKEW"; 71 case TRANSLATE: return "TRANSLATE"; 72 default: 73 SkDebugf("DrawType error 0x%08x\n", drawType); 74 SkASSERT(0); 75 break; 76 } 77 SkASSERT(0); 78 return NULL; 79 } 80 #endif 81 82 #ifdef SK_DEBUG_VALIDATE 83 static void validateMatrix(const SkMatrix* matrix) { 84 SkScalar scaleX = matrix->getScaleX(); 85 SkScalar scaleY = matrix->getScaleY(); 86 SkScalar skewX = matrix->getSkewX(); 87 SkScalar skewY = matrix->getSkewY(); 88 SkScalar perspX = matrix->getPerspX(); 89 SkScalar perspY = matrix->getPerspY(); 90 if (scaleX != 0 && skewX != 0) 91 SkDebugf("scaleX != 0 && skewX != 0\n"); 92 SkASSERT(scaleX == 0 || skewX == 0); 93 SkASSERT(scaleY == 0 || skewY == 0); 94 SkASSERT(perspX == 0); 95 SkASSERT(perspY == 0); 96 } 97 #endif 98 99 100 /////////////////////////////////////////////////////////////////////////////// 101 102 SkPicture::SkPicture() { 103 fRecord = NULL; 104 fPlayback = NULL; 105 fWidth = fHeight = 0; 106 } 107 108 SkPicture::SkPicture(const SkPicture& src) : SkRefCnt() { 109 fWidth = src.fWidth; 110 fHeight = src.fHeight; 111 fRecord = NULL; 112 113 /* We want to copy the src's playback. However, if that hasn't been built 114 yet, we need to fake a call to endRecording() without actually calling 115 it (since it is destructive, and we don't want to change src). 116 */ 117 if (src.fPlayback) { 118 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback)); 119 } else if (src.fRecord) { 120 // here we do a fake src.endRecording() 121 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord)); 122 } else { 123 fPlayback = NULL; 124 } 125 } 126 127 SkPicture::~SkPicture() { 128 SkSafeUnref(fRecord); 129 SkDELETE(fPlayback); 130 } 131 132 void SkPicture::swap(SkPicture& other) { 133 SkTSwap(fRecord, other.fRecord); 134 SkTSwap(fPlayback, other.fPlayback); 135 SkTSwap(fWidth, other.fWidth); 136 SkTSwap(fHeight, other.fHeight); 137 } 138 139 /////////////////////////////////////////////////////////////////////////////// 140 141 SkCanvas* SkPicture::beginRecording(int width, int height, 142 uint32_t recordingFlags) { 143 if (fPlayback) { 144 SkDELETE(fPlayback); 145 fPlayback = NULL; 146 } 147 148 if (NULL != fRecord) { 149 fRecord->unref(); 150 fRecord = NULL; 151 } 152 153 fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags)); 154 155 fWidth = width; 156 fHeight = height; 157 158 SkBitmap bm; 159 bm.setConfig(SkBitmap::kNo_Config, width, height); 160 fRecord->setBitmapDevice(bm); 161 162 return fRecord; 163 } 164 165 SkCanvas* SkPicture::getRecordingCanvas() const { 166 // will be null if we are not recording 167 return fRecord; 168 } 169 170 void SkPicture::endRecording() { 171 if (NULL == fPlayback) { 172 if (NULL != fRecord) { 173 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); 174 fRecord->unref(); 175 fRecord = NULL; 176 } 177 } 178 SkASSERT(NULL == fRecord); 179 } 180 181 void SkPicture::draw(SkCanvas* surface) { 182 this->endRecording(); 183 if (fPlayback) { 184 fPlayback->draw(*surface); 185 } 186 } 187 188 /////////////////////////////////////////////////////////////////////////////// 189 190 #include "SkStream.h" 191 192 #define PICTURE_VERSION 1 193 194 SkPicture::SkPicture(SkStream* stream) : SkRefCnt() { 195 const uint32_t pictureVersion = stream->readU32(); 196 if (pictureVersion != PICTURE_VERSION_ICS && 197 pictureVersion != PICTURE_VERSION_JB) { 198 sk_throw(); 199 } 200 201 fWidth = stream->readU32(); 202 fHeight = stream->readU32(); 203 204 fRecord = NULL; 205 fPlayback = NULL; 206 207 if (stream->readBool()) { 208 fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream, pictureVersion)); 209 } 210 } 211 212 void SkPicture::serialize(SkWStream* stream) const { 213 SkPicturePlayback* playback = fPlayback; 214 215 if (NULL == playback && fRecord) { 216 playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); 217 } 218 219 stream->write32(PICTURE_VERSION_JB); 220 stream->write32(fWidth); 221 stream->write32(fHeight); 222 if (playback) { 223 stream->writeBool(true); 224 playback->serialize(stream); 225 // delete playback if it is a local version (i.e. cons'd up just now) 226 if (playback != fPlayback) { 227 SkDELETE(playback); 228 } 229 } else { 230 stream->writeBool(false); 231 } 232 } 233 234 void SkPicture::abortPlayback() { 235 if (NULL == fPlayback) { 236 return; 237 } 238 fPlayback->abort(); 239 } 240 241 242