Allow specific files and multiple inputs for picture testing tools.

Changed the render_pictures, bench_pictures and test_pictures.py so that multiple inputs can be given. Furthermore, specific files can also be specified.

Unit tests have also been added for picture_utils.cpp.

Review URL: https://codereview.appspot.com/6345054

git-svn-id: http://skia.googlecode.com/svn/trunk@4486 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tools/bench_pictures_main.cpp b/tools/bench_pictures_main.cpp
index 355deb6..e06a63b 100644
--- a/tools/bench_pictures_main.cpp
+++ b/tools/bench_pictures_main.cpp
@@ -37,13 +37,13 @@
     SkDebugf("SkPicture benchmarking tool\n");
     SkDebugf("\n"
 "Usage: \n"
-"     %s <inputDir>\n"
+"     %s <inputDir>...\n"
 "     [--repeat] [--tile width height]"
 , argv0);
     SkDebugf("\n\n");
     SkDebugf(
-"     inputDir: directory to read the serialized SkPicture files."
-"                Files are expected to have the .skp extension.\n\n");
+"     inputDir:  A list of directories and files to use as input.\n"
+"                    Files are expected to have the .skp extension.\n\n");
     SkDebugf(
 "     --repeat : "
 "Set the number of times to repeat each test."
@@ -133,13 +133,10 @@
            options.fTileHeight, timer.fWall / options.fRepeats);
 }
 
-static void run_benchmark(const char* inputDir,
-                          const SkString& inputFilename,
-                          const Options& options) {
+static void run_single_benchmark(const SkString& inputPath,
+                                 const Options& options) {
     SkFILEStream inputStream;
 
-    SkString inputPath;
-    sk_tools::make_filepath(&inputPath, inputDir, inputFilename);
     inputStream.setPath(inputPath.c_str());
     if (!inputStream.isValid()) {
         SkDebugf("Could not open file %s\n", inputPath.c_str());
@@ -150,13 +147,16 @@
     SkBitmap bitmap;
     sk_tools::setup_bitmap(&bitmap, picture.width(), picture.height());
 
+    SkString filename;
+    sk_tools::get_basename(&filename, inputPath);
     printf("running bench [%i %i] %s ", picture.width(), picture.height(),
-           inputFilename.c_str());
+           filename.c_str());
+
     options.fBenchmark(&picture, bitmap, options);
 }
 
 static void parse_commandline(int argc, char* const argv[],
-                              const char** inputDir, Options* options) {
+                              SkTArray<SkString>* inputs, Options* options) {
     const char* argv0 = argv[0];
     char* const* stop = argv + argc;
 
@@ -205,32 +205,39 @@
             usage(argv0);
             exit(0);
         } else {
-            if (NULL == *inputDir) {
-                *inputDir = *argv;
-            } else {
-                usage(argv0);
-                exit(-1);
-            }
+            inputs->push_back(SkString(*argv));
         }
     }
 
-    if (NULL == *inputDir) {
+    if (inputs->count() < 1) {
         usage(argv0);
         exit(-1);
     }
+}
 
+static void process_input(const SkString& input, const Options& options) {
+    SkOSFile::Iter iter(input.c_str(), "skp");
+    SkString inputFilename;
+
+    if (iter.next(&inputFilename)) {
+        do {
+            SkString inputPath;
+            sk_tools::make_filepath(&inputPath, input.c_str(),
+                                    inputFilename);
+            run_single_benchmark(inputPath, options);
+        } while(iter.next(&inputFilename));
+    } else {
+          run_single_benchmark(input, options);
+    }
 }
 
 int main(int argc, char* const argv[]) {
-    const char* inputDir = NULL;
+    SkTArray<SkString> inputs;
     Options options;
 
-    parse_commandline(argc, argv, &inputDir, &options);
+    parse_commandline(argc, argv, &inputs, &options);
 
-    SkOSFile::Iter iter(inputDir, "skp");
-    SkString inputFilename;
-
-    while(iter.next(&inputFilename)) {
-        run_benchmark(inputDir, inputFilename, options);
+    for (int i = 0; i < inputs.count(); ++i) {
+        process_input(inputs[i], options);
     }
 }
diff --git a/tools/picture_utils.cpp b/tools/picture_utils.cpp
index 6a9e1f5..98351b8 100644
--- a/tools/picture_utils.cpp
+++ b/tools/picture_utils.cpp
@@ -22,6 +22,49 @@
         path->append(name);
     }
 
