2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "include/utils/SkCanvasStateUtils.h"
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkBitmap.h"
12 #include "include/core/SkCanvas.h"
13 #include "include/core/SkColorType.h"
14 #include "include/core/SkImageInfo.h"
15 #include "include/core/SkMatrix.h"
16 #include "include/core/SkPixmap.h"
17 #include "include/core/SkPoint.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkSize.h"
20 #include "include/private/SkMalloc.h"
21 #include "src/core/SkDevice.h"
22 #include "src/core/SkWriter32.h"
23 #include "src/utils/SkCanvasStack.h"
28 * WARNING: The structs below are part of a stable ABI and as such we explicitly
29 * use unambigious primitives (e.g. int32_t instead of an enum).
31 * ANY CHANGES TO THE STRUCTS BELOW THAT IMPACT THE ABI SHOULD RESULT IN A NEW
32 * NEW SUBCLASS OF SkCanvasState. SUCH CHANGES SHOULD ONLY BE MADE IF ABSOLUTELY
35 * In order to test changes, run the CanvasState tests. gyp/canvas_state_lib.gyp
36 * describes how to create a library to pass to the CanvasState tests. The tests
37 * should succeed when building the library with your changes and passing that to
38 * the tests running in the unchanged Skia.
41 kUnknown_RasterConfig = 0,
42 kRGB_565_RasterConfig = 1,
43 kARGB_8888_RasterConfig = 2
45 typedef int32_t RasterConfig;
48 kUnknown_CanvasBackend = 0,
49 kRaster_CanvasBackend = 1,
50 kGPU_CanvasBackend = 2,
51 kPDF_CanvasBackend = 3
53 typedef int32_t CanvasBackend;
56 int32_t left, top, right, bottom;
61 // NOTE: this only works for non-antialiased clips
62 int32_t clipRectCount;
66 // NOTE: If you add more members, create a new subclass of SkCanvasState with a
67 // new CanvasState::version.
68 struct SkCanvasLayerState {
78 RasterConfig config; // pixel format: a value from RasterConfigs.
79 uint64_t rowBytes; // Number of bytes from start of one line to next.
80 void* pixels; // The pixels, all (height * rowBytes) of them.
90 SkCanvasState(int32_t version, SkCanvas* canvas) {
92 this->version = version;
93 width = canvas->getBaseLayerSize().width();
94 height = canvas->getBaseLayerSize().height();
99 * The version this struct was built with. This field must always appear
100 * first in the struct so that when the versions don't match (and the
101 * remaining contents and size are potentially different) we can still
102 * compare the version numbers.
107 int32_t alignmentPadding;
110 class SkCanvasState_v1 : public SkCanvasState {
112 static const int32_t kVersion = 1;
114 SkCanvasState_v1(SkCanvas* canvas) : INHERITED(kVersion, canvas) {
117 mcState.clipRectCount = 0;
118 mcState.clipRects = nullptr;
119 originalCanvas = canvas;
122 ~SkCanvasState_v1() {
123 // loop through the layers and free the data allocated to the clipRects.
124 // See setup_MC_state, clipRects is only allocated when the clip isn't empty; and empty
125 // is implicitly represented as clipRectCount == 0.
126 for (int i = 0; i < layerCount; ++i) {
127 if (layers[i].mcState.clipRectCount > 0) {
128 sk_free(layers[i].mcState.clipRects);
132 if (mcState.clipRectCount > 0) {
133 sk_free(mcState.clipRects);
136 // layers is always allocated, even if it's with sk_malloc(0), so this is safe.
143 SkCanvasLayerState* layers;
145 SkCanvas* originalCanvas;
146 using INHERITED = SkCanvasState;
149 ////////////////////////////////////////////////////////////////////////////////
151 static void setup_MC_state(SkMCState* state, const SkMatrix& matrix, const SkIRect& clip) {
152 // initialize the struct
153 state->clipRectCount = 0;
155 // capture the matrix
156 for (int i = 0; i < 9; i++) {
157 state->matrix[i] = matrix.get(i);
161 * We only support a single clipRect, so we take the clip's bounds. Clients have long made
162 * this assumption anyway, so this restriction is fine.
164 SkSWriter32<sizeof(ClipRect)> clipWriter;
166 if (!clip.isEmpty()) {
167 state->clipRectCount = 1;
168 state->clipRects = (ClipRect*)sk_malloc_throw(sizeof(ClipRect));
169 state->clipRects->left = clip.fLeft;
170 state->clipRects->top = clip.fTop;
171 state->clipRects->right = clip.fRight;
172 state->clipRects->bottom = clip.fBottom;
176 SkCanvasState* SkCanvasStateUtils::CaptureCanvasState(SkCanvas* canvas) {
179 // Check the clip can be decomposed into rectangles (i.e. no soft clips).
180 if (canvas->androidFramework_isClipAA()) {
184 std::unique_ptr<SkCanvasState_v1> canvasState(new SkCanvasState_v1(canvas));
186 setup_MC_state(&canvasState->mcState, canvas->getTotalMatrix(), canvas->getDeviceClipBounds());
188 // Historically, the canvas state could report multiple top-level layers because SkCanvas
189 // supported unclipped layers. With that feature removed, all required information is contained
190 // by the canvas' top-most device.
191 SkBaseDevice* device = canvas->topDevice();
194 SkSWriter32<sizeof(SkCanvasLayerState)> layerWriter;
195 // we currently only work for bitmap backed devices
197 if (!device->accessPixels(&pmap) || 0 == pmap.width() || 0 == pmap.height()) {
200 // and for axis-aligned devices (so not transformed for an image filter)
201 if (!device->isPixelAlignedToGlobal()) {
205 SkIPoint origin = device->getOrigin(); // safe since it's pixel aligned
207 SkCanvasLayerState* layerState =
208 (SkCanvasLayerState*) layerWriter.reserve(sizeof(SkCanvasLayerState));
209 layerState->type = kRaster_CanvasBackend;
210 layerState->x = origin.x();
211 layerState->y = origin.y();
212 layerState->width = pmap.width();
213 layerState->height = pmap.height();
215 switch (pmap.colorType()) {
216 case kN32_SkColorType:
217 layerState->raster.config = kARGB_8888_RasterConfig;
219 case kRGB_565_SkColorType:
220 layerState->raster.config = kRGB_565_RasterConfig;
225 layerState->raster.rowBytes = pmap.rowBytes();
226 layerState->raster.pixels = pmap.writable_addr();
228 setup_MC_state(&layerState->mcState, device->localToDevice(), device->devClipBounds());
230 // allocate memory for the layers and then and copy them to the struct
231 SkASSERT(layerWriter.bytesWritten() == sizeof(SkCanvasLayerState));
232 canvasState->layerCount = 1;
233 canvasState->layers = (SkCanvasLayerState*) sk_malloc_throw(layerWriter.bytesWritten());
234 layerWriter.flatten(canvasState->layers);
236 return canvasState.release();
239 ////////////////////////////////////////////////////////////////////////////////
241 static void setup_canvas_from_MC_state(const SkMCState& state, SkCanvas* canvas) {
242 // reconstruct the matrix
244 for (int i = 0; i < 9; i++) {
245 matrix.set(i, state.matrix[i]);
248 // only realy support 1 rect, so if the caller (legacy?) sent us more, we just take the bounds
249 // of what they sent.
250 SkIRect bounds = SkIRect::MakeEmpty();
251 if (state.clipRectCount > 0) {
252 bounds.setLTRB(state.clipRects[0].left,
253 state.clipRects[0].top,
254 state.clipRects[0].right,
255 state.clipRects[0].bottom);
256 for (int i = 1; i < state.clipRectCount; ++i) {
257 bounds.join({state.clipRects[i].left,
258 state.clipRects[i].top,
259 state.clipRects[i].right,
260 state.clipRects[i].bottom});
264 canvas->clipRect(SkRect::Make(bounds));
265 canvas->concat(matrix);
268 static std::unique_ptr<SkCanvas>
269 make_canvas_from_canvas_layer(const SkCanvasLayerState& layerState) {
270 SkASSERT(kRaster_CanvasBackend == layerState.type);
273 SkColorType colorType =
274 layerState.raster.config == kARGB_8888_RasterConfig ? kN32_SkColorType :
275 layerState.raster.config == kRGB_565_RasterConfig ? kRGB_565_SkColorType :
276 kUnknown_SkColorType;
278 if (colorType == kUnknown_SkColorType) {
282 bitmap.installPixels(SkImageInfo::Make(layerState.width, layerState.height,
283 colorType, kPremul_SkAlphaType),
284 layerState.raster.pixels, (size_t) layerState.raster.rowBytes);
286 SkASSERT(!bitmap.empty());
287 SkASSERT(!bitmap.isNull());
289 std::unique_ptr<SkCanvas> canvas(new SkCanvas(bitmap));
291 // setup the matrix and clip
292 setup_canvas_from_MC_state(layerState.mcState, canvas.get());
297 std::unique_ptr<SkCanvas> SkCanvasStateUtils::MakeFromCanvasState(const SkCanvasState* state) {
299 // Currently there is only one possible version.
300 SkASSERT(SkCanvasState_v1::kVersion == state->version);
302 const SkCanvasState_v1* state_v1 = static_cast<const SkCanvasState_v1*>(state);
304 if (state_v1->layerCount < 1) {
308 std::unique_ptr<SkCanvasStack> canvas(new SkCanvasStack(state->width, state->height));
310 // setup the matrix and clip on the n-way canvas
311 setup_canvas_from_MC_state(state_v1->mcState, canvas.get());
313 // Iterate over the layers and add them to the n-way canvas. New clients will only send one
314 // layer since unclipped layers are no longer supported, but old canvas clients may still
316 for (int i = state_v1->layerCount - 1; i >= 0; --i) {
317 std::unique_ptr<SkCanvas> canvasLayer = make_canvas_from_canvas_layer(state_v1->layers[i]);
321 canvas->pushCanvas(std::move(canvasLayer), SkIPoint::Make(state_v1->layers[i].x,
322 state_v1->layers[i].y));
325 return std::move(canvas);
328 ////////////////////////////////////////////////////////////////////////////////
330 void SkCanvasStateUtils::ReleaseCanvasState(SkCanvasState* state) {
331 SkASSERT(!state || SkCanvasState_v1::kVersion == state->version);
332 // Upcast to the correct version of SkCanvasState. This avoids having a virtual destructor on
333 // SkCanvasState. That would be strange since SkCanvasState has no other virtual functions, and
334 // instead uses the field "version" to determine how to behave.
335 delete static_cast<SkCanvasState_v1*>(state);