blob: 4e88d0a5cdf0ef5b8dc2ad95cded52dcf4a5cd51 [file] [log] [blame]
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +00001/*
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
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +00008#include "SkDebugCanvas.h"
robertphillips@google.com801cee12012-10-19 19:06:11 +00009#include "SkDevice.h"
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000010#include "SkGraphics.h"
robertphillips@google.com4e4d75b2012-11-12 18:03:19 +000011#include "SkImageDecoder.h"
robertphillips@google.com801cee12012-10-19 19:06:11 +000012#include "SkImageEncoder.h"
djsollen@google.coma09e8832012-11-13 18:50:33 +000013#include "SkOSFile.h"
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000014#include "SkPicture.h"
robertphillips@google.com801cee12012-10-19 19:06:11 +000015#include "SkPicturePlayback.h"
16#include "SkPictureRecord.h"
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000017#include "SkStream.h"
djsollen@google.coma09e8832012-11-13 18:50:33 +000018#include "picture_utils.h"
robertphillips@google.comd3d377f2012-12-07 20:56:13 +000019#include "path_utils.h"
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000020
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000021static void usage() {
robertphillips@google.comd3d377f2012-12-07 20:56:13 +000022 SkDebugf("Usage: filter -i inFile [-o outFile] [--input-dir path] [--output-dir path]\n");
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +000023 SkDebugf(" [-h|--help]\n\n");
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000024 SkDebugf(" -i inFile : file to file.\n");
25 SkDebugf(" -o outFile : result of filtering.\n");
djsollen@google.coma09e8832012-11-13 18:50:33 +000026 SkDebugf(" --input-dir : process all files in dir with .skp extension.\n");
27 SkDebugf(" --output-dir : results of filtering the input dir.\n");
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000028 SkDebugf(" -h|--help : Show this help message.\n");
29}
30
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +000031// Is the supplied paint simply a color?
32static bool is_simple(const SkPaint& p) {
33 return NULL == p.getPathEffect() &&
34 NULL == p.getShader() &&
35 NULL == p.getXfermode() &&
36 NULL == p.getMaskFilter() &&
37 NULL == p.getColorFilter() &&
38 NULL == p.getRasterizer() &&
39 NULL == p.getLooper() &&
40 NULL == p.getImageFilter();
41}
robertphillips@google.comd3d377f2012-12-07 20:56:13 +000042
robertphillips@google.com73743552013-02-05 20:51:49 +000043// Check for:
44// SAVE_LAYER
45// DRAW_BITMAP_RECT_TO_RECT
46// RESTORE
47// where the saveLayer's color can be moved into the drawBitmapRect
48static bool check_0(const SkTDArray<SkDrawCommand*>& commands, int curCommand) {
49 if (SAVE_LAYER != commands[curCommand]->getType() ||
50 commands.count() <= curCommand+2 ||
51 DRAW_BITMAP_RECT_TO_RECT != commands[curCommand+1]->getType() ||
52 RESTORE != commands[curCommand+2]->getType())
53 return false;
54
55 SaveLayer* saveLayer = (SaveLayer*) commands[curCommand];
56 DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[curCommand+1];
57
58 const SkPaint* saveLayerPaint = saveLayer->paint();
59 SkPaint* dbmrPaint = dbmr->paint();
60
skia.committer@gmail.com3d18d062013-02-14 07:01:34 +000061 // For this optimization we only fold the saveLayer and drawBitmapRect
robertphillips@google.com1780a3c2013-02-13 13:27:44 +000062 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
63 // and the only difference in the colors is that the saveLayer's can have
64 // an alpha while the drawBitmapRect's is opaque.
65 // TODO: it should be possible to fold them together even if they both
66 // have different non-255 alphas but this is low priority since we have
67 // never seen that case
68 // If either operation lacks a paint then the collapse is trivial
69 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
70
robertphillips@google.com73743552013-02-05 20:51:49 +000071 return NULL == saveLayerPaint ||
72 NULL == dbmrPaint ||
robertphillips@google.com1780a3c2013-02-13 13:27:44 +000073 (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor);
robertphillips@google.com73743552013-02-05 20:51:49 +000074}
75
76// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
77// and restore
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +000078static void apply_0(SkTDArray<SkDrawCommand*>& commands, int curCommand) {
robertphillips@google.com73743552013-02-05 20:51:49 +000079 SaveLayer* saveLayer = (SaveLayer*) commands[curCommand];
80 DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[curCommand+1];
81 Restore* restore = (Restore*) commands[curCommand+2];
82
83 const SkPaint* saveLayerPaint = saveLayer->paint();
84 SkPaint* dbmrPaint = dbmr->paint();
85
86 if (NULL == saveLayerPaint) {
87 saveLayer->setVisible(false);
88 restore->setVisible(false);
89 } else if (NULL == dbmrPaint) {
90 saveLayer->setVisible(false);
91 dbmr->setPaint(*saveLayerPaint);
92 restore->setVisible(false);
93 } else {
94 saveLayer->setVisible(false);
95 SkColor newColor = SkColorSetA(dbmrPaint->getColor(),
96 SkColorGetA(saveLayerPaint->getColor()));
97 dbmrPaint->setColor(newColor);
98 restore->setVisible(false);
99 }
100}
101
102// Check for:
103// SAVE_LAYER
104// SAVE
105// CLIP_RECT
106// DRAW_BITMAP_RECT_TO_RECT
107// RESTORE
108// RESTORE
109// where the saveLayer's color can be moved into the drawBitmapRect
110static bool check_1(const SkTDArray<SkDrawCommand*>& commands, int curCommand) {
111 if (SAVE_LAYER != commands[curCommand]->getType() ||
112 commands.count() <= curCommand+5 ||
113 SAVE != commands[curCommand+1]->getType() ||
114 CLIP_RECT != commands[curCommand+2]->getType() ||
115 DRAW_BITMAP_RECT_TO_RECT != commands[curCommand+3]->getType() ||
116 RESTORE != commands[curCommand+4]->getType() ||
117 RESTORE != commands[curCommand+5]->getType())
118 return false;
119
120 SaveLayer* saveLayer = (SaveLayer*) commands[curCommand];
121 DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[curCommand+3];
122
123 const SkPaint* saveLayerPaint = saveLayer->paint();
124 SkPaint* dbmrPaint = dbmr->paint();
125
skia.committer@gmail.com3d18d062013-02-14 07:01:34 +0000126 // For this optimization we only fold the saveLayer and drawBitmapRect
robertphillips@google.com1780a3c2013-02-13 13:27:44 +0000127 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
128 // and the only difference in the colors is that the saveLayer's can have
129 // an alpha while the drawBitmapRect's is opaque.
130 // TODO: it should be possible to fold them together even if they both
131 // have different non-255 alphas but this is low priority since we have
132 // never seen that case
133 // If either operation lacks a paint then the collapse is trivial
134 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
135
robertphillips@google.com73743552013-02-05 20:51:49 +0000136 return NULL == saveLayerPaint ||
137 NULL == dbmrPaint ||
robertphillips@google.com1780a3c2013-02-13 13:27:44 +0000138 (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor);
robertphillips@google.com73743552013-02-05 20:51:49 +0000139}
140
141// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
142// and restore
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000143static void apply_1(SkTDArray<SkDrawCommand*>& commands, int curCommand) {
robertphillips@google.com73743552013-02-05 20:51:49 +0000144 SaveLayer* saveLayer = (SaveLayer*) commands[curCommand];
145 DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[curCommand+3];
146 Restore* restore = (Restore*) commands[curCommand+5];
147
148 const SkPaint* saveLayerPaint = saveLayer->paint();
149 SkPaint* dbmrPaint = dbmr->paint();
150
151 if (NULL == saveLayerPaint) {
152 saveLayer->setVisible(false);
153 restore->setVisible(false);
154 } else if (NULL == dbmrPaint) {
155 saveLayer->setVisible(false);
156 dbmr->setPaint(*saveLayerPaint);
157 restore->setVisible(false);
158 } else {
159 saveLayer->setVisible(false);
160 SkColor newColor = SkColorSetA(dbmrPaint->getColor(),
161 SkColorGetA(saveLayerPaint->getColor()));
162 dbmrPaint->setColor(newColor);
163 restore->setVisible(false);
164 }
165}
166
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000167// Check for:
168// SAVE
169// CLIP_RECT
170// DRAW_RECT
171// RESTORE
172// where the rect is entirely within the clip and the clip is an intersect
173static bool check_2(const SkTDArray<SkDrawCommand*>& commands, int curCommand) {
174 if (SAVE != commands[curCommand]->getType() ||
175 commands.count() <= curCommand+4 ||
176 CLIP_RECT != commands[curCommand+1]->getType() ||
177 DRAW_RECT != commands[curCommand+2]->getType() ||
178 RESTORE != commands[curCommand+3]->getType())
179 return false;
180
181 ClipRect* cr = (ClipRect*) commands[curCommand+1];
182 DrawRectC* dr = (DrawRectC*) commands[curCommand+2];
183
184 if (SkRegion::kIntersect_Op != cr->op()) {
185 return false;
186 }
187
188 return cr->rect().contains(dr->rect());
189}
190
191// Remove everything but the drawRect
192static void apply_2(SkTDArray<SkDrawCommand*>& commands, int curCommand) {
193 Save* save = (Save*) commands[curCommand];
194 ClipRect* cr = (ClipRect*) commands[curCommand+1];
195 Restore* restore = (Restore*) commands[curCommand+3];
196
197 save->setVisible(false);
198 cr->setVisible(false);
199 // leave the drawRect alone
200 restore->setVisible(false);
201}
202
203// Check for:
204// SAVE
205// CLIP_RRECT
206// DRAW_RECT
207// RESTORE
208// where the rect entirely encloses the clip
209static bool check_3(const SkTDArray<SkDrawCommand*>& commands, int curCommand) {
210 if (SAVE != commands[curCommand]->getType() ||
211 commands.count() <= curCommand+4 ||
212 CLIP_RRECT != commands[curCommand+1]->getType() ||
213 DRAW_RECT != commands[curCommand+2]->getType() ||
214 RESTORE != commands[curCommand+3]->getType())
215 return false;
216
217 ClipRRect* crr = (ClipRRect*) commands[curCommand+1];
218 DrawRectC* dr = (DrawRectC*) commands[curCommand+2];
219
220 if (SkRegion::kIntersect_Op != crr->op()) {
221 return false;
222 }
223
224 return dr->rect().contains(crr->rrect().rect());
225}
226
227// Replace everything with a drawRRect with the paint from the drawRect
228// and the AA settings from the clipRRect
229static void apply_3(SkTDArray<SkDrawCommand*>& commands, int curCommand) {
230 Save* save = (Save*) commands[curCommand];
231 ClipRRect* crr = (ClipRRect*) commands[curCommand+1];
232 DrawRectC* dr = (DrawRectC*) commands[curCommand+2];
233 Restore* restore = (Restore*) commands[curCommand+3];
234
235 save->setVisible(false);
236 crr->setVisible(false);
237 dr->setVisible(false);
238 restore->setVisible(false);
239
240 // TODO: could skip paint re-creation if the AA settings already match
robertphillips@google.com91217d02013-03-17 18:33:46 +0000241 SkPaint newPaint = dr->paint();
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000242 newPaint.setAntiAlias(crr->doAA());
243 DrawRRect* drr = new DrawRRect(crr->rrect(), newPaint);
244 commands[curCommand+2] = drr;
245}
246
247// Check for:
248// SAVE
249// CLIP_RECT
250// DRAW_BITMAP_RECT_TO_RECT
251// RESTORE
252// where the rect and drawBitmapRect dst exactly match
253static bool check_4(const SkTDArray<SkDrawCommand*>& commands, int curCommand) {
254 if (SAVE != commands[curCommand]->getType() ||
255 commands.count() <= curCommand+4 ||
256 CLIP_RECT != commands[curCommand+1]->getType() ||
257 DRAW_BITMAP_RECT_TO_RECT != commands[curCommand+2]->getType() ||
258 RESTORE != commands[curCommand+3]->getType())
259 return false;
260
261 ClipRect* cr = (ClipRect*) commands[curCommand+1];
262 DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[curCommand+2];
263
264 if (SkRegion::kIntersect_Op != cr->op()) {
265 return false;
266 }
267
268 return dbmr->dstRect() == cr->rect();
269}
270
271// Remove everything but the drawBitmapRect
272static void apply_4(SkTDArray<SkDrawCommand*>& commands, int curCommand) {
273 Save* save = (Save*) commands[curCommand];
274 ClipRect* cr = (ClipRect*) commands[curCommand+1];
275 Restore* restore = (Restore*) commands[curCommand+3];
276
277 save->setVisible(false);
278 cr->setVisible(false);
279 // leave drawBitmapRect alone
280 restore->setVisible(false);
281}
282
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000283// Check for:
284// TRANSLATE
285// where the translate is zero
286static bool check_5(const SkTDArray<SkDrawCommand*>& commands, int curCommand) {
287 if (TRANSLATE != commands[curCommand]->getType()) {
288 return false;
289 }
290
291 Translate* t = (Translate*) commands[curCommand];
292
293 return 0 == t->x() && 0 == t->y();
294}
295
296// Just remove the translate
297static void apply_5(SkTDArray<SkDrawCommand*>& commands, int curCommand) {
298 Translate* t = (Translate*) commands[curCommand];
299
300 t->setVisible(false);
301}
302
303// Check for:
304// SCALE
305// where the scale is 1,1
306static bool check_6(const SkTDArray<SkDrawCommand*>& commands, int curCommand) {
307 if (SCALE != commands[curCommand]->getType()) {
308 return false;
309 }
310
311 Scale* s = (Scale*) commands[curCommand];
312
313 return SK_Scalar1 == s->x() && SK_Scalar1 == s->y();
314}
315
316// Just remove the scale
317static void apply_6(SkTDArray<SkDrawCommand*>& commands, int curCommand) {
318 Scale* s = (Scale*) commands[curCommand];
319
320 s->setVisible(false);
321}
322
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000323// Check for:
324// SAVE
325// CLIP_RECT
326// SAVE_LAYER
327// SAVE
328// CLIP_RECT
329// SAVE_LAYER
330// SAVE
331// CLIP_RECT
332// DRAWBITMAPRECTTORECT
333// RESTORE
334// RESTORE
335// RESTORE
336// RESTORE
337// RESTORE
338// where:
339// all the clipRect's are BW, nested, intersections
340// the drawBitmapRectToRect is a 1-1 copy from src to dest
341// the last (smallest) clip rect is a subset of the drawBitmapRectToRect's dest rect
342// all the saveLayer's paints can be rolled into the drawBitmapRectToRect's paint
343// This pattern is used by Google spreadsheet when drawing the toolbar buttons
344static bool check_7(const SkTDArray<SkDrawCommand*>& commands, int curCommand) {
345 if (SAVE != commands[curCommand]->getType() ||
346 commands.count() <= curCommand+13 ||
347 CLIP_RECT != commands[curCommand+1]->getType() ||
348 SAVE_LAYER != commands[curCommand+2]->getType() ||
349 SAVE != commands[curCommand+3]->getType() ||
350 CLIP_RECT != commands[curCommand+4]->getType() ||
351 SAVE_LAYER != commands[curCommand+5]->getType() ||
352 SAVE != commands[curCommand+6]->getType() ||
353 CLIP_RECT != commands[curCommand+7]->getType() ||
354 DRAW_BITMAP_RECT_TO_RECT != commands[curCommand+8]->getType() ||
355 RESTORE != commands[curCommand+9]->getType() ||
356 RESTORE != commands[curCommand+10]->getType() ||
357 RESTORE != commands[curCommand+11]->getType() ||
358 RESTORE != commands[curCommand+12]->getType() ||
359 RESTORE != commands[curCommand+13]->getType())
360 return false;
361
362 ClipRect* clip0 = (ClipRect*) commands[curCommand+1];
363 SaveLayer* saveLayer0 = (SaveLayer*) commands[curCommand+2];
364 ClipRect* clip1 = (ClipRect*) commands[curCommand+4];
365 SaveLayer* saveLayer1 = (SaveLayer*) commands[curCommand+5];
366 ClipRect* clip2 = (ClipRect*) commands[curCommand+7];
367 DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[curCommand+8];
368
369 if (clip0->doAA() || clip1->doAA() || clip2->doAA()) {
370 return false;
371 }
372
373 if (SkRegion::kIntersect_Op != clip0->op() ||
374 SkRegion::kIntersect_Op != clip1->op() ||
375 SkRegion::kIntersect_Op != clip2->op()) {
376 return false;
377 }
378
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000379 if (!clip0->rect().contains(clip1->rect()) ||
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000380 !clip1->rect().contains(clip2->rect())) {
381 return false;
382 }
383
384 // The src->dest mapping needs to be 1-to-1
385 if (NULL == dbmr->srcRect()) {
386 if (dbmr->bitmap().width() != dbmr->dstRect().width() ||
387 dbmr->bitmap().height() != dbmr->dstRect().height()) {
388 return false;
389 }
390 } else {
391 if (dbmr->srcRect()->width() != dbmr->dstRect().width() ||
392 dbmr->srcRect()->height() != dbmr->dstRect().height()) {
393 return false;
394 }
395 }
396
397 if (!dbmr->dstRect().contains(clip2->rect())) {
398 return false;
399 }
400
401 const SkPaint* saveLayerPaint0 = saveLayer0->paint();
402 const SkPaint* saveLayerPaint1 = saveLayer1->paint();
403
404 if ((NULL != saveLayerPaint0 && !is_simple(*saveLayerPaint0)) ||
405 (NULL != saveLayerPaint1 && !is_simple(*saveLayerPaint1))) {
406 return false;
407 }
408
409 SkPaint* dbmrPaint = dbmr->paint();
410
411 if (NULL == dbmrPaint) {
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000412 return true;
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000413 }
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000414
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000415 if (NULL != saveLayerPaint0) {
416 SkColor layerColor0 = saveLayerPaint0->getColor() | 0xFF000000; // force opaque
417 if (dbmrPaint->getColor() != layerColor0) {
418 return false;
419 }
420 }
421
422 if (NULL != saveLayerPaint1) {
423 SkColor layerColor1 = saveLayerPaint1->getColor() | 0xFF000000; // force opaque
424 if (dbmrPaint->getColor() != layerColor1) {
425 return false;
426 }
427 }
428
429 return true;
430}
431
432// Reduce to a single drawBitmapRectToRect call by folding the clipRect's into
433// the src and dst Rects and the saveLayer paints into the drawBitmapRectToRect's
434// paint.
435static void apply_7(SkTDArray<SkDrawCommand*>& commands, int curCommand) {
436 Save* save0 = (Save*) commands[curCommand];
437 ClipRect* clip0 = (ClipRect*) commands[curCommand+1];
438 SaveLayer* saveLayer0 = (SaveLayer*) commands[curCommand+2];
439 Save* save1 = (Save*) commands[curCommand+3];
440 ClipRect* clip1 = (ClipRect*) commands[curCommand+4];
441 SaveLayer* saveLayer1 = (SaveLayer*) commands[curCommand+5];
442 Save* save2 = (Save*) commands[curCommand+6];
443 ClipRect* clip2 = (ClipRect*) commands[curCommand+7];
444 DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[curCommand+8];
445 Restore* restore0 = (Restore*) commands[curCommand+9];
446 Restore* restore1 = (Restore*) commands[curCommand+10];
447 Restore* restore2 = (Restore*) commands[curCommand+11];
448 Restore* restore3 = (Restore*) commands[curCommand+12];
449 Restore* restore4 = (Restore*) commands[curCommand+13];
450
451 SkScalar newSrcLeft = dbmr->srcRect()->fLeft + clip2->rect().fLeft - dbmr->dstRect().fLeft;
452 SkScalar newSrcTop = dbmr->srcRect()->fTop + clip2->rect().fTop - dbmr->dstRect().fTop;
453
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000454 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop,
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000455 clip2->rect().width(), clip2->rect().height());
456
457 dbmr->setSrcRect(newSrc);
458 dbmr->setDstRect(clip2->rect());
459
460 SkColor color = 0xFF000000;
461 int a0, a1;
462
463 const SkPaint* saveLayerPaint0 = saveLayer0->paint();
464 if (NULL != saveLayerPaint0) {
465 color = saveLayerPaint0->getColor();
466 a0 = SkColorGetA(color);
467 } else {
468 a0 = 0xFF;
469 }
470
471 const SkPaint* saveLayerPaint1 = saveLayer1->paint();
472 if (NULL != saveLayerPaint1) {
473 color = saveLayerPaint1->getColor();
474 a1 = SkColorGetA(color);
475 } else {
476 a1 = 0xFF;
477 }
478
479 int newA = (a0 * a1) / 255;
480 SkASSERT(newA <= 0xFF);
481
482 SkPaint* dbmrPaint = dbmr->paint();
483
484 if (NULL != dbmrPaint) {
485 SkColor newColor = SkColorSetA(dbmrPaint->getColor(), newA);
486 dbmrPaint->setColor(newColor);
487 } else {
488 SkColor newColor = SkColorSetA(color, newA);
489
490 SkPaint newPaint;
491 newPaint.setColor(newColor);
492 dbmr->setPaint(newPaint);
493 }
494
495 // remove everything except the drawbitmaprect
496 save0->setVisible(false);
497 clip0->setVisible(false);
498 saveLayer0->setVisible(false);
499 save1->setVisible(false);
500 clip1->setVisible(false);
501 saveLayer1->setVisible(false);
502 save2->setVisible(false);
503 clip2->setVisible(false);
504 restore0->setVisible(false);
505 restore1->setVisible(false);
506 restore2->setVisible(false);
507 restore3->setVisible(false);
508 restore4->setVisible(false);
509}
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000510
robertphillips@google.com73743552013-02-05 20:51:49 +0000511typedef bool (*PFCheck)(const SkTDArray<SkDrawCommand*>& commands, int curCommand);
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000512typedef void (*PFApply)(SkTDArray<SkDrawCommand*>& commands, int curCommand);
robertphillips@google.com73743552013-02-05 20:51:49 +0000513
514struct OptTableEntry {
515 PFCheck fCheck;
516 PFApply fApply;
517 int fNumTimesApplied;
518} gOptTable[] = {
519 { check_0, apply_0, 0 },
520 { check_1, apply_1, 0 },
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000521 { check_2, apply_2, 0 },
522 { check_3, apply_3, 0 },
523 { check_4, apply_4, 0 },
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000524 { check_5, apply_5, 0 },
525 { check_6, apply_6, 0 },
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000526 { check_7, apply_7, 0 },
robertphillips@google.com73743552013-02-05 20:51:49 +0000527};
528
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000529static int filter_picture(const SkString& inFile, const SkString& outFile) {
djsollen@google.coma09e8832012-11-13 18:50:33 +0000530 SkPicture* inPicture = NULL;
531
532 SkFILEStream inStream(inFile.c_str());
533 if (inStream.isValid()) {
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000534 inPicture = SkNEW_ARGS(SkPicture, (&inStream, NULL, &SkImageDecoder::DecodeMemory));
djsollen@google.coma09e8832012-11-13 18:50:33 +0000535 }
536
537 if (NULL == inPicture) {
538 SkDebugf("Could not read file %s\n", inFile.c_str());
539 return -1;
540 }
541
robertphillips@google.com73743552013-02-05 20:51:49 +0000542 int localCount[SK_ARRAY_COUNT(gOptTable)];
543
544 memset(localCount, 0, sizeof(localCount));
545
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000546 SkDebugCanvas debugCanvas(inPicture->width(), inPicture->height());
547 debugCanvas.setBounds(inPicture->width(), inPicture->height());
548 inPicture->draw(&debugCanvas);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000549
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000550 SkTDArray<SkDrawCommand*>& commands = debugCanvas.getDrawCommands();
djsollen@google.coma09e8832012-11-13 18:50:33 +0000551
skia.committer@gmail.comae683922013-02-06 07:01:54 +0000552 // hide the initial save and restore since replaying the commands will
robertphillips@google.com73743552013-02-05 20:51:49 +0000553 // re-add them
554 if (commands.count() > 0) {
555 commands[0]->setVisible(false);
556 commands[commands.count()-1]->setVisible(false);
557 }
558
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000559 for (int i = 0; i < commands.count(); ++i) {
robertphillips@google.com73743552013-02-05 20:51:49 +0000560 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
561 if ((*gOptTable[opt].fCheck)(commands, i)) {
562 (*gOptTable[opt].fApply)(commands, i);
563 ++gOptTable[opt].fNumTimesApplied;
564 ++localCount[opt];
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000565 }
566 }
567 }
djsollen@google.coma09e8832012-11-13 18:50:33 +0000568
569 if (!outFile.isEmpty()) {
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000570 SkPicture outPicture;
571
572 SkCanvas* canvas = outPicture.beginRecording(inPicture->width(), inPicture->height());
573 debugCanvas.draw(canvas);
574 outPicture.endRecording();
575
djsollen@google.coma09e8832012-11-13 18:50:33 +0000576 SkFILEWStream outStream(outFile.c_str());
577
578 outPicture.serialize(&outStream);
579 }
580
robertphillips@google.com73743552013-02-05 20:51:49 +0000581 bool someOptFired = false;
582 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
583 if (0 != localCount[opt]) {
584 SkDebugf("%d: %d ", opt, localCount[opt]);
585 someOptFired = true;
586 }
587 }
588
589 if (!someOptFired) {
590 SkDebugf("No opts fired\n");
591 } else {
592 SkDebugf("\n");
593 }
594
djsollen@google.coma09e8832012-11-13 18:50:33 +0000595 return 0;
596}
597
tfarina@chromium.orga5b7cc02012-10-08 14:41:10 +0000598// This function is not marked as 'static' so it can be referenced externally
599// in the iOS build.
humper@google.com05af1af2013-01-07 16:47:43 +0000600int tool_main(int argc, char** argv); // suppress a warning on mac
601
caryclark@google.com9598f422012-10-09 12:32:37 +0000602int tool_main(int argc, char** argv) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000603 SkGraphics::Init();
604
robertphillips@google.com801cee12012-10-19 19:06:11 +0000605 if (argc < 3) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000606 usage();
607 return -1;
608 }
609
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000610 SkString inFile, outFile, inDir, outDir;
robertphillips@google.com801cee12012-10-19 19:06:11 +0000611
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000612 char* const* stop = argv + argc;
613 for (++argv; argv < stop; ++argv) {
614 if (strcmp(*argv, "-i") == 0) {
615 argv++;
616 if (argv < stop && **argv) {
617 inFile.set(*argv);
618 } else {
robertphillips@google.com801cee12012-10-19 19:06:11 +0000619 SkDebugf("missing arg for -i\n");
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000620 usage();
621 return -1;
622 }
djsollen@google.coma09e8832012-11-13 18:50:33 +0000623 } else if (strcmp(*argv, "--input-dir") == 0) {
624 argv++;
625 if (argv < stop && **argv) {
626 inDir.set(*argv);
627 } else {
628 SkDebugf("missing arg for --input-dir\n");
629 usage();
630 return -1;
631 }
632 } else if (strcmp(*argv, "--output-dir") == 0) {
633 argv++;
634 if (argv < stop && **argv) {
635 outDir.set(*argv);
636 } else {
637 SkDebugf("missing arg for --output-dir\n");
638 usage();
639 return -1;
640 }
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000641 } else if (strcmp(*argv, "-o") == 0) {
642 argv++;
643 if (argv < stop && **argv) {
644 outFile.set(*argv);
645 } else {
robertphillips@google.com801cee12012-10-19 19:06:11 +0000646 SkDebugf("missing arg for -o\n");
647 usage();
648 return -1;
649 }
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000650 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) {
651 usage();
652 return 0;
653 } else {
654 SkDebugf("unknown arg %s\n", *argv);
655 usage();
656 return -1;
657 }
658 }
659
djsollen@google.coma09e8832012-11-13 18:50:33 +0000660 SkOSFile::Iter iter(inDir.c_str(), "skp");
humper@google.com05af1af2013-01-07 16:47:43 +0000661
djsollen@google.coma09e8832012-11-13 18:50:33 +0000662 SkString inputFilename, outputFilename;
663 if (iter.next(&inputFilename)) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000664
djsollen@google.coma09e8832012-11-13 18:50:33 +0000665 do {
666 sk_tools::make_filepath(&inFile, inDir, inputFilename);
667 if (!outDir.isEmpty()) {
668 sk_tools::make_filepath(&outFile, outDir, inputFilename);
669 }
670 SkDebugf("Executing %s\n", inputFilename.c_str());
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000671 filter_picture(inFile, outFile);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000672 } while(iter.next(&inputFilename));
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000673
djsollen@google.coma09e8832012-11-13 18:50:33 +0000674 } else if (!inFile.isEmpty()) {
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000675 filter_picture(inFile, outFile);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000676 } else {
677 usage();
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000678 return -1;
679 }
680
robertphillips@google.com73743552013-02-05 20:51:49 +0000681 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
682 SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied);
683 }
684
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000685 SkGraphics::Term();
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000686 return 0;
687}
688
689#if !defined SK_BUILD_FOR_IOS
690int main(int argc, char * const argv[]) {
caryclark@google.com9598f422012-10-09 12:32:37 +0000691 return tool_main(argc, (char**) argv);
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000692}
693#endif