Separate JSON functions from DMWriteTask.

Add JsonWriter, which handles Json output from DM, in preparation for
adding json output for tests. This change should not affect behavior.

BUG=skia:2454

Review URL: https://codereview.chromium.org/702513003
diff --git a/dm/DM.cpp b/dm/DM.cpp
index d309db1..2a0c636 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -18,13 +18,13 @@
 #include "DMCpuGMTask.h"
 #include "DMGpuGMTask.h"
 #include "DMGpuSupport.h"
+#include "DMJsonWriter.h"
 #include "DMPDFTask.h"
 #include "DMReporter.h"
 #include "DMSKPTask.h"
 #include "DMTask.h"
 #include "DMTaskRunner.h"
 #include "DMTestTask.h"
-#include "DMWriteTask.h"
 
 #ifdef SK_BUILD_POPPLER
 #  include "SkPDFRasterizer.h"
@@ -229,7 +229,7 @@
     kick_off_skps(skps, &reporter, &tasks);
     tasks.wait();
 
-    DM::WriteTask::DumpJson();
+    DM::JsonWriter::DumpJson();
 
     SkDebugf("\n");
 #ifdef SK_DEBUG
diff --git a/dm/DMJsonWriter.cpp b/dm/DMJsonWriter.cpp
new file mode 100644
index 0000000..f862647
--- /dev/null
+++ b/dm/DMJsonWriter.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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 "DMJsonWriter.h"
+
+#include "SkCommonFlags.h"
+#include "SkJSONCPP.h"
+#include "SkOSFile.h"
+#include "SkStream.h"
+#include "SkTArray.h"
+#include "SkThread.h"
+
+namespace DM {
+
+SkTArray<JsonWriter::BitmapResult> gBitmapResults;
+SK_DECLARE_STATIC_MUTEX(gBitmapResultLock);
+
+void JsonWriter::AddBitmapResult(const BitmapResult& result) {
+    SkAutoMutexAcquire lock(&gBitmapResultLock);
+    gBitmapResults.push_back(result);
+}
+
+void JsonWriter::DumpJson() {
+    if (FLAGS_writePath.isEmpty()) {
+        return;
+    }
+
+    Json::Value root;
+
+    for (int i = 1; i < FLAGS_properties.count(); i += 2) {
+        root[FLAGS_properties[i-1]] = FLAGS_properties[i];
+    }
+    for (int i = 1; i < FLAGS_key.count(); i += 2) {
+        root["key"][FLAGS_key[i-1]] = FLAGS_key[i];
+    }
+
+    {
+        SkAutoMutexAcquire lock(&gBitmapResultLock);
+        for (int i = 0; i < gBitmapResults.count(); i++) {
+            Json::Value result;
+            result["key"]["name"]            = gBitmapResults[i].name.c_str();
+            result["key"]["config"]          = gBitmapResults[i].config.c_str();
+            result["key"]["mode"]            = gBitmapResults[i].mode.c_str();
+            result["options"]["source_type"] = gBitmapResults[i].sourceType.c_str();
+            result["md5"]                    = gBitmapResults[i].md5.c_str();
+
+            root["results"].append(result);
+        }
+    }
+
+    SkString path = SkOSPath::Join(FLAGS_writePath[0], "dm.json");
+    SkFILEWStream stream(path.c_str());
+    stream.writeText(Json::StyledWriter().write(root).c_str());
+    stream.flush();
+}
+
+} // namespace DM
diff --git a/dm/DMJsonWriter.h b/dm/DMJsonWriter.h
new file mode 100644
index 0000000..c358fdd
--- /dev/null
+++ b/dm/DMJsonWriter.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef DMJsonWriter_DEFINED
+#define DMJsonWriter_DEFINED
+
+#include "SkString.h"
+
+namespace DM {
+
+/**
+ *  Class for collecting results from DM and writing to a json file.
+ *  All methods are thread-safe.
+ */
+class JsonWriter {
+public:
+    /**
+     *  Info describing a single run.
+     */
+    struct BitmapResult {
+        SkString name;            // E.g. "ninepatch-stretch", "desk-gws_skp"
+        SkString config;          //      "gpu", "8888"
+        SkString mode;            //      "direct", "default-tilegrid", "pipe"
+        SkString sourceType;      //      "GM", "SKP"
+        SkString md5;             // In ASCII, so 32 bytes long.
+    };
+
+    /**
+     *  Add a result to the end of the list of results.
+     */
+    static void AddBitmapResult(const BitmapResult&);
+
+    /**
+     *  Write all collected results to the file FLAGS_writePath[0]/dm.json.
+     */
+    static void DumpJson();
+};
+
+} // namespace DM
+#endif // DMJsonWriter_DEFINED
diff --git a/dm/DMWriteTask.cpp b/dm/DMWriteTask.cpp
index 35ae2a7..fa0d129 100644
--- a/dm/DMWriteTask.cpp
+++ b/dm/DMWriteTask.cpp
@@ -1,5 +1,6 @@
 #include "DMWriteTask.h"
 
