1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkCanvasStateUtils.h" 9 10 #include "SkDevice.h" 11 #include "SkCanvas.h" 12 #include "SkCanvasStack.h" 13 #include "SkWriter32.h" 14 15 typedef SkDevice SkBitmapDevice; 16 17 #define CANVAS_STATE_VERSION 1 18 /* 19 * WARNING: The structs below are part of a stable ABI and as such we explicitly 20 * use unambigious primitives (e.g. int32_t instead of an enum). 21 * 22 * ANY CHANGES TO THE STRUCTS BELOW THAT IMPACT THE ABI SHOULD RESULT IN AN 23 * UPDATE OF THE CANVAS_STATE_VERSION. SUCH CHANGES SHOULD ONLY BE MADE IF 24 * ABSOLUTELY NECESSARY! 25 */ 26 enum RasterConfigs { 27 kUnknown_RasterConfig = 0, 28 kRGB_565_RasterConfig = 1, 29 kARGB_8888_RasterConfig = 2 30 }; 31 typedef int32_t RasterConfig; 32 33 enum CanvasBackends { 34 kUnknown_CanvasBackend = 0, 35 kRaster_CanvasBackend = 1, 36 kGPU_CanvasBackend = 2, 37 kPDF_CanvasBackend = 3 38 }; 39 typedef int32_t CanvasBackend; 40 41 struct ClipRect { 42 int32_t left, top, right, bottom; 43 }; 44 45 struct SkMCState { 46 float matrix[9]; 47 // NOTE: this only works for non-antialiased clips 48 int32_t clipRectCount; 49 ClipRect* clipRects; 50 }; 51 52 // NOTE: If you add more members, bump CanvasState::version. 53 struct SkCanvasLayerState { 54 CanvasBackend type; 55 int32_t x, y; 56 int32_t width; 57 int32_t height; 58 59 SkMCState mcState; 60 61 union { 62 struct { 63 RasterConfig config; // pixel format: a value from RasterConfigs. 64 uint32_t rowBytes; // Number of bytes from start of one line to next. 65 void* pixels; // The pixels, all (height * rowBytes) of them. 66 } raster; 67 struct { 68 int32_t textureID; 69 } gpu; 70 }; 71 }; 72 73 class SkCanvasState { 74 public: 75 SkCanvasState(SkCanvas* canvas) { 76 SkASSERT(canvas); 77 version = CANVAS_STATE_VERSION; 78 width = canvas->getDeviceSize().width(); 79 height = canvas->getDeviceSize().height(); 80 layerCount = 0; 81 layers = NULL; 82 originalCanvas = SkRef(canvas); 83 84 mcState.clipRectCount = 0; 85 mcState.clipRects = NULL; 86 } 87 88 ~SkCanvasState() { 89 // loop through the layers and free the data allocated to the clipRects 90 for (int i = 0; i < layerCount; ++i) { 91 sk_free(layers[i].mcState.clipRects); 92 } 93 94 sk_free(mcState.clipRects); 95 sk_free(layers); 96 97 // it is now safe to free the canvas since there should be no remaining 98 // references to the content that is referenced by this canvas (e.g. pixels) 99 originalCanvas->unref(); 100 } 101 102 /** 103 * The version this struct was built with. This field must always appear 104 * first in the struct so that when the versions don't match (and the 105 * remaining contents and size are potentially different) we can still 106 * compare the version numbers. 107 */ 108 int32_t version; 109 110 int32_t width; 111 int32_t height; 112 113 SkMCState mcState; 114 115 int32_t layerCount; 116 SkCanvasLayerState* layers; 117 118 private: 119 SkCanvas* originalCanvas; 120 }; 121 122 //////////////////////////////////////////////////////////////////////////////// 123 124 class ClipValidator : public SkCanvas::ClipVisitor { 125 public: 126 ClipValidator() : fFailed(false) {} 127 bool failed() { return fFailed; } 128 129 // ClipVisitor 130 virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) SK_OVERRIDE { 131 fFailed |= antialias; 132 } 133 134 virtual void clipPath(const SkPath&, SkRegion::Op, bool antialias) SK_OVERRIDE { 135 fFailed |= antialias; 136 } 137 138 private: 139 bool fFailed; 140 }; 141 142 static void setup_MC_state(SkMCState* state, const SkMatrix& matrix, const SkRegion& clip) { 143 // initialize the struct 144 state->clipRectCount = 0; 145 146 // capture the matrix 147 for (int i = 0; i < 9; i++) { 148 state->matrix[i] = matrix.get(i); 149 } 150 151 /* 152 * capture the clip 153 * 154 * storage is allocated on the stack for the first 4 rects. This value was 155 * chosen somewhat arbitrarily, but does allow us to represent simple clips 156 * and some more common complex clips (e.g. a clipRect with a sub-rect 157 * clipped out of its interior) without needing to malloc any additional memory. 158 */ 159 const int clipBufferSize = 4 * sizeof(ClipRect); 160 char clipBuffer[clipBufferSize]; 161 SkWriter32 clipWriter(sizeof(ClipRect), clipBuffer, clipBufferSize); 162 163 if (!clip.isEmpty()) { 164 // only returns the b/w clip so aa clips fail 165 SkRegion::Iterator clip_iterator(clip); 166 for (; !clip_iterator.done(); clip_iterator.next()) { 167 // this assumes the SkIRect is stored in l,t,r,b ordering which 168 // matches the ordering of our ClipRect struct 169 clipWriter.writeIRect(clip_iterator.rect()); 170 state->clipRectCount++; 171 } 172 } 173 174 // allocate memory for the clip then and copy them to the struct 175 state->clipRects = (ClipRect*) sk_malloc_throw(clipWriter.size()); 176 clipWriter.flatten(state->clipRects); 177 } 178 179 180 181 SkCanvasState* SkCanvasStateUtils::CaptureCanvasState(SkCanvas* canvas) { 182 SkASSERT(canvas); 183 184 // Check the clip can be decomposed into rectangles (i.e. no soft clips). 185 ClipValidator validator; 186 canvas->replayClips(&validator); 187 if (validator.failed()) { 188 SkDEBUGF(("CaptureCanvasState does not support canvases with antialiased clips.\n")); 189 return NULL; 190 } 191 192 SkAutoTDelete<SkCanvasState> canvasState(SkNEW_ARGS(SkCanvasState, (canvas))); 193 194 // decompose the total matrix and clip 195 setup_MC_state(&canvasState->mcState, canvas->getTotalMatrix(), canvas->getTotalClip()); 196 197 /* 198 * decompose the layers 199 * 200 * storage is allocated on the stack for the first 3 layers. It is common in 201 * some view systems (e.g. Android) that a few non-clipped layers are present 202 * and we will not need to malloc any additional memory in those cases. 203 */ 204 const int layerBufferSize = 3 * sizeof(SkCanvasLayerState); 205 char layerBuffer[layerBufferSize]; 206 SkWriter32 layerWriter(sizeof(SkCanvasLayerState), layerBuffer, layerBufferSize); 207 int layerCount = 0; 208 for (SkCanvas::LayerIter layer(canvas, true/*skipEmptyClips*/); !layer.done(); layer.next()) { 209 210 // we currently only work for bitmap backed devices 211 const SkBitmap& bitmap = layer.device()->accessBitmap(true/*changePixels*/); 212 if (bitmap.empty() || bitmap.isNull() || !bitmap.lockPixelsAreWritable()) { 213 return NULL; 214 } 215 216 SkCanvasLayerState* layerState = 217 (SkCanvasLayerState*) layerWriter.reserve(sizeof(SkCanvasLayerState)); 218 layerState->type = kRaster_CanvasBackend; 219 layerState->x = layer.x(); 220 layerState->y = layer.y(); 221 layerState->width = bitmap.width(); 222 layerState->height = bitmap.height(); 223 224 switch (bitmap.config()) { 225 case SkBitmap::kARGB_8888_Config: 226 layerState->raster.config = kARGB_8888_RasterConfig; 227 break; 228 case SkBitmap::kRGB_565_Config: 229 layerState->raster.config = kRGB_565_RasterConfig; 230 break; 231 default: 232 return NULL; 233 } 234 layerState->raster.rowBytes = bitmap.rowBytes(); 235 layerState->raster.pixels = bitmap.getPixels(); 236 237 setup_MC_state(&layerState->mcState, layer.matrix(), layer.clip()); 238 layerCount++; 239 } 240 241 // allocate memory for the layers and then and copy them to the struct 242 SkASSERT(layerWriter.size() == layerCount * sizeof(SkCanvasLayerState)); 243 canvasState->layerCount = layerCount; 244 canvasState->layers = (SkCanvasLayerState*) sk_malloc_throw(layerWriter.size()); 245 layerWriter.flatten(canvasState->layers); 246 247 // for now, just ignore any client supplied DrawFilter. 248 if (canvas->getDrawFilter()) { 249 SkDEBUGF(("CaptureCanvasState will ignore the canvases draw filter.\n")); 250 } 251 252 return canvasState.detach(); 253 } 254 255 //////////////////////////////////////////////////////////////////////////////// 256 257 static void setup_canvas_from_MC_state(const SkMCState& state, SkCanvas* canvas) { 258 // reconstruct the matrix 259 SkMatrix matrix; 260 for (int i = 0; i < 9; i++) { 261 matrix.set(i, state.matrix[i]); 262 } 263 264 // reconstruct the clip 265 SkRegion clip; 266 for (int i = 0; i < state.clipRectCount; ++i) { 267 clip.op(SkIRect::MakeLTRB(state.clipRects[i].left, 268 state.clipRects[i].top, 269 state.clipRects[i].right, 270 state.clipRects[i].bottom), 271 SkRegion::kUnion_Op); 272 } 273 274 canvas->setMatrix(matrix); 275 canvas->setClipRegion(clip); 276 } 277 278 static SkCanvas* create_canvas_from_canvas_layer(const SkCanvasLayerState& layerState) { 279 SkASSERT(kRaster_CanvasBackend == layerState.type); 280 281 SkBitmap bitmap; 282 SkBitmap::Config config = 283 layerState.raster.config == kARGB_8888_RasterConfig ? SkBitmap::kARGB_8888_Config : 284 layerState.raster.config == kRGB_565_RasterConfig ? SkBitmap::kRGB_565_Config : 285 SkBitmap::kNo_Config; 286 287 if (config == SkBitmap::kNo_Config) { 288 return NULL; 289 } 290 291 bitmap.setConfig(config, layerState.width, layerState.height, 292 layerState.raster.rowBytes); 293 bitmap.setPixels(layerState.raster.pixels); 294 295 SkASSERT(!bitmap.empty()); 296 SkASSERT(!bitmap.isNull()); 297 298 // create a device & canvas 299 SkAutoTUnref<SkBitmapDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap))); 300 SkAutoTUnref<SkCanvas> canvas(SkNEW_ARGS(SkCanvas, (device.get()))); 301 302 // setup the matrix and clip 303 setup_canvas_from_MC_state(layerState.mcState, canvas.get()); 304 305 return canvas.detach(); 306 } 307 308 SkCanvas* SkCanvasStateUtils::CreateFromCanvasState(const SkCanvasState* state) { 309 SkASSERT(state); 310 311 // check that the versions match 312 if (CANVAS_STATE_VERSION != state->version) { 313 SkDebugf("CreateFromCanvasState version does not match the one use to create the input"); 314 return NULL; 315 } 316 317 if (state->layerCount < 1) { 318 return NULL; 319 } 320 321 SkAutoTUnref<SkCanvasStack> canvas(SkNEW_ARGS(SkCanvasStack, (state->width, state->height))); 322 323 // setup the matrix and clip on the n-way canvas 324 setup_canvas_from_MC_state(state->mcState, canvas); 325 326 // Iterate over the layers and add them to the n-way canvas 327 for (int i = state->layerCount - 1; i >= 0; --i) { 328 SkAutoTUnref<SkCanvas> canvasLayer(create_canvas_from_canvas_layer(state->layers[i])); 329 if (!canvasLayer.get()) { 330 return NULL; 331 } 332 canvas->pushCanvas(canvasLayer.get(), SkIPoint::Make(state->layers[i].x, 333 state->layers[i].y)); 334 } 335 336 return canvas.detach(); 337 } 338 339 //////////////////////////////////////////////////////////////////////////////// 340 341 void SkCanvasStateUtils::ReleaseCanvasState(SkCanvasState* state) { 342 SkDELETE(state); 343 } 344