blob: 59f6c6443eb29c3af09538cba9c9e4cfdfc884d8 [file] [log] [blame]
reed@android.com00dae862009-06-10 15:38:48 +00001#include "gm.h"
reed@android.comb9b9a182009-07-08 02:54:47 +00002#include "SkColorPriv.h"
reed@android.com8015dd82009-06-21 00:49:18 +00003#include "SkGraphics.h"
4#include "SkImageDecoder.h"
5#include "SkImageEncoder.h"
reed@android.com00dae862009-06-10 15:38:48 +00006
7using namespace skiagm;
8
9// need to explicitly declare this, or we get some weird infinite loop llist
10template GMRegistry* GMRegistry::gHead;
11
12class Iter {
13public:
14 Iter() {
reed@android.comdd0ac282009-06-20 02:38:16 +000015 fReg = GMRegistry::Head();
reed@android.com00dae862009-06-10 15:38:48 +000016 }
17
reed@android.comdd0ac282009-06-20 02:38:16 +000018 GM* next() {
reed@android.com00dae862009-06-10 15:38:48 +000019 if (fReg) {
reed@android.comdd0ac282009-06-20 02:38:16 +000020 GMRegistry::Factory fact = fReg->factory();
reed@android.com00dae862009-06-10 15:38:48 +000021 fReg = fReg->next();
reed@android.comdd0ac282009-06-20 02:38:16 +000022 return fact(0);
reed@android.com00dae862009-06-10 15:38:48 +000023 }
24 return NULL;
25 }
26
27 static int Count() {
reed@android.comdd0ac282009-06-20 02:38:16 +000028 const GMRegistry* reg = GMRegistry::Head();
reed@android.com00dae862009-06-10 15:38:48 +000029 int count = 0;
30 while (reg) {
31 count += 1;
32 reg = reg->next();
33 }
34 return count;
35 }
36
37private:
38 const GMRegistry* fReg;
39};
40
reed@android.com8015dd82009-06-21 00:49:18 +000041static SkString make_name(const char shortName[], const char configName[]) {
42 SkString name(shortName);
43 name.appendf("_%s", configName);
44 return name;
45}
46
47static SkString make_filename(const char path[], const SkString& name) {
48 SkString filename(path);
49 if (filename.size() && filename[filename.size() - 1] != '/') {
50 filename.append("/");
reed@android.com00dae862009-06-10 15:38:48 +000051 }
reed@android.com25b04342009-06-21 01:40:31 +000052 filename.appendf("%s.png", name.c_str());
reed@android.com8015dd82009-06-21 00:49:18 +000053 return filename;
54}
55
reed@android.comb9b9a182009-07-08 02:54:47 +000056/* since PNG insists on unpremultiplying our alpha, we take no precision chances
57 and force all pixels to be 100% opaque, otherwise on compare we may not get
58 a perfect match.
59 */
60static void force_all_opaque(const SkBitmap& bitmap) {
61 SkAutoLockPixels lock(bitmap);
62 for (int y = 0; y < bitmap.height(); y++) {
63 for (int x = 0; x < bitmap.width(); x++) {
64 *bitmap.getAddr32(x, y) |= (SK_A32_MASK << SK_A32_SHIFT);
65 }
66 }
67}
68
69static bool write_bitmap(const SkString& path, const SkBitmap& bitmap) {
70 SkBitmap copy;
71 bitmap.copyTo(&copy, SkBitmap::kARGB_8888_Config);
72 force_all_opaque(copy);
73 return SkImageEncoder::EncodeFile(path.c_str(), copy,
74 SkImageEncoder::kPNG_Type, 100);
75}
76
reed@android.com8015dd82009-06-21 00:49:18 +000077static void compare(const SkBitmap& target, const SkBitmap& base,
78 const SkString& name) {
reed@android.comb9b9a182009-07-08 02:54:47 +000079 SkBitmap copy;
80 const SkBitmap* bm = &target;
81 if (target.config() != SkBitmap::kARGB_8888_Config) {
82 target.copyTo(&copy, SkBitmap::kARGB_8888_Config);
83 bm = &copy;
84 }
85
86 force_all_opaque(*bm);
87
88 const int w = bm->width();
89 const int h = bm->height();
90 if (w != base.width() || h != base.height()) {
91 SkDebugf("---- dimensions mismatch for %s base [%d %d] current [%d %d]\n",
92 name.c_str(), base.width(), base.height(), w, h);
93 return;
94 }
95
96 SkAutoLockPixels bmLock(*bm);
97 SkAutoLockPixels baseLock(base);
98
99 for (int y = 0; y < h; y++) {
100 for (int x = 0; x < w; x++) {
101 SkPMColor c0 = *base.getAddr32(x, y);
102 SkPMColor c1 = *bm->getAddr32(x, y);
103 if (c0 != c1) {
104 SkDebugf("----- pixel mismatch for %s at [%d %d] base 0x%08X current 0x%08X\n",
105 name.c_str(), x, y, c0, c1);
106 return;
107 }
108 }
109 }
reed@android.com8015dd82009-06-21 00:49:18 +0000110}
reed@android.com00dae862009-06-10 15:38:48 +0000111
112static const struct {
113 SkBitmap::Config fConfig;
114 bool fUsePicture;
115 const char* fName;
116} gRec[] = {
117 { SkBitmap::kARGB_8888_Config, false, "8888" },
118 { SkBitmap::kARGB_4444_Config, false, "4444" },
119 { SkBitmap::kRGB_565_Config, false, "565" },
reed@android.com00dae862009-06-10 15:38:48 +0000120};
121
122int main (int argc, char * const argv[]) {
123 SkAutoGraphics ag;
124
reed@android.com8015dd82009-06-21 00:49:18 +0000125 const char* writePath = NULL; // if non-null, where we write the originals
126 const char* readPath = NULL; // if non-null, were we read from to compare
127
128 char* const* stop = argv + argc;
129 for (++argv; argv < stop; ++argv) {
130 if (strcmp(*argv, "-w") == 0) {
131 argv++;
132 if (argv < stop && **argv) {
133 writePath = *argv;
134 }
135 } else if (strcmp(*argv, "-r") == 0) {
136 argv++;
137 if (argv < stop && **argv) {
138 readPath = *argv;
139 }
140 }
141 }
142
reed@android.com00dae862009-06-10 15:38:48 +0000143 Iter iter;
144 GM* gm;
reed@android.com8015dd82009-06-21 00:49:18 +0000145
reed@android.com00dae862009-06-10 15:38:48 +0000146 while ((gm = iter.next()) != NULL) {
147 SkISize size = gm->getISize();
reed@android.comb9b9a182009-07-08 02:54:47 +0000148 SkDebugf("creating... %s [%d %d]\n", gm->shortName(),
reed@android.com8015dd82009-06-21 00:49:18 +0000149 size.width(), size.height());
150
reed@android.com00dae862009-06-10 15:38:48 +0000151 SkBitmap bitmap;
reed@android.comdd0ac282009-06-20 02:38:16 +0000152 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
reed@android.com00dae862009-06-10 15:38:48 +0000153 bitmap.setConfig(gRec[i].fConfig, size.width(), size.height());
154 bitmap.allocPixels();
155 bitmap.eraseColor(0);
156 SkCanvas canvas(bitmap);
157
158 gm->draw(&canvas);
reed@android.com8015dd82009-06-21 00:49:18 +0000159
160 SkString name = make_name(gm->shortName(), gRec[i].fName);
161
162 if (writePath) {
163 SkString path = make_filename(writePath, name);
reed@android.comb9b9a182009-07-08 02:54:47 +0000164 bool success = write_bitmap(path, bitmap);
reed@android.com8015dd82009-06-21 00:49:18 +0000165 if (!success) {
166 fprintf(stderr, "FAILED to write %s\n", path.c_str());
167 }
168 } else if (readPath) {
reed@android.comb9b9a182009-07-08 02:54:47 +0000169 SkString path = make_filename(readPath, name);
reed@android.com8015dd82009-06-21 00:49:18 +0000170 SkBitmap orig;
171 bool success = SkImageDecoder::DecodeFile(path.c_str(), &orig,
172 SkBitmap::kARGB_8888_Config,
173 SkImageDecoder::kDecodePixels_Mode, NULL);
174 if (success) {
175 compare(bitmap, orig, name);
176 } else {
177 fprintf(stderr, "FAILED to read %s\n", path.c_str());
178 }
179 }
reed@android.com00dae862009-06-10 15:38:48 +0000180 }
181 SkDELETE(gm);
182 }
183 return 0;
184}
reed@android.comdd0ac282009-06-20 02:38:16 +0000185
186///////////////////////////////////////////////////////////////////////////////
187
188using namespace skiagm;
189
190GM::GM() {}
191GM::~GM() {}
192
193void GM::draw(SkCanvas* canvas) {
194 this->onDraw(canvas);
195}
196
197