1#include "gm.h"
2#include "SkColorPriv.h"
3#include "SkGraphics.h"
4#include "SkImageDecoder.h"
5#include "SkImageEncoder.h"
6
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() {
15        fReg = GMRegistry::Head();
16    }
17
18    GM* next() {
19        if (fReg) {
20            GMRegistry::Factory fact = fReg->factory();
21            fReg = fReg->next();
22            return fact(0);
23        }
24        return NULL;
25    }
26
27    static int Count() {
28        const GMRegistry* reg = GMRegistry::Head();
29        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
41static 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("/");
51    }
52    filename.appendf("%s.png", name.c_str());
53    return filename;
54}
55
56/* 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
77static void compare(const SkBitmap& target, const SkBitmap& base,
78                    const SkString& name) {
79    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    }
110}
111
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" },
120};
121
122int main (int argc, char * const argv[]) {
123    SkAutoGraphics ag;
124
125    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
143    Iter iter;
144    GM* gm;
145
146    while ((gm = iter.next()) != NULL) {
147		SkISize size = gm->getISize();
148        SkDebugf("creating... %s [%d %d]\n", gm->shortName(),
149                 size.width(), size.height());
150
151		SkBitmap bitmap;
152		for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
153			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);
159
160            SkString name = make_name(gm->shortName(), gRec[i].fName);
161
162            if (writePath) {
163                SkString path = make_filename(writePath, name);
164                bool success = write_bitmap(path, bitmap);
165                if (!success) {
166                    fprintf(stderr, "FAILED to write %s\n", path.c_str());
167                }
168            } else if (readPath) {
169                SkString path = make_filename(readPath, name);
170                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            }
180		}
181        SkDELETE(gm);
182    }
183    return 0;
184}
185
186///////////////////////////////////////////////////////////////////////////////
187
188using namespace skiagm;
189
190GM::GM() {}
191GM::~GM() {}
192
193void GM::draw(SkCanvas* canvas) {
194	this->onDraw(canvas);
195}
196
197
198