GM: create GmResultDigest that encapsulates digest type ("bitmap-64bitMD5") and value (12345)

R=scroggo@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@9271 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/gm_expectations.cpp b/gm/gm_expectations.cpp
index 71311d5..8138af7 100644
--- a/gm/gm_expectations.cpp
+++ b/gm/gm_expectations.cpp
@@ -18,11 +18,14 @@
 const static char kJsonKey_ActualResults_FailureIgnored[]= "failure-ignored";
 const static char kJsonKey_ActualResults_NoComparison[]  = "no-comparison";
 const static char kJsonKey_ActualResults_Succeeded[]     = "succeeded";
-const static char kJsonKey_ActualResults_AnyStatus_BitmapHash[]  = "bitmap-64bitMD5";
 
 const static char kJsonKey_ExpectedResults[] = "expected-results";
-const static char kJsonKey_ExpectedResults_AllowedBitmapHashes[] = "allowed-bitmap-64bitMD5s";
-const static char kJsonKey_ExpectedResults_IgnoreFailure[]           = "ignore-failure";
+const static char kJsonKey_ExpectedResults_AllowedDigests[] = "allowed-digests";
+const static char kJsonKey_ExpectedResults_IgnoreFailure[]  = "ignore-failure";
+
+// Types of result hashes we support in the JSON file.
+const static char kJsonKey_Hashtype_Bitmap_64bitMD5[]  = "bitmap-64bitMD5";
+
 
 namespace skiagm {
 
@@ -43,15 +46,6 @@
         return result;
     }
 
-    // TODO(epoger): This currently assumes that the result SkHashDigest was
-    // generated as an SkHashDigest of an SkBitmap.  We'll need to allow for other
-    // hash types to cover non-bitmaps.
-    Json::Value ActualResultAsJsonValue(const SkHashDigest& result) {
-        Json::Value jsonValue;
-        jsonValue[kJsonKey_ActualResults_AnyStatus_BitmapHash] = asJsonValue(result);
-        return jsonValue;
-    }
-
     Json::Value CreateJsonTree(Json::Value expectedResults,
                                Json::Value actualResultsFailed,
                                Json::Value actualResultsFailureIgnored,
@@ -69,6 +63,62 @@
     }
 
 
