blob: 07f0e60dbd29f4f0fbefd8f3468e47234a529c1f [file] [log] [blame]
epoger@google.com37269602013-01-19 04:21:27 +00001/*
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"
epoger@google.com84a18022013-02-01 20:39:15 +000011#include "SkBitmap.h"
epoger@google.com37269602013-01-19 04:21:27 +000012#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
29namespace 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 /**
epoger@google.com84a18022013-02-01 20:39:15 +000066 * Expect exactly one image (appropriate for the case when we
epoger@google.com37269602013-01-19 04:21:27 +000067 * are comparing against a single PNG file).
68 *
69 * By default, DO NOT ignore failures.
70 */
epoger@google.com84a18022013-02-01 20:39:15 +000071 Expectations(const SkBitmap& bitmap, bool ignoreFailure=false) {
72 fBitmap = bitmap;
epoger@google.com37269602013-01-19 04:21:27 +000073 fIgnoreFailure = ignoreFailure;
epoger@google.com84a18022013-02-01 20:39:15 +000074 fAllowedChecksums.push_back() = SkBitmapChecksummer::Compute64(bitmap);
epoger@google.com37269602013-01-19 04:21:27 +000075 }
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 /**
epoger@google.com84a18022013-02-01 20:39:15 +0000103 * 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 /**
epoger@google.com37269602013-01-19 04:21:27 +0000113 * 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;
epoger@google.com84a18022013-02-01 20:39:15 +0000131 SkBitmap fBitmap;
epoger@google.com37269602013-01-19 04:21:27 +0000132 };
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) {
epoger@google.com84a18022013-02-01 20:39:15 +0000170 return Expectations(referenceBitmap);
epoger@google.com37269602013-01-19 04:21:27 +0000171 } 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