OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2012 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 "SkDebugCanvas.h" | |
9 #include "SkDevice.h" | |
10 #include "SkForceLinking.h" | |
11 #include "SkGraphics.h" | |
12 #include "SkImageDecoder.h" | |
13 #include "SkImageEncoder.h" | |
14 #include "SkOSFile.h" | |
15 #include "SkPicture.h" | |
16 #include "SkPictureRecord.h" | |
17 #include "SkPictureRecorder.h" | |
18 #include "SkStream.h" | |
19 #include "picture_utils.h" | |
20 | |
21 __SK_FORCE_IMAGE_DECODER_LINKING; | |
22 | |
23 static void usage() { | |
24 SkDebugf("Usage: filter -i inFile [-o outFile] [--input-dir path] [--output-
dir path]\n"); | |
25 SkDebugf(" [-h|--help]\n\n"); | |
26 SkDebugf(" -i inFile : file to filter.\n"); | |
27 SkDebugf(" -o outFile : result of filtering.\n"); | |
28 SkDebugf(" --input-dir : process all files in dir with .skp extension.\n"
); | |
29 SkDebugf(" --output-dir : results of filtering the input dir.\n"); | |
30 SkDebugf(" -h|--help : Show this help message.\n"); | |
31 } | |
32 | |
33 // Is the supplied paint simply a color? | |
34 static bool is_simple(const SkPaint& p) { | |
35 return nullptr == p.getPathEffect() && | |
36 nullptr == p.getShader() && | |
37 nullptr == p.getXfermode() && | |
38 nullptr == p.getMaskFilter() && | |
39 nullptr == p.getColorFilter() && | |
40 nullptr == p.getRasterizer() && | |
41 nullptr == p.getLooper() && | |
42 nullptr == p.getImageFilter(); | |
43 } | |
44 | |
45 | |
46 // Check for: | |
47 // SAVE_LAYER | |
48 // DRAW_BITMAP_RECT_TO_RECT | |
49 // RESTORE | |
50 // where the saveLayer's color can be moved into the drawBitmapRect | |
51 static bool check_0(SkDebugCanvas* canvas, int curCommand) { | |
52 if (SkDrawCommand::kSaveLayer_OpType != canvas->getDrawCommandAt(curCommand)
->getType() || | |
53 canvas->getSize() <= curCommand+2 || | |
54 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCom
mand+1)->getType() || | |
55 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+2)
->getType()) { | |
56 return false; | |
57 } | |
58 | |
59 SkSaveLayerCommand* saveLayer = | |
60 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); | |
61 SkDrawBitmapRectCommand* dbmr = | |
62 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
63 | |
64 const SkPaint* saveLayerPaint = saveLayer->paint(); | |
65 SkPaint* dbmrPaint = dbmr->paint(); | |
66 | |
67 // For this optimization we only fold the saveLayer and drawBitmapRect | |
68 // together if the saveLayer's draw is simple (i.e., no fancy effects) | |
69 // and the only difference in the colors is their alpha value | |
70 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaqu
e | |
71 SkColor dbmrColor = dbmrPaint->getColor() | 0xFF000000; // force opaqu
e | |
72 | |
73 // If either operation lacks a paint then the collapse is trivial | |
74 return nullptr == saveLayerPaint || | |
75 nullptr == dbmrPaint || | |
76 (is_simple(*saveLayerPaint) && dbmrColor == layerColor); | |
77 } | |
78 | |
79 // Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer | |
80 // and restore | |
81 static void apply_0(SkDebugCanvas* canvas, int curCommand) { | |
82 SkSaveLayerCommand* saveLayer = | |
83 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); | |
84 const SkPaint* saveLayerPaint = saveLayer->paint(); | |
85 | |
86 // if (nullptr == saveLayerPaint) the dbmr's paint doesn't need to be change
d | |
87 if (saveLayerPaint) { | |
88 SkDrawBitmapRectCommand* dbmr = | |
89 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
90 SkPaint* dbmrPaint = dbmr->paint(); | |
91 | |
92 if (nullptr == dbmrPaint) { | |
93 // if the DBMR doesn't have a paint just use the saveLayer's | |
94 dbmr->setPaint(*saveLayerPaint); | |
95 } else if (saveLayerPaint) { | |
96 // Both paints are present so their alphas need to be combined | |
97 SkColor color = saveLayerPaint->getColor(); | |
98 int a0 = SkColorGetA(color); | |
99 | |
100 color = dbmrPaint->getColor(); | |
101 int a1 = SkColorGetA(color); | |
102 | |
103 int newA = SkMulDiv255Round(a0, a1); | |
104 SkASSERT(newA <= 0xFF); | |
105 | |
106 SkColor newColor = SkColorSetA(color, newA); | |
107 dbmrPaint->setColor(newColor); | |
108 } | |
109 } | |
110 | |
111 canvas->deleteDrawCommandAt(curCommand+2); // restore | |
112 canvas->deleteDrawCommandAt(curCommand); // saveLayer | |
113 } | |
114 | |
115 // Check for: | |
116 // SAVE_LAYER | |
117 // SAVE | |
118 // CLIP_RECT | |
119 // DRAW_BITMAP_RECT_TO_RECT | |
120 // RESTORE | |
121 // RESTORE | |
122 // where the saveLayer's color can be moved into the drawBitmapRect | |
123 static bool check_1(SkDebugCanvas* canvas, int curCommand) { | |
124 if (SkDrawCommand::kSaveLayer_OpType != canvas->getDrawCommandAt(curCommand)
->getType() || | |
125 canvas->getSize() <= curCommand+5 || | |
126 SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand+1)->g
etType() || | |
127 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+2
)->getType() || | |
128 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCom
mand+3)->getType() || | |
129 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+4)
->getType() || | |
130 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+5)
->getType()) { | |
131 return false; | |
132 } | |
133 | |
134 SkSaveLayerCommand* saveLayer = | |
135 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); | |
136 SkDrawBitmapRectCommand* dbmr = | |
137 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+3); | |
138 | |
139 const SkPaint* saveLayerPaint = saveLayer->paint(); | |
140 SkPaint* dbmrPaint = dbmr->paint(); | |
141 | |
142 // For this optimization we only fold the saveLayer and drawBitmapRect | |
143 // together if the saveLayer's draw is simple (i.e., no fancy effects) and | |
144 // and the only difference in the colors is that the saveLayer's can have | |
145 // an alpha while the drawBitmapRect's is opaque. | |
146 // TODO: it should be possible to fold them together even if they both | |
147 // have different non-255 alphas but this is low priority since we have | |
148 // never seen that case | |
149 // If either operation lacks a paint then the collapse is trivial | |
150 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaqu
e | |
151 | |
152 return nullptr == saveLayerPaint || | |
153 nullptr == dbmrPaint || | |
154 (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor); | |
155 } | |
156 | |
157 // Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer | |
158 // and restore | |
159 static void apply_1(SkDebugCanvas* canvas, int curCommand) { | |
160 SkSaveLayerCommand* saveLayer = | |
161 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); | |
162 const SkPaint* saveLayerPaint = saveLayer->paint(); | |
163 | |
164 // if (nullptr == saveLayerPaint) the dbmr's paint doesn't need to be change
d | |
165 if (saveLayerPaint) { | |
166 SkDrawBitmapRectCommand* dbmr = | |
167 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+3); | |
168 SkPaint* dbmrPaint = dbmr->paint(); | |
169 | |
170 if (nullptr == dbmrPaint) { | |
171 dbmr->setPaint(*saveLayerPaint); | |
172 } else { | |
173 SkColor newColor = SkColorSetA(dbmrPaint->getColor(), | |
174 SkColorGetA(saveLayerPaint->getColor(
))); | |
175 dbmrPaint->setColor(newColor); | |
176 } | |
177 } | |
178 | |
179 canvas->deleteDrawCommandAt(curCommand+5); // restore | |
180 canvas->deleteDrawCommandAt(curCommand); // saveLayer | |
181 } | |
182 | |
183 // Check for: | |
184 // SAVE | |
185 // CLIP_RECT | |
186 // DRAW_RECT | |
187 // RESTORE | |
188 // where the rect is entirely within the clip and the clip is an intersect | |
189 static bool check_2(SkDebugCanvas* canvas, int curCommand) { | |
190 if (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->get
Type() || | |
191 canvas->getSize() <= curCommand+4 || | |
192 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1
)->getType() || | |
193 SkDrawCommand::kDrawRect_OpType != canvas->getDrawCommandAt(curCommand+2
)->getType() || | |
194 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+3)
->getType()) { | |
195 return false; | |
196 } | |
197 | |
198 SkClipRectCommand* cr = | |
199 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
200 SkDrawRectCommand* dr = | |
201 (SkDrawRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
202 | |
203 if (SkRegion::kIntersect_Op != cr->op()) { | |
204 return false; | |
205 } | |
206 | |
207 return cr->rect().contains(dr->rect()); | |
208 } | |
209 | |
210 // Remove everything but the drawRect | |
211 static void apply_2(SkDebugCanvas* canvas, int curCommand) { | |
212 canvas->deleteDrawCommandAt(curCommand+3); // restore | |
213 // drawRect | |
214 canvas->deleteDrawCommandAt(curCommand+1); // clipRect | |
215 canvas->deleteDrawCommandAt(curCommand); // save | |
216 } | |
217 | |
218 // Check for: | |
219 // SAVE | |
220 // CLIP_RRECT | |
221 // DRAW_RECT | |
222 // RESTORE | |
223 // where the rect entirely encloses the clip | |
224 static bool check_3(SkDebugCanvas* canvas, int curCommand) { | |
225 if (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->get
Type() || | |
226 canvas->getSize() <= curCommand+4 || | |
227 SkDrawCommand::kClipRRect_OpType != canvas->getDrawCommandAt(curCommand+
1)->getType() || | |
228 SkDrawCommand::kDrawRect_OpType != canvas->getDrawCommandAt(curCommand+2
)->getType() || | |
229 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+3)
->getType()) { | |
230 return false; | |
231 } | |
232 | |
233 SkClipRRectCommand* crr = | |
234 (SkClipRRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
235 SkDrawRectCommand* dr = | |
236 (SkDrawRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
237 | |
238 if (SkRegion::kIntersect_Op != crr->op()) { | |
239 return false; | |
240 } | |
241 | |
242 return dr->rect().contains(crr->rrect().rect()); | |
243 } | |
244 | |
245 // Replace everything with a drawRRect with the paint from the drawRect | |
246 // and the AA settings from the clipRRect | |
247 static void apply_3(SkDebugCanvas* canvas, int curCommand) { | |
248 | |
249 canvas->deleteDrawCommandAt(curCommand+3); // restore | |
250 | |
251 SkClipRRectCommand* crr = | |
252 (SkClipRRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
253 SkDrawRectCommand* dr = | |
254 (SkDrawRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
255 | |
256 // TODO: could skip paint re-creation if the AA settings already match | |
257 SkPaint newPaint = dr->paint(); | |
258 newPaint.setAntiAlias(crr->doAA()); | |
259 SkDrawRRectCommand* drr = new SkDrawRRectCommand(crr->rrect(), newPaint); | |
260 canvas->setDrawCommandAt(curCommand+2, drr); | |
261 | |
262 canvas->deleteDrawCommandAt(curCommand+1); // clipRRect | |
263 canvas->deleteDrawCommandAt(curCommand); // save | |
264 } | |
265 | |
266 // Check for: | |
267 // SAVE | |
268 // CLIP_RECT | |
269 // DRAW_BITMAP_RECT_TO_RECT | |
270 // RESTORE | |
271 // where the rect and drawBitmapRect dst exactly match | |
272 static bool check_4(SkDebugCanvas* canvas, int curCommand) { | |
273 if (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->get
Type() || | |
274 canvas->getSize() <= curCommand+4 || | |
275 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1
)->getType() || | |
276 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCom
mand+2)->getType() || | |
277 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+3)
->getType()) { | |
278 return false; | |
279 } | |
280 | |
281 SkClipRectCommand* cr = | |
282 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
283 SkDrawBitmapRectCommand* dbmr = | |
284 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
285 | |
286 if (SkRegion::kIntersect_Op != cr->op()) { | |
287 return false; | |
288 } | |
289 | |
290 return dbmr->dstRect() == cr->rect(); | |
291 } | |
292 | |
293 // Remove everything but the drawBitmapRect | |
294 static void apply_4(SkDebugCanvas* canvas, int curCommand) { | |
295 canvas->deleteDrawCommandAt(curCommand+3); // restore | |
296 // drawBitmapRectToRect | |
297 canvas->deleteDrawCommandAt(curCommand+1); // clipRect | |
298 canvas->deleteDrawCommandAt(curCommand); // save | |
299 } | |
300 | |
301 // Check for: | |
302 // SAVE | |
303 // CLIP_RECT | |
304 // SAVE_LAYER | |
305 // SAVE | |
306 // CLIP_RECT | |
307 // SAVE_LAYER | |
308 // SAVE | |
309 // CLIP_RECT | |
310 // DRAWBITMAPRECTTORECT | |
311 // RESTORE | |
312 // RESTORE | |
313 // RESTORE | |
314 // RESTORE | |
315 // RESTORE | |
316 // where: | |
317 // all the clipRect's are BW, nested, intersections | |
318 // the drawBitmapRectToRect is a 1-1 copy from src to dest | |
319 // the last (smallest) clip rect is a subset of the drawBitmapRectToRect's
dest rect | |
320 // all the saveLayer's paints can be rolled into the drawBitmapRectToRect's
paint | |
321 // This pattern is used by Google spreadsheet when drawing the toolbar buttons | |
322 static bool check_7(SkDebugCanvas* canvas, int curCommand) { | |
323 if (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->get
Type() || | |
324 canvas->getSize() <= curCommand+13 || | |
325 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1
)->getType() || | |
326 SkDrawCommand::kSaveLayer_OpType != canvas->getDrawCommandAt(curCommand+
2)->getType() || | |
327 SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand+3)->g
etType() || | |
328 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+4
)->getType() || | |
329 SkDrawCommand::kSaveLayer_OpType != canvas->getDrawCommandAt(curCommand+
5)->getType() || | |
330 SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand+6)->g
etType() || | |
331 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+7
)->getType() || | |
332 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCom
mand+8)->getType() || | |
333 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+9)
->getType() || | |
334 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+10
)->getType() || | |
335 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+11
)->getType() || | |
336 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+12
)->getType() || | |
337 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+13
)->getType()) { | |
338 return false; | |
339 } | |
340 | |
341 SkClipRectCommand* clip0 = | |
342 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
343 SkSaveLayerCommand* saveLayer0 = | |
344 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+2); | |
345 SkClipRectCommand* clip1 = | |
346 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+4); | |
347 SkSaveLayerCommand* saveLayer1 = | |
348 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+5); | |
349 SkClipRectCommand* clip2 = | |
350 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+7); | |
351 SkDrawBitmapRectCommand* dbmr = | |
352 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+8); | |
353 | |
354 if (clip0->doAA() || clip1->doAA() || clip2->doAA()) { | |
355 return false; | |
356 } | |
357 | |
358 if (SkRegion::kIntersect_Op != clip0->op() || | |
359 SkRegion::kIntersect_Op != clip1->op() || | |
360 SkRegion::kIntersect_Op != clip2->op()) { | |
361 return false; | |
362 } | |
363 | |
364 if (!clip0->rect().contains(clip1->rect()) || | |
365 !clip1->rect().contains(clip2->rect())) { | |
366 return false; | |
367 } | |
368 | |
369 // The src->dest mapping needs to be 1-to-1 | |
370 if (nullptr == dbmr->srcRect()) { | |
371 if (dbmr->bitmap().width() != dbmr->dstRect().width() || | |
372 dbmr->bitmap().height() != dbmr->dstRect().height()) { | |
373 return false; | |
374 } | |
375 } else { | |
376 if (dbmr->srcRect()->width() != dbmr->dstRect().width() || | |
377 dbmr->srcRect()->height() != dbmr->dstRect().height()) { | |
378 return false; | |
379 } | |
380 } | |
381 | |
382 if (!dbmr->dstRect().contains(clip2->rect())) { | |
383 return false; | |
384 } | |
385 | |
386 const SkPaint* saveLayerPaint0 = saveLayer0->paint(); | |
387 const SkPaint* saveLayerPaint1 = saveLayer1->paint(); | |
388 | |
389 if ((saveLayerPaint0 && !is_simple(*saveLayerPaint0)) || | |
390 (saveLayerPaint1 && !is_simple(*saveLayerPaint1))) { | |
391 return false; | |
392 } | |
393 | |
394 SkPaint* dbmrPaint = dbmr->paint(); | |
395 | |
396 if (nullptr == dbmrPaint) { | |
397 return true; | |
398 } | |
399 | |
400 if (saveLayerPaint0) { | |
401 SkColor layerColor0 = saveLayerPaint0->getColor() | 0xFF000000; // force
opaque | |
402 if (dbmrPaint->getColor() != layerColor0) { | |
403 return false; | |
404 } | |
405 } | |
406 | |
407 if (saveLayerPaint1) { | |
408 SkColor layerColor1 = saveLayerPaint1->getColor() | 0xFF000000; // force
opaque | |
409 if (dbmrPaint->getColor() != layerColor1) { | |
410 return false; | |
411 } | |
412 } | |
413 | |
414 return true; | |
415 } | |
416 | |
417 // Reduce to a single drawBitmapRectToRect call by folding the clipRect's into | |
418 // the src and dst Rects and the saveLayer paints into the drawBitmapRectToRect'
s | |
419 // paint. | |
420 static void apply_7(SkDebugCanvas* canvas, int curCommand) { | |
421 SkSaveLayerCommand* saveLayer0 = | |
422 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+2); | |
423 SkSaveLayerCommand* saveLayer1 = | |
424 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+5); | |
425 SkClipRectCommand* clip2 = | |
426 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+7); | |
427 SkDrawBitmapRectCommand* dbmr = | |
428 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+8); | |
429 | |
430 SkScalar newSrcLeft = dbmr->srcRect()->fLeft + clip2->rect().fLeft - dbmr->d
stRect().fLeft; | |
431 SkScalar newSrcTop = dbmr->srcRect()->fTop + clip2->rect().fTop - dbmr->dstR
ect().fTop; | |
432 | |
433 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop, | |
434 clip2->rect().width(), clip2->rect().height
()); | |
435 | |
436 dbmr->setSrcRect(newSrc); | |
437 dbmr->setDstRect(clip2->rect()); | |
438 | |
439 SkColor color = 0xFF000000; | |
440 int a0, a1; | |
441 | |
442 const SkPaint* saveLayerPaint0 = saveLayer0->paint(); | |
443 if (saveLayerPaint0) { | |
444 color = saveLayerPaint0->getColor(); | |
445 a0 = SkColorGetA(color); | |
446 } else { | |
447 a0 = 0xFF; | |
448 } | |
449 | |
450 const SkPaint* saveLayerPaint1 = saveLayer1->paint(); | |
451 if (saveLayerPaint1) { | |
452 color = saveLayerPaint1->getColor(); | |
453 a1 = SkColorGetA(color); | |
454 } else { | |
455 a1 = 0xFF; | |
456 } | |
457 | |
458 int newA = SkMulDiv255Round(a0, a1); | |
459 SkASSERT(newA <= 0xFF); | |
460 | |
461 SkPaint* dbmrPaint = dbmr->paint(); | |
462 | |
463 if (dbmrPaint) { | |
464 SkColor newColor = SkColorSetA(dbmrPaint->getColor(), newA); | |
465 dbmrPaint->setColor(newColor); | |
466 } else { | |
467 SkColor newColor = SkColorSetA(color, newA); | |
468 | |
469 SkPaint newPaint; | |
470 newPaint.setColor(newColor); | |
471 dbmr->setPaint(newPaint); | |
472 } | |
473 | |
474 // remove everything except the drawbitmaprect | |
475 canvas->deleteDrawCommandAt(curCommand+13); // restore | |
476 canvas->deleteDrawCommandAt(curCommand+12); // restore | |
477 canvas->deleteDrawCommandAt(curCommand+11); // restore | |
478 canvas->deleteDrawCommandAt(curCommand+10); // restore | |
479 canvas->deleteDrawCommandAt(curCommand+9); // restore | |
480 canvas->deleteDrawCommandAt(curCommand+7); // clipRect | |
481 canvas->deleteDrawCommandAt(curCommand+6); // save | |
482 canvas->deleteDrawCommandAt(curCommand+5); // saveLayer | |
483 canvas->deleteDrawCommandAt(curCommand+4); // clipRect | |
484 canvas->deleteDrawCommandAt(curCommand+3); // save | |
485 canvas->deleteDrawCommandAt(curCommand+2); // saveLayer | |
486 canvas->deleteDrawCommandAt(curCommand+1); // clipRect | |
487 canvas->deleteDrawCommandAt(curCommand); // save | |
488 } | |
489 | |
490 // Check for: | |
491 // SAVE | |
492 // CLIP_RECT | |
493 // DRAWBITMAPRECTTORECT | |
494 // RESTORE | |
495 // where: | |
496 // the drawBitmapRectToRect is a 1-1 copy from src to dest | |
497 // the clip rect is BW and a subset of the drawBitmapRectToRect's dest rect | |
498 static bool check_8(SkDebugCanvas* canvas, int curCommand) { | |
499 if (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->get
Type() || | |
500 canvas->getSize() <= curCommand+4 || | |
501 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1
)->getType() || | |
502 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCom
mand+2)->getType() || | |
503 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+3)
->getType()) { | |
504 return false; | |
505 } | |
506 | |
507 SkClipRectCommand* clip = | |
508 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
509 SkDrawBitmapRectCommand* dbmr = | |
510 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
511 | |
512 if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) { | |
513 return false; | |
514 } | |
515 | |
516 // The src->dest mapping needs to be 1-to-1 | |
517 if (nullptr == dbmr->srcRect()) { | |
518 if (dbmr->bitmap().width() != dbmr->dstRect().width() || | |
519 dbmr->bitmap().height() != dbmr->dstRect().height()) { | |
520 return false; | |
521 } | |
522 } else { | |
523 if (dbmr->srcRect()->width() != dbmr->dstRect().width() || | |
524 dbmr->srcRect()->height() != dbmr->dstRect().height()) { | |
525 return false; | |
526 } | |
527 } | |
528 | |
529 if (!dbmr->dstRect().contains(clip->rect())) { | |
530 return false; | |
531 } | |
532 | |
533 return true; | |
534 } | |
535 | |
536 // Fold the clipRect into the drawBitmapRectToRect's src and dest rects | |
537 static void apply_8(SkDebugCanvas* canvas, int curCommand) { | |
538 SkClipRectCommand* clip = | |
539 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
540 SkDrawBitmapRectCommand* dbmr = | |
541 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
542 | |
543 SkScalar newSrcLeft, newSrcTop; | |
544 | |
545 if (dbmr->srcRect()) { | |
546 newSrcLeft = dbmr->srcRect()->fLeft + clip->rect().fLeft - dbmr->dstRect
().fLeft; | |
547 newSrcTop = dbmr->srcRect()->fTop + clip->rect().fTop - dbmr->dstRect()
.fTop; | |
548 } else { | |
549 newSrcLeft = clip->rect().fLeft - dbmr->dstRect().fLeft; | |
550 newSrcTop = clip->rect().fTop - dbmr->dstRect().fTop; | |
551 } | |
552 | |
553 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop, | |
554 clip->rect().width(), clip->rect().height()
); | |
555 | |
556 dbmr->setSrcRect(newSrc); | |
557 dbmr->setDstRect(clip->rect()); | |
558 | |
559 // remove everything except the drawbitmaprect | |
560 canvas->deleteDrawCommandAt(curCommand+3); | |
561 canvas->deleteDrawCommandAt(curCommand+1); | |
562 canvas->deleteDrawCommandAt(curCommand); | |
563 } | |
564 | |
565 // Check for: | |
566 // SAVE | |
567 // CLIP_RECT | |
568 // DRAWBITMAPRECTTORECT | |
569 // RESTORE | |
570 // where: | |
571 // clipRect is BW and encloses the DBMR2R's dest rect | |
572 static bool check_9(SkDebugCanvas* canvas, int curCommand) { | |
573 if (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->get
Type() || | |
574 canvas->getSize() <= curCommand+4 || | |
575 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1
)->getType() || | |
576 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCom
mand+2)->getType() || | |
577 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+3)
->getType()) { | |
578 return false; | |
579 } | |
580 | |
581 SkClipRectCommand* clip = | |
582 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
583 SkDrawBitmapRectCommand* dbmr = | |
584 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
585 | |
586 if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) { | |
587 return false; | |
588 } | |
589 | |
590 if (!clip->rect().contains(dbmr->dstRect())) { | |
591 return false; | |
592 } | |
593 | |
594 return true; | |
595 } | |
596 | |
597 // remove everything except the drawbitmaprect | |
598 static void apply_9(SkDebugCanvas* canvas, int curCommand) { | |
599 canvas->deleteDrawCommandAt(curCommand+3); // restore | |
600 // drawBitmapRectToRect | |
601 canvas->deleteDrawCommandAt(curCommand+1); // clipRect | |
602 canvas->deleteDrawCommandAt(curCommand); // save | |
603 } | |
604 | |
605 typedef bool (*PFCheck)(SkDebugCanvas* canvas, int curCommand); | |
606 typedef void (*PFApply)(SkDebugCanvas* canvas, int curCommand); | |
607 | |
608 struct OptTableEntry { | |
609 PFCheck fCheck; | |
610 PFApply fApply; | |
611 int fNumTimesApplied; | |
612 } gOptTable[] = { | |
613 { check_0, apply_0, 0 }, | |
614 { check_1, apply_1, 0 }, | |
615 { check_2, apply_2, 0 }, | |
616 { check_3, apply_3, 0 }, | |
617 { check_4, apply_4, 0 }, | |
618 { check_7, apply_7, 0 }, | |
619 { check_8, apply_8, 0 }, | |
620 { check_9, apply_9, 0 }, | |
621 }; | |
622 | |
623 | |
624 static int filter_picture(const SkString& inFile, const SkString& outFile) { | |
625 SkAutoTUnref<SkPicture> inPicture; | |
626 | |
627 SkFILEStream inStream(inFile.c_str()); | |
628 if (inStream.isValid()) { | |
629 inPicture.reset(SkPicture::CreateFromStream(&inStream)); | |
630 } | |
631 | |
632 if (nullptr == inPicture.get()) { | |
633 SkDebugf("Could not read file %s\n", inFile.c_str()); | |
634 return -1; | |
635 } | |
636 | |
637 int localCount[SK_ARRAY_COUNT(gOptTable)]; | |
638 | |
639 memset(localCount, 0, sizeof(localCount)); | |
640 | |
641 SkDebugCanvas debugCanvas(SkScalarCeilToInt(inPicture->cullRect().width()), | |
642 SkScalarCeilToInt(inPicture->cullRect().height()))
; | |
643 inPicture->playback(&debugCanvas); | |
644 | |
645 // delete the initial save and restore since replaying the commands will | |
646 // re-add them | |
647 if (debugCanvas.getSize() > 1) { | |
648 debugCanvas.deleteDrawCommandAt(0); | |
649 debugCanvas.deleteDrawCommandAt(debugCanvas.getSize()-1); | |
650 } | |
651 | |
652 bool changed = true; | |
653 int numBefore = debugCanvas.getSize(); | |
654 | |
655 while (changed) { | |
656 changed = false; | |
657 for (int i = 0; i < debugCanvas.getSize(); ++i) { | |
658 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { | |
659 if ((*gOptTable[opt].fCheck)(&debugCanvas, i)) { | |
660 (*gOptTable[opt].fApply)(&debugCanvas, i); | |
661 | |
662 ++gOptTable[opt].fNumTimesApplied; | |
663 ++localCount[opt]; | |
664 | |
665 if (debugCanvas.getSize() == i) { | |
666 // the optimization removed all the remaining operations | |
667 break; | |
668 } | |
669 | |
670 opt = 0; // try all the opts all over again | |
671 changed = true; | |
672 } | |
673 } | |
674 } | |
675 } | |
676 | |
677 int numAfter = debugCanvas.getSize(); | |
678 | |
679 if (!outFile.isEmpty()) { | |
680 SkPictureRecorder recorder; | |
681 SkCanvas* canvas = recorder.beginRecording(inPicture->cullRect().width()
, | |
682 inPicture->cullRect().height(
), | |
683 nullptr, 0); | |
684 debugCanvas.draw(canvas); | |
685 SkAutoTUnref<SkPicture> outPicture(recorder.endRecording()); | |
686 | |
687 SkFILEWStream outStream(outFile.c_str()); | |
688 | |
689 outPicture->serialize(&outStream); | |
690 } | |
691 | |
692 bool someOptFired = false; | |
693 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { | |
694 if (0 != localCount[opt]) { | |
695 SkDebugf("%d: %d ", opt, localCount[opt]); | |
696 someOptFired = true; | |
697 } | |
698 } | |
699 | |
700 if (!someOptFired) { | |
701 SkDebugf("No opts fired\n"); | |
702 } else { | |
703 SkDebugf("\t before: %d after: %d delta: %d\n", | |
704 numBefore, numAfter, numBefore-numAfter); | |
705 } | |
706 | |
707 return 0; | |
708 } | |
709 | |
710 // This function is not marked as 'static' so it can be referenced externally | |
711 // in the iOS build. | |
712 int tool_main(int argc, char** argv); // suppress a warning on mac | |
713 | |
714 int tool_main(int argc, char** argv) { | |
715 SkGraphics::Init(); | |
716 | |
717 if (argc < 3) { | |
718 usage(); | |
719 return -1; | |
720 } | |
721 | |
722 SkString inFile, outFile, inDir, outDir; | |
723 | |
724 char* const* stop = argv + argc; | |
725 for (++argv; argv < stop; ++argv) { | |
726 if (strcmp(*argv, "-i") == 0) { | |
727 argv++; | |
728 if (argv < stop && **argv) { | |
729 inFile.set(*argv); | |
730 } else { | |
731 SkDebugf("missing arg for -i\n"); | |
732 usage(); | |
733 return -1; | |
734 } | |
735 } else if (strcmp(*argv, "--input-dir") == 0) { | |
736 argv++; | |
737 if (argv < stop && **argv) { | |
738 inDir.set(*argv); | |
739 } else { | |
740 SkDebugf("missing arg for --input-dir\n"); | |
741 usage(); | |
742 return -1; | |
743 } | |
744 } else if (strcmp(*argv, "--output-dir") == 0) { | |
745 argv++; | |
746 if (argv < stop && **argv) { | |
747 outDir.set(*argv); | |
748 } else { | |
749 SkDebugf("missing arg for --output-dir\n"); | |
750 usage(); | |
751 return -1; | |
752 } | |
753 } else if (strcmp(*argv, "-o") == 0) { | |
754 argv++; | |
755 if (argv < stop && **argv) { | |
756 outFile.set(*argv); | |
757 } else { | |
758 SkDebugf("missing arg for -o\n"); | |
759 usage(); | |
760 return -1; | |
761 } | |
762 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) { | |
763 usage(); | |
764 return 0; | |
765 } else { | |
766 SkDebugf("unknown arg %s\n", *argv); | |
767 usage(); | |
768 return -1; | |
769 } | |
770 } | |
771 | |
772 SkOSFile::Iter iter(inDir.c_str(), "skp"); | |
773 | |
774 SkString inputFilename, outputFilename; | |
775 if (iter.next(&inputFilename)) { | |
776 | |
777 do { | |
778 inFile = SkOSPath::Join(inDir.c_str(), inputFilename.c_str()); | |
779 if (!outDir.isEmpty()) { | |
780 outFile = SkOSPath::Join(outDir.c_str(), inputFilename.c_str()); | |
781 } | |
782 SkDebugf("Executing %s\n", inputFilename.c_str()); | |
783 filter_picture(inFile, outFile); | |
784 } while(iter.next(&inputFilename)); | |
785 | |
786 } else if (!inFile.isEmpty()) { | |
787 filter_picture(inFile, outFile); | |
788 } else { | |
789 usage(); | |
790 return -1; | |
791 } | |
792 | |
793 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { | |
794 SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied); | |
795 } | |
796 | |
797 return 0; | |
798 } | |
799 | |
800 #if !defined SK_BUILD_FOR_IOS | |
801 int main(int argc, char * const argv[]) { | |
802 return tool_main(argc, (char**) argv); | |
803 } | |
804 #endif | |
OLD | NEW |