+    // GmResultDigest class...
+
+    GmResultDigest::GmResultDigest(const SkBitmap &bitmap) {
+        fIsValid = SkBitmapHasher::ComputeDigest(bitmap, &fHashDigest);
+    }
+
+    GmResultDigest::GmResultDigest(const Json::Value &jsonTypeValuePair) {
+        fIsValid = false;
+        if (!jsonTypeValuePair.isArray()) {
+            gm_fprintf(stderr, "found non-array json value when parsing GmResultDigest: %s\n",
+                       jsonTypeValuePair.toStyledString().c_str());
+            DEBUGFAIL_SEE_STDERR;
+        } else if (2 != jsonTypeValuePair.size()) {
+            gm_fprintf(stderr, "found json array with wrong size when parsing GmResultDigest: %s\n",
+                       jsonTypeValuePair.toStyledString().c_str());
+            DEBUGFAIL_SEE_STDERR;
+        } else {
+            // TODO(epoger): The current implementation assumes that the
+            // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
+            Json::Value jsonHashValue = jsonTypeValuePair[1];
+            if (!jsonHashValue.isIntegral()) {
+                gm_fprintf(stderr,
+                           "found non-integer jsonHashValue when parsing GmResultDigest: %s\n",
+                           jsonTypeValuePair.toStyledString().c_str());
+                DEBUGFAIL_SEE_STDERR;
+            } else {
+                fHashDigest = jsonHashValue.asUInt64();
+                fIsValid = true;
+            }
+        }
+    }
+
+    bool GmResultDigest::isValid() const {
+        return fIsValid;
+    }
+
+    bool GmResultDigest::equals(const GmResultDigest &other) const {
+        // TODO(epoger): The current implementation assumes that this
+        // and other are always of type kJsonKey_Hashtype_Bitmap_64bitMD5
+        return (this->fIsValid && other.fIsValid && (this->fHashDigest == other.fHashDigest));
+    }
+
+    Json::Value GmResultDigest::asJsonTypeValuePair() const {
+        // TODO(epoger): The current implementation assumes that the
+        // result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
+        Json::Value jsonTypeValuePair;
+        if (fIsValid) {
+            jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitMD5));
+            jsonTypeValuePair.append(Json::UInt64(fHashDigest));
+        } else {
+            jsonTypeValuePair.append(Json::Value("INVALID"));
+        }
+        return jsonTypeValuePair;
+    }
+
+
     // Expectations class...
 
     Expectations::Expectations(bool ignoreFailure) {
@@ -78,13 +128,7 @@
     Expectations::Expectations(const SkBitmap& bitmap, bool ignoreFailure) {
         fBitmap = bitmap;
         fIgnoreFailure = ignoreFailure;
-        SkHashDigest digest;
-        // TODO(epoger): Better handling for error returned by ComputeDigest()?
-        // For now, we just report a digest of 0 in error cases, like before.
-        if (!SkBitmapHasher::ComputeDigest(bitmap, &digest)) {
-            digest = 0;
-        }
-        fAllowedBitmapChecksums.push_back() = digest;
+        fAllowedResultDigests.push_back(GmResultDigest(bitmap));
     }
 
     Expectations::Expectations(Json::Value jsonElement) {
@@ -105,36 +149,27 @@
                 fIgnoreFailure = ignoreFailure.asBool();
             }
 
-            Json::Value allowedChecksums =
-                jsonElement[kJsonKey_ExpectedResults_AllowedBitmapHashes];
-            if (allowedChecksums.isNull()) {
-                // ok, we'll just assume there aren't any expected checksums to compare against
-            } else if (!allowedChecksums.isArray()) {
+            Json::Value allowedDigests = jsonElement[kJsonKey_ExpectedResults_AllowedDigests];
+            if (allowedDigests.isNull()) {
+                // ok, we'll just assume there aren't any AllowedDigests to compare against
+            } else if (!allowedDigests.isArray()) {
                 gm_fprintf(stderr, "found non-array json value"
                            " for key '%s' in element '%s'\n",
-                           kJsonKey_ExpectedResults_AllowedBitmapHashes,
+                           kJsonKey_ExpectedResults_AllowedDigests,
                            jsonElement.toStyledString().c_str());
                 DEBUGFAIL_SEE_STDERR;
             } else {
-                for (Json::ArrayIndex i=0; i<allowedChecksums.size(); i++) {
-                    Json::Value checksumElement = allowedChecksums[i];
-                    if (!checksumElement.isIntegral()) {
-                        gm_fprintf(stderr, "found non-integer checksum"
-                                   " in json element '%s'\n",
-                                   jsonElement.toStyledString().c_str());
-                        DEBUGFAIL_SEE_STDERR;
-                    } else {
-                        fAllowedBitmapChecksums.push_back() = asChecksum(checksumElement);
-                    }
+                for (Json::ArrayIndex i=0; i<allowedDigests.size(); i++) {
+                    fAllowedResultDigests.push_back(GmResultDigest(allowedDigests[i]));
                 }
             }
         }
     }
 
-    bool Expectations::match(Checksum actualChecksum) const {
-        for (int i=0; i < this->fAllowedBitmapChecksums.count(); i++) {
-            Checksum allowedChecksum = this->fAllowedBitmapChecksums[i];
-            if (allowedChecksum == actualChecksum) {
+    bool Expectations::match(GmResultDigest actualGmResultDigest) const {
+        for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
+            GmResultDigest allowedResultDigest = this->fAllowedResultDigests[i];
+            if (allowedResultDigest.equals(actualGmResultDigest)) {
                 return true;
             }
         }
@@ -142,18 +177,17 @@
     }
 
     Json::Value Expectations::asJsonValue() const {
-        Json::Value allowedChecksumArray;
-        if (!this->fAllowedBitmapChecksums.empty()) {
-            for (int i=0; i < this->fAllowedBitmapChecksums.count(); i++) {
-                Checksum allowedChecksum = this->fAllowedBitmapChecksums[i];
-                allowedChecksumArray.append(Json::UInt64(allowedChecksum));
+        Json::Value allowedDigestArray;
+        if (!this->fAllowedResultDigests.empty()) {
+            for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
+                allowedDigestArray.append(this->fAllowedResultDigests[i].asJsonTypeValuePair());
             }
         }
 
-        Json::Value jsonValue;
-        jsonValue[kJsonKey_ExpectedResults_AllowedBitmapHashes] = allowedChecksumArray;
-        jsonValue[kJsonKey_ExpectedResults_IgnoreFailure] = this->ignoreFailure();
-        return jsonValue;
+        Json::Value jsonExpectations;
+        jsonExpectations[kJsonKey_ExpectedResults_AllowedDigests] = allowedDigestArray;
+        jsonExpectations[kJsonKey_ExpectedResults_IgnoreFailure]  = this->ignoreFailure();
+        return jsonExpectations;
     }
 
 
diff --git a/gm/gm_expectations.h b/gm/gm_expectations.h
index a8b29cd..8efb986 100644
--- a/gm/gm_expectations.h
+++ b/gm/gm_expectations.h
@@ -30,15 +30,6 @@
 
 namespace skiagm {
 
-    // The actual type we use to represent a checksum is hidden in here.
-    typedef Json::UInt64 Checksum;
-    static inline Json::Value asJsonValue(Checksum checksum) {
-        return checksum;
-    }
-    static inline Checksum asChecksum(Json::Value jsonValue) {
-        return jsonValue.asUInt64();
-    }
-
     void gm_fprintf(FILE *stream, const char format[], ...);
 
     /**
@@ -51,8 +42,6 @@
      */
     SkString SkPathJoin(const char *rootPath, const char *relativePath);
 
-    Json::Value ActualResultAsJsonValue(const SkHashDigest& result);
-
     Json::Value CreateJsonTree(Json::Value expectedResults,
                                Json::Value actualResultsFailed,
                                Json::Value actualResultsFailureIgnored,
@@ -60,7 +49,50 @@
                                Json::Value actualResultsSucceeded);
 
     /**
-     * Test expectations (allowed image checksums, etc.)
+     * The digest of a GM test result.
+     *
+     * Currently, this is always a uint64_t hash digest of an SkBitmap...
+     * but we will add other flavors soon.
+     */
+    class GmResultDigest {
+    public:
+        /**
+         * Create a ResultDigest representing an actual image result.
+         */
+        GmResultDigest(const SkBitmap &bitmap);
+
+        /**
+         * Create a ResultDigest representing an allowed result
+         * checksum within JSON expectations file, in the form
+         * ["bitmap-64bitMD5", 12345].
+         */
+        GmResultDigest(const Json::Value &jsonTypeValuePair);
+
+        /**
+         * Returns true if this GmResultDigest was fully and successfully
+         * created.
+         */
+        bool isValid() const;
+
+        /**
+         * Returns true if this and other GmResultDigest could
+         * represent identical results.
+         */
+        bool equals(const GmResultDigest &other) const;
+
+        /**
+         * Returns a JSON type/value pair representing this result,
+         * such as ["bitmap-64bitMD5", 12345].
+         */
+        Json::Value asJsonTypeValuePair() const;
+
+    private:
+        bool fIsValid; // always check this first--if it's false, other fields are meaningless
+        uint64_t fHashDigest;
+    };
+
+    /**
+     * Test expectations (allowed image results, etc.)
      */
     class Expectations {
     public:
@@ -90,16 +122,16 @@
         bool ignoreFailure() const { return this->fIgnoreFailure; }
 
         /**
-         * Returns true iff there are no allowed checksums.
+         * Returns true iff there are no allowed results.
          */
-        bool empty() const { return this->fAllowedBitmapChecksums.empty(); }
+        bool empty() const { return this->fAllowedResultDigests.empty(); }
 
         /**
-         * Returns true iff actualChecksum matches any allowedChecksum,
+         * Returns true iff resultDigest matches any allowed result,
          * regardless of fIgnoreFailure.  (The caller can check
          * that separately.)
          */
-        bool match(Checksum actualChecksum) const;
+        bool match(GmResultDigest resultDigest) const;
 
         /**
          * If this Expectation is based on a single SkBitmap, return a
@@ -119,7 +151,7 @@
     private:
         const static bool kDefaultIgnoreFailure = false;
 
-        SkTArray<Checksum> fAllowedBitmapChecksums;
+        SkTArray<GmResultDigest> fAllowedResultDigests;
         bool fIgnoreFailure;
         SkBitmap fBitmap;
     };
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index df8d28f..3481cf8 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -18,7 +18,6 @@
 #include "gm_expectations.h"
 #include "system_preferences.h"
 #include "SkBitmap.h"
-#include "SkBitmapHasher.h"
 #include "SkColorPriv.h"
 #include "SkCommandLineFlags.h"
 #include "SkData.h"
@@ -750,12 +749,7 @@
                                              const char *renderModeDescriptor,
                                              bool addToJsonSummary) {
         ErrorCombination errors;
-        SkHashDigest actualBitmapHash;
-        // TODO(epoger): Better handling for error returned by ComputeDigest()?
-        // For now, we just report a digest of 0 in error cases, like before.
-        if (!SkBitmapHasher::ComputeDigest(actualBitmap, &actualBitmapHash)) {
-            actualBitmapHash = 0;
-        }
+        GmResultDigest actualResultDigest(actualBitmap);
         SkString shortNamePlusConfig = make_shortname_plus_config(shortName, configName);
         SkString completeNameString(shortNamePlusConfig);
         completeNameString.append(renderModeDescriptor);
@@ -765,7 +759,7 @@
 
         if (expectations.empty()) {
             errors.add(kMissingExpectations_ErrorType);
-        } else if (!expectations.match(actualBitmapHash)) {
+        } else if (!expectations.match(actualResultDigest)) {
             addToJsonSummary = true;
             // The error mode we record depends on whether this was running
             // in a non-standard renderMode.
@@ -794,7 +788,7 @@
         RecordTestResults(errors, shortNamePlusConfig, renderModeDescriptor);
 
         if (addToJsonSummary) {
-            add_actual_results_to_json_summary(completeName, actualBitmapHash, errors,
+            add_actual_results_to_json_summary(completeName, actualResultDigest, errors,
                                                expectations.ignoreFailure());
             add_expected_results_to_json_summary(completeName, expectations);
         }
@@ -807,10 +801,10 @@
      * depending on errors encountered.
      */
     void add_actual_results_to_json_summary(const char testName[],
-                                            const SkHashDigest& actualResult,
+                                            const GmResultDigest &actualResultDigest,
                                             ErrorCombination errors,
                                             bool ignoreFailure) {
-        Json::Value jsonActualResults = ActualResultAsJsonValue(actualResult);
+        Json::Value jsonActualResults = actualResultDigest.asJsonTypeValuePair();
         if (errors.isEmpty()) {
             this->fJsonActualResults_Succeeded[testName] = jsonActualResults;
         } else {
@@ -896,13 +890,8 @@
         } else {
             // If we are running without expectations, we still want to
             // record the actual results.
-            SkHashDigest actualBitmapHash;
-            // TODO(epoger): Better handling for error returned by ComputeDigest()?
-            // For now, we just report a digest of 0 in error cases, like before.
-            if (!SkBitmapHasher::ComputeDigest(actualBitmap, &actualBitmapHash)) {
-                actualBitmapHash = 0;
-            }
-            add_actual_results_to_json_summary(nameWithExtension.c_str(), actualBitmapHash,
+            GmResultDigest actualResultDigest(actualBitmap);
+            add_actual_results_to_json_summary(nameWithExtension.c_str(), actualResultDigest,
                                                ErrorCombination(kMissingExpectations_ErrorType),
                                                false);
             RecordTestResults(ErrorCombination(kMissingExpectations_ErrorType),
diff --git a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/json-summary.txt
index e4fd005..7832eb0 100644
--- a/gm/tests/outputs/compared-against-different-pixels-images/output-expected/json-summary.txt
+++ b/gm/tests/outputs/compared-against-different-pixels-images/output-expected/json-summary.txt
@@ -1,12 +1,8 @@
 {
    "actual-results" : {
       "failed" : {
-         "565/selftest1.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "8888/selftest1.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         }
+         "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
       },
       "failure-ignored" : null,
       "no-comparison" : null,
@@ -14,11 +10,15 @@
    },
    "expected-results" : {
       "565/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 8863920166200910451 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 8863920166200910451 ]
+         ],
          "ignore-failure" : false
       },
       "8888/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 13451349865803053525 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 13451349865803053525 ]
+         ],
          "ignore-failure" : false
       }
    }
diff --git a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/json-summary.txt
index e4fd005..7832eb0 100644
--- a/gm/tests/outputs/compared-against-different-pixels-json/output-expected/json-summary.txt
+++ b/gm/tests/outputs/compared-against-different-pixels-json/output-expected/json-summary.txt
@@ -1,12 +1,8 @@
 {
    "actual-results" : {
       "failed" : {
-         "565/selftest1.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "8888/selftest1.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         }
+         "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
       },
       "failure-ignored" : null,
       "no-comparison" : null,
@@ -14,11 +10,15 @@
    },
    "expected-results" : {
       "565/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 8863920166200910451 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 8863920166200910451 ]
+         ],
          "ignore-failure" : false
       },
       "8888/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 13451349865803053525 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 13451349865803053525 ]
+         ],
          "ignore-failure" : false
       }
    }
diff --git a/gm/tests/outputs/compared-against-empty-dir/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-empty-dir/output-expected/json-summary.txt
index f65de30..57aee04 100644
--- a/gm/tests/outputs/compared-against-empty-dir/output-expected/json-summary.txt
+++ b/gm/tests/outputs/compared-against-empty-dir/output-expected/json-summary.txt
@@ -3,22 +3,18 @@
       "failed" : null,
       "failure-ignored" : null,
       "no-comparison" : {
-         "565/selftest1.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "8888/selftest1.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         }
+         "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
       },
       "succeeded" : null
    },
    "expected-results" : {
       "565/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : null,
+         "allowed-digests" : null,
          "ignore-failure" : false
       },
       "8888/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : null,
