1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2013 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/utils/SkCanvasStateUtils.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 11cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 12cb93a386Sopenharmony_ci#include "src/core/SkDevice.h" 13cb93a386Sopenharmony_ci#include "src/core/SkRasterClip.h" 14cb93a386Sopenharmony_ci#include "src/core/SkWriter32.h" 15cb93a386Sopenharmony_ci#include "src/utils/SkCanvasStack.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci/* 18cb93a386Sopenharmony_ci * WARNING: The structs below are part of a stable ABI and as such we explicitly 19cb93a386Sopenharmony_ci * use unambigious primitives (e.g. int32_t instead of an enum). 20cb93a386Sopenharmony_ci * 21cb93a386Sopenharmony_ci * ANY CHANGES TO THE STRUCTS BELOW THAT IMPACT THE ABI SHOULD RESULT IN A NEW 22cb93a386Sopenharmony_ci * NEW SUBCLASS OF SkCanvasState. SUCH CHANGES SHOULD ONLY BE MADE IF ABSOLUTELY 23cb93a386Sopenharmony_ci * NECESSARY! 24cb93a386Sopenharmony_ci * 25cb93a386Sopenharmony_ci * In order to test changes, run the CanvasState tests. gyp/canvas_state_lib.gyp 26cb93a386Sopenharmony_ci * describes how to create a library to pass to the CanvasState tests. The tests 27cb93a386Sopenharmony_ci * should succeed when building the library with your changes and passing that to 28cb93a386Sopenharmony_ci * the tests running in the unchanged Skia. 29cb93a386Sopenharmony_ci */ 30cb93a386Sopenharmony_cienum RasterConfigs { 31cb93a386Sopenharmony_ci kUnknown_RasterConfig = 0, 32cb93a386Sopenharmony_ci kRGB_565_RasterConfig = 1, 33cb93a386Sopenharmony_ci kARGB_8888_RasterConfig = 2 34cb93a386Sopenharmony_ci}; 35cb93a386Sopenharmony_citypedef int32_t RasterConfig; 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_cienum CanvasBackends { 38cb93a386Sopenharmony_ci kUnknown_CanvasBackend = 0, 39cb93a386Sopenharmony_ci kRaster_CanvasBackend = 1, 40cb93a386Sopenharmony_ci kGPU_CanvasBackend = 2, 41cb93a386Sopenharmony_ci kPDF_CanvasBackend = 3 42cb93a386Sopenharmony_ci}; 43cb93a386Sopenharmony_citypedef int32_t CanvasBackend; 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_cistruct ClipRect { 46cb93a386Sopenharmony_ci int32_t left, top, right, bottom; 47cb93a386Sopenharmony_ci}; 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_cistruct SkMCState { 50cb93a386Sopenharmony_ci float matrix[9]; 51cb93a386Sopenharmony_ci // NOTE: this only works for non-antialiased clips 52cb93a386Sopenharmony_ci int32_t clipRectCount; 53cb93a386Sopenharmony_ci ClipRect* clipRects; 54cb93a386Sopenharmony_ci}; 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci// NOTE: If you add more members, create a new subclass of SkCanvasState with a 57cb93a386Sopenharmony_ci// new CanvasState::version. 58cb93a386Sopenharmony_cistruct SkCanvasLayerState { 59cb93a386Sopenharmony_ci CanvasBackend type; 60cb93a386Sopenharmony_ci int32_t x, y; 61cb93a386Sopenharmony_ci int32_t width; 62cb93a386Sopenharmony_ci int32_t height; 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci SkMCState mcState; 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci union { 67cb93a386Sopenharmony_ci struct { 68cb93a386Sopenharmony_ci RasterConfig config; // pixel format: a value from RasterConfigs. 69cb93a386Sopenharmony_ci uint64_t rowBytes; // Number of bytes from start of one line to next. 70cb93a386Sopenharmony_ci void* pixels; // The pixels, all (height * rowBytes) of them. 71cb93a386Sopenharmony_ci } raster; 72cb93a386Sopenharmony_ci struct { 73cb93a386Sopenharmony_ci int32_t textureID; 74cb93a386Sopenharmony_ci } gpu; 75cb93a386Sopenharmony_ci }; 76cb93a386Sopenharmony_ci}; 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ciclass SkCanvasState { 79cb93a386Sopenharmony_cipublic: 80cb93a386Sopenharmony_ci SkCanvasState(int32_t version, SkCanvas* canvas) { 81cb93a386Sopenharmony_ci SkASSERT(canvas); 82cb93a386Sopenharmony_ci this->version = version; 83cb93a386Sopenharmony_ci width = canvas->getBaseLayerSize().width(); 84cb93a386Sopenharmony_ci height = canvas->getBaseLayerSize().height(); 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ci } 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci /** 89cb93a386Sopenharmony_ci * The version this struct was built with. This field must always appear 90cb93a386Sopenharmony_ci * first in the struct so that when the versions don't match (and the 91cb93a386Sopenharmony_ci * remaining contents and size are potentially different) we can still 92cb93a386Sopenharmony_ci * compare the version numbers. 93cb93a386Sopenharmony_ci */ 94cb93a386Sopenharmony_ci int32_t version; 95cb93a386Sopenharmony_ci int32_t width; 96cb93a386Sopenharmony_ci int32_t height; 97cb93a386Sopenharmony_ci int32_t alignmentPadding; 98cb93a386Sopenharmony_ci}; 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ciclass SkCanvasState_v1 : public SkCanvasState { 101cb93a386Sopenharmony_cipublic: 102cb93a386Sopenharmony_ci static const int32_t kVersion = 1; 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci SkCanvasState_v1(SkCanvas* canvas) : INHERITED(kVersion, canvas) { 105cb93a386Sopenharmony_ci layerCount = 0; 106cb93a386Sopenharmony_ci layers = nullptr; 107cb93a386Sopenharmony_ci mcState.clipRectCount = 0; 108cb93a386Sopenharmony_ci mcState.clipRects = nullptr; 109cb93a386Sopenharmony_ci originalCanvas = canvas; 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci ~SkCanvasState_v1() { 113cb93a386Sopenharmony_ci // loop through the layers and free the data allocated to the clipRects. 114cb93a386Sopenharmony_ci // See setup_MC_state, clipRects is only allocated when the clip isn't empty; and empty 115cb93a386Sopenharmony_ci // is implicitly represented as clipRectCount == 0. 116cb93a386Sopenharmony_ci for (int i = 0; i < layerCount; ++i) { 117cb93a386Sopenharmony_ci if (layers[i].mcState.clipRectCount > 0) { 118cb93a386Sopenharmony_ci sk_free(layers[i].mcState.clipRects); 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci if (mcState.clipRectCount > 0) { 123cb93a386Sopenharmony_ci sk_free(mcState.clipRects); 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci // layers is always allocated, even if it's with sk_malloc(0), so this is safe. 127cb93a386Sopenharmony_ci sk_free(layers); 128cb93a386Sopenharmony_ci } 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci SkMCState mcState; 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci int32_t layerCount; 133cb93a386Sopenharmony_ci SkCanvasLayerState* layers; 134cb93a386Sopenharmony_ciprivate: 135cb93a386Sopenharmony_ci SkCanvas* originalCanvas; 136cb93a386Sopenharmony_ci using INHERITED = SkCanvasState; 137cb93a386Sopenharmony_ci}; 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_cistatic void setup_MC_state(SkMCState* state, const SkMatrix& matrix, const SkIRect& clip) { 142cb93a386Sopenharmony_ci // initialize the struct 143cb93a386Sopenharmony_ci state->clipRectCount = 0; 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci // capture the matrix 146cb93a386Sopenharmony_ci for (int i = 0; i < 9; i++) { 147cb93a386Sopenharmony_ci state->matrix[i] = matrix.get(i); 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci /* 151cb93a386Sopenharmony_ci * We only support a single clipRect, so we take the clip's bounds. Clients have long made 152cb93a386Sopenharmony_ci * this assumption anyway, so this restriction is fine. 153cb93a386Sopenharmony_ci */ 154cb93a386Sopenharmony_ci SkSWriter32<sizeof(ClipRect)> clipWriter; 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci if (!clip.isEmpty()) { 157cb93a386Sopenharmony_ci state->clipRectCount = 1; 158cb93a386Sopenharmony_ci state->clipRects = (ClipRect*)sk_malloc_throw(sizeof(ClipRect)); 159cb93a386Sopenharmony_ci state->clipRects->left = clip.fLeft; 160cb93a386Sopenharmony_ci state->clipRects->top = clip.fTop; 161cb93a386Sopenharmony_ci state->clipRects->right = clip.fRight; 162cb93a386Sopenharmony_ci state->clipRects->bottom = clip.fBottom; 163cb93a386Sopenharmony_ci } 164cb93a386Sopenharmony_ci} 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ciSkCanvasState* SkCanvasStateUtils::CaptureCanvasState(SkCanvas* canvas) { 167cb93a386Sopenharmony_ci SkASSERT(canvas); 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci // Check the clip can be decomposed into rectangles (i.e. no soft clips). 170cb93a386Sopenharmony_ci if (canvas->androidFramework_isClipAA()) { 171cb93a386Sopenharmony_ci return nullptr; 172cb93a386Sopenharmony_ci } 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci std::unique_ptr<SkCanvasState_v1> canvasState(new SkCanvasState_v1(canvas)); 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_ci setup_MC_state(&canvasState->mcState, canvas->getTotalMatrix(), canvas->getDeviceClipBounds()); 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci // Historically, the canvas state could report multiple top-level layers because SkCanvas 179cb93a386Sopenharmony_ci // supported unclipped layers. With that feature removed, all required information is contained 180cb93a386Sopenharmony_ci // by the canvas' top-most device. 181cb93a386Sopenharmony_ci SkBaseDevice* device = canvas->topDevice(); 182cb93a386Sopenharmony_ci SkASSERT(device); 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ci SkSWriter32<sizeof(SkCanvasLayerState)> layerWriter; 185cb93a386Sopenharmony_ci // we currently only work for bitmap backed devices 186cb93a386Sopenharmony_ci SkPixmap pmap; 187cb93a386Sopenharmony_ci if (!device->accessPixels(&pmap) || 0 == pmap.width() || 0 == pmap.height()) { 188cb93a386Sopenharmony_ci return nullptr; 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci // and for axis-aligned devices (so not transformed for an image filter) 191cb93a386Sopenharmony_ci if (!device->isPixelAlignedToGlobal()) { 192cb93a386Sopenharmony_ci return nullptr; 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci SkIPoint origin = device->getOrigin(); // safe since it's pixel aligned 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ci SkCanvasLayerState* layerState = 198cb93a386Sopenharmony_ci (SkCanvasLayerState*) layerWriter.reserve(sizeof(SkCanvasLayerState)); 199cb93a386Sopenharmony_ci layerState->type = kRaster_CanvasBackend; 200cb93a386Sopenharmony_ci layerState->x = origin.x(); 201cb93a386Sopenharmony_ci layerState->y = origin.y(); 202cb93a386Sopenharmony_ci layerState->width = pmap.width(); 203cb93a386Sopenharmony_ci layerState->height = pmap.height(); 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_ci switch (pmap.colorType()) { 206cb93a386Sopenharmony_ci case kN32_SkColorType: 207cb93a386Sopenharmony_ci layerState->raster.config = kARGB_8888_RasterConfig; 208cb93a386Sopenharmony_ci break; 209cb93a386Sopenharmony_ci case kRGB_565_SkColorType: 210cb93a386Sopenharmony_ci layerState->raster.config = kRGB_565_RasterConfig; 211cb93a386Sopenharmony_ci break; 212cb93a386Sopenharmony_ci default: 213cb93a386Sopenharmony_ci return nullptr; 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci layerState->raster.rowBytes = pmap.rowBytes(); 216cb93a386Sopenharmony_ci layerState->raster.pixels = pmap.writable_addr(); 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ci setup_MC_state(&layerState->mcState, device->localToDevice(), device->devClipBounds()); 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci // allocate memory for the layers and then and copy them to the struct 221cb93a386Sopenharmony_ci SkASSERT(layerWriter.bytesWritten() == sizeof(SkCanvasLayerState)); 222cb93a386Sopenharmony_ci canvasState->layerCount = 1; 223cb93a386Sopenharmony_ci canvasState->layers = (SkCanvasLayerState*) sk_malloc_throw(layerWriter.bytesWritten()); 224cb93a386Sopenharmony_ci layerWriter.flatten(canvasState->layers); 225cb93a386Sopenharmony_ci 226cb93a386Sopenharmony_ci return canvasState.release(); 227cb93a386Sopenharmony_ci} 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_cistatic void setup_canvas_from_MC_state(const SkMCState& state, SkCanvas* canvas) { 232cb93a386Sopenharmony_ci // reconstruct the matrix 233cb93a386Sopenharmony_ci SkMatrix matrix; 234cb93a386Sopenharmony_ci for (int i = 0; i < 9; i++) { 235cb93a386Sopenharmony_ci matrix.set(i, state.matrix[i]); 236cb93a386Sopenharmony_ci } 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci // only realy support 1 rect, so if the caller (legacy?) sent us more, we just take the bounds 239cb93a386Sopenharmony_ci // of what they sent. 240cb93a386Sopenharmony_ci SkIRect bounds = SkIRect::MakeEmpty(); 241cb93a386Sopenharmony_ci if (state.clipRectCount > 0) { 242cb93a386Sopenharmony_ci bounds.setLTRB(state.clipRects[0].left, 243cb93a386Sopenharmony_ci state.clipRects[0].top, 244cb93a386Sopenharmony_ci state.clipRects[0].right, 245cb93a386Sopenharmony_ci state.clipRects[0].bottom); 246cb93a386Sopenharmony_ci for (int i = 1; i < state.clipRectCount; ++i) { 247cb93a386Sopenharmony_ci bounds.join({state.clipRects[i].left, 248cb93a386Sopenharmony_ci state.clipRects[i].top, 249cb93a386Sopenharmony_ci state.clipRects[i].right, 250cb93a386Sopenharmony_ci state.clipRects[i].bottom}); 251cb93a386Sopenharmony_ci } 252cb93a386Sopenharmony_ci } 253cb93a386Sopenharmony_ci 254cb93a386Sopenharmony_ci canvas->clipRect(SkRect::Make(bounds)); 255cb93a386Sopenharmony_ci canvas->concat(matrix); 256cb93a386Sopenharmony_ci} 257cb93a386Sopenharmony_ci 258cb93a386Sopenharmony_cistatic std::unique_ptr<SkCanvas> 259cb93a386Sopenharmony_cimake_canvas_from_canvas_layer(const SkCanvasLayerState& layerState) { 260cb93a386Sopenharmony_ci SkASSERT(kRaster_CanvasBackend == layerState.type); 261cb93a386Sopenharmony_ci 262cb93a386Sopenharmony_ci SkBitmap bitmap; 263cb93a386Sopenharmony_ci SkColorType colorType = 264cb93a386Sopenharmony_ci layerState.raster.config == kARGB_8888_RasterConfig ? kN32_SkColorType : 265cb93a386Sopenharmony_ci layerState.raster.config == kRGB_565_RasterConfig ? kRGB_565_SkColorType : 266cb93a386Sopenharmony_ci kUnknown_SkColorType; 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_ci if (colorType == kUnknown_SkColorType) { 269cb93a386Sopenharmony_ci return nullptr; 270cb93a386Sopenharmony_ci } 271cb93a386Sopenharmony_ci 272cb93a386Sopenharmony_ci bitmap.installPixels(SkImageInfo::Make(layerState.width, layerState.height, 273cb93a386Sopenharmony_ci colorType, kPremul_SkAlphaType), 274cb93a386Sopenharmony_ci layerState.raster.pixels, (size_t) layerState.raster.rowBytes); 275cb93a386Sopenharmony_ci 276cb93a386Sopenharmony_ci SkASSERT(!bitmap.empty()); 277cb93a386Sopenharmony_ci SkASSERT(!bitmap.isNull()); 278cb93a386Sopenharmony_ci 279cb93a386Sopenharmony_ci std::unique_ptr<SkCanvas> canvas(new SkCanvas(bitmap)); 280cb93a386Sopenharmony_ci 281cb93a386Sopenharmony_ci // setup the matrix and clip 282cb93a386Sopenharmony_ci setup_canvas_from_MC_state(layerState.mcState, canvas.get()); 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci return canvas; 285cb93a386Sopenharmony_ci} 286cb93a386Sopenharmony_ci 287cb93a386Sopenharmony_cistd::unique_ptr<SkCanvas> SkCanvasStateUtils::MakeFromCanvasState(const SkCanvasState* state) { 288cb93a386Sopenharmony_ci SkASSERT(state); 289cb93a386Sopenharmony_ci // Currently there is only one possible version. 290cb93a386Sopenharmony_ci SkASSERT(SkCanvasState_v1::kVersion == state->version); 291cb93a386Sopenharmony_ci 292cb93a386Sopenharmony_ci const SkCanvasState_v1* state_v1 = static_cast<const SkCanvasState_v1*>(state); 293cb93a386Sopenharmony_ci 294cb93a386Sopenharmony_ci if (state_v1->layerCount < 1) { 295cb93a386Sopenharmony_ci return nullptr; 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci 298cb93a386Sopenharmony_ci std::unique_ptr<SkCanvasStack> canvas(new SkCanvasStack(state->width, state->height)); 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_ci // setup the matrix and clip on the n-way canvas 301cb93a386Sopenharmony_ci setup_canvas_from_MC_state(state_v1->mcState, canvas.get()); 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci // Iterate over the layers and add them to the n-way canvas. New clients will only send one 304cb93a386Sopenharmony_ci // layer since unclipped layers are no longer supported, but old canvas clients may still 305cb93a386Sopenharmony_ci // create them. 306cb93a386Sopenharmony_ci for (int i = state_v1->layerCount - 1; i >= 0; --i) { 307cb93a386Sopenharmony_ci std::unique_ptr<SkCanvas> canvasLayer = make_canvas_from_canvas_layer(state_v1->layers[i]); 308cb93a386Sopenharmony_ci if (!canvasLayer) { 309cb93a386Sopenharmony_ci return nullptr; 310cb93a386Sopenharmony_ci } 311cb93a386Sopenharmony_ci canvas->pushCanvas(std::move(canvasLayer), SkIPoint::Make(state_v1->layers[i].x, 312cb93a386Sopenharmony_ci state_v1->layers[i].y)); 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci return std::move(canvas); 316cb93a386Sopenharmony_ci} 317cb93a386Sopenharmony_ci 318cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 319cb93a386Sopenharmony_ci 320cb93a386Sopenharmony_civoid SkCanvasStateUtils::ReleaseCanvasState(SkCanvasState* state) { 321cb93a386Sopenharmony_ci SkASSERT(!state || SkCanvasState_v1::kVersion == state->version); 322cb93a386Sopenharmony_ci // Upcast to the correct version of SkCanvasState. This avoids having a virtual destructor on 323cb93a386Sopenharmony_ci // SkCanvasState. That would be strange since SkCanvasState has no other virtual functions, and 324cb93a386Sopenharmony_ci // instead uses the field "version" to determine how to behave. 325cb93a386Sopenharmony_ci delete static_cast<SkCanvasState_v1*>(state); 326cb93a386Sopenharmony_ci} 327