filtermain.cpp revision c3410b8cbbf63ac7968262c25c996bdbaab20588
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 "SkGraphics.h"
11#include "SkImageDecoder.h"
12#include "SkImageEncoder.h"
13#include "SkOSFile.h"
14#include "SkPicture.h"
15#include "SkPicturePlayback.h"
16#include "SkPictureRecord.h"
17#include "SkStream.h"
18#include "picture_utils.h"
19#include "path_utils.h"
20
21static void usage() {
22    SkDebugf("Usage: filter -i inFile [-o outFile] [--input-dir path] [--output-dir path]\n");
23    SkDebugf("                        [-h|--help]\n\n");
24    SkDebugf("    -i inFile  : file to file.\n");
25    SkDebugf("    -o outFile : result of filtering.\n");
26    SkDebugf("    --input-dir : process all files in dir with .skp extension.\n");
27    SkDebugf("    --output-dir : results of filtering the input dir.\n");
28    SkDebugf("    -h|--help  : Show this help message.\n");
29}
30
31// 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}
42
43// 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
61    // For this optimization we only fold the saveLayer and drawBitmapRect
62    // 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
71    return NULL == saveLayerPaint ||
72           NULL == dbmrPaint ||
73           (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor);
74}
75
76// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
77// and restore
78static void apply_0(SkTDArray<SkDrawCommand*>& commands, int curCommand) {
79    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
126    // For this optimization we only fold the saveLayer and drawBitmapRect
127    // 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
136    return NULL == saveLayerPaint ||
137           NULL == dbmrPaint ||
138           (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor);
139}
140
141// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
142// and restore
143static void apply_1(SkTDArray<SkDrawCommand*>& commands, int curCommand) {
144    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
167// 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
241    SkPaint newPaint = dr->paint();
242    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
283// 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
323// 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
379    if (!clip0->rect().contains(clip1->rect()) ||
380        !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) {
412        return true;
413    }
414
415    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
454    SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop,
455                                     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}
510
511typedef bool (*PFCheck)(const SkTDArray<SkDrawCommand*>& commands, int curCommand);
512typedef void (*PFApply)(SkTDArray<SkDrawCommand*>& commands, int curCommand);
513
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 },
521    { check_2, apply_2, 0 },
522    { check_3, apply_3, 0 },
523    { check_4, apply_4, 0 },
524    { check_5, apply_5, 0 },
525    { check_6, apply_6, 0 },
526    { check_7, apply_7, 0 },
527};
528
529static int filter_picture(const SkString& inFile, const SkString& outFile) {
530    SkPicture* inPicture = NULL;
531
532    SkFILEStream inStream(inFile.c_str());
533    if (inStream.isValid()) {
534        inPicture = SkNEW_ARGS(SkPicture, (&inStream, NULL, &SkImageDecoder::DecodeMemory));
535    }
536
537    if (NULL == inPicture) {
538        SkDebugf("Could not read file %s\n", inFile.c_str());
539        return -1;
540    }
541
542    int localCount[SK_ARRAY_COUNT(gOptTable)];
543
544    memset(localCount, 0, sizeof(localCount));
545
546    SkDebugCanvas debugCanvas(inPicture->width(), inPicture->height());
547    debugCanvas.setBounds(inPicture->width(), inPicture->height());
548    inPicture->draw(&debugCanvas);
549
550    SkTDArray<SkDrawCommand*>& commands = debugCanvas.getDrawCommands();
551
552    // hide the initial save and restore since replaying the commands will
553    // re-add them
554    if (commands.count() > 0) {
555        commands[0]->setVisible(false);
556        commands[commands.count()-1]->setVisible(false);
557    }
558
559    for (int i = 0; i < commands.count(); ++i) {
560        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];
565            }
566        }
567    }
568
569    if (!outFile.isEmpty()) {
570        SkPicture outPicture;
571
572        SkCanvas* canvas = outPicture.beginRecording(inPicture->width(), inPicture->height());
573        debugCanvas.draw(canvas);
574        outPicture.endRecording();
575
576        SkFILEWStream outStream(outFile.c_str());
577
578        outPicture.serialize(&outStream);
579    }
580
581    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
595    return 0;
596}
597
598// This function is not marked as 'static' so it can be referenced externally
599// in the iOS build.
600int tool_main(int argc, char** argv); // suppress a warning on mac
601
602int tool_main(int argc, char** argv) {
603    SkGraphics::Init();
604
605    if (argc < 3) {
606        usage();
607        return -1;
608    }
609
610    SkString inFile, outFile, inDir, outDir;
611
612    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 {
619                SkDebugf("missing arg for -i\n");
620                usage();
621                return -1;
622            }
623        } 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            }
641        } else if (strcmp(*argv, "-o") == 0) {
642            argv++;
643            if (argv < stop && **argv) {
644                outFile.set(*argv);
645            } else {
646                SkDebugf("missing arg for -o\n");
647                usage();
648                return -1;
649            }
650        } 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
660    SkOSFile::Iter iter(inDir.c_str(), "skp");
661
662    SkString inputFilename, outputFilename;
663    if (iter.next(&inputFilename)) {
664
665        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());
671            filter_picture(inFile, outFile);
672        } while(iter.next(&inputFilename));
673
674    } else if (!inFile.isEmpty()) {
675        filter_picture(inFile, outFile);
676    } else {
677        usage();
678        return -1;
679    }
680
681    for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
682        SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied);
683    }
684
685    SkGraphics::Term();
686    return 0;
687}
688
689#if !defined SK_BUILD_FOR_IOS
690int main(int argc, char * const argv[]) {
691    return tool_main(argc, (char**) argv);
692}
693#endif
694