+         "allowed-digests" : null,
          "ignore-failure" : false
       }
    }
diff --git a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/json-summary.txt
index 64d1a3f..fad1ffe 100644
--- a/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/json-summary.txt
+++ b/gm/tests/outputs/compared-against-identical-bytes-images/output-expected/json-summary.txt
@@ -4,21 +4,21 @@
       "failure-ignored" : null,
       "no-comparison" : null,
       "succeeded" : {
-         "565/selftest1.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "8888/selftest1.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         }
+         "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
       }
    },
    "expected-results" : {
       "565/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 12927999507540085554 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 12927999507540085554 ]
+         ],
          "ignore-failure" : false
       },
       "8888/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 1209453360120438698 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 1209453360120438698 ]
+         ],
          "ignore-failure" : false
       }
    }
diff --git a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/json-summary.txt
index 64d1a3f..fad1ffe 100644
--- a/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/json-summary.txt
+++ b/gm/tests/outputs/compared-against-identical-bytes-json/output-expected/json-summary.txt
@@ -4,21 +4,21 @@
       "failure-ignored" : null,
       "no-comparison" : null,
       "succeeded" : {
-         "565/selftest1.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "8888/selftest1.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         }
+         "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
       }
    },
    "expected-results" : {
       "565/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 12927999507540085554 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 12927999507540085554 ]
+         ],
          "ignore-failure" : false
       },
       "8888/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 1209453360120438698 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 1209453360120438698 ]
