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