+#include "DMJsonWriter.h"
 #include "DMUtil.h"
 #include "SkColorPriv.h"
 #include "SkCommonFlags.h"
@@ -91,16 +92,6 @@
     return get_md5_string(&hasher);
 }
 
-struct JsonData {
-    SkString name;            // E.g. "ninepatch-stretch", "desk-gws_skp"
-    SkString config;          //      "gpu", "8888"
-    SkString mode;            //      "direct", "default-tilegrid", "pipe"
-    SkString sourceType;      //      "GM", "SKP"
-    SkString md5;             // In ASCII, so 32 bytes long.
-};
-SkTArray<JsonData> gJsonData;
-SK_DECLARE_STATIC_MUTEX(gJsonDataLock);
-
 void WriteTask::draw() {
     SkString md5;
     {
@@ -116,10 +107,13 @@
         mode = fSuffixes.fromBack(1);
     }
 
-    JsonData entry = { fBaseName, config, mode, fSourceType, md5 };
     {
-        SkAutoMutexAcquire lock(&gJsonDataLock);
-        gJsonData.push_back(entry);
+        const JsonWriter::BitmapResult entry = { fBaseName,
+                                                 config,
+                                                 mode,
+                                                 fSourceType,
+                                                 md5 };
+        JsonWriter::AddBitmapResult(entry);
     }
 
     SkString dir(FLAGS_writePath[0]);
@@ -178,38 +172,4 @@
     return FLAGS_writePath.isEmpty();
 }
 
-void WriteTask::DumpJson() {
-    if (FLAGS_writePath.isEmpty()) {
-        return;
-    }
-
-    Json::Value root;
-
-    for (int i = 1; i < FLAGS_properties.count(); i += 2) {
-        root[FLAGS_properties[i-1]] = FLAGS_properties[i];
-    }
-    for (int i = 1; i < FLAGS_key.count(); i += 2) {
-        root["key"][FLAGS_key[i-1]] = FLAGS_key[i];
-    }
-
-    {
-        SkAutoMutexAcquire lock(&gJsonDataLock);
-        for (int i = 0; i < gJsonData.count(); i++) {
-            Json::Value result;
-            result["key"]["name"]            = gJsonData[i].name.c_str();
-            result["key"]["config"]          = gJsonData[i].config.c_str();
-            result["key"]["mode"]            = gJsonData[i].mode.c_str();
-            result["options"]["source_type"] = gJsonData[i].sourceType.c_str();
-            result["md5"]                    = gJsonData[i].md5.c_str();
-
-            root["results"].append(result);
-        }
-    }
-
-    SkString path = SkOSPath::Join(FLAGS_writePath[0], "dm.json");
-    SkFILEWStream stream(path.c_str());
-    stream.writeText(Json::StyledWriter().write(root).c_str());
-    stream.flush();
-}
-
 }  // namespace DM
diff --git a/dm/DMWriteTask.h b/dm/DMWriteTask.h
index d2403ad..c6ef1cb 100644
--- a/dm/DMWriteTask.h
+++ b/dm/DMWriteTask.h
@@ -3,7 +3,6 @@
 
 #include "DMTask.h"
 #include "SkBitmap.h"
-#include "SkJSONCPP.h"
 #include "SkStream.h"
 #include "SkString.h"
 #include "SkTArray.h"
@@ -30,8 +29,6 @@
     virtual bool shouldSkip() const SK_OVERRIDE;
     virtual SkString name() const SK_OVERRIDE;
 
-    static void DumpJson();
-
 private:
     SkTArray<SkString> fSuffixes;
     const SkString fBaseName;
diff --git a/gyp/dm.gypi b/gyp/dm.gypi
index 932f430..4aa6b4a 100644
--- a/gyp/dm.gypi
+++ b/gyp/dm.gypi
@@ -32,6 +32,7 @@
     '../dm/DMCpuGMTask.cpp',
     '../dm/DMGpuGMTask.cpp',
     '../dm/DMPDFRasterizeTask.cpp',
+    '../dm/DMJsonWriter.cpp',
     '../dm/DMPDFTask.cpp',
     '../dm/DMPipeTask.cpp',
     '../dm/DMQuiltTask.cpp',