+         ],
          "ignore-failure" : false
       }
    }
diff --git a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/json-summary.txt
index 64d1a3f..fad1ffe 100644
--- a/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/json-summary.txt
+++ b/gm/tests/outputs/compared-against-identical-pixels-images/output-expected/json-summary.txt
@@ -4,21 +4,21 @@
       "failure-ignored" : null,
       "no-comparison" : null,
       "succeeded" : {
-         "565/selftest1.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "8888/selftest1.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         }
+         "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
       }
    },
    "expected-results" : {
       "565/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 12927999507540085554 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 12927999507540085554 ]
+         ],
          "ignore-failure" : false
       },
       "8888/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 1209453360120438698 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 1209453360120438698 ]
+         ],
          "ignore-failure" : false
       }
    }
diff --git a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/json-summary.txt b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/json-summary.txt
index 64d1a3f..fad1ffe 100644
--- a/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/json-summary.txt
+++ b/gm/tests/outputs/compared-against-identical-pixels-json/output-expected/json-summary.txt
@@ -4,21 +4,21 @@
       "failure-ignored" : null,
       "no-comparison" : null,
       "succeeded" : {
-         "565/selftest1.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "8888/selftest1.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         }
+         "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
       }
    },
    "expected-results" : {
       "565/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 12927999507540085554 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 12927999507540085554 ]
+         ],
          "ignore-failure" : false
       },
       "8888/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 1209453360120438698 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 1209453360120438698 ]
