Reland r9682, using new SkString::appendU64()

Review URL: https://codereview.chromium.org/17157005

git-svn-id: http://skia.googlecode.com/svn/trunk@9687 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index 443a26b..42b7bda 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -191,7 +191,8 @@
 
 class GMMain {
 public:
-    GMMain() : fUseFileHierarchy(false), fIgnorableErrorTypes(kDefaultIgnorableErrorTypes),
+    GMMain() : fUseFileHierarchy(false), fWriteChecksumBasedFilenames(false),
+               fIgnorableErrorTypes(kDefaultIgnorableErrorTypes),
                fMismatchPath(NULL), fTestsRun(0), fRenderModesEncountered(1) {}
 
     /**
@@ -228,6 +229,30 @@
         return SkOSPath::SkPathJoin(path, filename.c_str());
     }
 
+    /**
+     * Assemble filename suitable for writing out an SkBitmap.
+     */
+    SkString make_bitmap_filename(const char *path,
+                                  const char *shortName,
+                                  const char *configName,
+                                  const char *renderModeDescriptor,
+                                  const GmResultDigest &bitmapDigest) {
+        if (fWriteChecksumBasedFilenames) {
+            SkString filename;
+            filename.append(bitmapDigest.getHashType());
+            filename.appendUnichar('_');
+            filename.append(shortName);
+            filename.appendUnichar('_');
+            filename.append(bitmapDigest.getDigestValue());
+            filename.appendUnichar('.');
+            filename.append(kPNG_FileExtension);
+            return SkOSPath::SkPathJoin(path, filename.c_str());
+        } else {
+            return make_filename(path, shortName, configName, renderModeDescriptor,
+                                 kPNG_FileExtension);
+        }
+    }
+
     /* since PNG insists on unpremultiplying our alpha, we take no
        precision chances and force all pixels to be 100% opaque,
        otherwise on compare we may not get a perfect match.
@@ -637,7 +662,8 @@
 
     ErrorCombination write_reference_image(const ConfigData& gRec, const char writePath [],
                                            const char renderModeDescriptor [],
-                                           const char *shortName, SkBitmap& bitmap,
+                                           const char *shortName,
+                                           const BitmapAndDigest& bitmapAndDigest,
                                            SkDynamicMemoryWStream* document) {
         SkString path;
         bool success = false;
@@ -645,9 +671,9 @@
             gRec.fBackend == kGPU_Backend ||
             (gRec.fBackend == kPDF_Backend && CAN_IMAGE_PDF)) {
 
-            path = make_filename(writePath, shortName, gRec.fName, renderModeDescriptor,
-                                 kPNG_FileExtension);
-            success = write_bitmap(path, bitmap);
+            path = make_bitmap_filename(writePath, shortName, gRec.fName, renderModeDescriptor,
+                                        bitmapAndDigest.fDigest);
+            success = write_bitmap(path, bitmapAndDigest.fBitmap);
         }
         if (kPDF_Backend == gRec.fBackend) {
             path = make_filename(writePath, shortName, gRec.fName, renderModeDescriptor,
@@ -743,7 +769,7 @@
      * actual bitmap will be written out to a file within fMismatchPath.
      *
      * @param expectations what expectations to compare actualBitmap against
-     * @param actualBitmap the image we actually generated
+     * @param actualBitmapAndDigest the SkBitmap we actually generated, and its GmResultDigest
      * @param shortName name of test, e.g. "selftest1"
      * @param configName name of config, e.g. "8888"
      * @param renderModeDescriptor e.g., "-rtree", "-deferred"
@@ -755,12 +781,11 @@
      *        See https://codereview.chromium.org/13650002/ )
      */
     ErrorCombination compare_to_expectations(Expectations expectations,
-                                             const SkBitmap& actualBitmap,
+                                             const BitmapAndDigest& actualBitmapAndDigest,
                                              const char *shortName, const char *configName,
                                              const char *renderModeDescriptor,
                                              bool addToJsonSummary) {
         ErrorCombination errors;
-        GmResultDigest actualResultDigest(actualBitmap);
         SkString shortNamePlusConfig = make_shortname_plus_config(shortName, configName);
         SkString completeNameString(shortNamePlusConfig);
         completeNameString.append(renderModeDescriptor);
@@ -770,7 +795,7 @@
 
         if (expectations.empty()) {
             errors.add(kMissingExpectations_ErrorType);
-        } else if (!expectations.match(actualResultDigest)) {
+        } else if (!expectations.match(actualBitmapAndDigest.fDigest)) {
             addToJsonSummary = true;
             // The error mode we record depends on whether this was running
             // in a non-standard renderMode.
@@ -783,23 +808,24 @@
             // Write out the "actuals" for any mismatches, if we have
             // been directed to do so.
             if (fMismatchPath) {
-                SkString path =
-                    make_filename(fMismatchPath, shortName, configName, renderModeDescriptor,
-                                  kPNG_FileExtension);
-                write_bitmap(path, actualBitmap);
+                SkString path = make_bitmap_filename(fMismatchPath, shortName, configName,
+                                                     renderModeDescriptor,
+                                                     actualBitmapAndDigest.fDigest);
+                write_bitmap(path, actualBitmapAndDigest.fBitmap);
             }
 
             // If we have access to a single expected bitmap, log more
             // detail about the mismatch.
             const SkBitmap *expectedBitmapPtr = expectations.asBitmap();
             if (NULL != expectedBitmapPtr) {
-                report_bitmap_diffs(*expectedBitmapPtr, actualBitmap, completeName);
+                report_bitmap_diffs(*expectedBitmapPtr, actualBitmapAndDigest.fBitmap,
+                                    completeName);
             }
         }
         RecordTestResults(errors, shortNamePlusConfig, renderModeDescriptor);
 
         if (addToJsonSummary) {
-            add_actual_results_to_json_summary(completeName, actualResultDigest, errors,
+            add_actual_results_to_json_summary(completeName, actualBitmapAndDigest.fDigest, errors,
                                                expectations.ignoreFailure());
             add_expected_results_to_json_summary(completeName, expectations);
         }
@@ -874,6 +900,7 @@
         GM* gm, const ConfigData& gRec, const char writePath[],
         SkBitmap& actualBitmap, SkDynamicMemoryWStream* pdf) {
 
+        BitmapAndDigest actualBitmapAndDigest(actualBitmap);
         SkString shortNamePlusConfig = make_shortname_plus_config(gm->shortName(), gRec.fName);
         SkString nameWithExtension(shortNamePlusConfig);
         nameWithExtension.append(".");
@@ -896,13 +923,13 @@
              * See comments above complete_bitmap() for more detail.
              */
             Expectations expectations = expectationsSource->get(nameWithExtension.c_str());
-            errors.add(compare_to_expectations(expectations, actualBitmap,
+            errors.add(compare_to_expectations(expectations, actualBitmapAndDigest,
                                                gm->shortName(), gRec.fName, "", true));
         } else {
             // If we are running without expectations, we still want to
             // record the actual results.
-            GmResultDigest actualResultDigest(actualBitmap);
-            add_actual_results_to_json_summary(nameWithExtension.c_str(), actualResultDigest,
+            add_actual_results_to_json_summary(nameWithExtension.c_str(),
+                                               actualBitmapAndDigest.fDigest,
                                                ErrorCombination(kMissingExpectations_ErrorType),
                                                false);
             RecordTestResults(ErrorCombination(kMissingExpectations_ErrorType),
@@ -915,7 +942,7 @@
         // renderModes of all tests!  That would be a lot of files.
         if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
             errors.add(write_reference_image(gRec, writePath, "", gm->shortName(),
-                                             actualBitmap, pdf));
+                                             actualBitmapAndDigest, pdf));
         }
 
         return errors;
@@ -936,7 +963,8 @@
 
         SkASSERT(referenceBitmap);
         Expectations expectations(*referenceBitmap);
-        return compare_to_expectations(expectations, actualBitmap, shortName,
+        BitmapAndDigest actualBitmapAndDigest(actualBitmap);
+        return compare_to_expectations(expectations, actualBitmapAndDigest, shortName,
                                        configName, renderModeDescriptor, false);
     }
 
@@ -1146,7 +1174,7 @@
     // They are public for now, to allow easier setting by tool_main().
     //
 
-    bool fUseFileHierarchy;
+    bool fUseFileHierarchy, fWriteChecksumBasedFilenames;
     ErrorCombination fIgnorableErrorTypes;
 
     const char* fMismatchPath;
@@ -1306,9 +1334,11 @@
 DEFINE_bool(tileGrid, true, "Exercise the tile grid variant of SkPicture.");
 DEFINE_string(tileGridReplayScales, "", "Space separated list of floating-point scale "
               "factors to be used for tileGrid playback testing. Default value: 1.0");
-DEFINE_string(writeJsonSummaryPath, "", "Write a JSON-formatted result summary to this file.");
 DEFINE_bool2(verbose, v, false, "Give more detail (e.g. list all GMs run, more info about "
              "each test).");
+DEFINE_bool(writeChecksumBasedFilenames, false, "When writing out actual images, use checksum-"
+            "based filenames, as rebaseline.py will use when downloading them from Google Storage");
+DEFINE_string(writeJsonSummaryPath, "", "Write a JSON-formatted result summary to this file.");
 DEFINE_string2(writePath, w, "",  "Write rendered images into this directory.");
 DEFINE_string2(writePicturePath, p, "", "Write .skp files into this directory.");
 DEFINE_int32(pdfJpegQuality, -1, "Encodes images in JPEG at quality level N, "
@@ -1765,6 +1795,7 @@
     SkCommandLineFlags::Parse(argc, argv);
 
     gmmain.fUseFileHierarchy = FLAGS_hierarchy;
+    gmmain.fWriteChecksumBasedFilenames = FLAGS_writeChecksumBasedFilenames;
     if (FLAGS_mismatchPath.count() == 1) {
         gmmain.fMismatchPath = FLAGS_mismatchPath[0];
     }