Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkBitmap.h" | 8 #include "SkBitmap.h" |
| 9 #include "SkBitmapHasher.h" | 9 #include "SkBitmapHasher.h" |
| 10 #include "SkData.h" | |
| 10 #include "SkJSONCPP.h" | 11 #include "SkJSONCPP.h" |
| 11 #include "SkOSFile.h" | 12 #include "SkOSFile.h" |
| 12 #include "SkStream.h" | 13 #include "SkStream.h" |
| 13 #include "SkTypes.h" | 14 #include "SkTypes.h" |
| 14 | 15 |
| 15 #include "image_expectations.h" | 16 #include "image_expectations.h" |
| 16 | 17 |
| 17 /* | 18 /* |
| 18 * TODO(epoger): Make constant strings consistent instead of mixing hypenated an d camel-caps. | 19 * TODO(epoger): Make constant strings consistent instead of mixing hypenated an d camel-caps. |
| 19 * | 20 * |
| 20 * TODO(epoger): Similar constants are already maintained in 2 other places: | 21 * TODO(epoger): Similar constants are already maintained in 2 other places: |
| 21 * gm/gm_json.py and gm/gm_expectations.cpp. We shouldn't add yet a third place. | 22 * gm/gm_json.py and gm/gm_expectations.cpp. We shouldn't add yet a third place. |
| 22 * Figure out a way to share the definitions instead. | 23 * Figure out a way to share the definitions instead. |
| 23 * | 24 * |
| 24 * Note that, as of https://codereview.chromium.org/226293002 , the JSON | 25 * Note that, as of https://codereview.chromium.org/226293002 , the JSON |
| 25 * schema used here has started to differ from the one in gm_expectations.cpp . | 26 * schema used here has started to differ from the one in gm_expectations.cpp . |
| 26 * TODO(epoger): Consider getting GM and render_pictures to use the same JSON | 27 * TODO(epoger): Consider getting GM and render_pictures to use the same JSON |
| 27 * output module. | 28 * output module. |
| 28 */ | 29 */ |
| 29 const static char kJsonKey_ActualResults[] = "actual-results"; | 30 const static char kJsonKey_ActualResults[] = "actual-results"; |
| 31 const static char kJsonKey_ExpectedResults[] = "expected-results"; | |
| 30 const static char kJsonKey_Header[] = "header"; | 32 const static char kJsonKey_Header[] = "header"; |
| 31 const static char kJsonKey_Header_Type[] = "type"; | 33 const static char kJsonKey_Header_Type[] = "type"; |
| 32 const static char kJsonKey_Header_Revision[] = "revision"; // unique within Typ e | 34 const static char kJsonKey_Header_Revision[] = "revision"; |
| 33 const static char kJsonKey_Image_ChecksumAlgorithm[] = "checksumAlgorithm"; | 35 const static char kJsonKey_Image_ChecksumAlgorithm[] = "checksumAlgorithm"; |
| 34 const static char kJsonKey_Image_ChecksumValue[] = "checksumValue"; | 36 const static char kJsonKey_Image_ChecksumValue[] = "checksumValue"; |
| 35 const static char kJsonKey_Image_ComparisonResult[] = "comparisonResult"; | 37 const static char kJsonKey_Image_ComparisonResult[] = "comparisonResult"; |
| 36 const static char kJsonKey_Image_Filepath[] = "filepath"; | 38 const static char kJsonKey_Image_Filepath[] = "filepath"; |
| 39 const static char kJsonKey_Image_IgnoreFailure[] = "ignoreFailure"; | |
| 37 const static char kJsonKey_Source_TiledImages[] = "tiled-images"; | 40 const static char kJsonKey_Source_TiledImages[] = "tiled-images"; |
| 38 const static char kJsonKey_Source_WholeImage[] = "whole-image"; | 41 const static char kJsonKey_Source_WholeImage[] = "whole-image"; |
| 39 // Values (not keys) that are written out by this JSON generator | 42 // Values (not keys) that are written out by this JSON generator |
| 40 const static char kJsonValue_Header_Type[] = "ChecksummedImages"; | 43 const static char kJsonValue_Header_Type[] = "ChecksummedImages"; |
| 41 const static int kJsonValue_Header_Revision = 1; | 44 const static int kJsonValue_Header_Revision = 1; |
| 42 const static char kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5[] = "bitmap- 64bitMD5"; | 45 const static char kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5[] = "bitmap- 64bitMD5"; |
| 46 const static char kJsonValue_Image_ComparisonResult_Failed[] = "failed"; | |
| 47 const static char kJsonValue_Image_ComparisonResult_FailureIgnored[] = "failure- ignored"; | |
| 43 const static char kJsonValue_Image_ComparisonResult_NoComparison[] = "no-compari son"; | 48 const static char kJsonValue_Image_ComparisonResult_NoComparison[] = "no-compari son"; |
| 49 const static char kJsonValue_Image_ComparisonResult_Succeeded[] = "succeeded"; | |
| 44 | 50 |
| 45 namespace sk_tools { | 51 namespace sk_tools { |
| 46 | 52 |
| 47 void ImageResultsSummary::add(const char *sourceName, const char *fileName, uint64_t hash, | 53 // ImageDigest class... |
| 48 const int *tileNumber) { | 54 |
| 49 Json::Value image; | 55 ImageDigest::ImageDigest(const SkBitmap &bitmap) { |
| 50 image[kJsonKey_Image_ChecksumAlgorithm] = kJsonValue_Image_ChecksumAlgor ithm_Bitmap64bitMD5; | 56 if (!SkBitmapHasher::ComputeDigest(bitmap, &fHashValue)) { |
| 51 image[kJsonKey_Image_ChecksumValue] = Json::UInt64(hash); | 57 SkFAIL("unable to compute image digest"); |
| 52 image[kJsonKey_Image_ComparisonResult] = kJsonValue_Image_ComparisonResu lt_NoComparison; | |
| 53 image[kJsonKey_Image_Filepath] = fileName; | |
| 54 if (NULL == tileNumber) { | |
| 55 fActualResults[sourceName][kJsonKey_Source_WholeImage] = image; | |
| 56 } else { | |
| 57 fActualResults[sourceName][kJsonKey_Source_TiledImages][*tileNumber] = image; | |
| 58 } | 58 } |
| 59 } | 59 } |
| 60 | 60 |
| 61 void ImageResultsSummary::add(const char *sourceName, const char *fileName, const SkBitmap& bitmap, | 61 ImageDigest::ImageDigest(const SkString &hashType, uint64_t hashValue) { |
| 62 const int *tileNumber) { | 62 if (!hashType.equals(kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5)) { |
| 63 uint64_t hash; | 63 SkFAIL((SkString("unsupported hashType ")+=hashType).c_str()); |
| 64 SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash)); | 64 } else { |
| 65 this->add(sourceName, fileName, hash, tileNumber); | 65 fHashValue = hashValue; |
| 66 } | |
| 66 } | 67 } |
| 67 | 68 |
| 68 void ImageResultsSummary::writeToFile(const char *filename) { | 69 SkString ImageDigest::getHashType() const { |
| 70 // TODO(epoger): The current implementation assumes that the | |
| 71 // result digest is always of type kJsonValue_Image_ChecksumAlgorithm_Bi tmap64bitMD5 . | |
| 72 return SkString(kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5); | |
| 73 } | |
| 74 | |
| 75 uint64_t ImageDigest::getHashValue() const { | |
| 76 return fHashValue; | |
| 77 } | |
| 78 | |
| 79 // BitmapAndDigest class... | |
| 80 | |
| 81 BitmapAndDigest::BitmapAndDigest(const SkBitmap &bitmap) : | |
| 82 fBitmap(bitmap), fEPOGERImageDigest(bitmap) { | |
| 83 } | |
| 84 | |
| 85 const ImageDigest *BitmapAndDigest::getImageDigestPtr() { | |
| 86 return &fEPOGERImageDigest; | |
| 87 } | |
| 88 | |
| 89 const SkBitmap *BitmapAndDigest::getBitmapPtr() const { | |
| 90 return &fBitmap; | |
| 91 } | |
| 92 | |
| 93 // ImageResultsSummary class... | |
| 94 | |
| 95 bool ImageResultsSummary::readExpectationsFile(const char *jsonPath) { | |
| 96 if (Parse(jsonPath, &fExpectedJsonRoot)) { | |
| 97 fExpectedResults = fExpectedJsonRoot[kJsonKey_ExpectedResults]; | |
| 98 return true; | |
| 99 } else { | |
| 100 return false; | |
| 101 } | |
| 102 } | |
| 103 | |
| 104 void ImageResultsSummary::add(const char *sourceName, const char *fileName, | |
| 105 const ImageDigest &digest, const int *tileNumb er) { | |
| 106 // Get expectation, if any. | |
| 107 Json::Value expectedImage; | |
| 108 if (!fExpectedResults.isNull()) { | |
| 109 if (NULL == tileNumber) { | |
| 110 // EPOGER: before committing, add a unittest to exercise what ha ppens if | |
|
epoger
2014/05/09 15:37:13
something I will fix before committing the CL... (
| |
| 111 // we don't have an expectation for a single sourceName/wholeIma ge. | |
| 112 expectedImage = fExpectedResults[sourceName][kJsonKey_Source_Who leImage]; | |
| 113 } else { | |
| 114 // EPOGER: before committing, add a unittest to exercise what ha ppens if | |
| 115 // we don't have an expectation for a single sourceName/tiledIma ge. | |
| 116 expectedImage = fExpectedResults[sourceName][kJsonKey_Source_Til edImages] | |
| 117 [*tileNumber]; | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 // Fill in info about the actual result itself. | |
| 122 Json::Value actualChecksumAlgorithm = digest.getHashType().c_str(); | |
| 123 Json::Value actualChecksumValue = Json::UInt64(digest.getHashValue()); | |
| 124 Json::Value actualImage; | |
| 125 actualImage[kJsonKey_Image_ChecksumAlgorithm] = actualChecksumAlgorithm; | |
| 126 actualImage[kJsonKey_Image_ChecksumValue] = actualChecksumValue; | |
| 127 actualImage[kJsonKey_Image_Filepath] = fileName; | |
| 128 | |
| 129 // Compare against expectedImage to fill in comparisonResult. | |
| 130 Json::Value comparisonResult = kJsonValue_Image_ComparisonResult_NoCompa rison; | |
| 131 if (!expectedImage.isNull()) { | |
| 132 if ((actualChecksumAlgorithm == expectedImage[kJsonKey_Image_Checksu mAlgorithm]) && | |
| 133 (actualChecksumValue == expectedImage[kJsonKey_Image_ChecksumVal ue])) { | |
| 134 comparisonResult = kJsonValue_Image_ComparisonResult_Succeeded; | |
| 135 } else if (expectedImage[kJsonKey_Image_IgnoreFailure] == true) { | |
| 136 comparisonResult = kJsonValue_Image_ComparisonResult_FailureIgno red; | |
| 137 } else { | |
| 138 comparisonResult = kJsonValue_Image_ComparisonResult_Failed; | |
| 139 } | |
| 140 } | |
| 141 actualImage[kJsonKey_Image_ComparisonResult] = comparisonResult; | |
| 142 | |
| 143 // Add this actual result to our collection. | |
| 144 if (NULL == tileNumber) { | |
| 145 fActualResults[sourceName][kJsonKey_Source_WholeImage] = actualImage ; | |
| 146 } else { | |
| 147 fActualResults[sourceName][kJsonKey_Source_TiledImages][*tileNumber] = actualImage; | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 void ImageResultsSummary::writeToFile(const char *filename) const { | |
| 69 Json::Value header; | 152 Json::Value header; |
| 70 header[kJsonKey_Header_Type] = kJsonValue_Header_Type; | 153 header[kJsonKey_Header_Type] = kJsonValue_Header_Type; |
| 71 header[kJsonKey_Header_Revision] = kJsonValue_Header_Revision; | 154 header[kJsonKey_Header_Revision] = kJsonValue_Header_Revision; |
| 72 Json::Value root; | 155 Json::Value root; |
| 73 root[kJsonKey_Header] = header; | 156 root[kJsonKey_Header] = header; |
| 74 root[kJsonKey_ActualResults] = fActualResults; | 157 root[kJsonKey_ActualResults] = fActualResults; |
| 75 std::string jsonStdString = root.toStyledString(); | 158 std::string jsonStdString = root.toStyledString(); |
| 76 SkFILEWStream stream(filename); | 159 SkFILEWStream stream(filename); |
| 77 stream.write(jsonStdString.c_str(), jsonStdString.length()); | 160 stream.write(jsonStdString.c_str(), jsonStdString.length()); |
| 78 } | 161 } |
| 79 | 162 |
| 163 /*static*/ bool ImageResultsSummary::Parse(const char *jsonPath, Json::Value *jsonRoot) { | |
| 164 SkAutoDataUnref dataRef(SkData::NewFromFileName(jsonPath)); | |
| 165 if (NULL == dataRef.get()) { | |
| 166 SkDebugf("error reading JSON file %s\n", jsonPath); | |
| 167 return false; | |
| 168 } | |
| 169 | |
| 170 const char *bytes = reinterpret_cast<const char *>(dataRef.get()->data() ); | |
| 171 size_t size = dataRef.get()->size(); | |
| 172 Json::Reader reader; | |
| 173 if (!reader.parse(bytes, bytes+size, *jsonRoot)) { | |
| 174 SkDebugf("error parsing JSON file %s\n", jsonPath); | |
| 175 return false; | |
| 176 } | |
| 177 | |
| 178 return true; | |
| 179 } | |
| 180 | |
| 80 } // namespace sk_tools | 181 } // namespace sk_tools |
| OLD | NEW |