+         ],
          "ignore-failure" : false
       }
    }
diff --git a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/json-summary.txt b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/json-summary.txt
index e4fd005..7832eb0 100644
--- a/gm/tests/outputs/ignore-expectations-mismatch/output-expected/json-summary.txt
+++ b/gm/tests/outputs/ignore-expectations-mismatch/output-expected/json-summary.txt
@@ -1,12 +1,8 @@
 {
    "actual-results" : {
       "failed" : {
-         "565/selftest1.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "8888/selftest1.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         }
+         "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
       },
       "failure-ignored" : null,
       "no-comparison" : null,
@@ -14,11 +10,15 @@
    },
    "expected-results" : {
       "565/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 8863920166200910451 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 8863920166200910451 ]
+         ],
          "ignore-failure" : false
       },
       "8888/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 13451349865803053525 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 13451349865803053525 ]
+         ],
          "ignore-failure" : false
       }
    }
diff --git a/gm/tests/outputs/intentionally-skipped-tests/output-expected/json-summary.txt b/gm/tests/outputs/intentionally-skipped-tests/output-expected/json-summary.txt
index 45fe476..f6cd87b 100644
--- a/gm/tests/outputs/intentionally-skipped-tests/output-expected/json-summary.txt
+++ b/gm/tests/outputs/intentionally-skipped-tests/output-expected/json-summary.txt
@@ -3,18 +3,10 @@
       "failed" : null,
       "failure-ignored" : null,
       "no-comparison" : {
-         "565/selftest1.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "565/selftest2.png" : {
-            "bitmap-64bitMD5" : 8863920166200910451
-         },
-         "8888/selftest1.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         },
-         "8888/selftest2.png" : {
-            "bitmap-64bitMD5" : 13451349865803053525
-         }
+         "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "565/selftest2.png" : [ "bitmap-64bitMD5", 8863920166200910451 ],
+         "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ],
+         "8888/selftest2.png" : [ "bitmap-64bitMD5", 13451349865803053525 ]
       },
       "succeeded" : null
    },
