2 * Copyright 2012 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 "SkDebugCanvas.h"
10 #include "SkForceLinking.h"
11 #include "SkGraphics.h"
12 #include "SkImageDecoder.h"
13 #include "SkImageEncoder.h"
15 #include "SkPicture.h"
16 #include "SkPictureRecord.h"
17 #include "SkPictureRecorder.h"
19 #include "picture_utils.h"
21 __SK_FORCE_IMAGE_DECODER_LINKING;
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");
33 // Is the supplied paint simply a color?
34 static bool is_simple(const SkPaint& p) {
35 return NULL == p.getPathEffect() &&
36 NULL == p.getShader() &&
37 NULL == p.getXfermode() &&
38 NULL == p.getMaskFilter() &&
39 NULL == p.getColorFilter() &&
40 NULL == p.getRasterizer() &&
41 NULL == p.getLooper() &&
42 NULL == p.getImageFilter();
48 // DRAW_BITMAP_RECT_TO_RECT
50 // where the saveLayer's color can be moved into the drawBitmapRect
51 static bool check_0(SkDebugCanvas* canvas, int curCommand) {
52 if (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() ||
53 canvas->getSize() <= curCommand+2 ||
54 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
55 RESTORE != canvas->getDrawCommandAt(curCommand+2)->getType()) {
59 SkSaveLayerCommand* saveLayer =
60 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand);
61 SkDrawBitmapRectCommand* dbmr =
62 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1);
64 const SkPaint* saveLayerPaint = saveLayer->paint();
65 SkPaint* dbmrPaint = dbmr->paint();
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 opaque
71 SkColor dbmrColor = dbmrPaint->getColor() | 0xFF000000; // force opaque
73 // If either operation lacks a paint then the collapse is trivial
74 return NULL == saveLayerPaint ||
76 (is_simple(*saveLayerPaint) && dbmrColor == layerColor);
79 // Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
81 static void apply_0(SkDebugCanvas* canvas, int curCommand) {
82 SkSaveLayerCommand* saveLayer =
83 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand);
84 const SkPaint* saveLayerPaint = saveLayer->paint();
86 // if (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed
88 SkDrawBitmapRectCommand* dbmr =
89 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1);
90 SkPaint* dbmrPaint = dbmr->paint();
92 if (NULL == 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);
100 color = dbmrPaint->getColor();
101 int a1 = SkColorGetA(color);
103 int newA = SkMulDiv255Round(a0, a1);
104 SkASSERT(newA <= 0xFF);
106 SkColor newColor = SkColorSetA(color, newA);
107 dbmrPaint->setColor(newColor);
111 canvas->deleteDrawCommandAt(curCommand+2); // restore
112 canvas->deleteDrawCommandAt(curCommand); // saveLayer
119 // DRAW_BITMAP_RECT_TO_RECT
122 // where the saveLayer's color can be moved into the drawBitmapRect
123 static bool check_1(SkDebugCanvas* canvas, int curCommand) {
124 if (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() ||
125 canvas->getSize() <= curCommand+5 ||
126 SAVE != canvas->getDrawCommandAt(curCommand+1)->getType() ||
127 CLIP_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
128 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+3)->getType() ||
129 RESTORE != canvas->getDrawCommandAt(curCommand+4)->getType() ||
130 RESTORE != canvas->getDrawCommandAt(curCommand+5)->getType()) {
134 SkSaveLayerCommand* saveLayer =
135 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand);
136 SkDrawBitmapRectCommand* dbmr =
137 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+3);
139 const SkPaint* saveLayerPaint = saveLayer->paint();
140 SkPaint* dbmrPaint = dbmr->paint();
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 opaque
152 return NULL == saveLayerPaint ||
154 (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor);
157 // Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
159 static void apply_1(SkDebugCanvas* canvas, int curCommand) {
160 SkSaveLayerCommand* saveLayer =
161 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand);
162 const SkPaint* saveLayerPaint = saveLayer->paint();
164 // if (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed
165 if (saveLayerPaint) {
166 SkDrawBitmapRectCommand* dbmr =
167 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+3);
168 SkPaint* dbmrPaint = dbmr->paint();
170 if (NULL == dbmrPaint) {
171 dbmr->setPaint(*saveLayerPaint);
173 SkColor newColor = SkColorSetA(dbmrPaint->getColor(),
174 SkColorGetA(saveLayerPaint->getColor()));
175 dbmrPaint->setColor(newColor);
179 canvas->deleteDrawCommandAt(curCommand+5); // restore
180 canvas->deleteDrawCommandAt(curCommand); // saveLayer
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 (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
191 canvas->getSize() <= curCommand+4 ||
192 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
193 DRAW_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
194 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
198 SkClipRectCommand* cr =
199 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1);
200 SkDrawRectCommand* dr =
201 (SkDrawRectCommand*) canvas->getDrawCommandAt(curCommand+2);
203 if (SkRegion::kIntersect_Op != cr->op()) {
207 return cr->rect().contains(dr->rect());
210 // Remove everything but the drawRect
211 static void apply_2(SkDebugCanvas* canvas, int curCommand) {
212 canvas->deleteDrawCommandAt(curCommand+3); // restore
214 canvas->deleteDrawCommandAt(curCommand+1); // clipRect
215 canvas->deleteDrawCommandAt(curCommand); // save
223 // where the rect entirely encloses the clip
224 static bool check_3(SkDebugCanvas* canvas, int curCommand) {
225 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
226 canvas->getSize() <= curCommand+4 ||
227 CLIP_RRECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
228 DRAW_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
229 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
233 SkClipRRectCommand* crr =
234 (SkClipRRectCommand*) canvas->getDrawCommandAt(curCommand+1);
235 SkDrawRectCommand* dr =
236 (SkDrawRectCommand*) canvas->getDrawCommandAt(curCommand+2);
238 if (SkRegion::kIntersect_Op != crr->op()) {
242 return dr->rect().contains(crr->rrect().rect());
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) {
249 canvas->deleteDrawCommandAt(curCommand+3); // restore
251 SkClipRRectCommand* crr =
252 (SkClipRRectCommand*) canvas->getDrawCommandAt(curCommand+1);
253 SkDrawRectCommand* dr =
254 (SkDrawRectCommand*) canvas->getDrawCommandAt(curCommand+2);
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);
262 canvas->deleteDrawCommandAt(curCommand+1); // clipRRect
263 canvas->deleteDrawCommandAt(curCommand); // save
269 // DRAW_BITMAP_RECT_TO_RECT
271 // where the rect and drawBitmapRect dst exactly match
272 static bool check_4(SkDebugCanvas* canvas, int curCommand) {
273 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
274 canvas->getSize() <= curCommand+4 ||
275 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
276 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
277 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
281 SkClipRectCommand* cr =
282 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1);
283 SkDrawBitmapRectCommand* dbmr =
284 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2);
286 if (SkRegion::kIntersect_Op != cr->op()) {
290 return dbmr->dstRect() == cr->rect();
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
303 // where the translate is zero
304 static bool check_5(SkDebugCanvas* canvas, int curCommand) {
305 if (TRANSLATE != canvas->getDrawCommandAt(curCommand)->getType()) {
309 SkTranslateCommand* t =
310 (SkTranslateCommand*) canvas->getDrawCommandAt(curCommand);
312 return 0 == t->x() && 0 == t->y();
315 // Just remove the translate
316 static void apply_5(SkDebugCanvas* canvas, int curCommand) {
317 canvas->deleteDrawCommandAt(curCommand); // translate
322 // where the scale is 1,1
323 static bool check_6(SkDebugCanvas* canvas, int curCommand) {
324 if (SCALE != canvas->getDrawCommandAt(curCommand)->getType()) {
328 SkScaleCommand* s = (SkScaleCommand*) canvas->getDrawCommandAt(curCommand);
330 return SK_Scalar1 == s->x() && SK_Scalar1 == s->y();
333 // Just remove the scale
334 static void apply_6(SkDebugCanvas* canvas, int curCommand) {
335 canvas->deleteDrawCommandAt(curCommand); // scale
347 // DRAWBITMAPRECTTORECT
354 // all the clipRect's are BW, nested, intersections
355 // the drawBitmapRectToRect is a 1-1 copy from src to dest
356 // the last (smallest) clip rect is a subset of the drawBitmapRectToRect's dest rect
357 // all the saveLayer's paints can be rolled into the drawBitmapRectToRect's paint
358 // This pattern is used by Google spreadsheet when drawing the toolbar buttons
359 static bool check_7(SkDebugCanvas* canvas, int curCommand) {
360 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
361 canvas->getSize() <= curCommand+13 ||
362 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
363 SAVE_LAYER != canvas->getDrawCommandAt(curCommand+2)->getType() ||
364 SAVE != canvas->getDrawCommandAt(curCommand+3)->getType() ||
365 CLIP_RECT != canvas->getDrawCommandAt(curCommand+4)->getType() ||
366 SAVE_LAYER != canvas->getDrawCommandAt(curCommand+5)->getType() ||
367 SAVE != canvas->getDrawCommandAt(curCommand+6)->getType() ||
368 CLIP_RECT != canvas->getDrawCommandAt(curCommand+7)->getType() ||
369 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+8)->getType() ||
370 RESTORE != canvas->getDrawCommandAt(curCommand+9)->getType() ||
371 RESTORE != canvas->getDrawCommandAt(curCommand+10)->getType() ||
372 RESTORE != canvas->getDrawCommandAt(curCommand+11)->getType() ||
373 RESTORE != canvas->getDrawCommandAt(curCommand+12)->getType() ||
374 RESTORE != canvas->getDrawCommandAt(curCommand+13)->getType()) {
378 SkClipRectCommand* clip0 =
379 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1);
380 SkSaveLayerCommand* saveLayer0 =
381 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+2);
382 SkClipRectCommand* clip1 =
383 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+4);
384 SkSaveLayerCommand* saveLayer1 =
385 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+5);
386 SkClipRectCommand* clip2 =
387 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+7);
388 SkDrawBitmapRectCommand* dbmr =
389 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+8);
391 if (clip0->doAA() || clip1->doAA() || clip2->doAA()) {
395 if (SkRegion::kIntersect_Op != clip0->op() ||
396 SkRegion::kIntersect_Op != clip1->op() ||
397 SkRegion::kIntersect_Op != clip2->op()) {
401 if (!clip0->rect().contains(clip1->rect()) ||
402 !clip1->rect().contains(clip2->rect())) {
406 // The src->dest mapping needs to be 1-to-1
407 if (NULL == dbmr->srcRect()) {
408 if (dbmr->bitmap().width() != dbmr->dstRect().width() ||
409 dbmr->bitmap().height() != dbmr->dstRect().height()) {
413 if (dbmr->srcRect()->width() != dbmr->dstRect().width() ||
414 dbmr->srcRect()->height() != dbmr->dstRect().height()) {
419 if (!dbmr->dstRect().contains(clip2->rect())) {
423 const SkPaint* saveLayerPaint0 = saveLayer0->paint();
424 const SkPaint* saveLayerPaint1 = saveLayer1->paint();
426 if ((saveLayerPaint0 && !is_simple(*saveLayerPaint0)) ||
427 (saveLayerPaint1 && !is_simple(*saveLayerPaint1))) {
431 SkPaint* dbmrPaint = dbmr->paint();
433 if (NULL == dbmrPaint) {
437 if (saveLayerPaint0) {
438 SkColor layerColor0 = saveLayerPaint0->getColor() | 0xFF000000; // force opaque
439 if (dbmrPaint->getColor() != layerColor0) {
444 if (saveLayerPaint1) {
445 SkColor layerColor1 = saveLayerPaint1->getColor() | 0xFF000000; // force opaque
446 if (dbmrPaint->getColor() != layerColor1) {
454 // Reduce to a single drawBitmapRectToRect call by folding the clipRect's into
455 // the src and dst Rects and the saveLayer paints into the drawBitmapRectToRect's
457 static void apply_7(SkDebugCanvas* canvas, int curCommand) {
458 SkSaveLayerCommand* saveLayer0 =
459 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+2);
460 SkSaveLayerCommand* saveLayer1 =
461 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+5);
462 SkClipRectCommand* clip2 =
463 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+7);
464 SkDrawBitmapRectCommand* dbmr =
465 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+8);
467 SkScalar newSrcLeft = dbmr->srcRect()->fLeft + clip2->rect().fLeft - dbmr->dstRect().fLeft;
468 SkScalar newSrcTop = dbmr->srcRect()->fTop + clip2->rect().fTop - dbmr->dstRect().fTop;
470 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop,
471 clip2->rect().width(), clip2->rect().height());
473 dbmr->setSrcRect(newSrc);
474 dbmr->setDstRect(clip2->rect());
476 SkColor color = 0xFF000000;
479 const SkPaint* saveLayerPaint0 = saveLayer0->paint();
480 if (saveLayerPaint0) {
481 color = saveLayerPaint0->getColor();
482 a0 = SkColorGetA(color);
487 const SkPaint* saveLayerPaint1 = saveLayer1->paint();
488 if (saveLayerPaint1) {
489 color = saveLayerPaint1->getColor();
490 a1 = SkColorGetA(color);
495 int newA = SkMulDiv255Round(a0, a1);
496 SkASSERT(newA <= 0xFF);
498 SkPaint* dbmrPaint = dbmr->paint();
501 SkColor newColor = SkColorSetA(dbmrPaint->getColor(), newA);
502 dbmrPaint->setColor(newColor);
504 SkColor newColor = SkColorSetA(color, newA);
507 newPaint.setColor(newColor);
508 dbmr->setPaint(newPaint);
511 // remove everything except the drawbitmaprect
512 canvas->deleteDrawCommandAt(curCommand+13); // restore
513 canvas->deleteDrawCommandAt(curCommand+12); // restore
514 canvas->deleteDrawCommandAt(curCommand+11); // restore
515 canvas->deleteDrawCommandAt(curCommand+10); // restore
516 canvas->deleteDrawCommandAt(curCommand+9); // restore
517 canvas->deleteDrawCommandAt(curCommand+7); // clipRect
518 canvas->deleteDrawCommandAt(curCommand+6); // save
519 canvas->deleteDrawCommandAt(curCommand+5); // saveLayer
520 canvas->deleteDrawCommandAt(curCommand+4); // clipRect
521 canvas->deleteDrawCommandAt(curCommand+3); // save
522 canvas->deleteDrawCommandAt(curCommand+2); // saveLayer
523 canvas->deleteDrawCommandAt(curCommand+1); // clipRect
524 canvas->deleteDrawCommandAt(curCommand); // save
530 // DRAWBITMAPRECTTORECT
533 // the drawBitmapRectToRect is a 1-1 copy from src to dest
534 // the clip rect is BW and a subset of the drawBitmapRectToRect's dest rect
535 static bool check_8(SkDebugCanvas* canvas, int curCommand) {
536 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
537 canvas->getSize() <= curCommand+4 ||
538 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
539 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
540 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
544 SkClipRectCommand* clip =
545 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1);
546 SkDrawBitmapRectCommand* dbmr =
547 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2);
549 if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) {
553 // The src->dest mapping needs to be 1-to-1
554 if (NULL == dbmr->srcRect()) {
555 if (dbmr->bitmap().width() != dbmr->dstRect().width() ||
556 dbmr->bitmap().height() != dbmr->dstRect().height()) {
560 if (dbmr->srcRect()->width() != dbmr->dstRect().width() ||
561 dbmr->srcRect()->height() != dbmr->dstRect().height()) {
566 if (!dbmr->dstRect().contains(clip->rect())) {
573 // Fold the clipRect into the drawBitmapRectToRect's src and dest rects
574 static void apply_8(SkDebugCanvas* canvas, int curCommand) {
575 SkClipRectCommand* clip =
576 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1);
577 SkDrawBitmapRectCommand* dbmr =
578 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2);
580 SkScalar newSrcLeft, newSrcTop;
582 if (dbmr->srcRect()) {
583 newSrcLeft = dbmr->srcRect()->fLeft + clip->rect().fLeft - dbmr->dstRect().fLeft;
584 newSrcTop = dbmr->srcRect()->fTop + clip->rect().fTop - dbmr->dstRect().fTop;
586 newSrcLeft = clip->rect().fLeft - dbmr->dstRect().fLeft;
587 newSrcTop = clip->rect().fTop - dbmr->dstRect().fTop;
590 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop,
591 clip->rect().width(), clip->rect().height());
593 dbmr->setSrcRect(newSrc);
594 dbmr->setDstRect(clip->rect());
596 // remove everything except the drawbitmaprect
597 canvas->deleteDrawCommandAt(curCommand+3);
598 canvas->deleteDrawCommandAt(curCommand+1);
599 canvas->deleteDrawCommandAt(curCommand);
605 // DRAWBITMAPRECTTORECT
608 // clipRect is BW and encloses the DBMR2R's dest rect
609 static bool check_9(SkDebugCanvas* canvas, int curCommand) {
610 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
611 canvas->getSize() <= curCommand+4 ||
612 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
613 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
614 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
618 SkClipRectCommand* clip =
619 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1);
620 SkDrawBitmapRectCommand* dbmr =
621 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2);
623 if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) {
627 if (!clip->rect().contains(dbmr->dstRect())) {
634 // remove everything except the drawbitmaprect
635 static void apply_9(SkDebugCanvas* canvas, int curCommand) {
636 canvas->deleteDrawCommandAt(curCommand+3); // restore
637 // drawBitmapRectToRect
638 canvas->deleteDrawCommandAt(curCommand+1); // clipRect
639 canvas->deleteDrawCommandAt(curCommand); // save
642 typedef bool (*PFCheck)(SkDebugCanvas* canvas, int curCommand);
643 typedef void (*PFApply)(SkDebugCanvas* canvas, int curCommand);
645 struct OptTableEntry {
648 int fNumTimesApplied;
650 { check_0, apply_0, 0 },
651 { check_1, apply_1, 0 },
652 { check_2, apply_2, 0 },
653 { check_3, apply_3, 0 },
654 { check_4, apply_4, 0 },
655 { check_5, apply_5, 0 },
656 { check_6, apply_6, 0 },
657 { check_7, apply_7, 0 },
658 { check_8, apply_8, 0 },
659 { check_9, apply_9, 0 },
663 static int filter_picture(const SkString& inFile, const SkString& outFile) {
664 SkAutoTDelete<SkPicture> inPicture;
666 SkFILEStream inStream(inFile.c_str());
667 if (inStream.isValid()) {
668 inPicture.reset(SkPicture::CreateFromStream(&inStream));
671 if (NULL == inPicture.get()) {
672 SkDebugf("Could not read file %s\n", inFile.c_str());
676 int localCount[SK_ARRAY_COUNT(gOptTable)];
678 memset(localCount, 0, sizeof(localCount));
680 SkDebugCanvas debugCanvas(SkScalarCeilToInt(inPicture->cullRect().width()),
681 SkScalarCeilToInt(inPicture->cullRect().height()));
682 inPicture->playback(&debugCanvas);
684 // delete the initial save and restore since replaying the commands will
686 if (debugCanvas.getSize() > 1) {
687 debugCanvas.deleteDrawCommandAt(0);
688 debugCanvas.deleteDrawCommandAt(debugCanvas.getSize()-1);
692 int numBefore = debugCanvas.getSize();
696 for (int i = 0; i < debugCanvas.getSize(); ++i) {
697 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
698 if ((*gOptTable[opt].fCheck)(&debugCanvas, i)) {
699 (*gOptTable[opt].fApply)(&debugCanvas, i);
701 ++gOptTable[opt].fNumTimesApplied;
704 if (debugCanvas.getSize() == i) {
705 // the optimization removed all the remaining operations
709 opt = 0; // try all the opts all over again
716 int numAfter = debugCanvas.getSize();
718 if (!outFile.isEmpty()) {
719 SkPictureRecorder recorder;
720 SkCanvas* canvas = recorder.beginRecording(inPicture->cullRect().width(),
721 inPicture->cullRect().height(),
723 debugCanvas.draw(canvas);
724 SkAutoTUnref<SkPicture> outPicture(recorder.endRecording());
726 SkFILEWStream outStream(outFile.c_str());
728 outPicture->serialize(&outStream);
731 bool someOptFired = false;
732 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
733 if (0 != localCount[opt]) {
734 SkDebugf("%d: %d ", opt, localCount[opt]);
740 SkDebugf("No opts fired\n");
742 SkDebugf("\t before: %d after: %d delta: %d\n",
743 numBefore, numAfter, numBefore-numAfter);
749 // This function is not marked as 'static' so it can be referenced externally
751 int tool_main(int argc, char** argv); // suppress a warning on mac
753 int tool_main(int argc, char** argv) {
754 #if SK_ENABLE_INST_COUNT
755 gPrintInstCount = true;
765 SkString inFile, outFile, inDir, outDir;
767 char* const* stop = argv + argc;
768 for (++argv; argv < stop; ++argv) {
769 if (strcmp(*argv, "-i") == 0) {
771 if (argv < stop && **argv) {
774 SkDebugf("missing arg for -i\n");
778 } else if (strcmp(*argv, "--input-dir") == 0) {
780 if (argv < stop && **argv) {
783 SkDebugf("missing arg for --input-dir\n");
787 } else if (strcmp(*argv, "--output-dir") == 0) {
789 if (argv < stop && **argv) {
792 SkDebugf("missing arg for --output-dir\n");
796 } else if (strcmp(*argv, "-o") == 0) {
798 if (argv < stop && **argv) {
801 SkDebugf("missing arg for -o\n");
805 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) {
809 SkDebugf("unknown arg %s\n", *argv);
815 SkOSFile::Iter iter(inDir.c_str(), "skp");
817 SkString inputFilename, outputFilename;
818 if (iter.next(&inputFilename)) {
821 inFile = SkOSPath::Join(inDir.c_str(), inputFilename.c_str());
822 if (!outDir.isEmpty()) {
823 outFile = SkOSPath::Join(outDir.c_str(), inputFilename.c_str());
825 SkDebugf("Executing %s\n", inputFilename.c_str());
826 filter_picture(inFile, outFile);
827 } while(iter.next(&inputFilename));
829 } else if (!inFile.isEmpty()) {
830 filter_picture(inFile, outFile);
836 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
837 SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied);
844 #if !defined SK_BUILD_FOR_IOS
845 int main(int argc, char * const argv[]) {
846 return tool_main(argc, (char**) argv);