1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 #ifndef gm_expectations_DEFINED 8 #define gm_expectations_DEFINED 9 10 #include "gm.h" 11 #include "SkBitmap.h" 12 #include "SkBitmapChecksummer.h" 13 #include "SkImageDecoder.h" 14 #include "SkOSFile.h" 15 #include "SkRefCnt.h" 16 #include "SkTArray.h" 17 18 #ifdef SK_BUILD_FOR_WIN 19 // json includes xlocale which generates warning 4530 because we're compiling without 20 // exceptions; see https://code.google.com/p/skia/issues/detail?id=1067 21 #pragma warning(push) 22 #pragma warning(disable : 4530) 23 #endif 24 #include "json/value.h" 25 #ifdef SK_BUILD_FOR_WIN 26 #pragma warning(pop) 27 #endif 28 29 namespace skiagm { 30 31 // The actual type we use to represent a checksum is hidden in here. 32 typedef Json::UInt64 Checksum; 33 static inline Json::Value asJsonValue(Checksum checksum) { 34 return checksum; 35 } 36 37 static SkString make_filename(const char path[], 38 const char renderModeDescriptor[], 39 const char *name, 40 const char suffix[]) { 41 SkString filename(path); 42 if (filename.endsWith(SkPATH_SEPARATOR)) { 43 filename.remove(filename.size() - 1, 1); 44 } 45 filename.appendf("%c%s%s.%s", SkPATH_SEPARATOR, 46 name, renderModeDescriptor, suffix); 47 return filename; 48 } 49 50 /** 51 * Test expectations (allowed image checksums, etc.) 52 */ 53 class Expectations { 54 public: 55 /** 56 * No expectations at all. 57 * 58 * We set ignoreFailure to false by default, but it doesn't really 59 * matter... the result will always be "no-comparison" anyway. 60 */ 61 Expectations(bool ignoreFailure=false) { 62 fIgnoreFailure = ignoreFailure; 63 } 64 65 /** 66 * Expect exactly one image (appropriate for the case when we 67 * are comparing against a single PNG file). 68 * 69 * By default, DO NOT ignore failures. 70 */ 71 Expectations(const SkBitmap& bitmap, bool ignoreFailure=false) { 72 fBitmap = bitmap; 73 fIgnoreFailure = ignoreFailure; 74 fAllowedChecksums.push_back() = SkBitmapChecksummer::Compute64(bitmap); 75 } 76 77 /** 78 * Returns true iff we want to ignore failed expectations. 79 */ 80 bool ignoreFailure() const { return this->fIgnoreFailure; } 81 82 /** 83 * Returns true iff there are no allowed checksums. 84 */ 85 bool empty() const { return this->fAllowedChecksums.empty(); } 86 87 /** 88 * Returns true iff actualChecksum matches any allowedChecksum, 89 * regardless of fIgnoreFailure. (The caller can check 90 * that separately.) 91 */ 92 bool match(Checksum actualChecksum) const { 93 for (int i=0; i < this->fAllowedChecksums.count(); i++) { 94 Checksum allowedChecksum = this->fAllowedChecksums[i]; 95 if (allowedChecksum == actualChecksum) { 96 return true; 97 } 98 } 99 return false; 100 } 101 102 /** 103 * If this Expectation is based on a single SkBitmap, return a 104 * pointer to that SkBitmap. Otherwise (if the Expectation is 105 * empty, or if it was based on a list of checksums rather 106 * than a single bitmap), returns NULL. 107 */ 108 const SkBitmap *asBitmap() const { 109 return (SkBitmap::kNo_Config == fBitmap.config()) ? NULL : &fBitmap; 110 } 111 112 /** 113 * Return a JSON representation of the allowed checksums. 114 * This does NOT include any information about whether to 115 * ignore failures. 116 */ 117 Json::Value allowedChecksumsAsJson() const { 118 Json::Value allowedChecksumArray; 119 if (!this->fAllowedChecksums.empty()) { 120 for (int i=0; i < this->fAllowedChecksums.count(); i++) { 121 Checksum allowedChecksum = this->fAllowedChecksums[i]; 122 allowedChecksumArray.append(asJsonValue(allowedChecksum)); 123 } 124 } 125 return allowedChecksumArray; 126 } 127 128 private: 129 SkTArray<Checksum> fAllowedChecksums; 130 bool fIgnoreFailure; 131 SkBitmap fBitmap; 132 }; 133 134 /** 135 * Abstract source of Expectations objects for individual tests. 136 */ 137 class ExpectationsSource : public SkRefCnt { 138 public: 139 virtual Expectations get(const char *testName) = 0; 140 }; 141 142 /** 143 * Return Expectations based on individual image files on disk. 144 */ 145 class IndividualImageExpectationsSource : public ExpectationsSource { 146 public: 147 /** 148 * Create an ExpectationsSource that will return Expectations based on 149 * image files found within rootDir. 150 * 151 * rootDir: directory under which to look for image files 152 * (this string will be copied to storage within this object) 153 * notifyOfMissingFiles: whether to log a message to stderr if an image 154 * file cannot be found 155 */ 156 IndividualImageExpectationsSource(const char *rootDir, 157 bool notifyOfMissingFiles) : 158 fRootDir(rootDir), fNotifyOfMissingFiles(notifyOfMissingFiles) {} 159 160 Expectations get(const char *testName) SK_OVERRIDE { 161 SkString path = make_filename(fRootDir.c_str(), "", testName, 162 "png"); 163 SkBitmap referenceBitmap; 164 bool decodedReferenceBitmap = 165 SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap, 166 SkBitmap::kARGB_8888_Config, 167 SkImageDecoder::kDecodePixels_Mode, 168 NULL); 169 if (decodedReferenceBitmap) { 170 return Expectations(referenceBitmap); 171 } else { 172 if (fNotifyOfMissingFiles) { 173 fprintf(stderr, "FAILED to read %s\n", path.c_str()); 174 } 175 return Expectations(); 176 } 177 } 178 179 private: 180 const SkString fRootDir; 181 const bool fNotifyOfMissingFiles; 182 }; 183 184 } 185 #endif 186