diff --git a/gm/tests/outputs/no-hierarchy/output-expected/json-summary.txt b/gm/tests/outputs/no-hierarchy/output-expected/json-summary.txt
index fe6038e..b3e2a81 100644
--- a/gm/tests/outputs/no-hierarchy/output-expected/json-summary.txt
+++ b/gm/tests/outputs/no-hierarchy/output-expected/json-summary.txt
@@ -1,12 +1,8 @@
 {
    "actual-results" : {
       "failed" : {
-         "selftest1_565.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "selftest1_8888.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         }
+         "selftest1_565.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "selftest1_8888.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
       },
       "failure-ignored" : null,
       "no-comparison" : null,
@@ -14,11 +10,15 @@
    },
    "expected-results" : {
       "selftest1_565.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 8863920166200910451 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 8863920166200910451 ]
+         ],
          "ignore-failure" : false
       },
       "selftest1_8888.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 13451349865803053525 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 13451349865803053525 ]
+         ],
          "ignore-failure" : false
       }
    }
diff --git a/gm/tests/outputs/no-readpath/output-expected/json-summary.txt b/gm/tests/outputs/no-readpath/output-expected/json-summary.txt
index eeed6b4..006516e 100644
--- a/gm/tests/outputs/no-readpath/output-expected/json-summary.txt
+++ b/gm/tests/outputs/no-readpath/output-expected/json-summary.txt
@@ -3,12 +3,8 @@
       "failed" : null,
       "failure-ignored" : null,
       "no-comparison" : {
-         "565/selftest1.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "8888/selftest1.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         }
+         "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
       },
       "succeeded" : null
    },