+    namespace {
+        bool is_path_seperator(const char chr) {
+#if defined(SK_BUILD_FOR_WIN)
+            return chr == '\\' || chr == '/';
+#else
+            return chr == '/';
+#endif
+        }
+    }
+
+    void get_basename(SkString* basename, const SkString& path) {
+        if (path.size() == 0) {
+            basename->reset();
+            return;
+        }
+
+        size_t end = path.size() - 1;
+
+        // Paths pointing to directories often have a trailing slash,
+        // we remove it so the name is not empty
+        if (is_path_seperator(path[end])) {
+            if (end == 0) {
+                basename->reset();
+                return;
+            }
+
+            end -= 1;
+        }
+
+        size_t i = end;
+        do {
+            --i;
+            if (is_path_seperator(path[i])) {
+                  const char* basenameStart = path.c_str() + i + 1;
+                  size_t basenameLength = end - i;
+                  basename->set(basenameStart, basenameLength);
+                  return;
+            }
+        } while (i > 0);
+
+        basename->set(path.c_str(), end + 1);
+    }
+
     void setup_bitmap(SkBitmap* bitmap, int width, int height) {
         bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
         bitmap->allocPixels();
diff --git a/tools/picture_utils.h b/tools/picture_utils.h
index 21651cd..18efcb7 100644
--- a/tools/picture_utils.h
+++ b/tools/picture_utils.h
@@ -19,6 +19,12 @@
     // forward slash into path.
     void make_filepath(SkString* path, const char* dir, const SkString& name);
 
+    // Returns the last part of the path (file name or leaf directory name)
+    //
+    // This basically just looks for a foward slash or backslash (windows
+    // only)
+    void get_basename(SkString* basename, const SkString& path);
+
     // Prepares the bitmap so that it can be written.
     //
     // Specifically, it configures the bitmap, allocates pixels and then
diff --git a/tools/render_pictures_main.cpp b/tools/render_pictures_main.cpp
index 930089b..da7df63 100644
--- a/tools/render_pictures_main.cpp
+++ b/tools/render_pictures_main.cpp
@@ -21,10 +21,11 @@
     SkDebugf("SkPicture rendering tool\n");
     SkDebugf("\n"
 "Usage: \n"
-"     %s <inputDir> <outputDir> \n\n"
+"     %s <input>... <outputDir> \n\n"
 , argv0);
     SkDebugf(
-"     inputDir:  directory to read the serialized SkPicture files.\n");
+"     input:     A list of directories and files to use as input.\n"
+"                    Files are expected to have the .skp extension.\n");
     SkDebugf(
 "     outputDir: directory to write the rendered images.\n");
 }
@@ -73,12 +74,11 @@
     }
 }
 
-static void render_picture(const char* inputDir, const char* outputDir,
-                           const SkString& inputFilename) {
-    SkFILEStream inputStream;
+static void render_picture(const SkString& inputPath, const char* outputDir) {
+    SkString inputFilename;
+    sk_tools::get_basename(&inputFilename, inputPath);
 
-    SkString inputPath;
-    sk_tools::make_filepath(&inputPath, inputDir, inputFilename);
+    SkFILEStream inputStream;
     inputStream.setPath(inputPath.c_str());
     if (!inputStream.isValid()) {
         SkDebugf("Could not open file %s\n", inputPath.c_str());
@@ -91,20 +91,32 @@
     write_output(outputDir, inputFilename, bitmap);
 }
 
-int main(int argc, char* const argv[]) {
-    const char* inputDir;
-    const char* outputDir;
-    if (argc != 3) {
-        usage(argv[0]);
-    }
-
-    inputDir = argv[1];
-    outputDir = argv[2];
-
-    SkOSFile::Iter iter(inputDir, "skp");
+static void process_input(const char* input, const char* outputDir) {
+    SkOSFile::Iter iter(input, "skp");
     SkString inputFilename;
 
-    while(iter.next(&inputFilename)) {
-        render_picture(inputDir, outputDir, inputFilename);
+    if (iter.next(&inputFilename)) {
+        do {
+            SkString inputPath;
+            sk_tools::make_filepath(&inputPath, input, inputFilename);
+            render_picture(inputPath, outputDir);
+        } while(iter.next(&inputFilename));
+    } else {
+        SkString inputPath(input);
+        render_picture(inputPath, outputDir);
+    }
+}
+
+int main(int argc, char* const argv[]) {
+    const char* outputDir;
+    if (argc < 3) {
+        usage(argv[0]);
+        return -1;
+    }
+
+    outputDir = argv[argc - 1];
+
+    for (int i = 1; i < argc - 1; i ++) {
+        process_input(argv[i], outputDir);
     }
 }
diff --git a/tools/test_pictures.py b/tools/test_pictures.py
index 253bf4e..21eaa40 100644
--- a/tools/test_pictures.py
+++ b/tools/test_pictures.py
@@ -16,11 +16,12 @@
 import shutil
 import tempfile
 
-USAGE_STRING = 'Usage: %s inputDir expectedDir [renderDir [diffDir]]'
+USAGE_STRING = 'Usage: %s input... expectedDir'
 HELP_STRING = '''
 
-Compares the renderings of serialized SkPicture files in inputDir with the
-images in expectedDir.
+Compares the renderings of serialized SkPicture files and directories specified
+by input with the images in expectedDir. Note, files in directoriers are
+expected to end with .skp.
 '''
 
 def RunCommand(command):
@@ -49,16 +50,17 @@
                     'build %s?' % (program, possible_paths, program))
 
 
-def RenderImages(input_dir, render_dir):
+def RenderImages(inputs, render_dir):
     """Renders the serialized SkPictures.
 
     Uses the render_pictures program to do the rendering.
 
-    @param input_dir the location to read the serlialized SkPictures
+    @param inputs the location(s) to read the serlialized SkPictures
     @param render_dir the location to write out the rendered images
     """
     renderer_path = FindPathToProgram('render_pictures')
-    RunCommand('%s %s %s' % (renderer_path, input_dir, render_dir))
+    inputs_as_string = " ".join(inputs)
+    RunCommand('%s %s %s' % (renderer_path, inputs_as_string, render_dir))
 
 
 def DiffImages(expected_dir, comparison_dir, diff_dir):
@@ -107,8 +109,13 @@
 
     options, arguments = parser.parse_args(args)
 
-    input_dir = arguments[1]
-    expected_dir = arguments[2]
+    if (len(arguments) < 3):
+        print("Expected at least one input and one ouput folder.")
+        parser.print_help()
+        sys.exit(-1)
+
+    inputs = arguments[1:-1]
+    expected_dir = arguments[-1]
 
     if (options.render_dir):
         render_dir = options.render_dir
@@ -121,7 +128,7 @@
         diff_dir = tempfile.mkdtemp()
 
     try:
-        RenderImages(input_dir, render_dir)
+        RenderImages(inputs, render_dir)
         DiffImages(expected_dir, render_dir, diff_dir)
     finally:
         Cleanup(options, render_dir, diff_dir)