blob: cfac4152e384e8b961743829bc2af1890aeb6cd2 [file] [log] [blame]
mtklein@google.coma7a9f372013-10-18 20:52:44 +00001#include "DMWriteTask.h"
2
3#include "DMUtil.h"
commit-bot@chromium.org389fb7f2014-01-15 21:28:25 +00004#include "SkColorPriv.h"
mtklein@google.coma7a9f372013-10-18 20:52:44 +00005#include "SkCommandLineFlags.h"
6#include "SkImageEncoder.h"
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +00007#include "SkMallocPixelRef.h"
commit-bot@chromium.org1426c1e2014-03-03 15:43:56 +00008#include "SkStream.h"
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +00009#include "SkString.h"
mtklein@google.coma7a9f372013-10-18 20:52:44 +000010
11DEFINE_string2(writePath, w, "", "If set, write GMs here as .pngs.");
12
13namespace DM {
14
commit-bot@chromium.org99589af2013-12-10 14:53:16 +000015// Splits off the last N suffixes of name (splitting on _) and appends them to out.
16// Returns the total number of characters consumed.
17static int split_suffixes(int N, const char* name, SkTArray<SkString>* out) {
rmistry@google.comd6bab022013-12-02 13:50:38 +000018 SkTArray<SkString> split;
19 SkStrSplit(name, "_", &split);
commit-bot@chromium.org99589af2013-12-10 14:53:16 +000020 int consumed = 0;
21 for (int i = 0; i < N; i++) {
rmistry@google.comd6bab022013-12-02 13:50:38 +000022 // We're splitting off suffixes from the back to front.
commit-bot@chromium.org99589af2013-12-10 14:53:16 +000023 out->push_back(split[split.count()-i-1]);
24 consumed += out->back().size() + 1; // Add one for the _.
rmistry@google.comd6bab022013-12-02 13:50:38 +000025 }
commit-bot@chromium.org99589af2013-12-10 14:53:16 +000026 return consumed;
27}
28
commit-bot@chromium.org90b5a2a2014-05-14 17:55:32 +000029WriteTask::WriteTask(const Task& parent, SkBitmap bitmap, Mode mode)
30 : CpuTask(parent), fBitmap(bitmap) {
31 if (mode == kVerbatim_Mode) {
32 fGmName.set(parent.name());
33 } else {
34 const int suffixes = parent.depth() + 1;
35 const SkString& name = parent.name();
36 const int totalSuffixLength = split_suffixes(suffixes, name.c_str(), &fSuffixes);
37 fGmName.set(name.c_str(), name.size()-totalSuffixLength);
38 }
rmistry@google.comd6bab022013-12-02 13:50:38 +000039}
mtklein@google.coma7a9f372013-10-18 20:52:44 +000040
rmistry@google.comd6bab022013-12-02 13:50:38 +000041void WriteTask::makeDirOrFail(SkString dir) {
42 if (!sk_mkdir(dir.c_str())) {
43 this->fail();
44 }
mtklein@google.coma7a9f372013-10-18 20:52:44 +000045}
46
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +000047namespace {
48
commit-bot@chromium.org1426c1e2014-03-03 15:43:56 +000049// One file that first contains a .png of an SkBitmap, then its raw pixels.
50// We use this custom format to avoid premultiplied/unpremultiplied pixel conversions.
51struct PngAndRaw {
52 static bool Encode(SkBitmap bitmap, const char* path) {
53 SkFILEWStream stream(path);
54 if (!stream.isValid()) {
55 SkDebugf("Can't write %s.\n", path);
56 return false;
57 }
58
59 // Write a PNG first for humans and other tools to look at.
60 if (!SkImageEncoder::EncodeStream(&stream, bitmap, SkImageEncoder::kPNG_Type, 100)) {
61 SkDebugf("Can't encode a PNG.\n");
62 return false;
63 }
64
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +000065 // Pad out so the raw pixels start 4-byte aligned.
66 const uint32_t maxPadding = 0;
67 const size_t pos = stream.bytesWritten();
68 stream.write(&maxPadding, SkAlign4(pos) - pos);
69
commit-bot@chromium.org1426c1e2014-03-03 15:43:56 +000070 // Then write our secret raw pixels that only DM reads.
71 SkAutoLockPixels lock(bitmap);
72 return stream.write(bitmap.getPixels(), bitmap.getSize());
73 }
74
75 // This assumes bitmap already has allocated pixels of the correct size.
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +000076 static bool Decode(const char* path, SkImageInfo info, SkBitmap* bitmap) {
77 SkAutoTUnref<SkData> data(SkData::NewFromFileName(path));
78 if (!data) {
commit-bot@chromium.org1426c1e2014-03-03 15:43:56 +000079 SkDebugf("Can't read %s.\n", path);
80 return false;
81 }
82
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +000083 // The raw pixels are at the end of the file. We'll skip the encoded PNG at the front.
84 const size_t rowBytes = info.minRowBytes(); // Assume densely packed.
85 const size_t bitmapBytes = info.getSafeSize(rowBytes);
86 if (data->size() < bitmapBytes) {
commit-bot@chromium.org1426c1e2014-03-03 15:43:56 +000087 SkDebugf("%s is too small to contain the bitmap we're looking for.\n", path);
88 return false;
89 }
commit-bot@chromium.org1426c1e2014-03-03 15:43:56 +000090
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +000091 const size_t offset = data->size() - bitmapBytes;
commit-bot@chromium.org2c4e75c2014-04-21 21:08:14 +000092 SkAutoTUnref<SkData> subset(
93 SkData::NewSubset(data, offset, bitmapBytes));
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +000094 SkAutoTUnref<SkPixelRef> pixels(
commit-bot@chromium.org2c4e75c2014-04-21 21:08:14 +000095 SkMallocPixelRef::NewWithData(
96 info, rowBytes, NULL/*ctable*/, subset));
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +000097 SkASSERT(pixels);
commit-bot@chromium.org1426c1e2014-03-03 15:43:56 +000098
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +000099 bitmap->setConfig(info, rowBytes);
100 bitmap->setPixelRef(pixels);
commit-bot@chromium.org1426c1e2014-03-03 15:43:56 +0000101 return true;
102 }
103};
104
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000105} // namespace
106
mtklein@google.coma7a9f372013-10-18 20:52:44 +0000107void WriteTask::draw() {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000108 SkString dir(FLAGS_writePath[0]);
109 this->makeDirOrFail(dir);
110 for (int i = 0; i < fSuffixes.count(); i++) {
111 dir = SkOSPath::SkPathJoin(dir.c_str(), fSuffixes[i].c_str());
112 this->makeDirOrFail(dir);
113 }
commit-bot@chromium.org99589af2013-12-10 14:53:16 +0000114 SkString path = SkOSPath::SkPathJoin(dir.c_str(), fGmName.c_str());
115 path.append(".png");
commit-bot@chromium.org1426c1e2014-03-03 15:43:56 +0000116 if (!PngAndRaw::Encode(fBitmap, path.c_str())) {
mtklein@google.coma7a9f372013-10-18 20:52:44 +0000117 this->fail();
118 }
119}
120
121SkString WriteTask::name() const {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000122 SkString name("writing ");
123 for (int i = 0; i < fSuffixes.count(); i++) {
124 name.appendf("%s/", fSuffixes[i].c_str());
125 }
126 name.append(fGmName.c_str());
127 return name;
mtklein@google.coma7a9f372013-10-18 20:52:44 +0000128}
129
130bool WriteTask::shouldSkip() const {
131 return FLAGS_writePath.isEmpty();
132}
133
commit-bot@chromium.org99589af2013-12-10 14:53:16 +0000134static SkString path_to_expected_image(const char* root, const Task& task) {
135 SkString filename = task.name();
136
137 // We know that all names passed in here belong to top-level Tasks, which have a single suffix
138 // (8888, 565, gpu, etc.) indicating what subdirectory to look in.
139 SkTArray<SkString> suffixes;
140 const int suffixLength = split_suffixes(1, filename.c_str(), &suffixes);
141 SkASSERT(1 == suffixes.count());
142
143 // We'll look in root/suffix for images.
144 const SkString dir = SkOSPath::SkPathJoin(root, suffixes[0].c_str());
145
146 // Remove the suffix and tack on a .png.
147 filename.remove(filename.size() - suffixLength, suffixLength);
148 filename.append(".png");
149
commit-bot@chromium.org99589af2013-12-10 14:53:16 +0000150 return SkOSPath::SkPathJoin(dir.c_str(), filename.c_str());
151}
152
153bool WriteTask::Expectations::check(const Task& task, SkBitmap bitmap) const {
commit-bot@chromium.org0888b752014-02-10 16:39:40 +0000154 if (!FLAGS_writePath.isEmpty() && 0 == strcmp(FLAGS_writePath[0], fRoot)) {
155 SkDebugf("We seem to be reading and writing %s concurrently. This won't work.\n", fRoot);
156 return false;
157 }
158
commit-bot@chromium.org99589af2013-12-10 14:53:16 +0000159 const SkString path = path_to_expected_image(fRoot, task);
commit-bot@chromium.org69a0d7a2014-01-06 20:24:21 +0000160 SkBitmap expected;
commit-bot@chromium.orgeef834f2014-03-05 15:37:11 +0000161 if (!PngAndRaw::Decode(path.c_str(), bitmap.info(), &expected)) {
commit-bot@chromium.org69a0d7a2014-01-06 20:24:21 +0000162 return false;
163 }
164
commit-bot@chromium.org69a0d7a2014-01-06 20:24:21 +0000165 return BitmapsEqual(expected, bitmap);
commit-bot@chromium.org99589af2013-12-10 14:53:16 +0000166}
167
mtklein@google.coma7a9f372013-10-18 20:52:44 +0000168} // namespace DM