diff --git a/gm/tests/outputs/nonverbose/output-expected/json-summary.txt b/gm/tests/outputs/nonverbose/output-expected/json-summary.txt
index f65de30..57aee04 100644
--- a/gm/tests/outputs/nonverbose/output-expected/json-summary.txt
+++ b/gm/tests/outputs/nonverbose/output-expected/json-summary.txt
@@ -3,22 +3,18 @@
       "failed" : null,
       "failure-ignored" : null,
       "no-comparison" : {
-         "565/selftest1.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "8888/selftest1.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         }
+         "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
       },
       "succeeded" : null
    },
    "expected-results" : {
       "565/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : null,
+         "allowed-digests" : null,
          "ignore-failure" : false
       },
       "8888/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : null,
+         "allowed-digests" : null,
          "ignore-failure" : false
       }
    }
diff --git a/gm/tests/outputs/pipe-playback-failure/output-expected/json-summary.txt b/gm/tests/outputs/pipe-playback-failure/output-expected/json-summary.txt
index b4e6003..c99a8e9 100644
--- a/gm/tests/outputs/pipe-playback-failure/output-expected/json-summary.txt
+++ b/gm/tests/outputs/pipe-playback-failure/output-expected/json-summary.txt
@@ -1,32 +1,32 @@
 {
    "actual-results" : {
       "failed" : {
-         "comparison/selftest1-pipe.png" : {
-            "bitmap-64bitMD5" : 6140979239232854774
-         }
+         "comparison/selftest1-pipe.png" : [ "bitmap-64bitMD5", 6140979239232854774 ]
       },
       "failure-ignored" : null,
       "no-comparison" : null,
       "succeeded" : {
-         "565/selftest1.png" : {
-            "bitmap-64bitMD5" : 12927999507540085554
-         },
-         "8888/selftest1.png" : {
-            "bitmap-64bitMD5" : 1209453360120438698
-         }
+         "565/selftest1.png" : [ "bitmap-64bitMD5", 12927999507540085554 ],
+         "8888/selftest1.png" : [ "bitmap-64bitMD5", 1209453360120438698 ]
       }
    },
    "expected-results" : {
       "565/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 12927999507540085554 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 12927999507540085554 ]
+         ],
          "ignore-failure" : false
       },
       "8888/selftest1.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 1209453360120438698 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 1209453360120438698 ]
+         ],
          "ignore-failure" : false
       },
       "comparison/selftest1-pipe.png" : {
-         "allowed-bitmap-64bitMD5s" : [ 1209453360120438698 ],
+         "allowed-digests" : [
+            [ "bitmap-64bitMD5", 1209453360120438698 ]
+         ],
          "ignore-failure" : false
       }
    }
diff --git a/src/utils/SkBitmapHasher.cpp b/src/utils/SkBitmapHasher.cpp
index 5342d18..9f0affd 100644
--- a/src/utils/SkBitmapHasher.cpp
+++ b/src/utils/SkBitmapHasher.cpp
@@ -30,8 +30,7 @@
     return SkEndian_SwapLE64(*(reinterpret_cast<const uint64_t *>(bytearray)));
 }
 
