de-common the rest of the flags

Turns out lots of tools had two copies of many of these flags.

Some GN and .cpp file refactoring to make sure when flags are
present in a binary, they do something in that binary.

I think this finally finishes the flag refrag.

Change-Id: I01488e37ab73a5c4361786863ddb137a7f1095b1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/203420
Commit-Queue: Mike Klein <mtklein@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Auto-Submit: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 6e39713..7d7a66b 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1550,10 +1550,10 @@
       "tools/flags/CommandLineFlags.cpp",
     ]
   }
-  test_lib("common_flags") {
+
+  test_lib("common_flags_config") {
     public_include_dirs = [ "tools/flags" ]
     sources = [
-      "tools/flags/CommonFlags.cpp",
       "tools/flags/CommonFlagsConfig.cpp",
     ]
     deps = [
@@ -1563,6 +1563,36 @@
       ":gpu_tool_utils",
     ]
   }
+  test_lib("common_flags_gpu") {
+    public_include_dirs = [ "tools/flags" ]
+    sources = [
+      "tools/flags/CommonFlagsGpu.cpp",
+    ]
+    deps = [
+      ":flags",
+    ]
+    public_deps = [
+      ":gpu_tool_utils",
+    ]
+  }
+  test_lib("common_flags_images") {
+    public_include_dirs = [ "tools/flags" ]
+    sources = [
+      "tools/flags/CommonFlagsImages.cpp",
+    ]
+    deps = [
+      ":flags",
+    ]
+  }
+  test_lib("common_flags_aa") {
+    public_include_dirs = [ "tools/flags" ]
+    sources = [
+      "tools/flags/CommonFlagsAA.cpp",
+    ]
+    deps = [
+      ":flags",
+    ]
+  }
 
   test_lib("tool_utils") {
     public_include_dirs = [
@@ -1616,11 +1646,9 @@
     deps = [
       ":experimental_svg_model",
       ":flags",
+      ":gpu_tool_utils",
       "//third_party/libpng",
     ]
-    public_deps = [
-      ":common_flags",
-    ]
   }
 
   import("gn/gm.gni")
@@ -1804,6 +1832,7 @@
       deps = [
         ":experimental_svg_model",
         ":flags",
+        ":gpu_tool_utils",
         ":xml",
         "modules/sksg",
         "modules/skshaper",
@@ -1840,7 +1869,10 @@
         "dm/DMSrcSink.cpp",
       ]
       deps = [
-        ":common_flags",
+        ":common_flags_aa",
+        ":common_flags_config",
+        ":common_flags_gpu",
+        ":common_flags_images",
         ":experimental_svg_model",
         ":flags",
         ":gm",
@@ -1878,7 +1910,10 @@
     ]
     deps = [
       ":bench",
-      ":common_flags",
+      ":common_flags_aa",
+      ":common_flags_config",
+      ":common_flags_gpu",
+      ":common_flags_images",
       ":experimental_svg_model",
       ":flags",
       ":gm",
@@ -1904,6 +1939,8 @@
       "tools/skpbench/skpbench.cpp",
     ]
     deps = [
+      ":common_flags_config",
+      ":common_flags_gpu",
       ":flags",
       ":gpu_tool_utils",
       ":skia",
@@ -2320,6 +2357,7 @@
 
     include_dirs = [ "experimental" ]
     deps = [
+      ":common_flags_gpu",
       ":experimental_svg_model",
       ":flags",
       ":gm",
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp
index 9c0d213..ac9fb18 100644
--- a/bench/nanobench.cpp
+++ b/bench/nanobench.cpp
@@ -151,6 +151,34 @@
 static DEFINE_bool(simpleCodec, false,
                    "Runs of a subset of the codec tests, always N32, Premul or Opaque");
 
+static DEFINE_string2(match, m, nullptr,
+               "[~][^]substring[$] [...] of name to run.\n"
+               "Multiple matches may be separated by spaces.\n"
+               "~ causes a matching name to always be skipped\n"
+               "^ requires the start of the name to match\n"
+               "$ requires the end of the name to match\n"
+               "^ and $ requires an exact match\n"
+               "If a name does not match any list entry,\n"
+               "it is skipped unless some list entry starts with ~");
+
+static DEFINE_bool2(quiet, q, false, "if true, don't print status updates.");
+static DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
+
+
+static DEFINE_string(skps, "skps", "Directory to read skps from.");
+static DEFINE_string(svgs, "", "Directory to read SVGs from, or a single SVG file.");
+
+static DEFINE_int_2(threads, j, -1,
+               "Run threadsafe tests on a threadpool with this many extra threads, "
+               "defaulting to one extra thread per core.");
+
+static DEFINE_string2(writePath, w, "", "If set, write bitmaps here as .pngs.");
+
+static DEFINE_string(key, "",
+                     "Space-separated key/value pairs to add to JSON identifying this builder.");
+static DEFINE_string(properties, "",
+                     "Space-separated key/value pairs to add to JSON identifying this run.");
+
 static double now_ms() { return SkTime::GetNSecs() * 1e-6; }
 
 static SkString humanize(double ms) {
diff --git a/dm/DM.cpp b/dm/DM.cpp
index 9db3154..90b8abc 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -75,6 +75,8 @@
 
 static DEFINE_string2(readPath, r, "",
                       "If set check for equality with golden results in this directory.");
+DEFINE_string2(writePath, w, "", "If set, write bitmaps here as .pngs.");
+
 
 static DEFINE_string(uninterestingHashesFile, "",
         "File containing a list of uninteresting hashes. If a result hashes to something in "
@@ -118,6 +120,33 @@
                    "Runs of a subset of the codec tests, "
                    "with no scaling or subsetting, always using the canvas color type.");
 
+static DEFINE_string2(match, m, nullptr,
+               "[~][^]substring[$] [...] of name to run.\n"
+               "Multiple matches may be separated by spaces.\n"
+               "~ causes a matching name to always be skipped\n"
+               "^ requires the start of the name to match\n"
+               "$ requires the end of the name to match\n"
+               "^ and $ requires an exact match\n"
+               "If a name does not match any list entry,\n"
+               "it is skipped unless some list entry starts with ~");
+
+static DEFINE_bool2(quiet, q, false, "if true, don't print status updates.");
+static DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
+
+static DEFINE_string(skps, "skps", "Directory to read skps from.");
+static DEFINE_string(lotties, "lotties", "Directory to read (Bodymovin) jsons from.");
+static DEFINE_string(svgs, "", "Directory to read SVGs from, or a single SVG file.");
+
+static DEFINE_int_2(threads, j, -1,
+               "Run threadsafe tests on a threadpool with this many extra threads, "
+               "defaulting to one extra thread per core.");
+
+static DEFINE_string(key, "",
+                     "Space-separated key/value pairs to add to JSON identifying this builder.");
+static DEFINE_string(properties, "",
+                     "Space-separated key/value pairs to add to JSON identifying this run.");
+
+
 using namespace DM;
 using sk_gpu_test::GrContextFactory;
 using sk_gpu_test::GLTestContext;
@@ -175,6 +204,12 @@
     }
 };
 
+static void dump_json() {
+    if (!FLAGS_writePath.isEmpty()) {
+        JsonWriter::DumpJson(FLAGS_writePath[0], FLAGS_key, FLAGS_properties);
+    }
+}
+
 // We use a spinlock to make locking this in a signal handler _somewhat_ safe.
 static SkSpinlock        gMutex;
 static int               gPending;
@@ -198,7 +233,7 @@
     // We write out dm.json file and print out a progress update every once in a while.
     // Notice this also handles the final dm.json and progress update when pending == 0.
     if (pending % 500 == 0) {
-        JsonWriter::DumpJson();
+        dump_json();
 
         int curr = sk_tools::getCurrResidentSetSizeMB(),
             peak = sk_tools::getMaxResidentSetSizeMB();
@@ -1426,8 +1461,9 @@
         }
 
         const char* dir = FLAGS_writePath[0];
+        SkString resources = GetResourcePath();
         if (0 == strcmp(dir, "@")) {  // Needed for iOS.
-            dir = FLAGS_resourcePath[0];
+            dir = resources.c_str();
         }
         sk_mkdir(dir);
 
@@ -1556,7 +1592,8 @@
     GrContextOptions grCtxOptions;
     SetCtxOptionsFromCommonFlags(&grCtxOptions);
 
-    JsonWriter::DumpJson();  // It's handy for the bots to assume this is ~never missing.
+    dump_json();  // It's handy for the bots to assume this is ~never missing.
+
     SkAutoGraphics ag;
     SkTaskGroup::Enabler enabled(FLAGS_threads);
 
@@ -1624,7 +1661,7 @@
     // We'd better have run everything.
     SkASSERT(gPending == 0);
     // Make sure we've flushed all our results to disk.
-    JsonWriter::DumpJson();
+    dump_json();
 
     if (gFailures.count() > 0) {
         info("Failures:\n");
diff --git a/dm/DMJsonWriter.cpp b/dm/DMJsonWriter.cpp
index 573a302..3c6c42e 100644
--- a/dm/DMJsonWriter.cpp
+++ b/dm/DMJsonWriter.cpp
@@ -7,7 +7,6 @@
 
 #include "DMJsonWriter.h"
 
-#include "CommonFlags.h"
 #include "ProcStats.h"
 #include "SkData.h"
 #include "SkJSON.h"
@@ -36,25 +35,27 @@
     gFailures.push_back(failure);
 }
 
-void JsonWriter::DumpJson() {
-    if (FLAGS_writePath.isEmpty()) {
+void JsonWriter::DumpJson(const char* dir,
+                          CommandLineFlags::StringArray key,
+                          CommandLineFlags::StringArray properties) {
+    if (0 == strcmp(dir, "")) {
         return;
     }
 
-    SkString path = SkOSPath::Join(FLAGS_writePath[0], "dm.json");
-    sk_mkdir(FLAGS_writePath[0]);
+    SkString path = SkOSPath::Join(dir, "dm.json");
+    sk_mkdir(dir);
     SkFILEWStream stream(path.c_str());
     SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty);
 
     writer.beginObject(); // root
 
-    for (int i = 1; i < FLAGS_properties.count(); i += 2) {
-        writer.appendString(FLAGS_properties[i-1], FLAGS_properties[i]);
+    for (int i = 1; i < properties.count(); i += 2) {
+        writer.appendString(properties[i-1], properties[i]);
     }
 
     writer.beginObject("key");
-    for (int i = 1; i < FLAGS_key.count(); i += 2) {
-        writer.appendString(FLAGS_key[i-1], FLAGS_key[i]);
+    for (int i = 1; i < key.count(); i += 2) {
+        writer.appendString(key[i-1], key[i]);
     }
     writer.endObject();
 
diff --git a/dm/DMJsonWriter.h b/dm/DMJsonWriter.h
index 9e99861..1248c59 100644
--- a/dm/DMJsonWriter.h
+++ b/dm/DMJsonWriter.h
@@ -8,6 +8,7 @@
 #ifndef DMJsonWriter_DEFINED
 #define DMJsonWriter_DEFINED
 
+#include "CommandLineFlags.h"
 #include "SkString.h"
 #include "Test.h"
 
@@ -47,9 +48,11 @@
     static void AddTestFailure(const skiatest::Failure&);
 
     /**
-     *  Write all collected results to the file FLAGS_writePath[0]/dm.json.
+     *  Write all collected results to the file dir/dm.json.
      */
-    static void DumpJson();
+    static void DumpJson(const char* dir,
+                         CommandLineFlags::StringArray key,
+                         CommandLineFlags::StringArray properties);
 
     /**
      * Read JSON file at path written by DumpJson, calling callback for each
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 27d7224..41a36a4 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -6,7 +6,6 @@
  */
 
 #include "DMSrcSink.h"
-#include "CommonFlags.h"
 #include "DDLPromiseImageHelper.h"
 #include "DDLTileHelper.h"
 #include "DebugCanvas.h"
diff --git a/fuzz/FuzzGradients.cpp b/fuzz/FuzzGradients.cpp
index 8716888..35b623a 100644
--- a/fuzz/FuzzGradients.cpp
+++ b/fuzz/FuzzGradients.cpp
@@ -5,7 +5,7 @@
  * found in the LICENSE file.
  */
 
-#include "CommonFlags.h"
+#include "CommandLineFlags.h"
 #include "Fuzz.h"
 #include "SkCanvas.h"
 #include "SkGradientShader.h"
@@ -15,6 +15,8 @@
 #include <algorithm>
 #include <vector>
 
+static DEFINE_bool2(verbose, v, false, "log verbose linear gradient description");
+
 const int MAX_COUNT = 400;
 
 void makeMatrix(Fuzz* fuzz, SkMatrix* m) {
diff --git a/fuzz/oss_fuzz/FuzzGradients.cpp b/fuzz/oss_fuzz/FuzzGradients.cpp
index 0694802..238abde 100644
--- a/fuzz/oss_fuzz/FuzzGradients.cpp
+++ b/fuzz/oss_fuzz/FuzzGradients.cpp
@@ -9,7 +9,6 @@
 
 void fuzz_Gradients(Fuzz* f);
 
-bool FLAGS_verbose = false;
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
     auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size));
     fuzz_Gradients(&fuzz);
diff --git a/tests/CodecPriv.h b/tests/CodecPriv.h
index e447e78..d4457b9 100644
--- a/tests/CodecPriv.h
+++ b/tests/CodecPriv.h
@@ -7,7 +7,7 @@
 #ifndef CodecPriv_DEFINED
 #define CodecPriv_DEFINED
 
-#include "CommonFlags.h"
+#include "CommandLineFlags.h"
 #include "SkBitmap.h"
 #include "SkCodec.h"
 #include "SkData.h"
@@ -16,6 +16,9 @@
 #include "SkOSPath.h"
 #include "SkStream.h"
 
+static DEFINE_string(codecWritePath, "",
+                     "Dump image decodes from codec unit tests here.");
+
 inline bool decode_memory(const void* mem, size_t size, SkBitmap* bm) {
     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(SkData::MakeWithoutCopy(mem, size)));
     if (!codec) {
@@ -29,11 +32,11 @@
 }
 
 inline void write_bm(const char* name, const SkBitmap& bm) {
-    if (FLAGS_writePath.isEmpty()) {
+    if (FLAGS_codecWritePath.isEmpty()) {
         return;
     }
 
-    SkString filename = SkOSPath::Join(FLAGS_writePath[0], name);
+    SkString filename = SkOSPath::Join(FLAGS_codecWritePath[0], name);
     filename.appendf(".png");
     SkFILEWStream file(filename.c_str());
     if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) {
diff --git a/tests/skia_test.cpp b/tests/skia_test.cpp
index 7bd9115..776bd8e 100644
--- a/tests/skia_test.cpp
+++ b/tests/skia_test.cpp
@@ -6,7 +6,7 @@
  */
 
 #include <atomic>
-#include "CommonFlags.h"
+#include "CommandLineFlags.h"
 #include "CrashHandler.h"
 #include "GrContext.h"
 #include "GrContextFactory.h"
@@ -30,10 +30,25 @@
 static DEFINE_bool2(runFail, f, false, "check for success on tests known to fail.");
 static DEFINE_bool2(verifyOp, y, false, "compare the pathOps result against a region.");
 static DEFINE_string2(json, J, "", "write json version of tests.");
+static DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
 static DEFINE_bool2(veryVerbose, V, false, "tell individual tests to be verbose.");
 static DEFINE_bool(cpu, true, "master switch for running CPU-bound work.");
 static DEFINE_bool(gpu, true, "master switch for running GPU-bound work.");
 
+static DEFINE_string2(match, m, nullptr,
+               "[~][^]substring[$] [...] of name to run.\n"
+               "Multiple matches may be separated by spaces.\n"
+               "~ causes a matching name to always be skipped\n"
+               "^ requires the start of the name to match\n"
+               "$ requires the end of the name to match\n"
+               "^ and $ requires an exact match\n"
+               "If a name does not match any list entry,\n"
+               "it is skipped unless some list entry starts with ~");
+
+static DEFINE_int_2(threads, j, -1,
+               "Run threadsafe tests on a threadpool with this many extra threads, "
+               "defaulting to one extra thread per core.");
+
 #if DEBUG_COIN
 static DEFINE_bool2(coinTest, c, false, "detect unused coincidence algorithms.");
 #endif
diff --git a/tools/Resources.cpp b/tools/Resources.cpp
index 8c1f1a6..8d10b59 100644
--- a/tools/Resources.cpp
+++ b/tools/Resources.cpp
@@ -17,7 +17,8 @@
 #include "SkStream.h"
 #include "SkTypeface.h"
 
-DEFINE_string2(resourcePath, i, "resources", "Directory with test resources: images, fonts, etc.");
+static DEFINE_string2(resourcePath, i, "resources",
+                      "Directory with test resources: images, fonts, etc.");
 
 sk_sp<SkData> (*gResourceFactory)(const char*) = nullptr;
 
diff --git a/tools/flags/CommonFlags.cpp b/tools/flags/CommonFlags.cpp
deleted file mode 100644
index 7d42204..0000000
--- a/tools/flags/CommonFlags.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "CommonFlags.h"
-#include "GrContextOptions.h"
-#include "SkExecutor.h"
-#include "SkOSFile.h"
-#include "SkOSPath.h"
-#include "SkOnce.h"
-#include "SkScan.h"
-
-
-DEFINE_string2(match,
-               m,
-               nullptr,
-               "[~][^]substring[$] [...] of name to run.\n"
-               "Multiple matches may be separated by spaces.\n"
-               "~ causes a matching name to always be skipped\n"
-               "^ requires the start of the name to match\n"
-               "$ requires the end of the name to match\n"
-               "^ and $ requires an exact match\n"
-               "If a name does not match any list entry,\n"
-               "it is skipped unless some list entry starts with ~");
-
-DEFINE_bool2(quiet, q, false, "if true, don't print status updates.");
-
-#ifdef SK_BUILD_FOR_ANDROID
-DEFINE_string(skps, "/data/local/tmp/skps", "Directory to read skps from.");
-DEFINE_string(lotties, "/data/local/tmp/lotties", "Directory to read (Bodymovin) jsons from.");
-#else
-DEFINE_string(skps, "skps", "Directory to read skps from.");
-DEFINE_string(lotties, "lotties", "Directory to read (Bodymovin) jsons from.");
-#endif
-
-DEFINE_string(svgs, "", "Directory to read SVGs from, or a single SVG file.");
-
-DEFINE_int_2(threads,
-               j,
-               -1,
-               "Run threadsafe tests on a threadpool with this many extra threads, "
-               "defaulting to one extra thread per core.");
-
-DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
-
-DEFINE_string2(writePath, w, "", "If set, write bitmaps here as .pngs.");
-
-DEFINE_string(key, "", "Space-separated key/value pairs to add to JSON identifying this builder.");
-DEFINE_string(properties,
-              "",
-              "Space-separated key/value pairs to add to JSON identifying this run.");
-
-bool CollectImages(CommandLineFlags::StringArray images, SkTArray<SkString>* output) {
-    SkASSERT(output);
-
-    static const char* const exts[] = {
-        "bmp",
-        "gif",
-        "jpg",
-        "jpeg",
-        "png",
-        "webp",
-        "ktx",
-        "astc",
-        "wbmp",
-        "ico",
-#if !defined(SK_BUILD_FOR_WIN)
-        "BMP",
-        "GIF",
-        "JPG",
-        "JPEG",
-        "PNG",
-        "WEBP",
-        "KTX",
-        "ASTC",
-        "WBMP",
-        "ICO",
-#endif
-#ifdef SK_HAS_HEIF_LIBRARY
-        "heic",
-#if !defined(SK_BUILD_FOR_WIN)
-        "HEIC",
-#endif
-#endif
-#ifdef SK_CODEC_DECODES_RAW
-        "arw",
-        "cr2",
-        "dng",
-        "nef",
-        "nrw",
-        "orf",
-        "raf",
-        "rw2",
-        "pef",
-        "srw",
-#if !defined(SK_BUILD_FOR_WIN)
-        "ARW",
-        "CR2",
-        "DNG",
-        "NEF",
-        "NRW",
-        "ORF",
-        "RAF",
-        "RW2",
-        "PEF",
-        "SRW",
-#endif
-#endif
-    };
-
-    for (int i = 0; i < images.count(); ++i) {
-        const char* flag = images[i];
-        if (!sk_exists(flag)) {
-            SkDebugf("%s does not exist!\n", flag);
-            return false;
-        }
-
-        if (sk_isdir(flag)) {
-            // If the value passed in is a directory, add all the images
-            bool foundAnImage = false;
-            for (const char* ext : exts) {
-                SkOSFile::Iter it(flag, ext);
-                SkString       file;
-                while (it.next(&file)) {
-                    foundAnImage        = true;
-                    output->push_back() = SkOSPath::Join(flag, file.c_str());
-                }
-            }
-            if (!foundAnImage) {
-                SkDebugf("No supported images found in %s!\n", flag);
-                return false;
-            }
-        } else {
-            // Also add the value if it is a single image
-            output->push_back() = flag;
-        }
-    }
-    return true;
-}
-
-DEFINE_int(gpuThreads,
-             2,
-             "Create this many extra threads to assist with GPU work, "
-             "including software path rendering. Defaults to two.");
-
-static DEFINE_bool(cachePathMasks, true,
-                   "Allows path mask textures to be cached in GPU configs.");
-
-static DEFINE_bool(noGS, false, "Disables support for geometry shaders.");
-
-static DEFINE_string(pr, "",
-              "Set of enabled gpu path renderers. Defined as a list of: "
-              "[~]none [~]dashline [~]nvpr [~]ccpr [~]aahairline [~]aaconvex [~]aalinearizing "
-              "[~]small [~]tess] [~]all");
-
-static DEFINE_bool(disableDriverCorrectnessWorkarounds, false,
-                   "Disables all GPU driver correctness workarounds");
-
-static DEFINE_bool(reduceOpListSplitting, false, "Improve opList sorting");
-
-
-static GpuPathRenderers get_named_pathrenderers_flags(const char* name) {
-    if (!strcmp(name, "none")) {
-        return GpuPathRenderers::kNone;
-    } else if (!strcmp(name, "dashline")) {
-        return GpuPathRenderers::kDashLine;
-    } else if (!strcmp(name, "nvpr")) {
-        return GpuPathRenderers::kStencilAndCover;
-    } else if (!strcmp(name, "ccpr")) {
-        return GpuPathRenderers::kCoverageCounting;
-    } else if (!strcmp(name, "aahairline")) {
-        return GpuPathRenderers::kAAHairline;
-    } else if (!strcmp(name, "aaconvex")) {
-        return GpuPathRenderers::kAAConvex;
-    } else if (!strcmp(name, "aalinearizing")) {
-        return GpuPathRenderers::kAALinearizing;
-    } else if (!strcmp(name, "small")) {
-        return GpuPathRenderers::kSmall;
-    } else if (!strcmp(name, "tess")) {
-        return GpuPathRenderers::kTessellating;
-    } else if (!strcmp(name, "all")) {
-        return GpuPathRenderers::kAll;
-    }
-    SK_ABORT(SkStringPrintf("error: unknown named path renderer \"%s\"\n", name).c_str());
-    return GpuPathRenderers::kNone;
-}
-
-static GpuPathRenderers collect_gpu_path_renderers_from_flags() {
-    if (FLAGS_pr.isEmpty()) {
-        return GpuPathRenderers::kDefault;
-    }
-    GpuPathRenderers gpuPathRenderers = ('~' == FLAGS_pr[0][0])
-        ? GpuPathRenderers::kDefault
-        : GpuPathRenderers::kNone;
-
-    for (int i = 0; i < FLAGS_pr.count(); ++i) {
-        const char* name = FLAGS_pr[i];
-        if (name[0] == '~') {
-            gpuPathRenderers &= ~get_named_pathrenderers_flags(&name[1]);
-        } else {
-            gpuPathRenderers |= get_named_pathrenderers_flags(name);
-        }
-    }
-    return gpuPathRenderers;
-}
-
-void SetCtxOptionsFromCommonFlags(GrContextOptions* ctxOptions) {
-    static std::unique_ptr<SkExecutor> gGpuExecutor = (0 != FLAGS_gpuThreads)
-        ? SkExecutor::MakeFIFOThreadPool(FLAGS_gpuThreads)
-        : nullptr;
-
-    ctxOptions->fExecutor                            = gGpuExecutor.get();
-    ctxOptions->fAllowPathMaskCaching                = FLAGS_cachePathMasks;
-    ctxOptions->fSuppressGeometryShaders             = FLAGS_noGS;
-    ctxOptions->fGpuPathRenderers                    = collect_gpu_path_renderers_from_flags();
-    ctxOptions->fDisableDriverCorrectnessWorkarounds = FLAGS_disableDriverCorrectnessWorkarounds;
-
-    if (FLAGS_reduceOpListSplitting) {
-        ctxOptions->fReduceOpListSplitting = GrContextOptions::Enable::kYes;
-    }
-}
-
-static DEFINE_bool(analyticAA, true, "If false, disable analytic anti-aliasing");
-
-static DEFINE_bool(forceAnalyticAA, false,
-            "Force analytic anti-aliasing even if the path is complicated: "
-            "whether it's concave or convex, we consider a path complicated"
-            "if its number of points is comparable to its resolution.");
-
-void SetAnalyticAAFromCommonFlags() {
-    gSkUseAnalyticAA   = FLAGS_analyticAA;
-    gSkForceAnalyticAA = FLAGS_forceAnalyticAA;
-}
diff --git a/tools/flags/CommonFlags.h b/tools/flags/CommonFlags.h
index 04581e0..df6f218 100644
--- a/tools/flags/CommonFlags.h
+++ b/tools/flags/CommonFlags.h
@@ -4,26 +4,12 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-
-#ifndef SK_COMMON_FLAGS_H
-#define SK_COMMON_FLAGS_H
+#pragma once
 
 #include "../private/SkTArray.h"
 #include "CommandLineFlags.h"
 #include "SkString.h"
 
-DECLARE_string(match);
-DECLARE_bool(quiet);
-DECLARE_string(skps);
-DECLARE_string(lotties);
-DECLARE_string(svgs);
-DECLARE_int(threads);
-DECLARE_string(resourcePath);
-DECLARE_bool(verbose);
-DECLARE_string(writePath);
-DECLARE_string(key);
-DECLARE_string(properties);
-
 /**
  *  Helper to assist in collecting image paths from |dir| specified through a command line
  * flag.
@@ -53,5 +39,3 @@
  *  Enable, disable, or force analytic anti-aliasing using --analyticAA and --forceAnalyticAA.
  */
 void SetAnalyticAAFromCommonFlags();
-
-#endif
diff --git a/tools/flags/CommonFlagsAA.cpp b/tools/flags/CommonFlagsAA.cpp
new file mode 100644
index 0000000..651fecf
--- /dev/null
+++ b/tools/flags/CommonFlagsAA.cpp
@@ -0,0 +1,16 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "CommonFlags.h"
+#include "SkScan.h"
+
+static DEFINE_bool(analyticAA, true, "If false, disable analytic anti-aliasing");
+static DEFINE_bool(forceAnalyticAA, false,
+            "Force analytic anti-aliasing even if the path is complicated: "
+            "whether it's concave or convex, we consider a path complicated"
+            "if its number of points is comparable to its resolution.");
+
+void SetAnalyticAAFromCommonFlags() {
+    gSkUseAnalyticAA   = FLAGS_analyticAA;
+    gSkForceAnalyticAA = FLAGS_forceAnalyticAA;
+}
diff --git a/tools/flags/CommonFlagsGpu.cpp b/tools/flags/CommonFlagsGpu.cpp
new file mode 100644
index 0000000..3c5393a
--- /dev/null
+++ b/tools/flags/CommonFlagsGpu.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "CommonFlags.h"
+#include "GrContextOptions.h"
+#include "SkExecutor.h"
+
+
+DEFINE_int(gpuThreads,
+             2,
+             "Create this many extra threads to assist with GPU work, "
+             "including software path rendering. Defaults to two.");
+
+static DEFINE_bool(cachePathMasks, true,
+                   "Allows path mask textures to be cached in GPU configs.");
+
+static DEFINE_bool(noGS, false, "Disables support for geometry shaders.");
+
+static DEFINE_string(pr, "",
+              "Set of enabled gpu path renderers. Defined as a list of: "
+              "[~]none [~]dashline [~]nvpr [~]ccpr [~]aahairline [~]aaconvex [~]aalinearizing "
+              "[~]small [~]tess] [~]all");
+
+static DEFINE_bool(disableDriverCorrectnessWorkarounds, false,
+                   "Disables all GPU driver correctness workarounds");
+
+static DEFINE_bool(reduceOpListSplitting, false, "Improve opList sorting");
+
+
+static GpuPathRenderers get_named_pathrenderers_flags(const char* name) {
+    if (!strcmp(name, "none")) {
+        return GpuPathRenderers::kNone;
+    } else if (!strcmp(name, "dashline")) {
+        return GpuPathRenderers::kDashLine;
+    } else if (!strcmp(name, "nvpr")) {
+        return GpuPathRenderers::kStencilAndCover;
+    } else if (!strcmp(name, "ccpr")) {
+        return GpuPathRenderers::kCoverageCounting;
+    } else if (!strcmp(name, "aahairline")) {
+        return GpuPathRenderers::kAAHairline;
+    } else if (!strcmp(name, "aaconvex")) {
+        return GpuPathRenderers::kAAConvex;
+    } else if (!strcmp(name, "aalinearizing")) {
+        return GpuPathRenderers::kAALinearizing;
+    } else if (!strcmp(name, "small")) {
+        return GpuPathRenderers::kSmall;
+    } else if (!strcmp(name, "tess")) {
+        return GpuPathRenderers::kTessellating;
+    } else if (!strcmp(name, "all")) {
+        return GpuPathRenderers::kAll;
+    }
+    SK_ABORT(SkStringPrintf("error: unknown named path renderer \"%s\"\n", name).c_str());
+    return GpuPathRenderers::kNone;
+}
+
+static GpuPathRenderers collect_gpu_path_renderers_from_flags() {
+    if (FLAGS_pr.isEmpty()) {
+        return GpuPathRenderers::kDefault;
+    }
+    GpuPathRenderers gpuPathRenderers = ('~' == FLAGS_pr[0][0])
+        ? GpuPathRenderers::kDefault
+        : GpuPathRenderers::kNone;
+
+    for (int i = 0; i < FLAGS_pr.count(); ++i) {
+        const char* name = FLAGS_pr[i];
+        if (name[0] == '~') {
+            gpuPathRenderers &= ~get_named_pathrenderers_flags(&name[1]);
+        } else {
+            gpuPathRenderers |= get_named_pathrenderers_flags(name);
+        }
+    }
+    return gpuPathRenderers;
+}
+
+void SetCtxOptionsFromCommonFlags(GrContextOptions* ctxOptions) {
+    static std::unique_ptr<SkExecutor> gGpuExecutor = (0 != FLAGS_gpuThreads)
+        ? SkExecutor::MakeFIFOThreadPool(FLAGS_gpuThreads)
+        : nullptr;
+
+    ctxOptions->fExecutor                            = gGpuExecutor.get();
+    ctxOptions->fAllowPathMaskCaching                = FLAGS_cachePathMasks;
+    ctxOptions->fSuppressGeometryShaders             = FLAGS_noGS;
+    ctxOptions->fGpuPathRenderers                    = collect_gpu_path_renderers_from_flags();
+    ctxOptions->fDisableDriverCorrectnessWorkarounds = FLAGS_disableDriverCorrectnessWorkarounds;
+
+    if (FLAGS_reduceOpListSplitting) {
+        ctxOptions->fReduceOpListSplitting = GrContextOptions::Enable::kYes;
+    }
+}
diff --git a/tools/flags/CommonFlagsImages.cpp b/tools/flags/CommonFlagsImages.cpp
new file mode 100644
index 0000000..a89c989
--- /dev/null
+++ b/tools/flags/CommonFlagsImages.cpp
@@ -0,0 +1,94 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "CommonFlags.h"
+#include "SkOSFile.h"
+#include "SkOSPath.h"
+
+bool CollectImages(CommandLineFlags::StringArray images, SkTArray<SkString>* output) {
+    SkASSERT(output);
+
+    static const char* const exts[] = {
+        "bmp",
+        "gif",
+        "jpg",
+        "jpeg",
+        "png",
+        "webp",
+        "ktx",
+        "astc",
+        "wbmp",
+        "ico",
+#if !defined(SK_BUILD_FOR_WIN)
+        "BMP",
+        "GIF",
+        "JPG",
+        "JPEG",
+        "PNG",
+        "WEBP",
+        "KTX",
+        "ASTC",
+        "WBMP",
+        "ICO",
+#endif
+#ifdef SK_HAS_HEIF_LIBRARY
+        "heic",
+#if !defined(SK_BUILD_FOR_WIN)
+        "HEIC",
+#endif
+#endif
+#ifdef SK_CODEC_DECODES_RAW
+        "arw",
+        "cr2",
+        "dng",
+        "nef",
+        "nrw",
+        "orf",
+        "raf",
+        "rw2",
+        "pef",
+        "srw",
+#if !defined(SK_BUILD_FOR_WIN)
+        "ARW",
+        "CR2",
+        "DNG",
+        "NEF",
+        "NRW",
+        "ORF",
+        "RAF",
+        "RW2",
+        "PEF",
+        "SRW",
+#endif
+#endif
+    };
+
+    for (int i = 0; i < images.count(); ++i) {
+        const char* flag = images[i];
+        if (!sk_exists(flag)) {
+            SkDebugf("%s does not exist!\n", flag);
+            return false;
+        }
+
+        if (sk_isdir(flag)) {
+            // If the value passed in is a directory, add all the images
+            bool foundAnImage = false;
+            for (const char* ext : exts) {
+                SkOSFile::Iter it(flag, ext);
+                SkString       file;
+                while (it.next(&file)) {
+                    foundAnImage        = true;
+                    output->push_back() = SkOSPath::Join(flag, file.c_str());
+                }
+            }
+            if (!foundAnImage) {
+                SkDebugf("No supported images found in %s!\n", flag);
+                return false;
+            }
+        } else {
+            // Also add the value if it is a single image
+            output->push_back() = flag;
+        }
+    }
+    return true;
+}
diff --git a/tools/fonts/ToolUtilsFont.cpp b/tools/fonts/ToolUtilsFont.cpp
index d159c51..7d00682 100644
--- a/tools/fonts/ToolUtilsFont.cpp
+++ b/tools/fonts/ToolUtilsFont.cpp
@@ -7,7 +7,6 @@
 
 #include "ToolUtils.h"
 
-#include "CommonFlags.h"
 #include "Resources.h"
 #include "SkFontMgr.h"
 #include "SkFontStyle.h"
diff --git a/tools/viewer/SKPSlide.cpp b/tools/viewer/SKPSlide.cpp
index 2f7efce..caf18cd 100644
--- a/tools/viewer/SKPSlide.cpp
+++ b/tools/viewer/SKPSlide.cpp
@@ -7,7 +7,6 @@
 
 #include "SKPSlide.h"
 
-#include "CommonFlags.h"
 #include "SkCanvas.h"
 #include "SkOSFile.h"
 #include "SkStream.h"
diff --git a/tools/viewer/SampleSlide.cpp b/tools/viewer/SampleSlide.cpp
index 39ad265..f48f1dc 100644
--- a/tools/viewer/SampleSlide.cpp
+++ b/tools/viewer/SampleSlide.cpp
@@ -7,7 +7,6 @@
 
 #include "SampleSlide.h"
 
-#include "CommonFlags.h"
 #include "SkCanvas.h"
 #include "SkOSFile.h"
 #include "SkStream.h"
diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp
index f222a37..86782db 100644
--- a/tools/viewer/Viewer.cpp
+++ b/tools/viewer/Viewer.cpp
@@ -76,18 +76,38 @@
 
 static DEFINE_string(bisect, "", "Path to a .skp or .svg file to bisect.");
 
-DECLARE_int(threads)
-
 static DEFINE_string2(file, f, "", "Open a single file for viewing.");
 
+static DEFINE_string2(match, m, nullptr,
+               "[~][^]substring[$] [...] of name to run.\n"
+               "Multiple matches may be separated by spaces.\n"
+               "~ causes a matching name to always be skipped\n"
+               "^ requires the start of the name to match\n"
+               "$ requires the end of the name to match\n"
+               "^ and $ requires an exact match\n"
+               "If a name does not match any list entry,\n"
+               "it is skipped unless some list entry starts with ~");
+
 #if defined(SK_BUILD_FOR_ANDROID)
     static DEFINE_string(jpgs, "/data/local/tmp/resources", "Directory to read jpgs from.");
     static DEFINE_string(nimas, "/data/local/tmp/nimas", "Directory to read NIMA animations from.");
+    static DEFINE_string(skps, "/data/local/tmp/skps", "Directory to read skps from.");
+    static DEFINE_string(lotties, "/data/local/tmp/lotties",
+                         "Directory to read (Bodymovin) jsons from.");
 #else
     static DEFINE_string(jpgs, "jpgs", "Directory to read jpgs from.");
     static DEFINE_string(nimas, "nimas", "Directory to read NIMA animations from.");
+    static DEFINE_string(skps, "skps", "Directory to read skps from.");
+    static DEFINE_string(lotties, "lotties", "Directory to read (Bodymovin) jsons from.");
 #endif
 
+static DEFINE_string(svgs, "", "Directory to read SVGs from, or a single SVG file.");
+
+static DEFINE_int_2(threads, j, -1,
+               "Run threadsafe tests on a threadpool with this many extra threads, "
+               "defaulting to one extra thread per core.");
+
+
 const char* kBackendTypeStrings[sk_app::Window::kBackendTypeCount] = {
     "OpenGL",
 #if SK_ANGLE && defined(SK_BUILD_FOR_WIN)