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) : fBitmap(bitmap) { |
| 82 } |
| 83 |
| 84 const ImageDigest *BitmapAndDigest::getImageDigestPtr() { |
| 85 if (NULL == fImageDigestRef.get()) { |
| 86 fImageDigestRef.reset(SkNEW_ARGS(ImageDigest, (fBitmap))); |
| 87 } |
| 88 return fImageDigestRef.get(); |
| 89 } |
| 90 |
| 91 const SkBitmap *BitmapAndDigest::getBitmapPtr() const { |
| 92 return &fBitmap; |
| 93 } |
| 94 |
| 95 // ImageResultsAndExpectations class... |
| 96 |
| 97 bool ImageResultsAndExpectations::readExpectationsFile(const char *jsonPath)
{ |
| 98 if (Parse(jsonPath, &fExpectedJsonRoot)) { |
| 99 fExpectedResults = fExpectedJsonRoot[kJsonKey_ExpectedResults]; |
| 100 return true; |
| 101 } else { |
| 102 return false; |
| 103 } |
| 104 } |
| 105 |
| 106 void ImageResultsAndExpectations::add(const char *sourceName, const char *fi
leName, |
| 107 const ImageDigest &digest, const int *tileNumb
er) { |
| 108 // Get expectation, if any. |
| 109 Json::Value expectedImage; |
| 110 if (!fExpectedResults.isNull()) { |
| 111 if (NULL == tileNumber) { |
| 112 expectedImage = fExpectedResults[sourceName][kJsonKey_Source_Who
leImage]; |
| 113 } else { |
| 114 expectedImage = fExpectedResults[sourceName][kJsonKey_Source_Til
edImages] |
| 115 [*tileNumber]; |
| 116 } |
| 117 } |
| 118 |
| 119 // Fill in info about the actual result itself. |
| 120 Json::Value actualChecksumAlgorithm = digest.getHashType().c_str(); |
| 121 Json::Value actualChecksumValue = Json::UInt64(digest.getHashValue()); |
| 122 Json::Value actualImage; |
| 123 actualImage[kJsonKey_Image_ChecksumAlgorithm] = actualChecksumAlgorithm; |
| 124 actualImage[kJsonKey_Image_ChecksumValue] = actualChecksumValue; |
| 125 actualImage[kJsonKey_Image_Filepath] = fileName; |
| 126 |
| 127 // Compare against expectedImage to fill in comparisonResult. |
| 128 Json::Value comparisonResult = kJsonValue_Image_ComparisonResult_NoCompa
rison; |
| 129 if (!expectedImage.isNull()) { |
| 130 if ((actualChecksumAlgorithm == expectedImage[kJsonKey_Image_Checksu
mAlgorithm]) && |
| 131 (actualChecksumValue == expectedImage[kJsonKey_Image_ChecksumVal
ue])) { |
| 132 comparisonResult = kJsonValue_Image_ComparisonResult_Succeeded; |
| 133 } else if (expectedImage[kJsonKey_Image_IgnoreFailure] == true) { |
| 134 comparisonResult = kJsonValue_Image_ComparisonResult_FailureIgno
red; |
| 135 } else { |
| 136 comparisonResult = kJsonValue_Image_ComparisonResult_Failed; |
| 137 } |
| 138 } |
| 139 actualImage[kJsonKey_Image_ComparisonResult] = comparisonResult; |
| 140 |
| 141 // Add this actual result to our collection. |
| 142 if (NULL == tileNumber) { |
| 143 fActualResults[sourceName][kJsonKey_Source_WholeImage] = actualImage
; |
| 144 } else { |
| 145 fActualResults[sourceName][kJsonKey_Source_TiledImages][*tileNumber]
= actualImage; |
| 146 } |
| 147 } |
| 148 |
| 149 void ImageResultsAndExpectations::writeToFile(const char *filename) const { |
69 Json::Value header; | 150 Json::Value header; |
70 header[kJsonKey_Header_Type] = kJsonValue_Header_Type; | 151 header[kJsonKey_Header_Type] = kJsonValue_Header_Type; |
71 header[kJsonKey_Header_Revision] = kJsonValue_Header_Revision; | 152 header[kJsonKey_Header_Revision] = kJsonValue_Header_Revision; |
72 Json::Value root; | 153 Json::Value root; |
73 root[kJsonKey_Header] = header; | 154 root[kJsonKey_Header] = header; |
74 root[kJsonKey_ActualResults] = fActualResults; | 155 root[kJsonKey_ActualResults] = fActualResults; |
75 std::string jsonStdString = root.toStyledString(); | 156 std::string jsonStdString = root.toStyledString(); |
76 SkFILEWStream stream(filename); | 157 SkFILEWStream stream(filename); |
77 stream.write(jsonStdString.c_str(), jsonStdString.length()); | 158 stream.write(jsonStdString.c_str(), jsonStdString.length()); |
78 } | 159 } |
79 | 160 |
| 161 /*static*/ bool ImageResultsAndExpectations::Parse(const char *jsonPath, |
| 162 Json::Value *jsonRoot) { |
| 163 SkAutoDataUnref dataRef(SkData::NewFromFileName(jsonPath)); |
| 164 if (NULL == dataRef.get()) { |
| 165 SkDebugf("error reading JSON file %s\n", jsonPath); |
| 166 return false; |
| 167 } |
| 168 |
| 169 const char *bytes = reinterpret_cast<const char *>(dataRef.get()->data()
); |
| 170 size_t size = dataRef.get()->size(); |
| 171 Json::Reader reader; |
| 172 if (!reader.parse(bytes, bytes+size, *jsonRoot)) { |
| 173 SkDebugf("error parsing JSON file %s\n", jsonPath); |
| 174 return false; |
| 175 } |
| 176 |
| 177 return true; |
| 178 } |
| 179 |
80 } // namespace sk_tools | 180 } // namespace sk_tools |
OLD | NEW |