-/*static*/ bool SkBitmapHasher::ComputeDigestInternal(const SkBitmap& bitmap,
-                                                      SkHashDigest *result) {
+/*static*/ bool SkBitmapHasher::ComputeDigestInternal(const SkBitmap& bitmap, uint64_t *result) {
     SkMD5 out;
 
     // start with the x/y dimensions
@@ -50,7 +49,7 @@
     return true;
 }
 
-/*static*/ bool SkBitmapHasher::ComputeDigest(const SkBitmap& bitmap, SkHashDigest *result) {
+/*static*/ bool SkBitmapHasher::ComputeDigest(const SkBitmap& bitmap, uint64_t *result) {
     if (ComputeDigestInternal(bitmap, result)) {
         return true;
     }
diff --git a/src/utils/SkBitmapHasher.h b/src/utils/SkBitmapHasher.h
index 165da3d..d52a6d7 100644
--- a/src/utils/SkBitmapHasher.h
+++ b/src/utils/SkBitmapHasher.h
@@ -11,12 +11,8 @@
 
 #include "SkBitmap.h"
 
-// TODO(epoger): Soon, SkHashDigest will become a real class of its own,
-// and callers won't be able to assume it converts to/from a uint64_t.
-typedef uint64_t SkHashDigest;
-
 /**
- * Static class that can generate an SkHashDigest from an SkBitmap.
+ * Static class that generates a uint64 hash digest from an SkBitmap.
  */
 class SkBitmapHasher {
 public:
@@ -30,10 +26,10 @@
      * intermediate SkBitmap and copy the pixels over to it... so in some
      * cases, performance and memory usage can suffer.
      */
-    static bool ComputeDigest(const SkBitmap& bitmap, SkHashDigest *result);
+    static bool ComputeDigest(const SkBitmap& bitmap, uint64_t *result);
 
 private:
-    static bool ComputeDigestInternal(const SkBitmap& bitmap, SkHashDigest *result);
+    static bool ComputeDigestInternal(const SkBitmap& bitmap, uint64_t *result);
 };
 
 #endif
diff --git a/tests/BitmapHasherTest.cpp b/tests/BitmapHasherTest.cpp
index f7b297d..04de707 100644
--- a/tests/BitmapHasherTest.cpp
+++ b/tests/BitmapHasherTest.cpp
@@ -38,7 +38,7 @@
         void RunTest() {
             // Test SkBitmapHasher
             SkBitmap bitmap;
-            SkHashDigest digest;
+            uint64_t digest;
             // initial test case
             CreateTestBitmap(bitmap, SkBitmap::kARGB_8888_Config, 333, 555, SK_ColorBLUE);
             REPORTER_ASSERT(fReporter, SkBitmapHasher::ComputeDigest(bitmap, &digest));
diff --git a/tools/skimage_main.cpp b/tools/skimage_main.cpp
index 9739ced..f52cf32 100644
--- a/tools/skimage_main.cpp
+++ b/tools/skimage_main.cpp
@@ -7,7 +7,6 @@
 
 #include "gm_expectations.h"
 #include "SkBitmap.h"
-#include "SkBitmapHasher.h"
 #include "SkColorPriv.h"
 #include "SkCommandLineFlags.h"
 #include "SkData.h"
@@ -180,7 +179,7 @@
 static Json::Value gExpectationsToWrite;
 
 /**
- *  If expectations are to be recorded, record the expected checksum of bitmap into global
+ *  If expectations are to be recorded, record the bitmap expectations into global
  *  expectations array.
  */
 static void write_expectations(const SkBitmap& bitmap, const char* filename) {
@@ -219,16 +218,16 @@
         return false;
     }
 
-    SkHashDigest checksum;
-    if (!SkBitmapHasher::ComputeDigest(bitmap, &checksum)) {
+    skiagm::GmResultDigest resultDigest(bitmap);
+    if (!resultDigest.isValid()) {
         if (failureArray != NULL) {
-            failureArray->push_back().printf("decoded %s, but could not create a checksum.",
+            failureArray->push_back().printf("decoded %s, but could not create a GmResultDigest.",
                                              filename);
         }
         return false;
     }
 
-    if (jsExpectation.match(checksum)) {
+    if (jsExpectation.match(resultDigest)) {
         return true;
     }