DM: write failed comparison mode .pngs one more level deep in the tree.
E.g. instead of having to compare
/tmp/dm/565/optimizations.png
vs.
/tmp/dm/replay/optimizations_565.png
it's now
/tmp/dm/565/optimizations.png
vs.
/tmp/dm/replay/565/optimizations.png
This lets working with skdiff go a lot more smoothly.
BUG=
R=bsalomon@google.com
Review URL: https://codereview.chromium.org/88773002
git-svn-id: http://skia.googlecode.com/svn/trunk@12402 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/dm/DM.cpp b/dm/DM.cpp
index 8c30fe6..274ec2a 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -6,6 +6,7 @@
#include "SkCommandLineFlags.h"
#include "SkForceLinking.h"
#include "SkGraphics.h"
+#include "SkString.h"
#include "gm.h"
#include "DMReporter.h"
@@ -39,19 +40,6 @@
__SK_FORCE_IMAGE_DECODER_LINKING;
-// Split str on any characters in delimiters into out. (Think, strtok with a sane API.)
-static void split(const char* str, const char* delimiters, SkTArray<SkString>* out) {
- const char* end = str + strlen(str);
- while (str != end) {
- // Find a token.
- const size_t len = strcspn(str, delimiters);
- out->push_back().set(str, len);
- str += len;
- // Skip any delimiters.
- str += strspn(str, delimiters);
- }
-}
-
// "FooBar" -> "foobar". Obviously, ASCII only.
static SkString lowercase(SkString s) {
for (size_t i = 0; i < s.size(); i++) {
@@ -134,7 +122,7 @@
GM::SetResourcePath(FLAGS_resources[0]);
SkTArray<SkString> configs;
for (int i = 0; i < FLAGS_config.count(); i++) {
- split(FLAGS_config[i], ", ", &configs);
+ SkStrSplit(FLAGS_config[i], ", ", &configs);
}
SkTDArray<GMRegistry::Factory> gms;
diff --git a/dm/DMTask.cpp b/dm/DMTask.cpp
index ba74a5f..a5c75f0 100644
--- a/dm/DMTask.cpp
+++ b/dm/DMTask.cpp
@@ -8,14 +8,15 @@
namespace DM {
Task::Task(Reporter* reporter, TaskRunner* taskRunner)
- : fReporter(reporter), fTaskRunner(taskRunner) {
+ : fReporter(reporter), fTaskRunner(taskRunner), fDepth(0) {
fReporter->start();
}
-Task::Task(const Task& that)
- : INHERITED(that)
- , fReporter(that.fReporter)
- , fTaskRunner(that.fTaskRunner) {
+Task::Task(const Task& parent)
+ : INHERITED(parent)
+ , fReporter(parent.fReporter)
+ , fTaskRunner(parent.fTaskRunner)
+ , fDepth(parent.depth()+1) {
fReporter->start();
}
diff --git a/dm/DMTask.h b/dm/DMTask.h
index 5388196..0d3ef74 100644
--- a/dm/DMTask.h
+++ b/dm/DMTask.h
@@ -18,7 +18,7 @@
class Task : public SkRunnable {
public:
Task(Reporter* reporter, TaskRunner* taskRunner);
- Task(const Task& that);
+ Task(const Task& parent);
virtual ~Task();
void run() SK_OVERRIDE;
@@ -28,6 +28,10 @@
virtual bool shouldSkip() const = 0;
virtual SkString name() const = 0;
+ // Returns the number of parents above this task.
+ // Top-level tasks return 0, their children 1, and so on.
+ int depth() const { return fDepth; }
+
protected:
void spawnChild(Task* task);
void fail();
@@ -36,6 +40,7 @@
// Both unowned.
Reporter* fReporter;
TaskRunner* fTaskRunner;
+ int fDepth;
typedef SkRunnable INHERITED;
};
diff --git a/dm/DMWriteTask.cpp b/dm/DMWriteTask.cpp
index 011b339..c86381f 100644
--- a/dm/DMWriteTask.cpp
+++ b/dm/DMWriteTask.cpp
@@ -3,41 +3,54 @@
#include "DMUtil.h"
#include "SkCommandLineFlags.h"
#include "SkImageEncoder.h"
-
-#include <string.h>
+#include "SkString.h"
DEFINE_string2(writePath, w, "", "If set, write GMs here as .pngs.");
namespace DM {
-WriteTask::WriteTask(const Task& parent, SkBitmap bitmap)
- : Task(parent)
- , fBitmap(bitmap) {
- // Split parent's name <gmName>_<config> into gmName and config.
- const char* parentName = parent.name().c_str();
- const char* fromLastUnderscore = strrchr(parentName, '_');
- const ptrdiff_t gmNameLength = fromLastUnderscore - parentName;
+WriteTask::WriteTask(const Task& parent, SkBitmap bitmap) : Task(parent), fBitmap(bitmap) {
+ const int suffixes = parent.depth() + 1;
+ const char* name = parent.name().c_str();
+ SkTArray<SkString> split;
+ SkStrSplit(name, "_", &split);
+ int totalSuffixLength = 0;
+ for (int i = 0; i < suffixes; i++) {
+ // We're splitting off suffixes from the back to front.
+ fSuffixes.push_back(split[split.count()-i-1]);
+ totalSuffixLength += fSuffixes.back().size() + 1;
+ }
+ fGmName.set(name, strlen(name)-totalSuffixLength);
+}
- fConfig.set(fromLastUnderscore+1);
- fGmName.set(parentName, gmNameLength);
+void WriteTask::makeDirOrFail(SkString dir) {
+ if (!sk_mkdir(dir.c_str())) {
+ this->fail();
+ }
}
void WriteTask::draw() {
- const char* root = FLAGS_writePath[0];
- const SkString dir = SkOSPath::SkPathJoin(root, fConfig.c_str());
- if (!sk_mkdir(root) ||
- !sk_mkdir(dir.c_str()) ||
- !SkImageEncoder::EncodeFile(Png(SkOSPath::SkPathJoin(dir.c_str(), fGmName.c_str())).c_str(),
+ SkString dir(FLAGS_writePath[0]);
+ this->makeDirOrFail(dir);
+ for (int i = 0; i < fSuffixes.count(); i++) {
+ dir = SkOSPath::SkPathJoin(dir.c_str(), fSuffixes[i].c_str());
+ this->makeDirOrFail(dir);
+ }
+ if (!SkImageEncoder::EncodeFile(Png(SkOSPath::SkPathJoin(dir.c_str(), fGmName.c_str())).c_str(),
fBitmap,
SkImageEncoder::kPNG_Type,
- 100/*quality*/))
- {
+ 100/*quality*/)) {
this->fail();
}
}
SkString WriteTask::name() const {
- return SkStringPrintf("writing %s/%s.png", fConfig.c_str(), fGmName.c_str());
+ SkString name("writing ");
+ for (int i = 0; i < fSuffixes.count(); i++) {
+ name.appendf("%s/", fSuffixes[i].c_str());
+ }
+ name.append(fGmName.c_str());
+ return name;
}
bool WriteTask::shouldSkip() const {
diff --git a/dm/DMWriteTask.h b/dm/DMWriteTask.h
index 7a9b4fa..82a26bc 100644
--- a/dm/DMWriteTask.h
+++ b/dm/DMWriteTask.h
@@ -4,6 +4,7 @@
#include "DMTask.h"
#include "SkBitmap.h"
#include "SkString.h"
+#include "SkTArray.h"
// Writes a bitmap to a file.
@@ -12,7 +13,8 @@
class WriteTask : public Task {
public:
- WriteTask(const Task& parent, SkBitmap bitmap);
+ WriteTask(const Task& parent, // WriteTask must be a child Task. Pass its parent here.
+ SkBitmap bitmap); // Bitmap to write.
virtual void draw() SK_OVERRIDE;
virtual bool usesGpu() const SK_OVERRIDE { return false; }
@@ -20,9 +22,11 @@
virtual SkString name() const SK_OVERRIDE;
private:
- SkString fConfig;
+ SkTArray<SkString> fSuffixes;
SkString fGmName;
const SkBitmap fBitmap;
+
+ void makeDirOrFail(SkString dir);
};
} // namespace DM
diff --git a/include/core/SkString.h b/include/core/SkString.h
index 291bd65..ce87312 100644
--- a/include/core/SkString.h
+++ b/include/core/SkString.h
@@ -11,6 +11,7 @@
#define SkString_DEFINED
#include "SkScalar.h"
+#include "SkTArray.h"
#include <stdarg.h>
@@ -244,4 +245,7 @@
a.swap(b);
}
+// Split str on any characters in delimiters into out. (Think, strtok with a sane API.)
+void SkStrSplit(const char* str, const char* delimiters, SkTArray<SkString>* out);
+
#endif
diff --git a/src/core/SkString.cpp b/src/core/SkString.cpp
index e30b89f..643dfb1 100644
--- a/src/core/SkString.cpp
+++ b/src/core/SkString.cpp
@@ -634,5 +634,17 @@
return formattedOutput;
}
+void SkStrSplit(const char* str, const char* delimiters, SkTArray<SkString>* out) {
+ const char* end = str + strlen(str);
+ while (str != end) {
+ // Find a token.
+ const size_t len = strcspn(str, delimiters);
+ out->push_back().set(str, len);
+ str += len;
+ // Skip any delimiters.
+ str += strspn(str, delimiters);
+ }
+}
+
#undef VSNPRINTF
#undef SNPRINTF
diff --git a/tests/StringTest.cpp b/tests/StringTest.cpp
index 462fcfa..c8c10e1 100644
--- a/tests/StringTest.cpp
+++ b/tests/StringTest.cpp
@@ -192,3 +192,16 @@
#include "TestClassDef.h"
DEFINE_TESTCLASS("String", StringTestClass, TestString)
+
+DEF_TEST(String_SkStrSplit, r) {
+ SkTArray<SkString> results;
+
+ SkStrSplit("a-_b_c-dee--f-_-_-g-", "-_", &results);
+ REPORTER_ASSERT(r, results.count() == 6);
+ REPORTER_ASSERT(r, results[0].equals("a"));
+ REPORTER_ASSERT(r, results[1].equals("b"));
+ REPORTER_ASSERT(r, results[2].equals("c"));
+ REPORTER_ASSERT(r, results[3].equals("dee"));
+ REPORTER_ASSERT(r, results[4].equals("f"));
+ REPORTER_ASSERT(r, results[5].equals("g"));
+}