Reverting r12427

git-svn-id: http://skia.googlecode.com/svn/trunk@12428 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/DEPS b/DEPS
index c009f59..13282722 100644
--- a/DEPS
+++ b/DEPS
@@ -10,8 +10,7 @@
 deps = {
   # DEPS using https://chromium.googlesource.com are pulled from chromium @ r205199
   # (see https://chromium.googlesource.com/chromium/chromium/+/c59bfa8ef877f45bfa859669053859857af1d279)
-  # NOTE: Angle has been reverted to http://angleproject.googlecode.com/svn/trunk@1268
-  "third_party/externals/angle" : "https://chromium.googlesource.com/external/angleproject.git@e574e26f48223a6718feab841b4a7720785b497a",
+  "third_party/externals/angle" : "https://chromium.googlesource.com/external/angleproject.git",
   "third_party/externals/fontconfig" : "https://skia.googlesource.com/third_party/fontconfig.git@2.10.93",
   "third_party/externals/freetype" : "https://skia.googlesource.com/third_party/freetype2.git@VER-2-5-0-1",
   "third_party/externals/gyp" : "https://chromium.googlesource.com/external/gyp.git@d0176c0a2a9e558662905c328c3aa93fd25bbf12",
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/DMComparisonTask.cpp b/dm/DMComparisonTask.cpp
deleted file mode 100644
index bb4e656..0000000
--- a/dm/DMComparisonTask.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "DMComparisonTask.h"
-#include "DMUtil.h"
-
-namespace DM {
-
-ComparisonTask::ComparisonTask(const Task& parent,
-                               skiagm::Expectations expectations,
-                               SkBitmap bitmap)
-    : Task(parent)
-    , fName(parent.name())  // Masquerade as parent so failures are attributed to it.
-    , fExpectations(expectations)
-    , fBitmap(bitmap)
-    {}
-
-void ComparisonTask::draw() {
-    if (!MeetsExpectations(fExpectations, fBitmap)) {
-        this->fail();
-    }
-}
-
-}  // namespace DM
diff --git a/dm/DMComparisonTask.h b/dm/DMComparisonTask.h
deleted file mode 100644
index 265a58c..0000000
--- a/dm/DMComparisonTask.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef DMComparisonTask_DEFINED
-#define DMComparisonTask_DEFINED
-
-#include "DMTask.h"
-#include "SkBitmap.h"
-#include "SkString.h"
-#include "gm_expectations.h"
-
-namespace DM {
-
-// We use ComparisonTask to move CPU-bound comparison work of GpuTasks back to
-// the main thread pool, where we probably have more threads available.
-
-class ComparisonTask : public Task {
-public:
-    ComparisonTask(const Task& parent, skiagm::Expectations, SkBitmap);
-
-    virtual void draw() SK_OVERRIDE;
-    virtual bool usesGpu() const SK_OVERRIDE { return false; }
-    virtual bool shouldSkip() const SK_OVERRIDE { return false; }
-    virtual SkString name() const SK_OVERRIDE { return fName; }
-
-private:
-    const SkString fName;
-    const skiagm::Expectations fExpectations;
-    const SkBitmap fBitmap;
-};
-
-}  // namespace DM
-
-#endif  // DMComparisonTask_DEFINED
diff --git a/dm/DMCpuTask.cpp b/dm/DMCpuTask.cpp
index 1d1d401..3f51c8a 100644
--- a/dm/DMCpuTask.cpp
+++ b/dm/DMCpuTask.cpp
@@ -1,7 +1,9 @@
 #include "DMCpuTask.h"
+#include "DMChecksumTask.h"
 #include "DMPipeTask.h"
 #include "DMReplayTask.h"
 #include "DMSerializeTask.h"
+#include "DMTileGridTask.h"
 #include "DMUtil.h"
 #include "DMWriteTask.h"
 
@@ -30,19 +32,19 @@
     fGM->draw(&canvas);
     canvas.flush();
 
-    if (!MeetsExpectations(fExpectations, bitmap)) {
-        this->fail();
-    }
+#define SPAWN(ChildTask, ...) this->spawnChild(SkNEW_ARGS(ChildTask, (*this, __VA_ARGS__)))
+    SPAWN(ChecksumTask, fExpectations, bitmap);
 
-    this->spawnChild(SkNEW_ARGS(PipeTask, (*this, fGMFactory(NULL), bitmap, false, false)));
-    this->spawnChild(SkNEW_ARGS(PipeTask, (*this, fGMFactory(NULL), bitmap, true, false)));
-    this->spawnChild(SkNEW_ARGS(PipeTask, (*this, fGMFactory(NULL), bitmap, true, true)));
+    SPAWN(PipeTask, fGMFactory(NULL), bitmap, false, false);
+    SPAWN(PipeTask, fGMFactory(NULL), bitmap, true, false);
+    SPAWN(PipeTask, fGMFactory(NULL), bitmap, true, true);
+    SPAWN(ReplayTask, fGMFactory(NULL), bitmap, false);
+    SPAWN(ReplayTask, fGMFactory(NULL), bitmap, true);
+    SPAWN(SerializeTask, fGMFactory(NULL), bitmap);
+    SPAWN(TileGridTask, fGMFactory(NULL), bitmap, SkISize::Make(16,16));
 
-    this->spawnChild(SkNEW_ARGS(ReplayTask, (*this, fGMFactory(NULL), bitmap, true)));
-    this->spawnChild(SkNEW_ARGS(ReplayTask, (*this, fGMFactory(NULL), bitmap, false)));
-
-    this->spawnChild(SkNEW_ARGS(SerializeTask, (*this, fGMFactory(NULL), bitmap)));
-    this->spawnChild(SkNEW_ARGS(WriteTask, (*this, bitmap)));
+    SPAWN(WriteTask, bitmap);
+#undef SPAWN
 }
 
 bool CpuTask::shouldSkip() const {
diff --git a/dm/DMGpuTask.cpp b/dm/DMGpuTask.cpp
index 4d99356..d4c4254 100644
--- a/dm/DMGpuTask.cpp
+++ b/dm/DMGpuTask.cpp
@@ -1,6 +1,6 @@
 #include "DMGpuTask.h"
 
-#include "DMComparisonTask.h"
+#include "DMChecksumTask.h"
 #include "DMUtil.h"
 #include "DMWriteTask.h"
 #include "SkCommandLineFlags.h"
@@ -60,9 +60,7 @@
     gr->printCacheStats();
 #endif
 
-    // We offload checksum comparison to the main CPU threadpool.
-    // This cuts run time by about 30%.
-    this->spawnChild(SkNEW_ARGS(ComparisonTask, (*this, fExpectations, bitmap)));
+    this->spawnChild(SkNEW_ARGS(ChecksumTask, (*this, fExpectations, bitmap)));
     this->spawnChild(SkNEW_ARGS(WriteTask, (*this, bitmap)));
 }
 
diff --git a/dm/DMPipeTask.cpp b/dm/DMPipeTask.cpp
index 8a8fe62..de3897a 100644
--- a/dm/DMPipeTask.cpp
+++ b/dm/DMPipeTask.cpp
@@ -6,7 +6,7 @@
 #include "SkCommandLineFlags.h"
 #include "SkGPipe.h"
 
-DEFINE_bool(pipe, false, "If true, check several pipe variants against the reference bitmap.");
+DEFINE_bool(pipe, true, "If true, check several pipe variants against the reference bitmap.");
 
 namespace DM {
 
diff --git a/dm/DMReplayTask.cpp b/dm/DMReplayTask.cpp
index 0ec9e25..af8669b 100644
--- a/dm/DMReplayTask.cpp
+++ b/dm/DMReplayTask.cpp
@@ -5,8 +5,8 @@
 #include "SkCommandLineFlags.h"
 #include "SkPicture.h"
 
-DEFINE_bool(replay, false, "If true, run picture replay tests.");
-DEFINE_bool(rtree,  false, "If true, run picture replay tests with an rtree.");
+DEFINE_bool(replay, true, "If true, run picture replay tests.");
+DEFINE_bool(rtree,  true, "If true, run picture replay tests with an rtree.");
 
 namespace DM {
 
diff --git a/dm/DMReplayTask.h b/dm/DMReplayTask.h
index 1217c07..1245009 100644
--- a/dm/DMReplayTask.h
+++ b/dm/DMReplayTask.h
@@ -15,8 +15,8 @@
 
 public:
     ReplayTask(const Task& parent,  // ReplayTask must be a child task.  Pass its parent here.
-               skiagm::GM*,         // GM to run through a pipe.  Takes ownership.
-               SkBitmap reference,  // Bitmap to compare pipe results to.
+               skiagm::GM*,         // GM to run through a picture.  Takes ownership.
+               SkBitmap reference,  // Bitmap to compare picture replay results to.
                bool useRTree);      // Record with an RTree?
 
     virtual void draw() SK_OVERRIDE;
diff --git a/dm/DMReporter.cpp b/dm/DMReporter.cpp
index 0e01d71..31310d1 100644
--- a/dm/DMReporter.cpp
+++ b/dm/DMReporter.cpp
@@ -12,7 +12,7 @@
     }
 
     SkString status;
-    status.printf("\r\033[K%d / %d", this->finished(), this->started());
+    status.printf("\r\033[K%d tasks left", this->started() - this->finished());
     const int failed = this->failed();
     if (failed > 0) {
         status.appendf(", %d failed", failed);
diff --git a/dm/DMSerializeTask.cpp b/dm/DMSerializeTask.cpp
index d71dfdc..8bc8c8e 100644
--- a/dm/DMSerializeTask.cpp
+++ b/dm/DMSerializeTask.cpp
@@ -6,7 +6,7 @@
 #include "SkPicture.h"
 #include "SkPixelRef.h"
 
-DEFINE_bool(serialize, false, "If true, run picture serialization tests.");
+DEFINE_bool(serialize, true, "If true, run picture serialization tests.");
 
 namespace DM {
 
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/DMUtil.cpp b/dm/DMUtil.cpp
index d521484..6cf6c22 100644
--- a/dm/DMUtil.cpp
+++ b/dm/DMUtil.cpp
@@ -15,18 +15,9 @@
     return s;
 }
 
-bool MeetsExpectations(const skiagm::Expectations& expectations, const SkBitmap bitmap) {
-    if (expectations.ignoreFailure() || expectations.empty()) {
-        return true;
-    }
-    const skiagm::GmResultDigest digest(bitmap);
-    return expectations.match(digest);
-}
-
 void RecordPicture(skiagm::GM* gm, SkPicture* picture, uint32_t recordFlags) {
-    SkCanvas* canvas = picture->beginRecording(SkScalarCeilToInt(gm->width()),
-                                               SkScalarCeilToInt(gm->height()),
-                                               recordFlags);
+    const SkISize size = gm->getISize();
+    SkCanvas* canvas = picture->beginRecording(size.width(), size.height(), recordFlags);
     canvas->concat(gm->getInitialTransform());
     gm->draw(canvas);
     canvas->flush();
@@ -34,7 +25,8 @@
 }
 
 void SetupBitmap(const SkBitmap::Config config, skiagm::GM* gm, SkBitmap* bitmap) {
-    bitmap->setConfig(config, SkScalarCeilToInt(gm->width()), SkScalarCeilToInt(gm->height()));
+    const SkISize size = gm->getISize();
+    bitmap->setConfig(config, size.width(), size.height());
     bitmap->allocPixels();
     bitmap->eraseColor(0x00000000);
 }
diff --git a/dm/DMUtil.h b/dm/DMUtil.h
index 512ad64..5f22df0 100644
--- a/dm/DMUtil.h
+++ b/dm/DMUtil.h
@@ -15,9 +15,6 @@
 // Png("a") -> "a.png"
 SkString Png(SkString s);
 
-// Roughly, expectations.match(GmResultDigest(bitmap)), but calculates the digest lazily.
-bool MeetsExpectations(const skiagm::Expectations& expectations, const SkBitmap bitmap);
-
 // Draw gm to picture.  Passes recordFlags to SkPicture::beginRecording().
 void RecordPicture(skiagm::GM* gm, SkPicture* picture, uint32_t recordFlags = 0);
 
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/dm/README b/dm/README
index 6cde686..78b962e 100644
--- a/dm/README
+++ b/dm/README
@@ -7,7 +7,6 @@
   --writePicturePath
 
   --deferred
-  --tiledGrid
 
 
 DM's design is based around Tasks and a TaskRunner.
diff --git a/expectations/gm/Test-Android-GalaxyNexus-SGX540-Arm7-Debug/expected-results.json b/expectations/gm/Test-Android-GalaxyNexus-SGX540-Arm7-Debug/expected-results.json
index 67676ab..5b0db71 100644
--- a/expectations/gm/Test-Android-GalaxyNexus-SGX540-Arm7-Debug/expected-results.json
+++ b/expectations/gm/Test-Android-GalaxyNexus-SGX540-Arm7-Debug/expected-results.json
@@ -2095,24 +2095,18 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2789357359936426897
+          16101291896048576683
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11420474396559742656
+          6958362917585628191
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-Android-GalaxyNexus-SGX540-Arm7-Release/expected-results.json b/expectations/gm/Test-Android-GalaxyNexus-SGX540-Arm7-Release/expected-results.json
index 8a61559..28f1c4a 100644
--- a/expectations/gm/Test-Android-GalaxyNexus-SGX540-Arm7-Release/expected-results.json
+++ b/expectations/gm/Test-Android-GalaxyNexus-SGX540-Arm7-Release/expected-results.json
@@ -2095,24 +2095,18 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2789357359936426897
+          16101291896048576683
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11420474396559742656
+          6958362917585628191
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-Android-IntelRhb-SGX544-x86-Debug/expected-results.json b/expectations/gm/Test-Android-IntelRhb-SGX544-x86-Debug/expected-results.json
index c0de7a6..f0f3b23 100644
--- a/expectations/gm/Test-Android-IntelRhb-SGX544-x86-Debug/expected-results.json
+++ b/expectations/gm/Test-Android-IntelRhb-SGX544-x86-Debug/expected-results.json
@@ -2634,36 +2634,27 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2481797737367594615
+          7789211976036245847
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          8086938262113983689
+          12063547141229638542
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          10512095643464253945
+          8512582036956628519
         ]
       ], 
-      "bugs": [
-        1759
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-Android-IntelRhb-SGX544-x86-Release/expected-results.json b/expectations/gm/Test-Android-IntelRhb-SGX544-x86-Release/expected-results.json
index aa47a67..10b6836 100644
--- a/expectations/gm/Test-Android-IntelRhb-SGX544-x86-Release/expected-results.json
+++ b/expectations/gm/Test-Android-IntelRhb-SGX544-x86-Release/expected-results.json
@@ -2634,37 +2634,28 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2481797737367594615
+          7789211976036245847
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          8086938262113983689
+          12063547141229638542
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          10512095643464253945
+          8512582036956628519
         ]
       ], 
-      "bugs": [
-        1759
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "complexclip2_565.png": {
       "allowed-digests": [
diff --git a/expectations/gm/Test-Android-Nexus10-MaliT604-Arm7-Debug/expected-results.json b/expectations/gm/Test-Android-Nexus10-MaliT604-Arm7-Debug/expected-results.json
index 423b235..d90dab3 100644
--- a/expectations/gm/Test-Android-Nexus10-MaliT604-Arm7-Debug/expected-results.json
+++ b/expectations/gm/Test-Android-Nexus10-MaliT604-Arm7-Debug/expected-results.json
@@ -3214,48 +3214,36 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2789357359936426897
+          16101291896048576683
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11420474396559742656
+          6958362917585628191
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          12902148816415894358
+          17182697123061500145
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_msaa4.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          12902148816415894358
+          17182697123061500145
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-Android-Nexus10-MaliT604-Arm7-Release/expected-results.json b/expectations/gm/Test-Android-Nexus10-MaliT604-Arm7-Release/expected-results.json
index 423b235..d90dab3 100644
--- a/expectations/gm/Test-Android-Nexus10-MaliT604-Arm7-Release/expected-results.json
+++ b/expectations/gm/Test-Android-Nexus10-MaliT604-Arm7-Release/expected-results.json
@@ -3214,48 +3214,36 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2789357359936426897
+          16101291896048576683
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11420474396559742656
+          6958362917585628191
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          12902148816415894358
+          17182697123061500145
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_msaa4.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          12902148816415894358
+          17182697123061500145
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-Android-Nexus7-Tegra3-Arm7-Debug/expected-results.json b/expectations/gm/Test-Android-Nexus7-Tegra3-Arm7-Debug/expected-results.json
index 90af7d7..ae5d2b9 100644
--- a/expectations/gm/Test-Android-Nexus7-Tegra3-Arm7-Debug/expected-results.json
+++ b/expectations/gm/Test-Android-Nexus7-Tegra3-Arm7-Debug/expected-results.json
@@ -2437,36 +2437,27 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2789357359936426897
+          16101291896048576683
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11420474396559742656
+          6958362917585628191
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          6811779909537199081
+          829525110335272310
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-Android-Nexus7-Tegra3-Arm7-Release/expected-results.json b/expectations/gm/Test-Android-Nexus7-Tegra3-Arm7-Release/expected-results.json
index 90af7d7..ae5d2b9 100644
--- a/expectations/gm/Test-Android-Nexus7-Tegra3-Arm7-Release/expected-results.json
+++ b/expectations/gm/Test-Android-Nexus7-Tegra3-Arm7-Release/expected-results.json
@@ -2437,36 +2437,27 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2789357359936426897
+          16101291896048576683
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11420474396559742656
+          6958362917585628191
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          6811779909537199081
+          829525110335272310
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-Android-NexusS-SGX540-Arm7-Debug/expected-results.json b/expectations/gm/Test-Android-NexusS-SGX540-Arm7-Debug/expected-results.json
index f5cdea2..be01d1c 100644
--- a/expectations/gm/Test-Android-NexusS-SGX540-Arm7-Debug/expected-results.json
+++ b/expectations/gm/Test-Android-NexusS-SGX540-Arm7-Debug/expected-results.json
@@ -2125,24 +2125,18 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2407516010050573816
+          7322753158848112633
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          5735401648209592903
+          13587257461703619696
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-Android-NexusS-SGX540-Arm7-Release/expected-results.json b/expectations/gm/Test-Android-NexusS-SGX540-Arm7-Release/expected-results.json
index f5cdea2..be01d1c 100644
--- a/expectations/gm/Test-Android-NexusS-SGX540-Arm7-Release/expected-results.json
+++ b/expectations/gm/Test-Android-NexusS-SGX540-Arm7-Release/expected-results.json
@@ -2125,24 +2125,18 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2407516010050573816
+          7322753158848112633
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          5735401648209592903
+          13587257461703619696
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-Android-Xoom-Tegra2-Arm7-Debug/expected-results.json b/expectations/gm/Test-Android-Xoom-Tegra2-Arm7-Debug/expected-results.json
index f950faa..077035b 100644
--- a/expectations/gm/Test-Android-Xoom-Tegra2-Arm7-Debug/expected-results.json
+++ b/expectations/gm/Test-Android-Xoom-Tegra2-Arm7-Debug/expected-results.json
@@ -2485,36 +2485,27 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2407516010050573816
+          7322753158848112633
         ]
       ], 
-      "bugs": [
-        1759
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          5735401648209592903
+          13587257461703619696
         ]
       ], 
