OLD | NEW |
---|---|
(Empty) | |
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 "SkCanvasUtils.h" | |
9 #include "SkCanvas.h" | |
10 #include "SkDevice.h" | |
11 #include "SkNWayCanvas.h" | |
12 #include "SkSurface.h" | |
13 #include "SkTScopedPtr.h" | |
mtklein
2013/08/28 18:20:46
Ben will scream. I think the Ben-friendly version
djsollen
2013/08/29 15:09:19
Done.
| |
14 #include "SkWriter32.h" | |
15 | |
16 #define CANVAS_STATE_VERSION 1 | |
17 | |
18 enum RasterConfigs { | |
19 kRGB_565_RasterConfig = 4, | |
scroggo
2013/08/28 17:22:01
Maybe a comment explaining why these start with 4?
djsollen
2013/08/29 15:09:19
Done.
| |
20 kARGB_4444_RasterConfig = 5, | |
21 kARGB_8888_RasterConfig = 6 | |
22 }; | |
23 typedef int32_t RasterConfig; | |
mtklein
2013/08/28 18:20:46
Can you plaster a few warnings around to remind th
djsollen
2013/08/29 15:09:19
Done.
| |
24 | |
25 enum CanvasBackends { | |
26 kUnknown_CanvasBackend = 0, | |
27 kRaster_CanvasBackend = 1, | |
28 kGPU_CanvasBackend = 2, | |
29 kPDF_CanvasBackend = 3 | |
30 }; | |
31 typedef int32_t CanvasBackend; | |
32 | |
33 struct SkMCState { | |
34 // The Matrix and Clip are relative to |pixels|, not the source canvas. | |
35 float matrix[9]; // The matrix currently in effect on the canvas. | |
36 | |
37 // this only works for non-antialiased clips | |
38 int32_t clipRectCount; // Number of rects in |clip_rects|. | |
39 int32_t* clipRects; // Clip area: 4 ints per rect in {x,y,w,h} format. | |
mtklein
2013/08/28 18:20:46
Can't hurt to have a struct for this, right? Then
djsollen
2013/08/29 15:09:19
Done.
| |
40 | |
mtklein
2013/08/28 18:20:46
stray newline
djsollen
2013/08/29 15:09:19
Done.
| |
41 }; | |
42 | |
43 // NOTE: If you add more members, bump CanvasState::version. | |
44 struct SkCanvasLayerState { | |
45 CanvasBackend type; // |pixel| format: a value from AwPixelConfig. | |
mtklein
2013/08/28 18:20:46
Comment is confusing?
djsollen
2013/08/29 15:09:19
Done.
| |
46 int32_t x, y; | |
47 int32_t width; // In pixels. | |
48 int32_t height; // In pixels. | |
49 | |
50 SkMCState mcState; | |
51 | |
52 union { | |
53 struct { | |
54 RasterConfig config; // |pixel| format: a value from RasterConfigs. | |
55 int32_t rowBytes; // Number of bytes from start of one line to nex t. | |
scroggo
2013/08/28 17:22:01
nit: alignment of //'s
Also, should rowBytes be s
djsollen
2013/08/29 15:09:19
No size_t is not guaranteed to always be 32 bits.
| |
56 void* pixels; // The pixels, all (height * row_bytes) of them . | |
57 } raster; | |
58 struct { | |
59 int32_t textureID; | |
60 } gpu; | |
61 } content; | |
mtklein
2013/08/28 18:20:46
You may find it more readable to remove the name "
djsollen
2013/08/29 15:09:19
Done.
| |
62 }; | |
63 | |
64 class SkCanvasState { | |
scroggo
2013/08/28 17:22:01
Should this inherit from SkNoncopyable and hide th
djsollen
2013/08/29 15:09:19
This needs to stay as close to a simple struct as
| |
65 public: | |
66 SkCanvasState(const SkISize& size) { | |
67 version = CANVAS_STATE_VERSION; | |
68 width = size.width(); | |
69 height = size.height(); | |
70 layerCount = 0; | |
71 layers = NULL; | |
72 } | |
73 | |
74 ~SkCanvasState() { | |
75 // loop through the layers and free the data allocated to the clipRects | |
76 for (int i = 0; i < layerCount; ++i) { | |
77 sk_free(layers[i].mcState.clipRects); | |
78 } | |
79 | |
80 sk_free(mcState.clipRects); | |
scroggo
2013/08/28 17:22:01
Should we set this to NULL in the constructor?
mtklein
2013/08/28 18:20:46
More than that, what about initializing the struct
| |
81 sk_free(layers); | |
82 } | |
83 | |
84 int32_t version; // The CanvasState version this struct was built with. | |
scroggo
2013/08/28 17:22:01
Is there a reason these don't follow our conventio
mtklein
2013/08/28 18:20:46
Given that they're public members, I personally li
mtklein
2013/08/28 18:20:46
Add a reminder that we can never reorder around th
| |
85 int32_t width; | |
86 int32_t height; | |
87 | |
88 SkMCState mcState; | |
89 | |
90 int32_t layerCount; | |
91 SkCanvasLayerState* layers; | |
92 }; | |
93 | |
94 //////////////////////////////////////////////////////////////////////////////// | |
95 | |
96 class ClipValidator : public SkCanvas::ClipVisitor { | |
97 public: | |
scroggo
2013/08/28 17:22:01
nit: spacing. We typically have no spaces before "
djsollen
2013/08/29 15:09:19
Done.
| |
98 ClipValidator() : failed_(false) {} | |
99 bool failed() { return failed_; } | |
100 | |
101 // ClipVisitor | |
102 virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) { | |
scroggo
2013/08/28 17:22:01
SK_OVERRIDE?
djsollen
2013/08/29 15:09:19
Done.
| |
103 failed_ |= antialias; | |
104 } | |
105 | |
106 virtual void clipPath(const SkPath&, SkRegion::Op, bool antialias) { | |
scroggo
2013/08/28 17:22:01
SK_OVERRIDE?
djsollen
2013/08/29 15:09:19
Done.
| |
107 failed_ |= antialias; | |
108 } | |
109 | |
110 private: | |
scroggo
2013/08/28 17:22:01
Same spacing nit.
djsollen
2013/08/29 15:09:19
Done.
| |
111 bool failed_; | |
112 }; | |
113 | |
114 static void setup_MC_state(SkMCState* state, const SkMatrix& matrix, const SkReg ion& clip) { | |
115 // initialize the struct | |
116 state->clipRectCount = 0; | |
117 | |
118 // capture the matrix | |
119 for (int i = 0; i < 9; i++) { | |
120 state->matrix[i] = matrix.get(i); | |
121 } | |
122 | |
123 // capture the clip | |
124 const int clipBufferSize = 3 * sizeof(SkIRect); | |
125 char clipBuffer[clipBufferSize]; | |
126 SkWriter32 clipWriter(sizeof(SkIRect), clipBuffer, clipBufferSize); | |
127 | |
128 if (!clip.isEmpty()) { | |
129 // only returns the b/w clip so aa clips fail | |
130 SkRegion::Iterator clip_iterator(clip); | |
131 for (; !clip_iterator.done(); clip_iterator.next()) { | |
132 clipWriter.writeIRect(clip_iterator.rect()); | |
133 state->clipRectCount++; | |
134 } | |
135 } | |
136 | |
137 // allocate memory for the clip then and copy them to the struct | |
138 state->clipRects = (int32_t*) sk_malloc_throw(clipWriter.size()); | |
139 clipWriter.flatten(state->clipRects); | |
140 } | |
141 | |
142 | |
143 | |
144 SkCanvasState* SkCanvasUtils::CaptureCanvasState(SkCanvas* canvas) { | |
scroggo
2013/08/28 17:22:01
Should we check for a NULL canvas?
djsollen
2013/08/29 15:09:19
Done.
| |
145 // Check the clip can be decomposed into simple rectangles. | |
scroggo
2013/08/28 17:22:01
Comment seems inaccurate; the validator checks for
djsollen
2013/08/29 15:09:19
non-antialiased arbitrary paths are OK as the get
| |
146 ClipValidator validator; | |
147 canvas->replayClips(&validator); | |
148 if (validator.failed()) { | |
149 SkDEBUGF(("CaptureCanvasState does not currently support canvases with a ntialiased clips")); | |
150 return NULL; | |
151 } | |
152 | |
153 const SkISize canvasSize = canvas->getDeviceSize(); | |
154 SkTScopedPtr<SkCanvasState> canvasState(SkNEW_ARGS(SkCanvasState, (canvasSiz e))); | |
scroggo
2013/08/28 17:22:01
Aren't we moving away from SkTScopedPtr?
djsollen
2013/08/29 15:09:19
Done.
| |
155 | |
156 // decompose the total matrix and clip | |
157 setup_MC_state(&canvasState->mcState, canvas->getTotalMatrix(), canvas->getT otalClip()); | |
158 | |
159 // decompose the layers | |
160 const int layerBufferSize = 3 * sizeof(SkCanvasLayerState); | |
mtklein
2013/08/28 18:20:46
Remind us where 3 comes from? Just a guess about
djsollen
2013/08/29 15:09:19
Done.
| |
161 char layerBuffer[layerBufferSize]; | |
162 SkWriter32 layerWriter(sizeof(SkCanvasLayerState), layerBuffer, layerBufferS ize); | |
163 | |
164 for (SkCanvas::LayerIter layer(canvas, false); !layer.done(); layer.next()) { | |
mtklein
2013/08/28 18:20:46
can you add an inline "false /*meaning*/" comment
djsollen
2013/08/29 15:09:19
Done.
| |
165 // if the layer is clipped out then we can skip it | |
166 if (layer.clip().isEmpty()) { | |
167 continue; | |
168 } | |
169 | |
170 // we currently only work for a bitmap backed devices | |
scroggo
2013/08/28 17:22:01
nit: The word 'a' is not needed here
djsollen
2013/08/29 15:09:19
Done.
| |
171 const SkBitmap& bitmap = layer.device()->accessBitmap(true); | |
mtklein
2013/08/28 18:20:46
Same for true?
djsollen
2013/08/29 15:09:19
Done.
| |
172 if (bitmap.empty() || bitmap.isNull() || !bitmap.lockPixelsAreWritable() ) { | |
173 return NULL; | |
174 } | |
175 | |
176 SkCanvasLayerState* layerState = (SkCanvasLayerState*) layerWriter.reser ve(sizeof(SkCanvasLayerState)); | |
scroggo
2013/08/28 17:22:01
100 chars.
| |
177 layerState->type = kRaster_CanvasBackend; | |
178 layerState->x = layer.x(); | |
179 layerState->y = layer.y(); | |
180 layerState->width = bitmap.width(); | |
181 layerState->height = bitmap.height(); | |
182 | |
183 layerState->content.raster.config = | |
scroggo
2013/08/28 17:22:01
nit: I find a switch statement much more readable
| |
184 bitmap.config() == SkBitmap::kARGB_8888_Config ? kARGB_8888_RasterConf ig : | |
185 bitmap.config() == SkBitmap::kARGB_4444_Config ? kARGB_4444_RasterConf ig : | |
mtklein
2013/08/28 18:20:46
Can't we just screw 4444 now?
| |
186 bitmap.config() == SkBitmap::kRGB_565_Config ? kRGB_565_RasterConfig : -1; | |
mtklein
2013/08/28 18:20:46
return NULL on the failure case?
djsollen
2013/08/29 15:09:19
Done.
| |
187 layerState->content.raster.rowBytes = bitmap.rowBytes(); | |
188 layerState->content.raster.pixels = bitmap.getPixels(); | |
189 | |
190 if (layerState->content.raster.config < 0) { | |
mtklein
2013/08/28 18:20:46
Oh. :) Maybe move this up with the rest of raste
| |
191 return NULL; | |
192 } | |
193 | |
194 setup_MC_state(&layerState->mcState, layer.matrix(), layer.clip()); | |
195 canvasState->layerCount++; | |
196 } | |
197 | |
198 // allocate memory for the layers and then and copy them to the struct | |
199 canvasState->layers = (SkCanvasLayerState*) sk_malloc_throw(layerWriter.size ()); | |
mtklein
2013/08/28 18:20:46
Slight paranoia... add an assert that layerWriter.
djsollen
2013/08/29 15:09:19
Done.
| |
200 layerWriter.flatten(canvasState->layers); | |
201 | |
202 // for now, just ignore any client supplied DrawFilter. | |
203 if (canvas->getDrawFilter()) { | |
204 SkDEBUGF(("CaptureCanvasState will ignore the canvas' draw filter.")); | |
205 } | |
206 | |
207 return canvasState.release(); | |
208 } | |
209 | |
210 //////////////////////////////////////////////////////////////////////////////// | |
211 | |
212 static void setup_canvas_from_MC_state(const SkMCState& state, SkCanvas* canvas) { | |
213 // reconstruct the matrix | |
214 SkMatrix matrix; | |
215 for (int i = 0; i < 9; i++) { | |
216 matrix.set(i, state.matrix[i]); | |
217 } | |
218 | |
219 // reconstruct the clip | |
220 SkRegion clip; | |
221 for (int i = 0; i < state.clipRectCount; ++i) { | |
222 const int32_t rect_offset = i * 4; | |
223 clip.op(SkIRect::MakeLTRB(state.clipRects[rect_offset + 0], | |
224 state.clipRects[rect_offset + 1], | |
225 state.clipRects[rect_offset + 2], | |
226 state.clipRects[rect_offset + 3]), | |
227 SkRegion::kUnion_Op); | |
mtklein
2013/08/28 18:20:46
dedent SkRegion::kUnion_Op to line up with SkIRect
djsollen
2013/08/29 15:09:19
Done.
| |
228 } | |
229 | |
230 canvas->setMatrix(matrix); | |
231 canvas->setClipRegion(clip); | |
232 } | |
233 | |
234 static SkCanvas* create_canvas_from_canvas_layer(const SkCanvasLayerState& layer State) { | |
235 SkASSERT(kRaster_CanvasBackend == layerState.type); | |
236 | |
237 SkBitmap bitmap; | |
238 SkBitmap::Config config = | |
239 layerState.content.raster.config == kARGB_8888_RasterConfig ? SkBitmap:: kARGB_8888_Config : | |
240 layerState.content.raster.config == kRGB_565_RasterConfig ? SkBitmap::kR GB_565_Config : | |
241 SkBitmap::kNo_Config; | |
mtklein
2013/08/28 18:20:46
Why the asymmetry for 4444? We let a 4444 canvas
djsollen
2013/08/29 15:09:19
Done.
| |
242 | |
243 if (config == SkBitmap::kNo_Config) { | |
244 return NULL; | |
245 } | |
246 | |
247 bitmap.setConfig(config, layerState.width, layerState.height, | |
248 layerState.content.raster.rowBytes); | |
249 bitmap.setPixels(layerState.content.raster.pixels); | |
250 | |
251 SkASSERT(!bitmap.empty()); | |
252 SkASSERT(!bitmap.isNull()); | |
253 | |
254 // create a device & canvas | |
255 SkAutoTUnref<SkDevice> device(SkNEW_ARGS(SkDevice, (bitmap))); | |
256 SkAutoTUnref<SkCanvas> canvas(SkNEW_ARGS(SkCanvas, (device.get()))); | |
mtklein
2013/08/28 18:20:46
Given that you don't otherwise use the device, and
scroggo
2013/08/28 20:42:02
The SkCanvas constructor will ref the device, so w
| |
257 | |
258 // setup the matrix and clip | |
259 setup_canvas_from_MC_state(layerState.mcState, canvas.get()); | |
260 | |
261 return canvas.detach(); | |
262 } | |
263 | |
264 SkCanvas* SkCanvasUtils::CreateFromCanvasState(SkCanvasState* state) { | |
scroggo
2013/08/28 17:22:01
Should we check for a NULL state?
| |
265 | |
266 // check that the versions match | |
267 if (CANVAS_STATE_VERSION != state->version) { | |
268 SkDebugf("CreateFromCanvasState version does not match the one use to cr eate the input"); | |
269 return NULL; | |
270 } | |
271 | |
272 if (state->layerCount < 1) | |
scroggo
2013/08/28 17:22:01
Braces.
| |
273 return NULL; | |
scroggo
2013/08/28 17:22:01
4 space tabs
| |
274 | |
275 SkAutoTUnref<SkNWayCanvas> canvas(SkNEW_ARGS(SkNWayCanvas, (state->width, st ate->height))); | |
276 | |
277 // setup the matrix and clip on the n-way canvas | |
278 setup_canvas_from_MC_state(state->mcState, canvas); | |
279 | |
280 // Iterate over the layers and add them to the n-way canvas | |
281 for (int i = 0; i < state->layerCount; ++i) { | |
282 SkAutoTUnref<SkCanvas> canvasLayer(create_canvas_from_canvas_layer(state ->layers[i])); | |
283 if (!canvasLayer.get()) { | |
284 return NULL; | |
285 } | |
286 canvas->addCanvas(canvasLayer.get()); | |
mtklein
2013/08/28 18:20:46
Would it be effectively the same to call canvasLay
scroggo
2013/08/28 20:42:02
No, addCanvas refs it, so we want canvasLayer to g
djsollen
2013/08/29 15:09:19
the detach would run first which would push the re
| |
287 } | |
288 | |
289 return canvas.detach(); | |
290 } | |
291 | |
292 //////////////////////////////////////////////////////////////////////////////// | |
293 | |
294 void SkCanvasUtils::ReleaseCanvasState(SkCanvasState* state) { | |
295 SkDELETE(state); | |
296 } | |
OLD | NEW |