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