-      "bugs": [
-        1759
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          16722577663537717052
+          10584626711301986223
         ]
       ], 
-      "bugs": [
-        1759
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-Android-Xoom-Tegra2-Arm7-Release/expected-results.json b/expectations/gm/Test-Android-Xoom-Tegra2-Arm7-Release/expected-results.json
index b693c15..f934f7e 100644
--- a/expectations/gm/Test-Android-Xoom-Tegra2-Arm7-Release/expected-results.json
+++ b/expectations/gm/Test-Android-Xoom-Tegra2-Arm7-Release/expected-results.json
@@ -2485,37 +2485,28 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2407516010050573816
+          7322753158848112633
         ]
       ], 
-      "bugs": [
-        1759
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          5735401648209592903
+          13587257461703619696
         ]
       ], 
-      "bugs": [
-        1759
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          16722577663537717052
+          10584626711301986223
         ]
       ], 
-      "bugs": [
-        1759
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "complexclip2_565.png": {
       "allowed-digests": [
diff --git a/expectations/gm/Test-ChromeOS-Alex-GMA3150-x86-Debug/expected-results.json b/expectations/gm/Test-ChromeOS-Alex-GMA3150-x86-Debug/expected-results.json
index af5c50c..767cef6 100644
--- a/expectations/gm/Test-ChromeOS-Alex-GMA3150-x86-Debug/expected-results.json
+++ b/expectations/gm/Test-ChromeOS-Alex-GMA3150-x86-Debug/expected-results.json
@@ -1900,25 +1900,19 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          10175733445319554072
+          4055619075226987340
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2036989462359391258
+          4557992853592297566
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "complexclip2_565.png": {
       "allowed-digests": [
diff --git a/expectations/gm/Test-ChromeOS-Alex-GMA3150-x86-Release/expected-results.json b/expectations/gm/Test-ChromeOS-Alex-GMA3150-x86-Release/expected-results.json
index 85a0df3..d9b5065 100644
--- a/expectations/gm/Test-ChromeOS-Alex-GMA3150-x86-Release/expected-results.json
+++ b/expectations/gm/Test-ChromeOS-Alex-GMA3150-x86-Release/expected-results.json
@@ -1900,24 +1900,18 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          10175733445319554072
+          4055619075226987340
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2036989462359391258
+          4557992853592297566
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-ChromeOS-Daisy-MaliT604-Arm7-Debug/expected-results.json b/expectations/gm/Test-ChromeOS-Daisy-MaliT604-Arm7-Debug/expected-results.json
index 0883236..f3e1235 100644
--- a/expectations/gm/Test-ChromeOS-Daisy-MaliT604-Arm7-Debug/expected-results.json
+++ b/expectations/gm/Test-ChromeOS-Daisy-MaliT604-Arm7-Debug/expected-results.json
@@ -1900,25 +1900,19 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          7633944210736451677
+          4723751871359287410
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2594983628740042115
+          16275740961157987318
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "complexclip2_565.png": {
       "allowed-digests": [
diff --git a/expectations/gm/Test-ChromeOS-Daisy-MaliT604-Arm7-Release/expected-results.json b/expectations/gm/Test-ChromeOS-Daisy-MaliT604-Arm7-Release/expected-results.json
index 0883236..80a500e 100644
--- a/expectations/gm/Test-ChromeOS-Daisy-MaliT604-Arm7-Release/expected-results.json
+++ b/expectations/gm/Test-ChromeOS-Daisy-MaliT604-Arm7-Release/expected-results.json
@@ -1900,24 +1900,18 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          7633944210736451677
+          4723751871359287410
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2594983628740042115
+          16275740961157987318
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-ChromeOS-Link-HD4000-x86_64-Debug/expected-results.json b/expectations/gm/Test-ChromeOS-Link-HD4000-x86_64-Debug/expected-results.json
index b3b2c30..7f77929 100644
--- a/expectations/gm/Test-ChromeOS-Link-HD4000-x86_64-Debug/expected-results.json
+++ b/expectations/gm/Test-ChromeOS-Link-HD4000-x86_64-Debug/expected-results.json
@@ -1900,24 +1900,18 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          10175733445319554072
+          4055619075226987340
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2036989462359391258
+          4557992853592297566
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-ChromeOS-Link-HD4000-x86_64-Release/expected-results.json b/expectations/gm/Test-ChromeOS-Link-HD4000-x86_64-Release/expected-results.json
index b3b2c30..7f77929 100644
--- a/expectations/gm/Test-ChromeOS-Link-HD4000-x86_64-Release/expected-results.json
+++ b/expectations/gm/Test-ChromeOS-Link-HD4000-x86_64-Release/expected-results.json
@@ -1900,24 +1900,18 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          10175733445319554072
+          4055619075226987340
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2036989462359391258
+          4557992853592297566
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "complexclip2_565.png": {
diff --git a/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug/expected-results.json b/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug/expected-results.json
index 317e32e..7641da1 100644
--- a/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug/expected-results.json
+++ b/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug/expected-results.json
@@ -4588,12 +4588,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3224501961775566147
+          15826989673456070846
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-mac.png": {
diff --git a/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release/expected-results.json b/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release/expected-results.json
index ade1275..743fbf1 100644
--- a/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release/expected-results.json
+++ b/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release/expected-results.json
@@ -4048,12 +4048,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3224501961775566147
+          15826989673456070846
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-mac.png": {
diff --git a/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json b/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
index 02c316e..bf3379e 100644
--- a/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
+++ b/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
@@ -4588,13 +4588,10 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3224501961775566147
+          15826989673456070846
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_pdf-mac.png": {
       "allowed-digests": [
diff --git a/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json b/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json
index 89df3d4..caaec84 100644
--- a/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json
+++ b/expectations/gm/Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json
@@ -3724,12 +3724,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3224501961775566147
+          15826989673456070846
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-mac.png": {
diff --git a/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug/expected-results.json b/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug/expected-results.json
index 4c9d207..8d472c3 100644
--- a/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug/expected-results.json
+++ b/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug/expected-results.json
@@ -4927,12 +4927,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3224501961775566147
+          15826989673456070846
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-mac.png": {
diff --git a/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release/expected-results.json b/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release/expected-results.json
index 8b0e389..3e21464 100644
--- a/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release/expected-results.json
+++ b/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release/expected-results.json
@@ -4483,13 +4483,10 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3224501961775566147
+          15826989673456070846
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_pdf-mac.png": {
       "allowed-digests": [
diff --git a/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json b/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
index 989a384..d14b996 100644
--- a/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
+++ b/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
@@ -4927,12 +4927,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3224501961775566147
+          15826989673456070846
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-mac.png": {
diff --git a/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json b/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json
index 20e9ca9..da61ed9 100644
--- a/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json
+++ b/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json
@@ -4075,12 +4075,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3224501961775566147
+          15826989673456070846
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-mac.png": {
diff --git a/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug/expected-results.json b/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug/expected-results.json
index 77fe9e8..40de340 100644
--- a/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug/expected-results.json
+++ b/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug/expected-results.json
@@ -4789,13 +4789,10 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3224501961775566147
+          15826989673456070846
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_pdf-mac.png": {
       "allowed-digests": [
diff --git a/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release/expected-results.json b/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release/expected-results.json
index d31b0ec..964263f 100644
--- a/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release/expected-results.json
+++ b/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release/expected-results.json
@@ -4513,12 +4513,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3224501961775566147
+          15826989673456070846
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-mac.png": {
diff --git a/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json b/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
index bcd9ee1..e1a0d9c 100644
--- a/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
+++ b/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
@@ -4789,12 +4789,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3224501961775566147
+          15826989673456070846
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-mac.png": {
diff --git a/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json b/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json
index 35ec04a..09cb6eb 100644
--- a/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json
+++ b/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json
@@ -4378,12 +4378,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3224501961775566147
+          15826989673456070846
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-mac.png": {
diff --git a/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug/expected-results.json b/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug/expected-results.json
index 3a5992c..fdd0ce5 100644
--- a/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug/expected-results.json
+++ b/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug/expected-results.json
@@ -3502,36 +3502,27 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11405847735693538070
+          14602262721761630857
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          4978814888142061167
+          3481217777013051559
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          10275865613222220507
+          16802525720487425080
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-poppler.png": {
diff --git a/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86-Release/expected-results.json b/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86-Release/expected-results.json
index 31009a5..4d014d1 100644
--- a/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86-Release/expected-results.json
+++ b/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86-Release/expected-results.json
@@ -3502,36 +3502,27 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11405847735693538070
+          14602262721761630857
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          4978814888142061167
+          3481217777013051559
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          10275865613222220507
+          16802525720487425080
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-poppler.png": {
diff --git a/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug/expected-results.json b/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug/expected-results.json
index dcc6e94..b04d258 100644
--- a/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug/expected-results.json
+++ b/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug/expected-results.json
@@ -3502,37 +3502,28 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11405847735693538070
+          14602262721761630857
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          4978814888142061167
+          3481217777013051559
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          10275865613222220507
+          16802525720487425080
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_pdf-poppler.png": {
       "allowed-digests": [
diff --git a/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release/expected-results.json b/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release/expected-results.json
index 851a205..5ee204c 100644
--- a/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release/expected-results.json
+++ b/expectations/gm/Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release/expected-results.json
@@ -3502,36 +3502,27 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11405847735693538070
+          14602262721761630857
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          4978814888142061167
+          3481217777013051559
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          10275865613222220507
+          16802525720487425080
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-poppler.png": {
diff --git a/expectations/gm/Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug/expected-results.json b/expectations/gm/Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug/expected-results.json
index 63be5e1..e02d876 100644
--- a/expectations/gm/Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug/expected-results.json
+++ b/expectations/gm/Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug/expected-results.json
@@ -3142,24 +3142,18 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11405847735693538070
+          14602262721761630857
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          4978814888142061167
+          3481217777013051559
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-poppler.png": {
diff --git a/expectations/gm/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN/expected-results.json b/expectations/gm/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN/expected-results.json
index 86f2324..43fb2e6 100644
--- a/expectations/gm/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN/expected-results.json
+++ b/expectations/gm/Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN/expected-results.json
@@ -3832,37 +3832,28 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11405847735693538070
+          14602262721761630857
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          4978814888142061167
+          3481217777013051559
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          1439955102723765584
+          16802525720487425080
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_pdf-poppler.png": {
       "allowed-digests": [
diff --git a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE/expected-results.json b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE/expected-results.json
index 2bb4b09..b18d04c 100644
--- a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE/expected-results.json
+++ b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE/expected-results.json
@@ -1149,9 +1149,11 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          8745200028676261652
+          12587234088162094708
         ]
-      ]
+      ], 
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "bleed_gpu.png": {
       "allowed-digests": [
@@ -4684,24 +4686,18 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11235313591528676486
+          16744651928576717976
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11235313591528676486
+          16744651928576717976
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-poppler.png": {
@@ -5940,10 +5936,8 @@
           12241316569839901585
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "downsamplebitmap_checkerboard_high_512_256_gpu.png": {
       "allowed-digests": [
@@ -6060,10 +6054,8 @@
           12241316569839901585
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "downsamplebitmap_checkerboard_medium_512_256_gpu.png": {
       "allowed-digests": [
@@ -6180,10 +6172,8 @@
           13919524755191883787
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "downsamplebitmap_image_high_mandrill_512.png_gpu.png": {
       "allowed-digests": [
@@ -6300,10 +6290,8 @@
           13919524755191883787
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "downsamplebitmap_image_medium_mandrill_512.png_gpu.png": {
       "allowed-digests": [
@@ -6420,10 +6408,8 @@
           3631077966779184085
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "downsamplebitmap_text_high_72.00pt_gpu.png": {
       "allowed-digests": [
@@ -6540,10 +6526,8 @@
           3631077966779184085
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "downsamplebitmap_text_medium_72.00pt_gpu.png": {
       "allowed-digests": [
@@ -7182,10 +7166,8 @@
           8650483291288564728
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "filterbitmap_checkerboard_192_192_gpu.png": {
       "allowed-digests": [
@@ -7602,10 +7584,8 @@
           7154075947687660440
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "filterbitmap_image_mandrill_256.png_gpu.png": {
       "allowed-digests": [
@@ -7722,10 +7702,8 @@
           14830136006359090292
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "filterbitmap_image_mandrill_512.png_gpu.png": {
       "allowed-digests": [
diff --git a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite/expected-results.json b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite/expected-results.json
index 0c8720a..d68a12b 100644
--- a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite/expected-results.json
+++ b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite/expected-results.json
@@ -3541,12 +3541,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2373323581539004655
+          14984702717513096997
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-poppler.png": {
diff --git a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Debug/expected-results.json b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Debug/expected-results.json
index 04e392d..2d328f5 100644
--- a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Debug/expected-results.json
+++ b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Debug/expected-results.json
@@ -3523,12 +3523,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11235313591528676486
+          16744651928576717976
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-poppler.png": {
diff --git a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE/expected-results.json b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE/expected-results.json
index 39bcba2..104c394 100644
--- a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE/expected-results.json
+++ b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE/expected-results.json
@@ -1149,9 +1149,11 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          8745200028676261652
+          12587234088162094708
         ]
-      ]
+      ], 
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "bleed_gpu.png": {
       "allowed-digests": [
@@ -4684,24 +4686,18 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11235313591528676486
+          16744651928576717976
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11235313591528676486
+          16744651928576717976
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-poppler.png": {
@@ -5940,10 +5936,8 @@
           12241316569839901585
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "downsamplebitmap_checkerboard_high_512_256_gpu.png": {
       "allowed-digests": [
@@ -6060,10 +6054,8 @@
           12241316569839901585
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "downsamplebitmap_checkerboard_medium_512_256_gpu.png": {
       "allowed-digests": [
@@ -6180,10 +6172,8 @@
           13919524755191883787
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "downsamplebitmap_image_high_mandrill_512.png_gpu.png": {
       "allowed-digests": [
@@ -6300,10 +6290,8 @@
           13919524755191883787
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "downsamplebitmap_image_medium_mandrill_512.png_gpu.png": {
       "allowed-digests": [
@@ -6420,10 +6408,8 @@
           3631077966779184085
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "downsamplebitmap_text_high_72.00pt_gpu.png": {
       "allowed-digests": [
@@ -6540,10 +6526,8 @@
           3631077966779184085
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "downsamplebitmap_text_medium_72.00pt_gpu.png": {
       "allowed-digests": [
@@ -7182,10 +7166,8 @@
           8650483291288564728
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "filterbitmap_checkerboard_192_192_gpu.png": {
       "allowed-digests": [
@@ -7602,10 +7584,8 @@
           7154075947687660440
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "filterbitmap_image_mandrill_256.png_gpu.png": {
       "allowed-digests": [
@@ -7722,10 +7702,8 @@
           14830136006359090292
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "ignore-failure": true, 
+      "reviewed-by-human": true
     }, 
     "filterbitmap_image_mandrill_512.png_gpu.png": {
       "allowed-digests": [
diff --git a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite/expected-results.json b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite/expected-results.json
index 2d2dd03..bb69797 100644
--- a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite/expected-results.json
+++ b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite/expected-results.json
@@ -3541,13 +3541,10 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          7353287899127074472
+          13257802686942423930
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "colortype_pdf-poppler.png": {
       "allowed-digests": [
diff --git a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Release/expected-results.json b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Release/expected-results.json
index 450fdaa..b6f3c43 100644
--- a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Release/expected-results.json
+++ b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86-Release/expected-results.json
@@ -3523,12 +3523,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11235313591528676486
+          16744651928576717976
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-poppler.png": {
diff --git a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86_64-Debug/expected-results.json b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86_64-Debug/expected-results.json
index 7790e15..d1c8f1f 100644
--- a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86_64-Debug/expected-results.json
+++ b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86_64-Debug/expected-results.json
@@ -3523,12 +3523,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11235313591528676486
+          16744651928576717976
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-poppler.png": {
diff --git a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86_64-Release/expected-results.json b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86_64-Release/expected-results.json
index 7790e15..d1c8f1f 100644
--- a/expectations/gm/Test-Win7-ShuttleA-HD2000-x86_64-Release/expected-results.json
+++ b/expectations/gm/Test-Win7-ShuttleA-HD2000-x86_64-Release/expected-results.json
@@ -3523,12 +3523,9 @@
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11235313591528676486
+          16744651928576717976
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
       "reviewed-by-human": false
     }, 
     "colortype_pdf-poppler.png": {
diff --git a/gm/bitmapcopy.cpp b/gm/bitmapcopy.cpp
index 5e88cfd..928b403 100644
--- a/gm/bitmapcopy.cpp
+++ b/gm/bitmapcopy.cpp
@@ -11,7 +11,6 @@
 
 static const char* gConfigNames[] = {
     "unknown config",
-    "A1",
     "A8",
     "Index8",
     "565",
diff --git a/gm/bitmapfilters.cpp b/gm/bitmapfilters.cpp
index f0153e4..5856f87 100644
--- a/gm/bitmapfilters.cpp
+++ b/gm/bitmapfilters.cpp
@@ -47,7 +47,6 @@
 
 static const char* gConfigNames[] = {
     "unknown config",
-    "A1",
     "A8",
     "Index8",
     "565",
diff --git a/gm/rebaseline_server/server.py b/gm/rebaseline_server/server.py
index 47ee236..670c94d 100755
--- a/gm/rebaseline_server/server.py
+++ b/gm/rebaseline_server/server.py
@@ -19,8 +19,10 @@
 import re
 import shutil
 import socket
+import subprocess
 import sys
 import thread
+import threading
 import time
 import urlparse
 
@@ -42,8 +44,6 @@
 
 ACTUALS_SVN_REPO = 'http://skia-autogen.googlecode.com/svn/gm-actual'
 PATHSPLIT_RE = re.compile('/([^/]+)/(.+)')
-TRUNK_DIRECTORY = os.path.dirname(os.path.dirname(os.path.dirname(
-    os.path.realpath(__file__))))
 EXPECTATIONS_DIR = os.path.join(TRUNK_DIRECTORY, 'expectations', 'gm')
 GENERATED_IMAGES_ROOT = os.path.join(PARENT_DIRECTORY, 'static',
                                      'generated-images')
@@ -67,6 +67,29 @@
 
 _SERVER = None   # This gets filled in by main()
 
+
+def _run_command(args, directory):
+  """Runs a command and returns stdout as a single string.
+
+  Args:
+    args: the command to run, as a list of arguments
+    directory: directory within which to run the command
+
+  Returns: stdout, as a string
+
+  Raises an Exception if the command failed (exited with nonzero return code).
+  """
+  logging.debug('_run_command: %s in directory %s' % (args, directory))
+  proc = subprocess.Popen(args, cwd=directory,
+                          stdout=subprocess.PIPE,
+                          stderr=subprocess.PIPE)
+  (stdout, stderr) = proc.communicate()
+  if proc.returncode is not 0:
+    raise Exception('command "%s" failed in dir "%s": %s' %
+                    (args, directory, stderr))
+  return stdout
+
+
 def _get_routable_ip_address():
   """Returns routable IP address of this host (the IP address of its network
      interface that would be used for most traffic, not its localhost
@@ -77,6 +100,7 @@
   sock.close()
   return host
 
+
 def _create_svn_checkout(dir_path, repo_url):
   """Creates local checkout of an SVN repository at the specified directory
   path, returning an svn.Svn object referring to the local checkout.
@@ -120,69 +144,87 @@
     self._actuals_repo = _create_svn_checkout(
         dir_path=actuals_dir, repo_url=ACTUALS_SVN_REPO)
 
-    # We only update the expectations dir if the server was run with a
-    # nonzero --reload argument; otherwise, we expect the user to maintain
-    # her own expectations as she sees fit.
-    #
-    # TODO(epoger): Use git instead of svn to update the expectations dir, since
-    # the Skia repo is moving to git.
-    # When we make that change, we will have to update the entire workspace,
-    # not just the expectations dir, because git only operates on the repo
-    # as a whole.
-    # And since Skia uses depot_tools to manage its dependencies, we will have
-    # to run "gclient sync" rather than a raw "git pull".
-    if reload_seconds:
-      self._expectations_repo = svn.Svn(EXPECTATIONS_DIR)
-    else:
-      self._expectations_repo = None
+    # Reentrant lock that must be held whenever updating EITHER of:
+    # 1. self._results
+    # 2. the expected or actual results on local disk
+    self.results_rlock = threading.RLock()
+    # self._results will be filled in by calls to update_results()
+    self._results = None
 
+  @property
+  def results(self):
+    """ Returns the most recently generated results, or None if update_results()
+    has not been called yet. """
+    return self._results
+
+  @property
   def is_exported(self):
     """ Returns true iff HTTP clients on other hosts are allowed to access
     this server. """
     return self._export
 
+  @property
   def is_editable(self):
     """ Returns true iff HTTP clients are allowed to submit new baselines. """
     return self._editable
 
+  @property
   def reload_seconds(self):
     """ Returns the result reload period in seconds, or 0 if we don't reload
     results. """
     return self._reload_seconds
 
   def update_results(self):
-    """ Create or update self.results, based on the expectations in
+    """ Create or update self._results, based on the expectations in
     EXPECTATIONS_DIR and the latest actuals from skia-autogen.
+
+    We hold self.results_rlock while we do this, to guarantee that no other
+    thread attempts to update either self._results or the underlying files at
+    the same time.
     """
-    logging.info('Updating actual GM results in %s from SVN repo %s ...' % (
-        self._actuals_dir, ACTUALS_SVN_REPO))
-    self._actuals_repo.Update('.')
+    with self.results_rlock:
+      logging.info('Updating actual GM results in %s from SVN repo %s ...' % (
+          self._actuals_dir, ACTUALS_SVN_REPO))
+      self._actuals_repo.Update('.')
 
-    if self._expectations_repo:
+      # We only update the expectations dir if the server was run with a
+      # nonzero --reload argument; otherwise, we expect the user to maintain
+      # her own expectations as she sees fit.
+      #
+      # Because the Skia repo is moving from SVN to git, and git does not
+      # support updating a single directory tree, we have to update the entire
+      # repo checkout.
+      #
+      # Because Skia uses depot_tools, we have to update using "gclient sync"
+      # instead of raw git (or SVN) update.  Happily, this will work whether
+      # the checkout was created using git or SVN.
+      if self._reload_seconds:
+        logging.info(
+            'Updating expected GM results in %s by syncing Skia repo ...' %
+            EXPECTATIONS_DIR)
+        _run_command(['gclient', 'sync'], TRUNK_DIRECTORY)
+
       logging.info(
-          'Updating expected GM results in %s ...' % EXPECTATIONS_DIR)
-      self._expectations_repo.Update('.')
-
-    logging.info(
           ('Parsing results from actuals in %s and expectations in %s, '
-          + 'and generating pixel diffs (may take a while) ...') % (
-          self._actuals_dir, EXPECTATIONS_DIR))
-    self.results = results.Results(
-        actuals_root=self._actuals_dir,
-        expected_root=EXPECTATIONS_DIR,
-        generated_images_root=GENERATED_IMAGES_ROOT)
+           + 'and generating pixel diffs (may take a while) ...') % (
+               self._actuals_dir, EXPECTATIONS_DIR))
+      self._results = results.Results(
+          actuals_root=self._actuals_dir,
+          expected_root=EXPECTATIONS_DIR,
+          generated_images_root=GENERATED_IMAGES_ROOT)
 
   def _result_reloader(self):
-    """ If --reload argument was specified, reload results at the appropriate
-    interval.
+    """ Reload results at the appropriate interval.  This never exits, so it
+    should be run in its own thread.
     """
-    while self._reload_seconds:
+    while True:
       time.sleep(self._reload_seconds)
       self.update_results()
 
   def run(self):
     self.update_results()
-    thread.start_new_thread(self._result_reloader, ())
+    if self._reload_seconds:
+      thread.start_new_thread(self._result_reloader, ())
 
     if self._export:
       server_address = ('', self._port)
@@ -256,9 +298,9 @@
         # We only return these timestamps if the --reload argument was passed;
         # otherwise, we have no idea when the expectations were last updated
         # (we allow the user to maintain her own expectations as she sees fit).
-        'timeUpdated': time_updated if _SERVER.reload_seconds() else None,
+        'timeUpdated': time_updated if _SERVER.reload_seconds else None,
         'timeNextUpdateAvailable': (
-            (time_updated+_SERVER.reload_seconds()) if _SERVER.reload_seconds()
+            (time_updated+_SERVER.reload_seconds) if _SERVER.reload_seconds
             else None),
 
         # The type we passed to get_results_of_type()
@@ -269,10 +311,10 @@
         'dataHash': str(hash(repr(response_dict['testData']))),
 
         # Whether the server will accept edits back.
-        'isEditable': _SERVER.is_editable(),
+        'isEditable': _SERVER.is_editable,
 
         # Whether the service is accessible from other hosts.
-        'isExported': _SERVER.is_exported(),
+        'isExported': _SERVER.is_exported,
       }
       self.send_json_dict(response_dict)
     except:
@@ -343,7 +385,7 @@
 
     Raises an Exception if there were any problems.
     """
-    if not _SERVER.is_editable():
+    if not _SERVER.is_editable:
       raise Exception('this server is not running in --editable mode')
 
     content_type = self.headers[_HTTP_HEADER_CONTENT_TYPE]
@@ -357,22 +399,23 @@
     logging.debug('do_POST_edits: received new GM expectations data [%s]' %
                   data)
 
-    # Since we must make multiple calls to the Results object, grab a
-    # reference to it in case it is updated to point at a new Results
-    # object within another thread.
-    results_obj = _SERVER.results
-    oldResultsType = data['oldResultsType']
-    oldResults = results_obj.get_results_of_type(oldResultsType)
-    oldResultsHash = str(hash(repr(oldResults['testData'])))
-    if oldResultsHash != data['oldResultsHash']:
-      raise Exception('results of type "%s" changed while the client was '
-                      'making modifications. The client should reload the '
-                      'results and submit the modifications again.' %
-                      oldResultsType)
-    results_obj.edit_expectations(data['modifications'])
-
-    # Now that the edits have been committed, update results to reflect them.
-    _SERVER.update_results()
+    # Update the results on disk with the information we received from the
+    # client.
+    # We must hold _SERVER.results_rlock while we do this, to guarantee that
+    # no other thread updates expectations (from the Skia repo) while we are
+    # updating them (using the info we received from the client).
+    with _SERVER.results_rlock:
+      oldResultsType = data['oldResultsType']
+      oldResults = _SERVER.results.get_results_of_type(oldResultsType)
+      oldResultsHash = str(hash(repr(oldResults['testData'])))
+      if oldResultsHash != data['oldResultsHash']:
+        raise Exception('results of type "%s" changed while the client was '
+                        'making modifications. The client should reload the '
+                        'results and submit the modifications again.' %
+                        oldResultsType)
+      _SERVER.results.edit_expectations(data['modifications'])
+      # Read the updated results back from disk.
+      _SERVER.update_results()
 
   def redirect_to(self, url):
     """ Redirect the HTTP client to a different url.
@@ -445,7 +488,8 @@
   parser.add_argument('--reload', type=int,
                       help=('How often (a period in seconds) to update the '
                             'results.  If specified, both expected and actual '
-                            'results will be updated.  '
+                            'results will be updated by running "gclient sync" '
+                            'on your Skia checkout as a whole.  '
                             'By default, we do not reload at all, and you '
                             'must restart the server to pick up new data.'),
                       default=0)
@@ -456,5 +500,6 @@
                    reload_seconds=args.reload)
   _SERVER.run()
 
+
 if __name__ == '__main__':
   main()
diff --git a/gyp/angle.gyp b/gyp/angle.gyp
index 2a88d56..2b38abf 100644
--- a/gyp/angle.gyp
+++ b/gyp/angle.gyp
@@ -4,9 +4,30 @@
   'conditions': [
     [ 'skia_angle', {
       'target_defaults': {
+        'include_dirs': [
+          '$(DXSDK_DIR)/Include',
+        ],
+        'msvs_settings': {
+          'VCLinkerTool': {
+            'conditions': [
+              [ 'skia_arch_width == 32 ', {
+                'AdditionalLibraryDirectories': [
+                  '$(DXSDK_DIR)/Lib/x86',
+                ],
+              },{
+                'AdditionalLibraryDirectories': [
+                  '$(DXSDK_DIR)/Lib/x64',
+                ],
+              }],
+            ],
+          },
+        },
         'defines': [
           'NOMINMAX',
         ],
+        'defines/': [
+          ['exclude', 'ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES'],
+        ],
       },
       'variables': {
         'component': 'static_library',
diff --git a/gyp/bench.gyp b/gyp/bench.gyp
index 040f7a4..595d77c 100644
--- a/gyp/bench.gyp
+++ b/gyp/bench.gyp
@@ -13,14 +13,89 @@
         '../src/effects',
         '../src/utils',
       ],
-      'includes': [
-        'bench.gypi'
-      ],
       'dependencies': [
         'skia_lib.gyp:skia_lib',
         'bench_timer',
         'flags.gyp:flags',
       ],
+      'sources': [
+        '../bench/AAClipBench.cpp',
+        '../bench/BicubicBench.cpp',
+        '../bench/BitmapBench.cpp',
+        '../bench/BitmapRectBench.cpp',
+        '../bench/BitmapScaleBench.cpp',
+        '../bench/BlurBench.cpp',
+        '../bench/BlurImageFilterBench.cpp',
+        '../bench/BlurRectBench.cpp',
+        '../bench/BlurRoundRectBench.cpp',
+        '../bench/ChartBench.cpp',
+        '../bench/ChecksumBench.cpp',
+        '../bench/ChromeBench.cpp',
+        '../bench/CmapBench.cpp',
+        '../bench/ColorFilterBench.cpp',
+        '../bench/CoverageBench.cpp',
+        '../bench/DashBench.cpp',
+        '../bench/DecodeBench.cpp',
+        '../bench/DeferredCanvasBench.cpp',
+        '../bench/DeferredSurfaceCopyBench.cpp',
+        '../bench/DisplacementBench.cpp',
+        '../bench/FSRectBench.cpp',
+        '../bench/FontCacheBench.cpp',
+        '../bench/FontScalerBench.cpp',
+        '../bench/GameBench.cpp',
+        '../bench/GrMemoryPoolBench.cpp',
+        '../bench/GrResourceCacheBench.cpp',
+        '../bench/GradientBench.cpp',
+        '../bench/HairlinePathBench.cpp',
+        '../bench/ImageCacheBench.cpp',
+        '../bench/ImageDecodeBench.cpp',
+        '../bench/InterpBench.cpp',
+        '../bench/LightingBench.cpp',
+        '../bench/LineBench.cpp',
+        '../bench/MagnifierBench.cpp',
+        '../bench/MathBench.cpp',
+        '../bench/Matrix44Bench.cpp',
+        '../bench/MatrixBench.cpp',
+        '../bench/MatrixConvolutionBench.cpp',
+        '../bench/MemoryBench.cpp',
+        '../bench/MemsetBench.cpp',
+        '../bench/MergeBench.cpp',
+        '../bench/MorphologyBench.cpp',
+        '../bench/MutexBench.cpp',
+        '../bench/PathBench.cpp',
+        '../bench/PathIterBench.cpp',
+        '../bench/PathUtilsBench.cpp',
+        '../bench/PerlinNoiseBench.cpp',
+        '../bench/PicturePlaybackBench.cpp',
+        '../bench/PictureRecordBench.cpp',
+        '../bench/PremulAndUnpremulAlphaOpsBench.cpp',
+        '../bench/RTreeBench.cpp',
+        '../bench/ReadPixBench.cpp',
+        '../bench/RectBench.cpp',
+        '../bench/RectoriBench.cpp',
+        '../bench/RefCntBench.cpp',
+        '../bench/RegionBench.cpp',
+        '../bench/RegionContainBench.cpp',
+        '../bench/RepeatTileBench.cpp',
+        '../bench/ScalarBench.cpp',
+        '../bench/ShaderMaskBench.cpp',
+        '../bench/SkipZeroesBench.cpp',
+        '../bench/SortBench.cpp',
+        '../bench/StrokeBench.cpp',
+        '../bench/TableBench.cpp',
+        '../bench/TextBench.cpp',
+        '../bench/TileBench.cpp',
+        '../bench/VertBench.cpp',
+        '../bench/WritePixelsBench.cpp',
+        '../bench/WriterBench.cpp',
+        '../bench/XfermodeBench.cpp',
+
+        '../bench/SkBenchLogger.cpp',
+        '../bench/SkBenchLogger.h',
+        '../bench/SkBenchmark.cpp',
+        '../bench/SkBenchmark.h',
+        '../bench/benchmain.cpp',
+      ],
       'conditions': [
         ['skia_gpu == 1',
           {
diff --git a/gyp/bench.gypi b/gyp/bench.gypi
deleted file mode 100644
index 33f0dba..0000000
--- a/gyp/bench.gypi
+++ /dev/null
@@ -1,88 +0,0 @@
-# sources and conditions used in skia's bench.gyp and chromium's skia.gyp
-#
-{
-  'sources': [
-    '../bench/benchmain.cpp',
-    '../bench/SkBenchmark.h',
-    '../bench/SkBenchmark.cpp',
-    '../bench/AAClipBench.cpp',
-    '../bench/BicubicBench.cpp',
-    '../bench/BitmapBench.cpp',
-    '../bench/BitmapRectBench.cpp',
-    '../bench/BitmapScaleBench.cpp',
-    '../bench/BlurBench.cpp',
-    '../bench/BlurImageFilterBench.cpp',
-    '../bench/BlurRectBench.cpp',
-    '../bench/BlurRoundRectBench.cpp',
-    '../bench/ChecksumBench.cpp',
-    '../bench/ChartBench.cpp',
-    '../bench/ChromeBench.cpp',
-    '../bench/CmapBench.cpp',
-    '../bench/ColorFilterBench.cpp',
-    '../bench/CoverageBench.cpp',
-    '../bench/DashBench.cpp',
-    '../bench/DecodeBench.cpp',
-    '../bench/DeferredCanvasBench.cpp',
-    '../bench/DeferredSurfaceCopyBench.cpp',
-    '../bench/DisplacementBench.cpp',
-    '../bench/FontCacheBench.cpp',
-    '../bench/FontScalerBench.cpp',
-    '../bench/FSRectBench.cpp',
-    '../bench/GameBench.cpp',
-    '../bench/GradientBench.cpp',
-    '../bench/GrMemoryPoolBench.cpp',
-    '../bench/GrResourceCacheBench.cpp',
-    '../bench/ImageCacheBench.cpp',
-    '../bench/ImageDecodeBench.cpp',
-    '../bench/InterpBench.cpp',
-    '../bench/HairlinePathBench.cpp',
-    '../bench/LineBench.cpp',
-    '../bench/LightingBench.cpp',
-    '../bench/MagnifierBench.cpp',
-    '../bench/MathBench.cpp',
-    '../bench/Matrix44Bench.cpp',
-    '../bench/MatrixBench.cpp',
-    '../bench/MatrixConvolutionBench.cpp',
-    '../bench/MemoryBench.cpp',
-    '../bench/MemsetBench.cpp',
-    '../bench/MergeBench.cpp',
-    '../bench/MorphologyBench.cpp',
-    '../bench/MutexBench.cpp',
-    '../bench/PathBench.cpp',
-    '../bench/PathIterBench.cpp',
-    '../bench/PathUtilsBench.cpp',
-    '../bench/PerlinNoiseBench.cpp',
-    '../bench/PicturePlaybackBench.cpp',
-    '../bench/PictureRecordBench.cpp',
-    '../bench/ReadPixBench.cpp',
-    '../bench/PremulAndUnpremulAlphaOpsBench.cpp',
-    '../bench/RectBench.cpp',
-    '../bench/RectoriBench.cpp',
-    '../bench/RefCntBench.cpp',
-    '../bench/RegionBench.cpp',
-    '../bench/RegionContainBench.cpp',
-    '../bench/RepeatTileBench.cpp',
-    '../bench/RTreeBench.cpp',
-    '../bench/ScalarBench.cpp',
-    '../bench/ShaderMaskBench.cpp',
-    '../bench/SkipZeroesBench.cpp',
-    '../bench/SortBench.cpp',
-    '../bench/StrokeBench.cpp',
-    '../bench/TableBench.cpp',
-    '../bench/TextBench.cpp',
-    '../bench/TileBench.cpp',
-    '../bench/VertBench.cpp',
-    '../bench/WriterBench.cpp',
-    '../bench/XfermodeBench.cpp',
-    '../bench/WritePixelsBench.cpp',
-
-    '../bench/SkBenchLogger.h',
-    '../bench/SkBenchLogger.cpp',
-  ],
-}
-
-# Local Variables:
-# tab-width:2
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/core.gypi b/gyp/core.gypi
index 54e23ef..530b118 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -44,7 +44,6 @@
         '<(skia_src_path)/core/SkBlitRow_D32.cpp',
         '<(skia_src_path)/core/SkBlitter.h',
         '<(skia_src_path)/core/SkBlitter.cpp',
-        '<(skia_src_path)/core/SkBlitter_A1.cpp',
         '<(skia_src_path)/core/SkBlitter_A8.cpp',
         '<(skia_src_path)/core/SkBlitter_ARGB32.cpp',
         '<(skia_src_path)/core/SkBlitter_RGB16.cpp',
diff --git a/gyp/dm.gyp b/gyp/dm.gyp
index 80838a9..7d8d5d8 100644
--- a/gyp/dm.gyp
+++ b/gyp/dm.gyp
@@ -18,7 +18,7 @@
         'includes': [ 'gmslides.gypi' ],
         'sources': [
             '../dm/DM.cpp',
-            '../dm/DMComparisonTask.cpp',
+            '../dm/DMChecksumTask.cpp',
             '../dm/DMCpuTask.cpp',
             '../dm/DMGpuTask.cpp',
             '../dm/DMPipeTask.cpp',
@@ -27,6 +27,7 @@
             '../dm/DMSerializeTask.cpp',
             '../dm/DMTask.cpp',
             '../dm/DMTaskRunner.cpp',
+            '../dm/DMTileGridTask.cpp',
             '../dm/DMUtil.cpp',
             '../dm/DMWriteTask.cpp',
             '../gm/gm.cpp',
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index 542de0f..c8a82c2 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -50,6 +50,7 @@
     '../gm/downsamplebitmap.cpp',
     '../gm/drawbitmaprect.cpp',
     '../gm/drawlooper.cpp',
+    '../gm/dropshadowimagefilter.cpp',
     '../gm/extractbitmap.cpp',
     '../gm/emptypath.cpp',
     '../gm/fatpathfill.cpp',
@@ -104,6 +105,7 @@
     '../gm/perlinnoise.cpp',
     '../gm/points.cpp',
     '../gm/poly2poly.cpp',
+    '../gm/polygons.cpp',
     '../gm/quadpaths.cpp',
     '../gm/rects.cpp',
     '../gm/rrect.cpp',
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 16f5369..f4c243c 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -126,7 +126,6 @@
       '<(skia_src_path)/gpu/GrTextureAccess.cpp',
       '<(skia_src_path)/gpu/GrTHashTable.h',
       '<(skia_src_path)/gpu/GrVertexBuffer.h',
-      '<(skia_src_path)/gpu/gr_unittests.cpp',
 
       '<(skia_src_path)/gpu/effects/Gr1DKernelEffect.h',
       '<(skia_src_path)/gpu/effects/GrConfigConversionEffect.cpp',
diff --git a/gyp/opts.gyp b/gyp/opts.gyp
index 01bcdde..bf93926 100644
--- a/gyp/opts.gyp
+++ b/gyp/opts.gyp
@@ -177,6 +177,7 @@
         '../src/opts/SkBitmapProcState_matrixProcs_neon.cpp',
         '../src/opts/SkBitmapProcState_matrix_clamp_neon.h',
         '../src/opts/SkBitmapProcState_matrix_repeat_neon.h',
+        '../src/opts/SkBlitMask_opts_arm_neon.cpp',
         '../src/opts/SkBlitRow_opts_arm_neon.cpp',
         '../src/opts/SkMorphology_opts_neon.cpp',
         '../src/opts/SkXfermode_opts_arm_neon.cpp',
diff --git a/gyp/tests.gyp b/gyp/tests.gyp
index 841baf7..5525b84 100644
--- a/gyp/tests.gyp
+++ b/gyp/tests.gyp
@@ -83,6 +83,7 @@
         '../tests/GradientTest.cpp',
         '../tests/GrMemoryPoolTest.cpp',
         '../tests/GrSurfaceTest.cpp',
+        '../tests/GrUnitTests.cpp',
         '../tests/HashCacheTest.cpp',
         '../tests/ImageCacheTest.cpp',
         '../tests/ImageDecodingTest.cpp',
diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h
index b58925c..cd85b6a 100644
--- a/include/core/SkBitmap.h
+++ b/include/core/SkBitmap.h
@@ -42,12 +42,6 @@
 
     enum Config {
         kNo_Config,         //!< bitmap has not been configured
-        /**
-         *  1-bit per pixel, (0 is transparent, 1 is opaque)
-         *  Valid as a destination (target of a canvas), but not valid as a src.
-         *  i.e. you can draw into a 1-bit bitmap, but you cannot draw from one.
-         */
-        kA1_Config,
         kA8_Config,         //!< 8-bits per pixel, with only alpha specified (0 is transparent, 0xFF is opaque)
         kIndex8_Config,     //!< 8-bits per pixel, using SkColorTable to specify the colors
         kRGB_565_Config,    //!< 16-bits per pixel, (see SkColorPriv.h for packing)
@@ -489,14 +483,6 @@
      */
     inline uint8_t* getAddr8(int x, int y) const;
 
-    /** Returns the address of the byte containing the pixel specified by x,y
-     *  for 1bit pixels.
-     *  In debug build, this asserts that the pixels are allocated and locked,
-     *  and that the config is 1-bit, however none of these checks are performed
-     *  in the release build.
-     */
-    inline uint8_t* getAddr1(int x, int y) const;
-
     /** Returns the color corresponding to the pixel specified by x,y for
      *  colortable based bitmaps.
      *  In debug build, this asserts that the pixels are allocated and locked,
@@ -818,12 +804,4 @@
     return (*fColorTable)[*((const uint8_t*)fPixels + y * fRowBytes + x)];
 }
 
-// returns the address of the byte that contains the x coordinate
-inline uint8_t* SkBitmap::getAddr1(int x, int y) const {
-    SkASSERT(fPixels);
-    SkASSERT(fConfig == kA1_Config);
-    SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight);
-    return (uint8_t*)fPixels + y * fRowBytes + (x >> 3);
-}
-
 #endif
diff --git a/include/core/SkImageDecoder.h b/include/core/SkImageDecoder.h
index a7e3646..5745dbd 100644
--- a/include/core/SkImageDecoder.h
+++ b/include/core/SkImageDecoder.h
@@ -186,7 +186,7 @@
             src: 32/24,   no-alpha  -> 4
             src: 32/24,   yes-alpha -> 5
      */
-    void setPrefConfigTable(const SkBitmap::Config pref[6]);
+    void setPrefConfigTable(const SkBitmap::Config pref[5]);
 
     /**
      *  Optional table describing the caller's preferred config based on
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index e371c43..42566ed 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -218,13 +218,14 @@
     // V13: add flag to drawBitmapRectToRect
     //      parameterize blurs by sigma rather than radius
     // V14: Add flags word to PathRef serialization
+    // V15: Remove A1 bitmpa config (and renumber remaining configs)
 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO
     static const uint32_t PRIOR_PRIOR_PICTURE_VERSION = 12;  // TODO: remove when .skps regenerated
 #endif
 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TOO
     static const uint32_t PRIOR_PICTURE_VERSION2 = 13;  // TODO: remove when .skps regenerated
 #endif
-    static const uint32_t PICTURE_VERSION = 14;
+    static const uint32_t PICTURE_VERSION = 15;
 
     // fPlayback, fRecord, fWidth & fHeight are protected to allow derived classes to
     // install their own SkPicturePlayback-derived players,SkPictureRecord-derived
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/include/effects/SkDropShadowImageFilter.h b/include/effects/SkDropShadowImageFilter.h
index 501df7c..5a58a0a 100644
--- a/include/effects/SkDropShadowImageFilter.h
+++ b/include/effects/SkDropShadowImageFilter.h
@@ -12,6 +12,7 @@
 class SK_API SkDropShadowImageFilter : public SkImageFilter {
 public:
     SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigma, SkColor, SkImageFilter* input = NULL);
+    SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, SkColor, SkImageFilter* input = NULL, const CropRect* cropRect = NULL);
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDropShadowImageFilter)
 
 protected:
@@ -20,7 +21,7 @@
     virtual bool onFilterImage(Proxy*, const SkBitmap& source, const SkMatrix&, SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
 
 private:
-    SkScalar fDx, fDy, fSigma;
+    SkScalar fDx, fDy, fSigmaX, fSigmaY;
     SkColor fColor;
     typedef SkImageFilter INHERITED;
 };
diff --git a/include/ports/SkFontMgr.h b/include/ports/SkFontMgr.h
index accb0c5..97ae2f1 100644
--- a/include/ports/SkFontMgr.h
+++ b/include/ports/SkFontMgr.h
@@ -105,7 +105,6 @@
     virtual SkTypeface* onCreateFromStream(SkStream*, int ttcIndex) = 0;
     virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) = 0;
 
-    // TODO: make this pure-virtual once all ports know about it
     virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
                                                unsigned styleBits) = 0;
 private:
diff --git a/platform_tools/android/app/src/com/skia/SkiaSampleActivity.java b/platform_tools/android/app/src/com/skia/SkiaSampleActivity.java
index 62f81a5..0a7a569 100644
--- a/platform_tools/android/app/src/com/skia/SkiaSampleActivity.java
+++ b/platform_tools/android/app/src/com/skia/SkiaSampleActivity.java
@@ -43,6 +43,11 @@
 
         try {
             System.loadLibrary("skia_android");
+        } catch (UnsatisfiedLinkError e) {
+            // This might be because skia was linked to SampleApp statically.
+        }
+
+        try {
             System.loadLibrary("SampleApp");
 
             LinearLayout holder = (LinearLayout) findViewById(R.id.holder);
diff --git a/platform_tools/android/bin/android_run_skia b/platform_tools/android/bin/android_run_skia
index 3314225..11c3675 100755
--- a/platform_tools/android/bin/android_run_skia
+++ b/platform_tools/android/bin/android_run_skia
@@ -28,7 +28,10 @@
 fi
 
 adb_push_if_needed "${SKIA_OUT}/${configuration}/skia_launcher" /data/local/tmp
-adb_push_if_needed "${SKIA_OUT}/${configuration}/lib.target/libskia_android.so" /data/local/tmp
+if [ -f "${SKIA_OUT}/${configuration}/lib.target/libskia_android.so" ]; then
+    # Does not exist for builds with static skia.
+    adb_push_if_needed "${SKIA_OUT}/${configuration}/lib.target/libskia_android.so" /data/local/tmp
+fi
 adb_push_if_needed "${SKIA_OUT}/${configuration}/lib.target/lib${runVars[0]}.so" /data/local/tmp
 
 STATUS_FILENAME="/data/local/tmp/.skia_tmp_$(date +%s%N)"
diff --git a/platform_tools/android/bin/android_setup.sh b/platform_tools/android/bin/android_setup.sh
index 1a5ccf9..b11fcac 100755
--- a/platform_tools/android/bin/android_setup.sh
+++ b/platform_tools/android/bin/android_setup.sh
@@ -161,7 +161,9 @@
   DEFINES="${DEFINES} host_os=$(uname -s | sed -e 's/Linux/linux/;s/Darwin/mac/')"
   DEFINES="${DEFINES} skia_os=android"
   DEFINES="${DEFINES} android_base=${SCRIPT_DIR}/.."
-  DEFINES="${DEFINES} skia_shared_lib=1"
+  if [[ "$GYP_DEFINES" != *skia_shared_lib=* ]]; then
+      DEFINES="${DEFINES} skia_shared_lib=1"
+  fi
 
   # Setup the build variation depending on the target device
   TARGET_DEVICE="$1"
diff --git a/platform_tools/android/gyp/skia_android.gypi b/platform_tools/android/gyp/skia_android.gypi
index d4f865a..270b934 100644
--- a/platform_tools/android/gyp/skia_android.gypi
+++ b/platform_tools/android/gyp/skia_android.gypi
@@ -30,9 +30,16 @@
         # still build.
         {
           'destination': '<(PRODUCT_DIR)/android/libs/<(android_arch)',
-          'files': [
-            '<(SHARED_LIB_DIR)/libSampleApp.so',
-            '<(SHARED_LIB_DIR)/libskia_android.so',
+          'conditions': [
+            [ 'skia_shared_lib', {
+              'files': [
+                '<(SHARED_LIB_DIR)/libSampleApp.so',
+                '<(SHARED_LIB_DIR)/libskia_android.so',
+              ]}, {
+              'files': [
+                '<(SHARED_LIB_DIR)/libSampleApp.so',
+             ]}
+           ],
           ],
         },
       ],
diff --git a/platform_tools/android/launcher/skia_launcher.cpp b/platform_tools/android/launcher/skia_launcher.cpp
index 718a717..746d470 100644
--- a/platform_tools/android/launcher/skia_launcher.cpp
+++ b/platform_tools/android/launcher/skia_launcher.cpp
@@ -67,12 +67,16 @@
         return -1;
     }
 
+    void* skiaLibrary;
+
+#if defined(SKIA_DLL)
     // load the local skia shared library
-    void* skiaLibrary = load_library(appLocation, "skia_android");
+    skiaLibrary = load_library(appLocation, "skia_android");
     if (NULL == skiaLibrary)
     {
         return -1;
     }
+#endif
 
     // load the appropriate library
     void* appLibrary = load_library(appLocation, argv[1]);
@@ -80,6 +84,10 @@
         return -1;
     }
 
+#if !defined(SKIA_DLL)
+    skiaLibrary = appLibrary;
+#endif
+
     // find the address of the main function
     int (*app_main)(int, const char**);
     *(void **) (&app_main) = dlsym(appLibrary, "main");
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index bb22685..7162b7b 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -1537,7 +1537,6 @@
 
 static SkBitmap::Config gConfigCycle[] = {
     SkBitmap::kNo_Config,           // none -> none
-    SkBitmap::kNo_Config,           // a1 -> none
     SkBitmap::kNo_Config,           // a8 -> none
     SkBitmap::kNo_Config,           // index8 -> none
     SkBitmap::kARGB_4444_Config,    // 565 -> 4444
@@ -2074,7 +2073,6 @@
 
 static const char* gConfigNames[] = {
     "unknown config",
-    "A1",
     "A8",
     "Index8",
     "565",
diff --git a/samplecode/SampleFilter.cpp b/samplecode/SampleFilter.cpp
index 71ab62f..7f902d5 100644
--- a/samplecode/SampleFilter.cpp
+++ b/samplecode/SampleFilter.cpp
@@ -67,7 +67,6 @@
 
 static const char* gConfigNames[] = {
     "unknown config",
-    "A1",
     "A8",
     "Index8",
     "565",
diff --git a/src/animator/SkDrawBitmap.cpp b/src/animator/SkDrawBitmap.cpp
index 568401d..327e813 100644
--- a/src/animator/SkDrawBitmap.cpp
+++ b/src/animator/SkDrawBitmap.cpp
@@ -75,11 +75,10 @@
     const char* formatName;
     switch (format) {
         case 0: formatName = "none"; break;
-        case 1: formatName = "A1"; break;
-        case 2: formatName = "A8"; break;
-        case 3: formatName = "Index8"; break;
-        case 4: formatName = "RGB16"; break;
-        case 5: formatName = "RGB32"; break;
+        case 1: formatName = "A8"; break;
+        case 2: formatName = "Index8"; break;
+        case 3: formatName = "RGB16"; break;
+        case 4: formatName = "RGB32"; break;
     }
     SkDebugf("format=\"%s\" />\n", formatName);
 }
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index 429d092..9d4aa87 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -161,7 +161,6 @@
     int bpp;
     switch (config) {
         case kNo_Config:
-        case kA1_Config:
             bpp = 0;   // not applicable
             break;
         case kA8_Config:
@@ -194,11 +193,6 @@
     switch (c) {
         case kNo_Config:
             break;
-        case kA1_Config:
-            rowBytes.set(width);
-            rowBytes.add(7);
-            rowBytes.shiftRight(3);
-            break;
         case kA8_Config:
         case kIndex8_Config:
             rowBytes.set(width);
@@ -275,7 +269,6 @@
         case SkBitmap::kNo_Config:
             alphaType = kIgnore_SkAlphaType;
             break;
-        case SkBitmap::kA1_Config:
         case SkBitmap::kA8_Config:
             if (kUnpremul_SkAlphaType == alphaType) {
                 alphaType = kPremul_SkAlphaType;
@@ -291,6 +284,8 @@
         case SkBitmap::kRGB_565_Config:
             alphaType = kOpaque_SkAlphaType;
             break;
+        default:
+            return false;
     }
     if (canonical) {
         *canonical = alphaType;
@@ -606,8 +601,6 @@
             case SkBitmap::kIndex8_Config:
                 base += x;
                 break;
-            case SkBitmap::kA1_Config:
-                base += x >> 3;
                 break;
             default:
                 SkDEBUGFAIL("Can't return addr for config");
@@ -623,15 +616,6 @@
     SkASSERT((unsigned)y < (unsigned)this->height());
 
     switch (this->config()) {
-        case SkBitmap::kA1_Config: {
-            uint8_t* addr = this->getAddr1(x, y);
-            uint8_t mask = 1 << (7  - (x % 8));
-            if (addr[0] & mask) {
-                return SK_ColorBLACK;
-            } else {
-                return 0;
-            }
-        }
         case SkBitmap::kA8_Config: {
             uint8_t* addr = this->getAddr8(x, y);
             return SkColorSetA(0, addr[0]);
@@ -654,6 +638,7 @@
             return SkUnPreMultiply::PMColorToColor(addr[0]);
         }
         case kNo_Config:
+        default:
             SkASSERT(false);
             return 0;
     }
@@ -671,9 +656,6 @@
     const int width = bm.width();
 
     switch (bm.config()) {
-        case SkBitmap::kA1_Config: {
-            // TODO
-        } break;
         case SkBitmap::kA8_Config: {
             unsigned a = 0xFF;
             for (int y = 0; y < height; ++y) {
@@ -779,38 +761,6 @@
     }
 
     switch (fConfig) {
-        case kA1_Config: {
-            uint8_t* p = this->getAddr1(area.fLeft, area.fTop);
-            const int left = area.fLeft >> 3;
-            const int right = area.fRight >> 3;
-
-            int middle = right - left - 1;
-
-            uint8_t leftMask = 0xFF >> (area.fLeft & 7);
-            uint8_t rightMask = ~(0xFF >> (area.fRight & 7));
-            if (left == right) {
-                leftMask &= rightMask;
-                rightMask = 0;
-            }
-
-            a = (a >> 7) ? 0xFF : 0;
-            while (--height >= 0) {
-                uint8_t* startP = p;
-
-                *p = (*p & ~leftMask) | (a & leftMask);
-                p++;
-                if (middle > 0) {
-                    memset(p, a, middle);
-                    p += middle;
-                }
-                if (rightMask) {
-                    *p = (*p & ~rightMask) | (a & rightMask);
-                }
-
-                p = startP + rowBytes;
-            }
-            break;
-        }
         case kA8_Config: {
             uint8_t* p = this->getAddr8(area.fLeft, area.fTop);
             while (--height >= 0) {
@@ -896,7 +846,6 @@
             break;
 
         case SkBitmap::kNo_Config:
-        case SkBitmap::kA1_Config:
         default:
             return SUB_OFFSET_FAILURE;
     }
@@ -939,8 +888,6 @@
 
         case SkBitmap::kNo_Config:
             // Fall through.
-        case SkBitmap::kA1_Config:
-            // Fall through.
         default:
             return false;
     }
@@ -1021,7 +968,6 @@
         case kRGB_565_Config:
         case kARGB_8888_Config:
             break;
-        case kA1_Config:
         case kIndex8_Config:
             if (!sameConfigs) {
                 return false;
@@ -1032,12 +978,6 @@
         default:
             return false;
     }
-
-    // do not copy src if srcConfig == kA1_Config while dstConfig != kA1_Config
-    if (this->config() == kA1_Config && !sameConfigs) {
-        return false;
-    }
-
     return true;
 }
 
@@ -1683,7 +1623,7 @@
 void SkBitmap::toString(SkString* str) const {
 
     static const char* gConfigNames[kConfigCount] = {
-        "NONE", "A1", "A8", "INDEX8", "565", "4444", "8888"
+        "NONE", "A8", "INDEX8", "565", "4444", "8888"
     };
 
     str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
index dc7946a..9682d55 100644
--- a/src/core/SkBlitter.cpp
+++ b/src/core/SkBlitter.cpp
@@ -945,11 +945,6 @@
 
 
     switch (device.config()) {
-        case SkBitmap::kA1_Config:
-            SK_PLACEMENT_NEW_ARGS(blitter, SkA1_Blitter,
-                                  storage, storageSize, (device, *paint));
-            break;
-
         case SkBitmap::kA8_Config:
             if (drawCoverage) {
                 SkASSERT(NULL == shader);
diff --git a/src/core/SkBlitter_A1.cpp b/src/core/SkBlitter_A1.cpp
deleted file mode 100644
index b64afe2..0000000
--- a/src/core/SkBlitter_A1.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#include "SkCoreBlitters.h"
-
-SkA1_Blitter::SkA1_Blitter(const SkBitmap& device, const SkPaint& paint)
-        : INHERITED(device) {
-    fSrcA = paint.getAlpha();
-}
-
-void SkA1_Blitter::blitH(int x, int y, int width) {
-    SkASSERT(x >= 0 && y >= 0 &&
-             (unsigned)(x + width) <= (unsigned)fDevice.width());
-
-    if (fSrcA <= 0x7F) {
-        return;
-    }
-    uint8_t* dst = fDevice.getAddr1(x, y);
-    int right = x + width;
-
-    int left_mask = 0xFF >> (x & 7);
-    int rite_mask = 0xFF << (8 - (right & 7));
-    int full_runs = (right >> 3) - ((x + 7) >> 3);
-
-    // check for empty right mask, so we don't read off the end
-    // (or go slower than we need to)
-    if (rite_mask == 0) {
-        SkASSERT(full_runs >= 0);
-        full_runs -= 1;
-        rite_mask = 0xFF;
-    }
-    if (left_mask == 0xFF) {
-        full_runs -= 1;
-    }
-    if (full_runs < 0) {
-        SkASSERT((left_mask & rite_mask) != 0);
-        *dst |= (left_mask & rite_mask);
-    } else {
-        *dst++ |= left_mask;
-        memset(dst, 0xFF, full_runs);
-        dst += full_runs;
-        *dst |= rite_mask;
-    }
-}
diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h
index 673b874..1605a52 100644
--- a/src/core/SkCoreBlitters.h
+++ b/src/core/SkCoreBlitters.h
@@ -162,22 +162,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-class SkA1_Blitter : public SkRasterBlitter {
-public:
-    SkA1_Blitter(const SkBitmap& device, const SkPaint& paint);
-    virtual void blitH(int x, int y, int width) SK_OVERRIDE;
-
-private:
-    uint8_t fSrcA;
-
-    // illegal
-    SkA1_Blitter& operator=(const SkA1_Blitter&);
-
-    typedef SkRasterBlitter INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
 /*  These return the correct subclass of blitter for their device config.
 
     Currently, they make the following assumptions about the state of the
diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp
index faa3f89..a78b197 100644
--- a/src/core/SkGlyphCache.cpp
+++ b/src/core/SkGlyphCache.cpp
@@ -87,8 +87,6 @@
 
     fGlyphArray.setReserve(kMinGlyphCount);
 
-    fMetricsCount = 0;
-    fAdvanceCount = 0;
     fAuxProcList = NULL;
 }
 
@@ -320,11 +318,9 @@
 
     if (kJustAdvance_MetricsType == mtype) {
         fScalerContext->getAdvance(glyph);
-        fAdvanceCount += 1;
     } else {
         SkASSERT(kFull_MetricsType == mtype);
         fScalerContext->getMetrics(glyph);
-        fMetricsCount += 1;
     }
 
     return glyph;
diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h
index 52a8132..7b2ebb8 100644
--- a/src/core/SkGlyphCache.h
+++ b/src/core/SkGlyphCache.h
@@ -211,8 +211,6 @@
     SkTDArray<SkGlyph*> fGlyphArray;
     SkChunkAlloc        fGlyphAlloc;
 
-    int fMetricsCount, fAdvanceCount;
-
     struct CharGlyphRec {
         uint32_t    fID;    // unichar + subpixel
         SkGlyph*    fGlyph;
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index d6948dd..91a76e1 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -2005,11 +2005,7 @@
 };
 
 // The size of a flat paint's POD fields
-// Include an SkScalar for hinting scale factor whether it is
-// supported or not so that an SKP is valid whether it was
-// created with support or not.
-
-static const uint32_t kPODPaintSize =   6 * sizeof(SkScalar) +
+static const uint32_t kPODPaintSize =   5 * sizeof(SkScalar) +
                                         1 * sizeof(SkColor) +
                                         1 * sizeof(uint16_t) +
                                         6 * sizeof(uint8_t);
@@ -2046,8 +2042,6 @@
         ptr = write_scalar(ptr, this->getTextSize());
         ptr = write_scalar(ptr, this->getTextScaleX());
         ptr = write_scalar(ptr, this->getTextSkewX());
-        // Dummy value for obsolete hinting scale factor.  TODO: remove with next picture version
-        ptr = write_scalar(ptr, SK_Scalar1);
         ptr = write_scalar(ptr, this->getStrokeWidth());
         ptr = write_scalar(ptr, this->getStrokeMiter());
         *ptr++ = this->getColor();
@@ -2064,8 +2058,6 @@
         buffer.writeScalar(fTextSize);
         buffer.writeScalar(fTextScaleX);
         buffer.writeScalar(fTextSkewX);
-        // Dummy value for obsolete hinting scale factor.  TODO: remove with next picture version
-        buffer.writeScalar(SK_Scalar1);
         buffer.writeScalar(fWidth);
         buffer.writeScalar(fMiterLimit);
         buffer.writeColor(fColor);
@@ -2120,8 +2112,6 @@
         this->setTextSize(read_scalar(pod));
         this->setTextScaleX(read_scalar(pod));
         this->setTextSkewX(read_scalar(pod));
-        // Skip the hinting scalar factor, which is not supported.
-        read_scalar(pod);
         this->setStrokeWidth(read_scalar(pod));
         this->setStrokeMiter(read_scalar(pod));
         this->setColor(*pod++);
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index 4acc549..2520e6b 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -266,11 +266,20 @@
 
 #include "SkStream.h"
 
+static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
+
 bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
     if (NULL == stream) {
         return false;
     }
 
+    // Check magic bytes.
+    char magic[sizeof(kMagic)];
+    stream->read(magic, sizeof(kMagic));
+    if (0 != memcmp(magic, kMagic, sizeof(kMagic))) {
+        return false;
+    }
+
     SkPictInfo info;
     if (!stream->read(&info, sizeof(SkPictInfo))) {
         return false;
@@ -341,6 +350,10 @@
         info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
     }
 
+    // Write 8 magic bytes to ID this file format.
+    SkASSERT(sizeof(kMagic) == 8);
+    stream->write(kMagic, sizeof(kMagic));
+
     stream->write(&info, sizeof(info));
     if (playback) {
         stream->writeBool(true);
diff --git a/src/core/SkScaledImageCache.cpp b/src/core/SkScaledImageCache.cpp
index ea29843..55eadb8 100644
--- a/src/core/SkScaledImageCache.cpp
+++ b/src/core/SkScaledImageCache.cpp
@@ -49,7 +49,7 @@
     return hash;
 }
 
-struct Key {
+struct SkScaledImageCache::Key {
     Key(uint32_t genID,
         SkScalar scaleX,
         SkScalar scaleY,
@@ -129,22 +129,24 @@
 #include "SkTDynamicHash.h"
 
 namespace { // can't use static functions w/ template parameters
-const Key& key_from_rec(const SkScaledImageCache::Rec& rec) {
+const SkScaledImageCache::Key& key_from_rec(const SkScaledImageCache::Rec& rec) {
     return rec.fKey;
 }
 
-uint32_t hash_from_key(const Key& key) {
+uint32_t hash_from_key(const SkScaledImageCache::Key& key) {
     return key.fHash;
 }
 
-bool eq_rec_key(const SkScaledImageCache::Rec& rec, const Key& key) {
+bool eq_rec_key(const SkScaledImageCache::Rec& rec, const SkScaledImageCache::Key& key) {
     return rec.fKey == key;
 }
 }
 
 class SkScaledImageCache::Hash : public SkTDynamicHash<SkScaledImageCache::Rec,
-                                   Key, key_from_rec, hash_from_key,
-                                   eq_rec_key> {};
+                                                       SkScaledImageCache::Key,
+                                                       key_from_rec,
+                                                       hash_from_key,
+                                                       eq_rec_key> {};
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -187,17 +189,22 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-/**
-   This private method is the fully general record finder. All other
-   record finders should call this funtion. */
+
 SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(uint32_t genID,
                                                         SkScalar scaleX,
                                                         SkScalar scaleY,
                                                         const SkIRect& bounds) {
-    if (bounds.isEmpty()) {
+    const Key key(genID, scaleX, scaleY, bounds);
+    return this->findAndLock(key);
+}
+
+/**
+   This private method is the fully general record finder. All other
+   record finders should call this function or the one above. */
+SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkScaledImageCache::Key& key) {
+    if (key.fBounds.isEmpty()) {
         return NULL;
     }
-    Key key(genID, scaleX, scaleY, bounds);
 #ifdef USE_HASH
     Rec* rec = fHash->find(key);
 #else
@@ -275,8 +282,14 @@
 /**
    This private method is the fully general record adder. All other
    record adders should call this funtion. */
-void SkScaledImageCache::addAndLock(SkScaledImageCache::Rec* rec) {
+SkScaledImageCache::ID* SkScaledImageCache::addAndLock(SkScaledImageCache::Rec* rec) {
     SkASSERT(rec);
+    // See if we already have this key (racy inserts, etc.)
+    Rec* existing = this->findAndLock(rec->fKey);
+    if (existing != NULL) {
+        return rec_to_id(existing);
+    }
+
     this->addToHead(rec);
     SkASSERT(1 == rec->fLockCount);
 #ifdef USE_HASH
@@ -285,6 +298,7 @@
 #endif
     // We may (now) be overbudget, so see if we need to purge something.
     this->purgeAsNeeded();
+    return rec_to_id(rec);
 }
 
 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(uint32_t genID,
@@ -293,8 +307,7 @@
                                                        const SkBitmap& bitmap) {
     Key key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeWH(width, height));
     Rec* rec = SkNEW_ARGS(Rec, (key, bitmap));
-    this->addAndLock(rec);
-    return rec_to_id(rec);
+    return this->addAndLock(rec);
 }
 
 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig,
@@ -311,8 +324,7 @@
     }
     Key key(orig.getGenerationID(), scaleX, scaleY, bounds);
     Rec* rec = SkNEW_ARGS(Rec, (key, scaled));
-    this->addAndLock(rec);
-    return rec_to_id(rec);
+    return this->addAndLock(rec);
 }
 
 SkScaledImageCache::ID* SkScaledImageCache::addAndLockMip(const SkBitmap& orig,
@@ -323,8 +335,7 @@
     }
     Key key(orig.getGenerationID(), 0, 0, bounds);
     Rec* rec = SkNEW_ARGS(Rec, (key, mip));
-    this->addAndLock(rec);
-    return rec_to_id(rec);
+    return this->addAndLock(rec);
 }
 
 void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) {
diff --git a/src/core/SkScaledImageCache.h b/src/core/SkScaledImageCache.h
index fee69d2..44ef1f8 100644
--- a/src/core/SkScaledImageCache.h
+++ b/src/core/SkScaledImageCache.h
@@ -126,6 +126,7 @@
 
 public:
     struct Rec;
+    struct Key;
 private:
     Rec*    fHead;
     Rec*    fTail;
@@ -139,7 +140,8 @@
 
     Rec* findAndLock(uint32_t generationID, SkScalar sx, SkScalar sy,
                      const SkIRect& bounds);
-    void addAndLock(Rec* rec);
+    Rec* findAndLock(const Key& key);
+    ID* addAndLock(Rec* rec);
 
     void purgeAsNeeded();
 
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index 1d6c2f7..4996a73 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -352,16 +352,16 @@
             glyph->fHeight  = SkToU16(ir.height());
 
             if (glyph->fWidth > 0) {
-            switch (fRec.fMaskFormat) {
-            case SkMask::kLCD16_Format:
-            case SkMask::kLCD32_Format:
-                glyph->fWidth += 2;
-                glyph->fLeft -= 1;
-                break;
-            default:
-                break;
+                switch (fRec.fMaskFormat) {
+                case SkMask::kLCD16_Format:
+                case SkMask::kLCD32_Format:
+                    glyph->fWidth += 2;
+                    glyph->fLeft -= 1;
+                    break;
+                default:
+                    break;
+                }
             }
-    }
         }
     }
 
@@ -523,10 +523,54 @@
     }
 }
 
+static inline int convert_8_to_1(unsigned byte) {
+    SkASSERT(byte <= 0xFF);
+    return byte >> 7;
+}
+
+static uint8_t pack_8_to_1(const uint8_t alpha[8]) {
+    unsigned bits = 0;
+    for (int i = 0; i < 8; ++i) {
+        bits <<= 1;
+        bits |= convert_8_to_1(alpha[i]);
+    }
+    return SkToU8(bits);
+}
+
+static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
+    const int height = mask.fBounds.height();
+    const int width = mask.fBounds.width();
+    const int octs = width >> 3;
+    const int leftOverBits = width & 7;
+
+    uint8_t* dst = mask.fImage;
+    const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
+    SkASSERT(dstPad >= 0);
+
+    const int srcPad = srcRB - width;
+    SkASSERT(srcPad >= 0);
+
+    for (int y = 0; y < height; ++y) {
+        for (int i = 0; i < octs; ++i) {
+            *dst++ = pack_8_to_1(src);
+            src += 8;
+        }
+        if (leftOverBits > 0) {
+            unsigned bits = 0;
+            int shift = 7;
+            for (int i = 0; i < leftOverBits; ++i, --shift) {
+                bits |= convert_8_to_1(*src++ >> 7) << shift;
+            }
+            *dst++ = bits;
+        }
+        src += srcPad;
+        dst += dstPad;
+    }
+}
+
 static void generateMask(const SkMask& mask, const SkPath& path,
                          const SkMaskGamma::PreBlend& maskPreBlend) {
-    SkBitmap::Config config;
-    SkPaint     paint;
+    SkPaint paint;
 
     int srcW = mask.fBounds.width();
     int srcH = mask.fBounds.height();
@@ -538,27 +582,25 @@
     matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
                         -SkIntToScalar(mask.fBounds.fTop));
 
-    if (SkMask::kBW_Format == mask.fFormat) {
-        config = SkBitmap::kA1_Config;
-        paint.setAntiAlias(false);
-    } else {
-        config = SkBitmap::kA8_Config;
-        paint.setAntiAlias(true);
-        switch (mask.fFormat) {
-            case SkMask::kA8_Format:
-                break;
-            case SkMask::kLCD16_Format:
-            case SkMask::kLCD32_Format:
-                // TODO: trigger off LCD orientation
-                dstW = 4*dstW - 8;
-                matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1),
-                                    -SkIntToScalar(mask.fBounds.fTop));
-                matrix.postScale(SkIntToScalar(4), SK_Scalar1);
-                dstRB = 0;  // signals we need a copy
-                break;
-            default:
-                SkDEBUGFAIL("unexpected mask format");
-        }
+    SkBitmap::Config config = SkBitmap::kA8_Config;
+    paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat);
+    switch (mask.fFormat) {
+        case SkMask::kBW_Format:
+            dstRB = 0;  // signals we need a copy
+            break;
+        case SkMask::kA8_Format:
+            break;
+        case SkMask::kLCD16_Format:
+        case SkMask::kLCD32_Format:
+            // TODO: trigger off LCD orientation
+            dstW = 4*dstW - 8;
+            matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1),
+                                -SkIntToScalar(mask.fBounds.fTop));
+            matrix.postScale(SkIntToScalar(4), SK_Scalar1);
+            dstRB = 0;  // signals we need a copy
+            break;
+        default:
+            SkDEBUGFAIL("unexpected mask format");
     }
 
     SkRasterClip clip;
@@ -587,6 +629,9 @@
     draw.drawPath(path, paint);
 
     switch (mask.fFormat) {
+        case SkMask::kBW_Format:
+            packA8ToA1(mask, bm.getAddr8(0, 0), bm.rowBytes());
+            break;
         case SkMask::kA8_Format:
             if (maskPreBlend.isApplicable()) {
                 applyLUTToA8Mask(mask, maskPreBlend.fG);
diff --git a/src/core/SkScalerContext.h b/src/core/SkScalerContext.h
index 2820b5a..e4950ed 100644
--- a/src/core/SkScalerContext.h
+++ b/src/core/SkScalerContext.h
@@ -202,16 +202,57 @@
     Rec         fRec;
     unsigned    fBaseGlyphCount;
 
-    virtual unsigned generateGlyphCount() = 0;
-    virtual uint16_t generateCharToGlyph(SkUnichar) = 0;
-    virtual void generateAdvance(SkGlyph*) = 0;
-    virtual void generateMetrics(SkGlyph*) = 0;
-    virtual void generateImage(const SkGlyph&) = 0;
-    virtual void generatePath(const SkGlyph&, SkPath*) = 0;
+    /** Generates the contents of glyph.fAdvanceX and glyph.fAdvanceY.
+     *  May call getMetrics if that would be just as fast.
+     */
+    virtual void generateAdvance(SkGlyph* glyph) = 0;
+
+    /** Generates the contents of glyph.fWidth, fHeight, fTop, fLeft,
+     *  as well as fAdvanceX and fAdvanceY if not already set.
+     *
+     *  TODO: fMaskFormat is set by getMetrics later; cannot be set here.
+     */
+    virtual void generateMetrics(SkGlyph* glyph) = 0;
+
+    /** Generates the contents of glyph.fImage.
+     *  When called, glyph.fImage will be pointing to a pre-allocated,
+     *  uninitialized region of memory of size glyph.computeImageSize().
+     *  This method may change glyph.fMaskFormat if the new image size is
+     *  less than or equal to the old image size.
+     *
+     *  Because glyph.computeImageSize() will determine the size of fImage,
+     *  generateMetrics will be called before generateImage.
+     */
+    virtual void generateImage(const SkGlyph& glyph) = 0;
+
+    /** Sets the passed path to the glyph outline.
+     *  If this cannot be done the path is set to empty;
+     *  this is indistinguishable from a glyph with an empty path.
+     *  This does not set glyph.fPath.
+     *
+     *  TODO: path is always glyph.fPath, no reason to pass separately.
+     */
+    virtual void generatePath(const SkGlyph& glyph, SkPath* path) = 0;
+
+    /** Retrieves font metrics.
+     *  TODO: there is now a vertical bit, no need for two parameters.
+     */
     virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
                                      SkPaint::FontMetrics* mY) = 0;
-    // default impl returns 0, indicating failure.
-    virtual SkUnichar generateGlyphToChar(uint16_t);
+
+    /** Returns the number of glyphs in the font. */
+    virtual unsigned generateGlyphCount() = 0;
+
+    /** Returns the glyph id for the given unichar.
+     *  If there is no 1:1 mapping from the unichar to a glyph id, returns 0.
+     */
+    virtual uint16_t generateCharToGlyph(SkUnichar unichar) = 0;
+
+    /** Returns the unichar for the given glyph id.
+     *  If there is no 1:1 mapping from the glyph id to a unichar, returns 0.
+     *  The default implementation always returns 0, indicating failure.
+     */
+    virtual SkUnichar generateGlyphToChar(uint16_t glyphId);
 
     void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
 
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/src/core/SkValidatingReadBuffer.cpp b/src/core/SkValidatingReadBuffer.cpp
index a92c1b9..4a8ac47 100644
--- a/src/core/SkValidatingReadBuffer.cpp
+++ b/src/core/SkValidatingReadBuffer.cpp
@@ -203,7 +203,7 @@
 uint32_t SkValidatingReadBuffer::getArrayCount() {
     const size_t inc = sizeof(uint32_t);
     fError = fError || !IsPtrAlign4(fReader.peek()) || !fReader.isAvailable(inc);
-    return *(uint32_t*)fReader.peek();
+    return fError ? 0 : *(uint32_t*)fReader.peek();
 }
 
 void SkValidatingReadBuffer::readBitmap(SkBitmap* bitmap) {
diff --git a/src/effects/SkDropShadowImageFilter.cpp b/src/effects/SkDropShadowImageFilter.cpp
index b4d8689..5be633e 100644
--- a/src/effects/SkDropShadowImageFilter.cpp
+++ b/src/effects/SkDropShadowImageFilter.cpp
@@ -15,10 +15,21 @@
 #include "SkFlattenableBuffers.h"
 
 SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigma, SkColor color, SkImageFilter* input)
-    : SkImageFilter(input)
+    : INHERITED(input)
     , fDx(dx)
     , fDy(dy)
-    , fSigma(sigma)
+    , fSigmaX(sigma)
+    , fSigmaY(sigma)
+    , fColor(color)
+{
+}
+
+SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, SkColor color, SkImageFilter* input, const CropRect* cropRect)
+    : INHERITED(input, cropRect)
+    , fDx(dx)
+    , fDy(dy)
+    , fSigmaX(sigmaX)
+    , fSigmaY(sigmaY)
     , fColor(color)
 {
 }
@@ -27,11 +38,13 @@
  : INHERITED(1, buffer) {
     fDx = buffer.readScalar();
     fDy = buffer.readScalar();
-    fSigma = buffer.readScalar();
+    fSigmaX = buffer.readScalar();
+    fSigmaY = buffer.readScalar();
     fColor = buffer.readColor();
     buffer.validate(SkScalarIsFinite(fDx) &&
                     SkScalarIsFinite(fDy) &&
-                    SkScalarIsFinite(fSigma));
+                    SkScalarIsFinite(fSigmaX) &&
+                    SkScalarIsFinite(fSigmaY));
 }
 
 void SkDropShadowImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const
@@ -39,7 +52,8 @@
     this->INHERITED::flatten(buffer);
     buffer.writeScalar(fDx);
     buffer.writeScalar(fDy);
-    buffer.writeScalar(fSigma);
+    buffer.writeScalar(fSigmaX);
+    buffer.writeScalar(fSigmaY);
     buffer.writeColor(fColor);
 }
 
@@ -49,17 +63,26 @@
     if (getInput(0) && !getInput(0)->filterImage(proxy, source, matrix, &src, loc))
         return false;
 
-    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(src.width(), src.height()));
+    SkIRect bounds;
+    src.getBounds(&bounds);
+    if (!this->applyCropRect(&bounds, matrix)) {
+        return false;
+    }
+
+    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
     SkCanvas canvas(device.get());
 
-    SkAutoTUnref<SkImageFilter> blurFilter(new SkBlurImageFilter(fSigma, fSigma));
+    SkAutoTUnref<SkImageFilter> blurFilter(new SkBlurImageFilter(fSigmaX, fSigmaY));
     SkAutoTUnref<SkColorFilter> colorFilter(SkColorFilter::CreateModeFilter(fColor, SkXfermode::kSrcIn_Mode));
     SkPaint paint;
     paint.setImageFilter(blurFilter.get());
     paint.setColorFilter(colorFilter.get());
     paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+    canvas.translate(-SkIntToScalar(bounds.fLeft), -SkIntToScalar(bounds.fTop));
     canvas.drawBitmap(src, fDx, fDy, &paint);
     canvas.drawBitmap(src, 0, 0);
     *result = device->accessBitmap(false);
+    loc->fX += bounds.fLeft;
+    loc->fY += bounds.fTop;
     return true;
 }
diff --git a/src/effects/SkTransparentShader.cpp b/src/effects/SkTransparentShader.cpp
index 970e74f..1d7e808 100644
--- a/src/effects/SkTransparentShader.cpp
+++ b/src/effects/SkTransparentShader.cpp
@@ -94,9 +94,6 @@
             }
             break;
         }
-        case SkBitmap::kA1_Config:
-            SkDEBUGFAIL("kA1_Config umimplemented at this time");
-            break;
         default:    // to avoid warnings
             break;
     }
diff --git a/src/fonts/SkGScalerContext.cpp b/src/fonts/SkGScalerContext.cpp
index f0543c5..551b01c 100644
--- a/src/fonts/SkGScalerContext.cpp
+++ b/src/fonts/SkGScalerContext.cpp
@@ -176,6 +176,8 @@
 
 void SkGTypeface::onFilterRec(SkScalerContextRec* rec) const {
     fProxy->filterRec(rec);
+    rec->setHinting(SkPaint::kNo_Hinting);
+    rec->fMaskFormat = SkMask::kARGB32_Format;
 }
 
 SkAdvancedTypefaceMetrics* SkGTypeface::onGetAdvancedTypefaceMetrics(
diff --git a/src/gpu/GrBinHashKey.h b/src/gpu/GrBinHashKey.h
index 7d4aa0f..585a1a1 100644
--- a/src/gpu/GrBinHashKey.h
+++ b/src/gpu/GrBinHashKey.h
@@ -13,37 +13,19 @@
 #include "GrTypes.h"
 
 /**
- *  Hash function class that can take a data chunk of any predetermined length. The hash function
- *  used is the One-at-a-Time Hash (http://burtleburtle.net/bob/hash/doobs.html).
- *
- *  Keys are computed from ENTRY objects. ENTRY must be fully ordered by a member:
- *      int compare(const GrTBinHashKey<ENTRY, ..>& k);
- *  which returns negative if the ENTRY < k, 0 if it equals k, and positive if k < the ENTRY.
- *  Additionally, ENTRY must be flattenable into the key using setKeyData.
- *
- *  This class satisfies the requirements to be a key for a GrTHashTable.
+ *  GrBinHashKey is a hash key class that can take a data chunk of any predetermined
+ *  length. The hash function used is the One-at-a-Time Hash
+ *  (http://burtleburtle.net/bob/hash/doobs.html).
  */
-template<typename ENTRY, size_t KEY_SIZE>
-class GrTBinHashKey {
+template<size_t KEY_SIZE>
+class GrBinHashKey {
 public:
     enum { kKeySize = KEY_SIZE };
 
-    GrTBinHashKey() {
+    GrBinHashKey() {
         this->reset();
     }
 
-    GrTBinHashKey(const GrTBinHashKey<ENTRY, KEY_SIZE>& other) {
-        *this = other;
-    }
-
-    GrTBinHashKey<ENTRY, KEY_SIZE>& operator=(const GrTBinHashKey<ENTRY, KEY_SIZE>& other) {
-        memcpy(this, &other, sizeof(*this));
-        return *this;
-    }
-
-    ~GrTBinHashKey() {
-    }
-
     void reset() {
         fHash = 0;
 #ifdef SK_DEBUG
@@ -52,39 +34,49 @@
     }
 
     void setKeyData(const uint32_t* SK_RESTRICT data) {
-        SkASSERT(GrIsALIGN4(KEY_SIZE));
+        SK_COMPILE_ASSERT(KEY_SIZE % 4 == 0, key_size_mismatch);
         memcpy(&fData, data, KEY_SIZE);
 
         uint32_t hash = 0;
         size_t len = KEY_SIZE;
         while (len >= 4) {
             hash += *data++;
-            hash += (fHash << 10);
+            hash += (hash << 10);
             hash ^= (hash >> 6);
             len -= 4;
         }
-        hash += (fHash << 3);
-        hash ^= (fHash >> 11);
-        hash += (fHash << 15);
+        hash += (hash << 3);
+        hash ^= (hash >> 11);
+        hash += (hash << 15);
 #ifdef SK_DEBUG
         fIsValid = true;
 #endif
         fHash = hash;
     }
 
-    int compare(const GrTBinHashKey<ENTRY, KEY_SIZE>& key) const {
+    bool operator==(const GrBinHashKey<KEY_SIZE>& key) const {
         SkASSERT(fIsValid && key.fIsValid);
-        return memcmp(fData, key.fData, KEY_SIZE);
+        if (fHash != key.fHash) {
+            return false;
+        }
+        for (size_t i = 0; i < SK_ARRAY_COUNT(fData); ++i) {
+            if (fData[i] != key.fData[i]) {
+                return false;
+            }
+        }
+        return true;
     }
 
-    static bool EQ(const ENTRY& entry, const GrTBinHashKey<ENTRY, KEY_SIZE>& key) {
-        SkASSERT(key.fIsValid);
-        return 0 == entry.compare(key);
-    }
-
-    static bool LT(const ENTRY& entry, const GrTBinHashKey<ENTRY, KEY_SIZE>& key) {
-        SkASSERT(key.fIsValid);
-        return entry.compare(key) < 0;
+    bool operator<(const GrBinHashKey<KEY_SIZE>& key) const {
+        SkASSERT(fIsValid && key.fIsValid);
+        for (size_t i = 0; i < SK_ARRAY_COUNT(fData); ++i) {
+            if (fData[i] < key.fData[i]) {
+                return true;
+            } else if (fData[i] > key.fData[i]) {
+                return false;
+            }
+        }
+        return false;
     }
 
     uint32_t getHash() const {
@@ -94,12 +86,12 @@
 
     const uint8_t* getData() const {
         SkASSERT(fIsValid);
-        return fData;
+        return reinterpret_cast<const uint8_t*>(fData);
     }
 
 private:
     uint32_t            fHash;
-    uint8_t             fData[KEY_SIZE];  // Buffer for key storage
+    uint32_t            fData[KEY_SIZE / sizeof(uint32_t)];  // Buffer for key storage.
 
 #ifdef SK_DEBUG
 public:
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h
index 38378ac..ca30732 100644
--- a/src/gpu/GrResourceCache.h
+++ b/src/gpu/GrResourceCache.h
@@ -54,7 +54,7 @@
     }
 
     GrResourceKey() {
-        fKey.fHashedKey.reset();
+        fKey.reset();
     }
 
     void reset(const GrCacheID& id, ResourceType type, ResourceFlags flags) {
@@ -63,41 +63,34 @@
 
     //!< returns hash value [0..kHashMask] for the key
     int getHash() const {
-        return fKey.fHashedKey.getHash() & kHashMask;
+        return fKey.getHash() & kHashMask;
     }
 
     bool isScratch() const {
         return ScratchDomain() ==
-            *reinterpret_cast<const GrCacheID::Domain*>(fKey.fHashedKey.getData() +
+            *reinterpret_cast<const GrCacheID::Domain*>(fKey.getData() +
                                                         kCacheIDDomainOffset);
     }
 
     ResourceType getResourceType() const {
-        return *reinterpret_cast<const ResourceType*>(fKey.fHashedKey.getData() +
+        return *reinterpret_cast<const ResourceType*>(fKey.getData() +
                                                       kResourceTypeOffset);
     }
 
     ResourceFlags getResourceFlags() const {
-        return *reinterpret_cast<const ResourceFlags*>(fKey.fHashedKey.getData() +
+        return *reinterpret_cast<const ResourceFlags*>(fKey.getData() +
                                                        kResourceFlagsOffset);
     }
 
-    int compare(const GrResourceKey& other) const {
-        return fKey.fHashedKey.compare(other.fKey.fHashedKey);
-    }
+    bool operator==(const GrResourceKey& other) const { return fKey == other.fKey; }
+    bool operator<(const GrResourceKey& other) const { return fKey < other.fKey; }
 
-    static bool LT(const GrResourceKey& a, const GrResourceKey& b) {
-        return a.compare(b) < 0;
-    }
-
-    static bool EQ(const GrResourceKey& a, const GrResourceKey& b) {
-        return 0 == a.compare(b);
-    }
-
-    inline static bool LT(const GrResourceEntry& entry, const GrResourceKey& key);
-    inline static bool EQ(const GrResourceEntry& entry, const GrResourceKey& key);
-    inline static bool LT(const GrResourceEntry& a, const GrResourceEntry& b);
-    inline static bool EQ(const GrResourceEntry& a, const GrResourceEntry& b);
+    static bool LessThan(const GrResourceEntry& entry, const GrResourceKey& key);
+    static bool Equals(const GrResourceEntry& entry, const GrResourceKey& key);
+#ifdef SK_DEBUG
+    static bool LessThan(const GrResourceEntry& a, const GrResourceEntry& b);
+    static bool Equals(const GrResourceEntry& a, const GrResourceEntry& b);
+#endif
 
 private:
     enum {
@@ -125,21 +118,9 @@
         memcpy(k + kResourceTypeOffset, &type, sizeof(ResourceType));
         memcpy(k + kResourceFlagsOffset, &flags, sizeof(ResourceFlags));
         memset(k + kPadOffset, 0, kPadSize);
-        fKey.fHashedKey.setKeyData(keyData.fKey32);
+        fKey.setKeyData(keyData.fKey32);
     }
-
-    struct Key;
-    typedef GrTBinHashKey<Key, kKeySize> HashedKey;
-
-    struct Key {
-        int compare(const HashedKey& hashedKey) const {
-            return fHashedKey.compare(hashedKey);
-        }
-
-        HashedKey fHashedKey;
-    };
-
-    Key fKey;
+    GrBinHashKey<kKeySize> fKey;
 };
 
 // The cache listens for these messages to purge junk resources proactively.
@@ -174,21 +155,23 @@
     friend class GrDLinkedList;
 };
 
-bool GrResourceKey::LT(const GrResourceEntry& entry, const GrResourceKey& key) {
-    return LT(entry.key(), key);
+inline bool GrResourceKey::LessThan(const GrResourceEntry& entry, const GrResourceKey& key) {
+    return entry.key() < key;
 }
 
-bool GrResourceKey::EQ(const GrResourceEntry& entry, const GrResourceKey& key) {
-    return EQ(entry.key(), key);
+inline bool GrResourceKey::Equals(const GrResourceEntry& entry, const GrResourceKey& key) {
+    return entry.key() == key;
 }
 
-bool GrResourceKey::LT(const GrResourceEntry& a, const GrResourceEntry& b) {
-    return LT(a.key(), b.key());
+#ifdef SK_DEBUG
+inline bool GrResourceKey::LessThan(const GrResourceEntry& a, const GrResourceEntry& b) {
+    return a.key() < b.key();
 }
 
-bool GrResourceKey::EQ(const GrResourceEntry& a, const GrResourceEntry& b) {
-    return EQ(a.key(), b.key());
+inline bool GrResourceKey::Equals(const GrResourceEntry& a, const GrResourceEntry& b) {
+    return a.key() == b.key();
 }
+#endif
 
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/gpu/GrTHashTable.h b/src/gpu/GrTHashTable.h
index 3b32977..83462c7 100644
--- a/src/gpu/GrTHashTable.h
+++ b/src/gpu/GrTHashTable.h
@@ -16,8 +16,10 @@
 
 /**
  *  Key needs
- *      static bool EQ(const Entry&, const HashKey&);
- *      static bool LT(const Entry&, const HashKey&);
+ *      static bool Equals(const Entry&, const Key&);
+ *      static bool LessThan(const Entry&, const Key&);
+ *      static bool Equals(const Entry&, const Entry&); for SK_DEBUG if GrTHashTable::validate() is called
+ *      static bool LessThan(const Entry&, const Entry&); for SK_DEBUG if GrTHashTable::validate() is called
  *      uint32_t getHash() const;
  *
  *  Allows duplicate key entries but on find you may get
@@ -90,7 +92,7 @@
     int low = 0;
     while (high > low) {
         int index = (low + high) >> 1;
-        if (Key::LT(*array[index], key)) {
+        if (Key::LessThan(*array[index], key)) {
             low = index + 1;
         } else {
             high = index;
@@ -98,15 +100,15 @@
     }
 
     // check if we found it
-    if (Key::EQ(*array[high], key)) {
+    if (Key::Equals(*array[high], key)) {
         // above search should have found the first occurrence if there
         // are multiple.
-        SkASSERT(0 == high || Key::LT(*array[high - 1], key));
+        SkASSERT(0 == high || Key::LessThan(*array[high - 1], key));
         return high;
     }
 
     // now return the ~ of where we should insert it
-    if (Key::LT(*array[high], key)) {
+    if (Key::LessThan(*array[high], key)) {
         high += 1;
     }
     return ~high;
@@ -119,7 +121,7 @@
     int hashIndex = hash2Index(key.getHash());
     T* elem = fHash[hashIndex];
 
-    if (NULL != elem && Key::EQ(*elem, key) && filter(elem)) {
+    if (NULL != elem && Key::Equals(*elem, key) && filter(elem)) {
         return elem;
     }
 
@@ -133,9 +135,9 @@
 
     // above search should have found the first occurrence if there
     // are multiple.
-    SkASSERT(0 == index || Key::LT(*array[index - 1], key));
+    SkASSERT(0 == index || Key::LessThan(*array[index - 1], key));
 
-    for ( ; index < count() && Key::EQ(*array[index], key); ++index) {
+    for ( ; index < count() && Key::Equals(*array[index], key); ++index) {
         if (filter(fSorted[index])) {
             // update the hash
             fHash[hashIndex] = fSorted[index];
@@ -192,8 +194,8 @@
 void GrTHashTable<T, Key, kHashBits>::validate() const {
     int count = fSorted.count();
     for (int i = 1; i < count; i++) {
-        SkASSERT(Key::LT(*fSorted[i - 1], *fSorted[i]) ||
-                 Key::EQ(*fSorted[i - 1], *fSorted[i]));
+        SkASSERT(Key::LessThan(*fSorted[i - 1], *fSorted[i]) ||
+                 Key::Equals(*fSorted[i - 1], *fSorted[i]));
     }
 }
 
diff --git a/src/gpu/GrTextStrike_impl.h b/src/gpu/GrTextStrike_impl.h
index 4297185..0691eaa 100644
--- a/src/gpu/GrTextStrike_impl.h
+++ b/src/gpu/GrTextStrike_impl.h
@@ -19,10 +19,10 @@
 
     intptr_t getHash() const { return fFontScalerKey->getHash(); }
 
-    static bool LT(const GrTextStrike& strike, const Key& key) {
+    static bool LessThan(const GrTextStrike& strike, const Key& key) {
         return *strike.getFontScalerKey() < *key.fFontScalerKey;
     }
-    static bool EQ(const GrTextStrike& strike, const Key& key) {
+    static bool Equals(const GrTextStrike& strike, const Key& key) {
         return *strike.getFontScalerKey() == *key.fFontScalerKey;
     }
 
@@ -88,10 +88,10 @@
 
     uint32_t getHash() const { return fPackedID; }
 
-    static bool LT(const GrGlyph& glyph, const Key& key) {
+    static bool LessThan(const GrGlyph& glyph, const Key& key) {
         return glyph.fPackedID < key.fPackedID;
     }
-    static bool EQ(const GrGlyph& glyph, const Key& key) {
+    static bool Equals(const GrGlyph& glyph, const Key& key) {
         return glyph.fPackedID == key.fPackedID;
     }
 
diff --git a/src/gpu/SkGrFontScaler.cpp b/src/gpu/SkGrFontScaler.cpp
index 6514866..1ca9357 100644
--- a/src/gpu/SkGrFontScaler.cpp
+++ b/src/gpu/SkGrFontScaler.cpp
@@ -85,6 +85,8 @@
             return kA8_GrMaskFormat;
         case SkMask::kLCD16_Format:
             return kA565_GrMaskFormat;
+        // TODO: properly support kARGB32_Format.
+        case SkMask::kARGB32_Format:
         case SkMask::kLCD32_Format:
             return kA888_GrMaskFormat;
         default:
diff --git a/src/gpu/effects/GrTextureStripAtlas.h b/src/gpu/effects/GrTextureStripAtlas.h
index e56e736..e06e273 100644
--- a/src/gpu/effects/GrTextureStripAtlas.h
+++ b/src/gpu/effects/GrTextureStripAtlas.h
@@ -136,12 +136,15 @@
 
     // Hash table entry for atlases
     class AtlasEntry;
-    typedef GrTBinHashKey<AtlasEntry, sizeof(GrTextureStripAtlas::Desc)> AtlasHashKey;
+    class AtlasHashKey : public GrBinHashKey<sizeof(GrTextureStripAtlas::Desc)> {
+    public:
+        static bool Equals(const AtlasEntry& entry, const AtlasHashKey& key);
+        static bool LessThan(const AtlasEntry& entry, const AtlasHashKey& key);
+    };
     class AtlasEntry : public ::SkNoncopyable {
     public:
         AtlasEntry() : fAtlas(NULL) {}
         ~AtlasEntry() { SkDELETE(fAtlas); }
-        int compare(const AtlasHashKey& key) const { return fKey.compare(key); }
         AtlasHashKey fKey;
         GrTextureStripAtlas* fAtlas;
     };
@@ -178,4 +181,14 @@
     SkTDArray<AtlasRow*> fKeyTable;
 };
 
+inline bool GrTextureStripAtlas::AtlasHashKey::Equals(const AtlasEntry& entry,
+                                                      const AtlasHashKey& key) {
+    return entry.fKey == key;
+}
+
+inline bool GrTextureStripAtlas::AtlasHashKey::LessThan(const AtlasEntry& entry,
+                                                        const AtlasHashKey& key) {
+    return entry.fKey < key;
+}
+
 #endif
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 9cf39b6..00d27b3 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -1276,6 +1276,7 @@
             return;
         }
     }
+
     this->flushRenderTarget(rect);
     GrAutoTRestore<ScissorState> asr(&fScissorState);
     fScissorState.fEnabled = (NULL != rect);
@@ -1522,10 +1523,16 @@
     if (fHWBoundRenderTarget != rt) {
         GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, rt->renderFBOID()));
 #ifdef SK_DEBUG
-        GrGLenum status;
-        GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
-        if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
-            GrPrintf("GrGpuGL::flushRenderTarget glCheckFramebufferStatus %x\n", status);
+        // don't do this check in Chromium -- this is causing
+        // lots of repeated command buffer flushes when the compositor is
+        // rendering with Ganesh, which is really slow; even too slow for
+        // Debug mode.
+        if (!this->glContext().info().isChromium()) {
+            GrGLenum status;
+            GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+            if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
+                GrPrintf("GrGpuGL::flushRenderTarget glCheckFramebufferStatus %x\n", status);
+            }
         }
 #endif
         fHWBoundRenderTarget = rt;
diff --git a/src/gpu/gr_unittests.cpp b/src/gpu/gr_unittests.cpp
deleted file mode 100644
index ae9f67f..0000000
--- a/src/gpu/gr_unittests.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-
-/*
- * Copyright 2010 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrBinHashKey.h"
-#include "GrDrawTarget.h"
-#include "SkMatrix.h"
-#include "GrRedBlackTree.h"
-
-// FIXME: needs to be in a header
-void gr_run_unittests();
-
-// If we aren't inheriting these as #defines from elsewhere,
-// clang demands they be declared before we #include the template
-// that relies on them.
-#ifdef SK_DEBUG
-static bool LT(const int& elem, int value) {
-    return elem < value;
-}
-static bool EQ(const int& elem, int value) {
-    return elem == value;
-}
-#include "GrTBSearch.h"
-
-static void test_bsearch() {
-    const int array[] = {
-        1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99
-    };
-
-    for (int n = 0; n < static_cast<int>(GR_ARRAY_COUNT(array)); ++n) {
-        for (int i = 0; i < n; i++) {
-            int index = GrTBSearch<int, int>(array, n, array[i]);
-            SkASSERT(index == (int) i);
-            index = GrTBSearch<int, int>(array, n, -array[i]);
-            SkASSERT(index < 0);
-        }
-    }
-}
-#endif
-
-// bogus empty class for GrBinHashKey
-class BogusEntry {};
-
-static void test_binHashKey()
-{
-    const char* testStringA_ = "abcdABCD";
-    const char* testStringB_ = "abcdBBCD";
-    const uint32_t* testStringA = reinterpret_cast<const uint32_t*>(testStringA_);
-    const uint32_t* testStringB = reinterpret_cast<const uint32_t*>(testStringB_);
-    enum {
-        kDataLenUsedForKey = 8
-    };
-
-    GrTBinHashKey<BogusEntry, kDataLenUsedForKey> keyA;
-    keyA.setKeyData(testStringA);
-    // test copy constructor and comparison
-    GrTBinHashKey<BogusEntry, kDataLenUsedForKey> keyA2(keyA);
-    SkASSERT(keyA.compare(keyA2) == 0);
-    SkASSERT(keyA.getHash() == keyA2.getHash());
-    // test re-init
-    keyA2.setKeyData(testStringA);
-    SkASSERT(keyA.compare(keyA2) == 0);
-    SkASSERT(keyA.getHash() == keyA2.getHash());
-    // test sorting
-    GrTBinHashKey<BogusEntry, kDataLenUsedForKey> keyB;
-    keyB.setKeyData(testStringB);
-    SkASSERT(keyA.compare(keyB) < 0);
-    SkASSERT(keyA.getHash() != keyB.getHash());
-}
-
-
-void gr_run_unittests() {
-    SkDEBUGCODE(test_bsearch();)
-    test_binHashKey();
-    GrRedBlackTree<int>::UnitTest();
-}
diff --git a/src/opts/SkBlitMask_opts_arm.cpp b/src/opts/SkBlitMask_opts_arm.cpp
index 0ad0919..2bf7603 100644
--- a/src/opts/SkBlitMask_opts_arm.cpp
+++ b/src/opts/SkBlitMask_opts_arm.cpp
@@ -1,14 +1,39 @@
 
+#include "SkColor.h"
+#include "SkColorPriv.h"
 #include "SkBlitMask.h"
+#include "SkUtilsArm.h"
+#include "SkBlitMask_opts_arm_neon.h"
 
 SkBlitMask::ColorProc SkBlitMask::PlatformColorProcs(SkBitmap::Config dstConfig,
                                                      SkMask::Format maskFormat,
                                                      SkColor color) {
+#if SK_ARM_NEON_IS_NONE
+    return NULL;
+#else
+#if SK_ARM_NEON_IS_DYNAMIC
+    if (!sk_cpu_arm_has_neon()) {
+        return NULL;
+    }
+#endif
+    if ((SkBitmap::kARGB_8888_Config == dstConfig) &&
+        (SkMask::kA8_Format == maskFormat)) {
+            return D32_A8_Factory_neon(color);
+    }
+#endif
+
+    // We don't need to handle the SkMask::kLCD16_Format case as the default
+    // LCD16 will call us through SkBlitMask::PlatformBlitRowProcs16()
+
     return NULL;
 }
 
 SkBlitMask::BlitLCD16RowProc SkBlitMask::PlatformBlitRowProcs16(bool isOpaque) {
-    return NULL;
+    if (isOpaque) {
+        return SK_ARM_NEON_WRAP(SkBlitLCD16OpaqueRow);
+    } else {
+        return SK_ARM_NEON_WRAP(SkBlitLCD16Row);
+    }
 }
 
 SkBlitMask::RowProc SkBlitMask::PlatformRowProcs(SkBitmap::Config dstConfig,
diff --git a/src/opts/SkColor_opts_neon.h b/src/opts/SkColor_opts_neon.h
index f812397..85752f5 100644
--- a/src/opts/SkColor_opts_neon.h
+++ b/src/opts/SkColor_opts_neon.h
@@ -2,6 +2,7 @@
 #define SkColor_opts_neon_DEFINED
 
 #include "SkTypes.h"
+#include "SkColorPriv.h"
 
 #include <arm_neon.h>
 
@@ -65,4 +66,20 @@
     return ret;
 }
 
+/* This function blends 8 pixels of the same channel in the exact same way as
+ * SkBlend32.
+ */
+static inline uint8x8_t SkBlend32_neon8(uint8x8_t src, uint8x8_t dst, uint16x8_t scale) {
+    int16x8_t src_wide, dst_wide;
+
+    src_wide = vreinterpretq_s16_u16(vmovl_u8(src));
+    dst_wide = vreinterpretq_s16_u16(vmovl_u8(dst));
+
+    src_wide = (src_wide - dst_wide) * vreinterpretq_s16_u16(scale);
+
+    dst_wide += vshrq_n_s16(src_wide, 5);
+
+    return vmovn_u16(vreinterpretq_u16_s16(dst_wide));
+}
+
 #endif /* #ifndef SkColor_opts_neon_DEFINED */
diff --git a/src/pdf/SkPDFImage.cpp b/src/pdf/SkPDFImage.cpp
index a99c9fe..81adcc2 100644
--- a/src/pdf/SkPDFImage.cpp
+++ b/src/pdf/SkPDFImage.cpp
@@ -36,7 +36,6 @@
             return srcRect.width() * 3 * srcRect.height();
         case SkBitmap::kARGB_8888_Config:
             return srcRect.width() * 3 * srcRect.height();
-        case SkBitmap::kA1_Config:
         case SkBitmap::kA8_Config:
             return 1;
         default:
@@ -166,48 +165,6 @@
     return stream;
 }
 
-static SkStream* extract_a1_alpha(const SkBitmap& bitmap,
-                                  const SkIRect& srcRect,
-                                  bool* isOpaque,
-                                  bool* isTransparent) {
-    const int alphaRowBytes = (srcRect.width() + 7) / 8;
-    SkStream* stream = SkNEW_ARGS(SkMemoryStream,
-                                  (alphaRowBytes * srcRect.height()));
-    uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
-
-    int offset1 = srcRect.fLeft % 8;
-    int offset2 = 8 - offset1;
-
-    for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
-        uint8_t* src = bitmap.getAddr1(0, y);
-        // This may read up to one byte after src, but the
-        // potentially invalid bits are never used for computation.
-        for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8)  {
-            if (offset1) {
-                alphaDst[0] = src[x / 8] << offset1 |
-                    src[x / 8 + 1] >> offset2;
-            } else {
-                alphaDst[0] = src[x / 8];
-            }
-            if (x + 7 < srcRect.fRight) {
-                *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE;
-                *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT;
-            }
-            alphaDst++;
-        }
-        // Calculate the mask of bits we're interested in within the
-        // last byte of alphaDst.
-        // width mod 8  == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE
-        uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1);
-        if (srcRect.width() % 8) {
-            *isOpaque &= (alphaDst[-1] & mask) == (SK_AlphaOPAQUE & mask);
-            *isTransparent &=
-                    (alphaDst[-1] & mask) == (SK_AlphaTRANSPARENT & mask);
-        }
-    }
-    return stream;
-}
-
 static SkStream* extract_a8_alpha(const SkBitmap& bitmap,
                                   const SkIRect& srcRect,
                                   bool* isOpaque,
@@ -283,14 +240,6 @@
             stream = extract_argb8888_data(bitmap, srcRect, extractAlpha,
                                            &isOpaque, &transparent);
             break;
-        case SkBitmap::kA1_Config:
-            if (!extractAlpha) {
-                stream = create_black_image();
-            } else {
-                stream = extract_a1_alpha(bitmap, srcRect,
-                                          &isOpaque, &transparent);
-            }
-            break;
         case SkBitmap::kA8_Config:
             if (!extractAlpha) {
                 stream = create_black_image();
@@ -574,8 +523,7 @@
     insertName("Type", "XObject");
     insertName("Subtype", "Image");
 
-    bool alphaOnly = (config == SkBitmap::kA1_Config ||
-                      config == SkBitmap::kA8_Config);
+    bool alphaOnly = (config == SkBitmap::kA8_Config);
 
     if (!isAlpha && alphaOnly) {
         // For alpha only images, we stretch a single pixel of black for
@@ -601,8 +549,6 @@
     int bitsPerComp = 8;
     if (config == SkBitmap::kARGB_4444_Config) {
         bitsPerComp = 4;
-    } else if (isAlpha && config == SkBitmap::kA1_Config) {
-        bitsPerComp = 1;
     }
     insertInt("BitsPerComponent", bitsPerComp);
 
diff --git a/src/utils/debugger/SkObjectParser.cpp b/src/utils/debugger/SkObjectParser.cpp
index 54ae077..ebbd400 100644
--- a/src/utils/debugger/SkObjectParser.cpp
+++ b/src/utils/debugger/SkObjectParser.cpp
@@ -26,9 +26,9 @@
     mBitmap->appendS32(bitmap.height());
 
     const char* gConfigStrings[] = {
-        "None", "A1", "A8", "Index8", "RGB565", "ARGB4444", "ARGB8888"
+        "None", "A8", "Index8", "RGB565", "ARGB4444", "ARGB8888"
     };
-    SkASSERT(SkBitmap::kConfigCount == 7);
+    SkASSERT(SkBitmap::kConfigCount == SK_ARRAY_COUNT(gConfigStrings));
 
     mBitmap->append(" Config: ");
     mBitmap->append(gConfigStrings[bitmap.config()]);
diff --git a/tests/BitmapCopyTest.cpp b/tests/BitmapCopyTest.cpp
index 5cef1eb..f61d55e 100644
--- a/tests/BitmapCopyTest.cpp
+++ b/tests/BitmapCopyTest.cpp
@@ -15,7 +15,7 @@
 
 // these are in the same order as the SkBitmap::Config enum
 static const char* gConfigName[] = {
-    "None", "A1", "A8", "Index8", "565", "4444", "8888", "RLE_Index8"
+    "None", "A8", "Index8", "565", "4444", "8888"
 };
 
 static void report_opaqueness(skiatest::Reporter* reporter, const SkBitmap& src,
@@ -57,10 +57,6 @@
     if (bitmap.getPixels()) {
         if (bitmap.getColorTable()) {
             sk_bzero(bitmap.getPixels(), bitmap.getSize());
-        } else if (SkBitmap::kA1_Config == bitmap.config()) {
-            // The A1 config can have uninitialized bits at the
-            // end of each row if eraseColor is used
-            memset(bitmap.getPixels(), 0xff, bitmap.getSafeSize());
         } else {
             bitmap.eraseColor(SK_ColorWHITE);
         }
@@ -92,7 +88,7 @@
 static uint32_t getPixel(int x, int y, const SkBitmap& bm) {
     uint32_t val = 0;
     uint16_t val16;
-    uint8_t val8, shift;
+    uint8_t val8;
     SkAutoLockPixels lock(bm);
     const void* rawAddr = bm.getAddr(x,y);
 
@@ -110,11 +106,6 @@
             memcpy(&val8, rawAddr, sizeof(uint8_t));
             val = val8;
             break;
-        case SkBitmap::kA1_Config:
-            memcpy(&val8, rawAddr, sizeof(uint8_t));
-            shift = x % 8;
-            val = (val8 >> shift) & 0x1 ;
-            break;
         default:
             break;
     }
@@ -126,7 +117,7 @@
 // converted to, but at present uint32_t can handle all formats.
 static void setPixel(int x, int y, uint32_t val, SkBitmap& bm) {
     uint16_t val16;
-    uint8_t val8, shift;
+    uint8_t val8;
     SkAutoLockPixels lock(bm);
     void* rawAddr = bm.getAddr(x,y);
 
@@ -144,15 +135,6 @@
             val8 = val & 0xFF;
             memcpy(rawAddr, &val8, sizeof(uint8_t));
             break;
-        case SkBitmap::kA1_Config:
-            shift = x % 8; // We assume we're in the right byte.
-            memcpy(&val8, rawAddr, sizeof(uint8_t));
-            if (val & 0x1) // Turn bit on.
-                val8 |= (0x1 << shift);
-            else // Turn bit off.
-                val8 &= ~(0x1 << shift);
-            memcpy(rawAddr, &val8, sizeof(uint8_t));
-            break;
         default:
             // Ignore.
             break;
@@ -164,7 +146,6 @@
 static const char* getSkConfigName(const SkBitmap& bm) {
     switch (bm.config()) {
         case SkBitmap::kNo_Config: return "SkBitmap::kNo_Config";
-        case SkBitmap::kA1_Config: return "SkBitmap::kA1_Config";
         case SkBitmap::kA8_Config: return "SkBitmap::kA8_Config";
         case SkBitmap::kIndex8_Config: return "SkBitmap::kIndex8_Config";
         case SkBitmap::kRGB_565_Config: return "SkBitmap::kRGB_565_Config";
@@ -225,13 +206,12 @@
 
 static void TestBitmapCopy(skiatest::Reporter* reporter) {
     static const Pair gPairs[] = {
-        { SkBitmap::kNo_Config,         "00000000"  },
-        { SkBitmap::kA1_Config,         "01000000"  },
-        { SkBitmap::kA8_Config,         "00101010"  },
-        { SkBitmap::kIndex8_Config,     "00111010"  },
-        { SkBitmap::kRGB_565_Config,    "00101010"  },
-        { SkBitmap::kARGB_4444_Config,  "00101110"  },
-        { SkBitmap::kARGB_8888_Config,  "00101110"  },
+        { SkBitmap::kNo_Config,         "0000000"  },
+        { SkBitmap::kA8_Config,         "0101010"  },
+        { SkBitmap::kIndex8_Config,     "0111010"  },
+        { SkBitmap::kRGB_565_Config,    "0101010"  },
+        { SkBitmap::kARGB_4444_Config,  "0101110"  },
+        { SkBitmap::kARGB_8888_Config,  "0101110"  },
     };
 
     static const bool isExtracted[] = {
@@ -375,12 +355,6 @@
                 case SkBitmap::kNo_Config:
                     break;
 
-                case SkBitmap::kA1_Config:
-                    if (safeSize.fHi != 0x470DE ||
-                        safeSize.fLo != 0x4DF82000)
-                        sizeFail = true;
-                    break;
-
                 case SkBitmap::kA8_Config:
                 case SkBitmap::kIndex8_Config:
                     if (safeSize.fHi != 0x2386F2 ||
@@ -411,21 +385,8 @@
                 reporter->reportFailed(str);
             }
 
-            int subW, subH;
-            // Set sizes to be height = 2 to force the last row of the
-            // source to be used, thus verifying correct operation if
-            // the bitmap is an extracted subset.
-            if (gPairs[i].fConfig == SkBitmap::kA1_Config) {
-                // If one-bit per pixel, use 9 pixels to force more than
-                // one byte per row.
-                subW = 9;
-                subH = 2;
-            } else {
-                // All other configurations are at least one byte per pixel,
-                // and different configs will test copying different numbers
-                // of bytes.
-                subW = subH = 2;
-            }
+            int subW = 2;
+            int subH = 2;
 
             // Create bitmap to act as source for copies and subsets.
             SkBitmap src, subset;
@@ -449,12 +410,7 @@
                 // The extractedSubset() test case allows us to test copy-
                 // ing when src and dst mave possibly different strides.
                 SkIRect r;
-                if (gPairs[i].fConfig == SkBitmap::kA1_Config)
-                    // This config seems to need byte-alignment of
-                    // extracted subset bits.
-                    r.set(0, 0, subW, subH);
-                else
-                    r.set(1, 0, 1 + subW, subH); // 2x2 extracted bitmap
+                r.set(1, 0, 1 + subW, subH); // 2x2 extracted bitmap
 
                 srcReady = src.extractSubset(&subset, r);
             } else {
diff --git a/tests/BitmapGetColorTest.cpp b/tests/BitmapGetColorTest.cpp
index 11c22e6..40aa3e2 100644
--- a/tests/BitmapGetColorTest.cpp
+++ b/tests/BitmapGetColorTest.cpp
@@ -10,67 +10,6 @@
 #include "SkRect.h"
 #include "SkRandom.h"
 
-static int nextRand(SkRandom& rand, int min, int max) {
-    return min + (int)rand.nextRangeU(0, max - min);
-}
-
-static void rand_irect(SkIRect* rect, int W, int H, SkRandom& rand) {
-    const int DX = W / 2;
-    const int DY = H / 2;
-
-    rect->fLeft   = nextRand(rand, -DX, W + DX);
-    rect->fTop    = nextRand(rand, -DY, H + DY);
-    rect->fRight  = nextRand(rand, -DX, W + DX);
-    rect->fBottom = nextRand(rand, -DY, H + DY);
-    rect->sort();
-}
-
-static void test_equal_A1_A8(skiatest::Reporter* reporter,
-                       const SkBitmap& bm1, const SkBitmap& bm8) {
-    SkASSERT(SkBitmap::kA1_Config == bm1.config());
-    SkASSERT(SkBitmap::kA8_Config == bm8.config());
-
-    REPORTER_ASSERT(reporter, bm1.width() == bm8.width());
-    REPORTER_ASSERT(reporter, bm1.height() == bm8.height());
-    for (int y = 0; y < bm1.height(); ++y) {
-        for (int x = 0; x < bm1.width(); ++x) {
-            int p1 = *bm1.getAddr1(x, y) & (1 << (7 - (x & 7)));
-            SkASSERT(SkIsPow2(p1));
-            p1 = p1 ? 0xFF : 0;
-
-            int p8 = *bm8.getAddr8(x, y);
-            SkASSERT(0 == p8 || 0xFF == p8);
-
-            REPORTER_ASSERT(reporter, p1 == p8);
-        }
-    }
-}
-
-static void test_eraserect_A1(skiatest::Reporter* reporter) {
-    const int W = 43;
-    const int H = 13;
-
-    SkBitmap bm1, bm8;
-
-    bm1.setConfig(SkBitmap::kA1_Config, W, H);
-    bm1.allocPixels();
-    bm8.setConfig(SkBitmap::kA8_Config, W, H);
-    bm8.allocPixels();
-
-    SkRandom rand;
-    for (int i = 0; i < 10000; ++i) {
-        SkIRect area;
-        rand_irect(&area, W, H, rand);
-
-        bm1.eraseColor(0);
-        bm8.eraseColor(0);
-
-        bm1.eraseArea(area, SK_ColorWHITE);
-        bm8.eraseArea(area, SK_ColorWHITE);
-        test_equal_A1_A8(reporter, bm1, bm8);
-    }
-}
-
 static void TestGetColor(skiatest::Reporter* reporter) {
     static const struct Rec {
         SkBitmap::Config    fConfig;
@@ -105,8 +44,6 @@
         SkColor c = bm.getColor(1, 1);
         REPORTER_ASSERT(reporter, c == gRec[i].fOutColor);
     }
-
-    test_eraserect_A1(reporter);
 }
 
 #include "TestClassDef.h"
diff --git a/tests/BlitRowTest.cpp b/tests/BlitRowTest.cpp
index 3903efb..8576110 100644
--- a/tests/BlitRowTest.cpp
+++ b/tests/BlitRowTest.cpp
@@ -14,7 +14,7 @@
 
 // these are in the same order as the SkBitmap::Config enum
 static const char* gConfigName[] = {
-    "None", "A1", "A8", "Index8", "565", "4444", "8888", "RLE_Index8"
+    "None", "A8", "Index8", "565", "4444", "8888"
 };
 
 /** Returns -1 on success, else the x coord of the first bad pixel, return its
diff --git a/tests/HashCacheTest.cpp b/tests/HashCacheTest.cpp
index bd28c44..1a5c470 100644
--- a/tests/HashCacheTest.cpp
+++ b/tests/HashCacheTest.cpp
@@ -39,21 +39,18 @@
 
     uint32_t getHash() const { return fKey; }
 
-    static bool LT(const HashElement& entry, const HashKey& key) {
+    static bool LessThan(const HashElement& entry, const HashKey& key) {
         return entry.fKey < key.fKey;
     }
-    static bool EQ(const HashElement& entry, const HashKey& key) {
+    static bool Equals(const HashElement& entry, const HashKey& key) {
         return entry.fKey == key.fKey;
     }
 
 #ifdef SK_DEBUG
-    static uint32_t GetHash(const HashElement& entry) {
-        return entry.fKey;
-    }
-    static bool LT(const HashElement& a, const HashElement& b) {
+    static bool LessThan(const HashElement& a, const HashElement& b) {
         return a.fKey < b.fKey;
     }
-    static bool EQ(const HashElement& a, const HashElement& b) {
+    static bool Equals(const HashElement& a, const HashElement& b) {
         return a.fKey == b.fKey;
     }
 #endif
diff --git a/tests/ImageCacheTest.cpp b/tests/ImageCacheTest.cpp
index 877591a..b8815a3 100644
--- a/tests/ImageCacheTest.cpp
+++ b/tests/ImageCacheTest.cpp
@@ -63,3 +63,22 @@
 
 #include "TestClassDef.h"
 DEFINE_TESTCLASS("ImageCache", TestImageCacheClass, TestImageCache)
+
+DEF_TEST(ImageCache_doubleAdd, r) {
+    // Adding the same key twice should be safe.
+    SkScaledImageCache cache(1024);
+
+    SkBitmap original;
+    original.setConfig(SkBitmap::kARGB_8888_Config, 40, 40);
+    original.allocPixels();
+
+    SkBitmap scaled;
+    scaled.setConfig(SkBitmap::kARGB_8888_Config, 20, 20);
+    scaled.allocPixels();
+
+    SkScaledImageCache::ID* id1 = cache.addAndLock(original, 0.5f, 0.5f, scaled);
+    SkScaledImageCache::ID* id2 = cache.addAndLock(original, 0.5f, 0.5f, scaled);
+    // We don't really care if id1 == id2 as long as unlocking both works.
+    cache.unlock(id1);
+    cache.unlock(id2);
+}
diff --git a/tests/ImageDecodingTest.cpp b/tests/ImageDecodingTest.cpp
index 56193f4..6fcef1d 100644
--- a/tests/ImageDecodingTest.cpp
+++ b/tests/ImageDecodingTest.cpp
@@ -148,7 +148,7 @@
         // the list is that each one is different, so we can test
         // to make sure the correct config is chosen.
         const SkBitmap::Config configs[] = {
-            SkBitmap::kA1_Config,
+            SkBitmap::kA8_Config,
             SkBitmap::kA8_Config,
             SkBitmap::kIndex8_Config,
             SkBitmap::kRGB_565_Config,
diff --git a/tests/SerializationTest.cpp b/tests/SerializationTest.cpp
index f49abe9..9e63249 100644
--- a/tests/SerializationTest.cpp
+++ b/tests/SerializationTest.cpp
@@ -173,37 +173,43 @@
 
     // Test rrect serialization
     {
+        // SkRRect does not initialize anything.
+        // An uninitialized SkRRect can be serialized,
+        // but will branch on uninitialized data when deserialized.
         SkRRect rrect;
+        SkRect rect = SkRect::MakeXYWH(1, 2, 20, 30);
+        SkVector corners[4] = { {1, 2}, {2, 3}, {3,4}, {4,5} };
+        rrect.setRectRadii(rect, corners);
         TestAlignment(&rrect, reporter);
     }
 
     // Test readByteArray
     {
-        unsigned char data[kArraySize] = {0};
+        unsigned char data[kArraySize] = { 1, 2, 3 };
         TestArraySerialization(data, reporter);
     }
 
     // Test readColorArray
     {
-        SkColor data[kArraySize];
+        SkColor data[kArraySize] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorRED };
         TestArraySerialization(data, reporter);
     }
 
     // Test readIntArray
     {
-        int32_t data[kArraySize];
+        int32_t data[kArraySize] = { 1, 2, 4, 8 };
         TestArraySerialization(data, reporter);
     }
 
     // Test readPointArray
     {
-        SkPoint data[kArraySize];
+        SkPoint data[kArraySize] = { {6, 7}, {42, 128} };
         TestArraySerialization(data, reporter);
     }
 
     // Test readScalarArray
     {
-        SkScalar data[kArraySize];
+        SkScalar data[kArraySize] = { SK_Scalar1, SK_ScalarHalf, SK_ScalarMax };
         TestArraySerialization(data, reporter);
     }
 }
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"));
+}
diff --git a/whitespace.txt b/whitespace.txt
index eea24cc..3ee84cb 100644
--- a/whitespace.txt
+++ b/whitespace.txt
@@ -172,6 +172,11 @@
 
 
 
+
+
+
+
+
 This file has gotten so boring.