Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / tools / filtermain.cpp
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 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();
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 (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()) {
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 opaque
71     SkColor dbmrColor = dbmrPaint->getColor() | 0xFF000000;       // force opaque
72
73     // If either operation lacks a paint then the collapse is trivial
74     return NULL == saveLayerPaint ||
75            NULL == 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 (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed
87     if (saveLayerPaint) {
88         SkDrawBitmapRectCommand* dbmr =
89             (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1);
90         SkPaint* dbmrPaint = dbmr->paint();
91
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);
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 (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()) {
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 opaque
151
152     return NULL == saveLayerPaint ||
153            NULL == 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 (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();
169
170         if (NULL == 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 (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()) {
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 (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()) {
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 (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()) {
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 //    TRANSLATE
303 // where the translate is zero
304 static bool check_5(SkDebugCanvas* canvas, int curCommand) {
305     if (TRANSLATE != canvas->getDrawCommandAt(curCommand)->getType()) {
306         return false;
307     }
308
309     SkTranslateCommand* t =
310         (SkTranslateCommand*) canvas->getDrawCommandAt(curCommand);
311
312     return 0 == t->x() && 0 == t->y();
313 }
314
315 // Just remove the translate
316 static void apply_5(SkDebugCanvas* canvas, int curCommand) {
317     canvas->deleteDrawCommandAt(curCommand);    // translate
318 }
319
320 // Check for:
321 //    SCALE
322 // where the scale is 1,1
323 static bool check_6(SkDebugCanvas* canvas, int curCommand) {
324     if (SCALE != canvas->getDrawCommandAt(curCommand)->getType()) {
325         return false;
326     }
327
328     SkScaleCommand* s = (SkScaleCommand*) canvas->getDrawCommandAt(curCommand);
329
330     return SK_Scalar1 == s->x() && SK_Scalar1 == s->y();
331 }
332
333 // Just remove the scale
334 static void apply_6(SkDebugCanvas* canvas, int curCommand) {
335     canvas->deleteDrawCommandAt(curCommand);   // scale
336 }
337
338 // Check for:
339 //  SAVE
340 //      CLIP_RECT
341 //      SAVE_LAYER
342 //          SAVE
343 //              CLIP_RECT
344 //              SAVE_LAYER
345 //                  SAVE
346 //                      CLIP_RECT
347 //                      DRAWBITMAPRECTTORECT
348 //                  RESTORE
349 //              RESTORE
350 //          RESTORE
351 //      RESTORE
352 //  RESTORE
353 // where:
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()) {
375         return false;
376     }
377
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);
390
391     if (clip0->doAA() || clip1->doAA() || clip2->doAA()) {
392         return false;
393     }
394
395     if (SkRegion::kIntersect_Op != clip0->op() ||
396         SkRegion::kIntersect_Op != clip1->op() ||
397         SkRegion::kIntersect_Op != clip2->op()) {
398         return false;
399     }
400
401     if (!clip0->rect().contains(clip1->rect()) ||
402         !clip1->rect().contains(clip2->rect())) {
403         return false;
404     }
405
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()) {
410             return false;
411         }
412     } else {
413         if (dbmr->srcRect()->width() != dbmr->dstRect().width() ||
414             dbmr->srcRect()->height() != dbmr->dstRect().height()) {
415             return false;
416         }
417     }
418
419     if (!dbmr->dstRect().contains(clip2->rect())) {
420         return false;
421     }
422
423     const SkPaint* saveLayerPaint0 = saveLayer0->paint();
424     const SkPaint* saveLayerPaint1 = saveLayer1->paint();
425
426     if ((saveLayerPaint0 && !is_simple(*saveLayerPaint0)) ||
427         (saveLayerPaint1 && !is_simple(*saveLayerPaint1))) {
428         return false;
429     }
430
431     SkPaint* dbmrPaint = dbmr->paint();
432
433     if (NULL == dbmrPaint) {
434         return true;
435     }
436
437     if (saveLayerPaint0) {
438         SkColor layerColor0 = saveLayerPaint0->getColor() | 0xFF000000; // force opaque
439         if (dbmrPaint->getColor() != layerColor0) {
440             return false;
441         }
442     }
443
444     if (saveLayerPaint1) {
445         SkColor layerColor1 = saveLayerPaint1->getColor() | 0xFF000000; // force opaque
446         if (dbmrPaint->getColor() != layerColor1) {
447             return false;
448         }
449     }
450
451     return true;
452 }
453
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
456 // paint.
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);
466
467     SkScalar newSrcLeft = dbmr->srcRect()->fLeft + clip2->rect().fLeft - dbmr->dstRect().fLeft;
468     SkScalar newSrcTop = dbmr->srcRect()->fTop + clip2->rect().fTop - dbmr->dstRect().fTop;
469
470     SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop,
471                                      clip2->rect().width(), clip2->rect().height());
472
473     dbmr->setSrcRect(newSrc);
474     dbmr->setDstRect(clip2->rect());
475
476     SkColor color = 0xFF000000;
477     int a0, a1;
478
479     const SkPaint* saveLayerPaint0 = saveLayer0->paint();
480     if (saveLayerPaint0) {
481         color = saveLayerPaint0->getColor();
482         a0 = SkColorGetA(color);
483     } else {
484         a0 = 0xFF;
485     }
486
487     const SkPaint* saveLayerPaint1 = saveLayer1->paint();
488     if (saveLayerPaint1) {
489         color = saveLayerPaint1->getColor();
490         a1 = SkColorGetA(color);
491     } else {
492         a1 = 0xFF;
493     }
494
495     int newA = SkMulDiv255Round(a0, a1);
496     SkASSERT(newA <= 0xFF);
497
498     SkPaint* dbmrPaint = dbmr->paint();
499
500     if (dbmrPaint) {
501         SkColor newColor = SkColorSetA(dbmrPaint->getColor(), newA);
502         dbmrPaint->setColor(newColor);
503     } else {
504         SkColor newColor = SkColorSetA(color, newA);
505
506         SkPaint newPaint;
507         newPaint.setColor(newColor);
508         dbmr->setPaint(newPaint);
509     }
510
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
525 }
526
527 // Check for:
528 //    SAVE
529 //       CLIP_RECT
530 //       DRAWBITMAPRECTTORECT
531 //    RESTORE
532 // where:
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()) {
541         return false;
542     }
543
544     SkClipRectCommand* clip =
545         (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1);
546     SkDrawBitmapRectCommand* dbmr =
547         (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2);
548
549     if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) {
550         return false;
551     }
552
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()) {
557             return false;
558         }
559     } else {
560         if (dbmr->srcRect()->width() != dbmr->dstRect().width() ||
561             dbmr->srcRect()->height() != dbmr->dstRect().height()) {
562             return false;
563         }
564     }
565
566     if (!dbmr->dstRect().contains(clip->rect())) {
567         return false;
568     }
569
570     return true;
571 }
572
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);
579
580     SkScalar newSrcLeft, newSrcTop;
581
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;
585     } else {
586         newSrcLeft = clip->rect().fLeft - dbmr->dstRect().fLeft;
587         newSrcTop  = clip->rect().fTop - dbmr->dstRect().fTop;
588     }
589
590     SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop,
591                                      clip->rect().width(), clip->rect().height());
592
593     dbmr->setSrcRect(newSrc);
594     dbmr->setDstRect(clip->rect());
595
596     // remove everything except the drawbitmaprect
597     canvas->deleteDrawCommandAt(curCommand+3);
598     canvas->deleteDrawCommandAt(curCommand+1);
599     canvas->deleteDrawCommandAt(curCommand);
600 }
601
602 // Check for:
603 //  SAVE
604 //    CLIP_RECT
605 //    DRAWBITMAPRECTTORECT
606 //  RESTORE
607 // where:
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()) {
615         return false;
616     }
617
618     SkClipRectCommand* clip =
619         (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1);
620     SkDrawBitmapRectCommand* dbmr =
621         (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2);
622
623     if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) {
624         return false;
625     }
626
627     if (!clip->rect().contains(dbmr->dstRect())) {
628         return false;
629     }
630
631     return true;
632 }
633
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
640 }
641
642 typedef bool (*PFCheck)(SkDebugCanvas* canvas, int curCommand);
643 typedef void (*PFApply)(SkDebugCanvas* canvas, int curCommand);
644
645 struct OptTableEntry {
646     PFCheck fCheck;
647     PFApply fApply;
648     int fNumTimesApplied;
649 } gOptTable[] = {
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 },
660 };
661
662
663 static int filter_picture(const SkString& inFile, const SkString& outFile) {
664     SkAutoTDelete<SkPicture> inPicture;
665
666     SkFILEStream inStream(inFile.c_str());
667     if (inStream.isValid()) {
668         inPicture.reset(SkPicture::CreateFromStream(&inStream));
669     }
670
671     if (NULL == inPicture.get()) {
672         SkDebugf("Could not read file %s\n", inFile.c_str());
673         return -1;
674     }
675
676     int localCount[SK_ARRAY_COUNT(gOptTable)];
677
678     memset(localCount, 0, sizeof(localCount));
679
680     SkDebugCanvas debugCanvas(SkScalarCeilToInt(inPicture->cullRect().width()), 
681                               SkScalarCeilToInt(inPicture->cullRect().height()));
682     inPicture->playback(&debugCanvas);
683
684     // delete the initial save and restore since replaying the commands will
685     // re-add them
686     if (debugCanvas.getSize() > 1) {
687         debugCanvas.deleteDrawCommandAt(0);
688         debugCanvas.deleteDrawCommandAt(debugCanvas.getSize()-1);
689     }
690
691     bool changed = true;
692     int numBefore = debugCanvas.getSize();
693
694     while (changed) {
695         changed = false;
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);
700
701                     ++gOptTable[opt].fNumTimesApplied;
702                     ++localCount[opt];
703
704                     if (debugCanvas.getSize() == i) {
705                         // the optimization removed all the remaining operations
706                         break;
707                     }
708
709                     opt = 0;          // try all the opts all over again
710                     changed = true;
711                 }
712             }
713         }
714     }
715
716     int numAfter = debugCanvas.getSize();
717
718     if (!outFile.isEmpty()) {
719         SkPictureRecorder recorder;
720         SkCanvas* canvas = recorder.beginRecording(inPicture->cullRect().width(), 
721                                                    inPicture->cullRect().height(), 
722                                                    NULL, 0);
723         debugCanvas.draw(canvas);
724         SkAutoTUnref<SkPicture> outPicture(recorder.endRecording());
725
726         SkFILEWStream outStream(outFile.c_str());
727
728         outPicture->serialize(&outStream);
729     }
730
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]);
735             someOptFired = true;
736         }
737     }
738
739     if (!someOptFired) {
740         SkDebugf("No opts fired\n");
741     } else {
742         SkDebugf("\t before: %d after: %d delta: %d\n",
743                  numBefore, numAfter, numBefore-numAfter);
744     }
745
746     return 0;
747 }
748
749 // This function is not marked as 'static' so it can be referenced externally
750 // in the iOS build.
751 int tool_main(int argc, char** argv); // suppress a warning on mac
752
753 int tool_main(int argc, char** argv) {
754 #if SK_ENABLE_INST_COUNT
755     gPrintInstCount = true;
756 #endif
757
758     SkGraphics::Init();
759
760     if (argc < 3) {
761         usage();
762         return -1;
763     }
764
765     SkString inFile, outFile, inDir, outDir;
766
767     char* const* stop = argv + argc;
768     for (++argv; argv < stop; ++argv) {
769         if (strcmp(*argv, "-i") == 0) {
770             argv++;
771             if (argv < stop && **argv) {
772                 inFile.set(*argv);
773             } else {
774                 SkDebugf("missing arg for -i\n");
775                 usage();
776                 return -1;
777             }
778         } else if (strcmp(*argv, "--input-dir") == 0) {
779             argv++;
780             if (argv < stop && **argv) {
781                 inDir.set(*argv);
782             } else {
783                 SkDebugf("missing arg for --input-dir\n");
784                 usage();
785                 return -1;
786             }
787         } else if (strcmp(*argv, "--output-dir") == 0) {
788             argv++;
789             if (argv < stop && **argv) {
790                 outDir.set(*argv);
791             } else {
792                 SkDebugf("missing arg for --output-dir\n");
793                 usage();
794                 return -1;
795             }
796         } else if (strcmp(*argv, "-o") == 0) {
797             argv++;
798             if (argv < stop && **argv) {
799                 outFile.set(*argv);
800             } else {
801                 SkDebugf("missing arg for -o\n");
802                 usage();
803                 return -1;
804             }
805         } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) {
806             usage();
807             return 0;
808         } else {
809             SkDebugf("unknown arg %s\n", *argv);
810             usage();
811             return -1;
812         }
813     }
814
815     SkOSFile::Iter iter(inDir.c_str(), "skp");
816
817     SkString inputFilename, outputFilename;
818     if (iter.next(&inputFilename)) {
819
820         do {
821             inFile = SkOSPath::Join(inDir.c_str(), inputFilename.c_str());
822             if (!outDir.isEmpty()) {
823                 outFile = SkOSPath::Join(outDir.c_str(), inputFilename.c_str());
824             }
825             SkDebugf("Executing %s\n", inputFilename.c_str());
826             filter_picture(inFile, outFile);
827         } while(iter.next(&inputFilename));
828
829     } else if (!inFile.isEmpty()) {
830         filter_picture(inFile, outFile);
831     } else {
832         usage();
833         return -1;
834     }
835
836     for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
837         SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied);
838     }
839
840     SkGraphics::Term();
841     return 0;
842 }
843
844 #if !defined SK_BUILD_FOR_IOS
845 int main(int argc, char * const argv[]) {
846     return tool_main(argc, (char**) argv);
847 }
848 #endif