Sanitizing source files in Housekeeper-Nightly

git-svn-id: http://skia.googlecode.com/svn/trunk/src@12427 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/animator/SkDrawBitmap.cpp b/animator/SkDrawBitmap.cpp
index 327e813..568401d 100644
--- a/animator/SkDrawBitmap.cpp
+++ b/animator/SkDrawBitmap.cpp
@@ -75,10 +75,11 @@
     const char* formatName;
     switch (format) {
         case 0: formatName = "none"; break;
-        case 1: formatName = "A8"; break;
-        case 2: formatName = "Index8"; break;
-        case 3: formatName = "RGB16"; break;
-        case 4: formatName = "RGB32"; 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;
     }
     SkDebugf("format=\"%s\" />\n", formatName);
 }
diff --git a/core/SkBitmap.cpp b/core/SkBitmap.cpp
index 9d4aa87..429d092 100644
--- a/core/SkBitmap.cpp
+++ b/core/SkBitmap.cpp
@@ -161,6 +161,7 @@
     int bpp;
     switch (config) {
         case kNo_Config:
+        case kA1_Config:
             bpp = 0;   // not applicable
             break;
         case kA8_Config:
@@ -193,6 +194,11 @@
     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);
@@ -269,6 +275,7 @@
         case SkBitmap::kNo_Config:
             alphaType = kIgnore_SkAlphaType;
             break;
+        case SkBitmap::kA1_Config:
         case SkBitmap::kA8_Config:
             if (kUnpremul_SkAlphaType == alphaType) {
                 alphaType = kPremul_SkAlphaType;
@@ -284,8 +291,6 @@
         case SkBitmap::kRGB_565_Config:
             alphaType = kOpaque_SkAlphaType;
             break;
-        default:
-            return false;
     }
     if (canonical) {
         *canonical = alphaType;
@@ -601,6 +606,8 @@
             case SkBitmap::kIndex8_Config:
                 base += x;
                 break;
+            case SkBitmap::kA1_Config:
+                base += x >> 3;
                 break;
             default:
                 SkDEBUGFAIL("Can't return addr for config");
@@ -616,6 +623,15 @@
     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]);
@@ -638,7 +654,6 @@
             return SkUnPreMultiply::PMColorToColor(addr[0]);
         }
         case kNo_Config:
-        default:
             SkASSERT(false);
             return 0;
     }
@@ -656,6 +671,9 @@
     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) {
@@ -761,6 +779,38 @@
     }
 
     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) {
@@ -846,6 +896,7 @@
             break;
 
         case SkBitmap::kNo_Config:
+        case SkBitmap::kA1_Config:
         default:
             return SUB_OFFSET_FAILURE;
     }
@@ -888,6 +939,8 @@
 
         case SkBitmap::kNo_Config:
             // Fall through.
+        case SkBitmap::kA1_Config:
+            // Fall through.
         default:
             return false;
     }
@@ -968,6 +1021,7 @@
         case kRGB_565_Config:
         case kARGB_8888_Config:
             break;
+        case kA1_Config:
         case kIndex8_Config:
             if (!sameConfigs) {
                 return false;
@@ -978,6 +1032,12 @@
         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;
 }
 
@@ -1623,7 +1683,7 @@
 void SkBitmap::toString(SkString* str) const {
 
     static const char* gConfigNames[kConfigCount] = {
-        "NONE", "A8", "INDEX8", "565", "4444", "8888"
+        "NONE", "A1", "A8", "INDEX8", "565", "4444", "8888"
     };
 
     str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
diff --git a/core/SkBlitter.cpp b/core/SkBlitter.cpp
index 9682d55..dc7946a 100644
--- a/core/SkBlitter.cpp
+++ b/core/SkBlitter.cpp
@@ -945,6 +945,11 @@
 
 
     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/core/SkBlitter_A1.cpp b/core/SkBlitter_A1.cpp
new file mode 100644
index 0000000..b64afe2
--- /dev/null
+++ b/core/SkBlitter_A1.cpp
@@ -0,0 +1,50 @@
+
+/*
+ * 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/core/SkCoreBlitters.h b/core/SkCoreBlitters.h
index 1605a52..673b874 100644
--- a/core/SkCoreBlitters.h
+++ b/core/SkCoreBlitters.h
@@ -162,6 +162,22 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+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/core/SkGlyphCache.cpp b/core/SkGlyphCache.cpp
index a78b197..faa3f89 100644
--- a/core/SkGlyphCache.cpp
+++ b/core/SkGlyphCache.cpp
@@ -87,6 +87,8 @@
 
     fGlyphArray.setReserve(kMinGlyphCount);
 
+    fMetricsCount = 0;
+    fAdvanceCount = 0;
     fAuxProcList = NULL;
 }
 
@@ -318,9 +320,11 @@
 
     if (kJustAdvance_MetricsType == mtype) {
         fScalerContext->getAdvance(glyph);
+        fAdvanceCount += 1;
     } else {
         SkASSERT(kFull_MetricsType == mtype);
         fScalerContext->getMetrics(glyph);
+        fMetricsCount += 1;
     }
 
     return glyph;
diff --git a/core/SkGlyphCache.h b/core/SkGlyphCache.h
index 7b2ebb8..52a8132 100644
--- a/core/SkGlyphCache.h
+++ b/core/SkGlyphCache.h
@@ -211,6 +211,8 @@
     SkTDArray<SkGlyph*> fGlyphArray;
     SkChunkAlloc        fGlyphAlloc;
 
+    int fMetricsCount, fAdvanceCount;
+
     struct CharGlyphRec {
         uint32_t    fID;    // unichar + subpixel
         SkGlyph*    fGlyph;
diff --git a/core/SkPaint.cpp b/core/SkPaint.cpp
index 91a76e1..d6948dd 100644
--- a/core/SkPaint.cpp
+++ b/core/SkPaint.cpp
@@ -2005,7 +2005,11 @@
 };
 
 // The size of a flat paint's POD fields
-static const uint32_t kPODPaintSize =   5 * sizeof(SkScalar) +
+// 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) +
                                         1 * sizeof(SkColor) +
                                         1 * sizeof(uint16_t) +
                                         6 * sizeof(uint8_t);
@@ -2042,6 +2046,8 @@
         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();
@@ -2058,6 +2064,8 @@
         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);
@@ -2112,6 +2120,8 @@
         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/core/SkPicture.cpp b/core/SkPicture.cpp
index 2520e6b..4acc549 100644
--- a/core/SkPicture.cpp
+++ b/core/SkPicture.cpp
@@ -266,20 +266,11 @@
 
 #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;
@@ -350,10 +341,6 @@
         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/core/SkScaledImageCache.cpp b/core/SkScaledImageCache.cpp
index 55eadb8..ea29843 100644
--- a/core/SkScaledImageCache.cpp
+++ b/core/SkScaledImageCache.cpp
@@ -49,7 +49,7 @@
     return hash;
 }
 
-struct SkScaledImageCache::Key {
+struct Key {
     Key(uint32_t genID,
         SkScalar scaleX,
         SkScalar scaleY,
@@ -129,24 +129,22 @@
 #include "SkTDynamicHash.h"
 
 namespace { // can't use static functions w/ template parameters
-const SkScaledImageCache::Key& key_from_rec(const SkScaledImageCache::Rec& rec) {
+const Key& key_from_rec(const SkScaledImageCache::Rec& rec) {
     return rec.fKey;
 }
 
-uint32_t hash_from_key(const SkScaledImageCache::Key& key) {
+uint32_t hash_from_key(const Key& key) {
     return key.fHash;
 }
 
-bool eq_rec_key(const SkScaledImageCache::Rec& rec, const SkScaledImageCache::Key& key) {
+bool eq_rec_key(const SkScaledImageCache::Rec& rec, const Key& key) {
     return rec.fKey == key;
 }
 }
 
 class SkScaledImageCache::Hash : public SkTDynamicHash<SkScaledImageCache::Rec,
-                                                       SkScaledImageCache::Key,
-                                                       key_from_rec,
-                                                       hash_from_key,
-                                                       eq_rec_key> {};
+                                   Key, key_from_rec, hash_from_key,
+                                   eq_rec_key> {};
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -189,22 +187,17 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-
+/**
+   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) {
-    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()) {
+    if (bounds.isEmpty()) {
         return NULL;
     }
+    Key key(genID, scaleX, scaleY, bounds);
 #ifdef USE_HASH
     Rec* rec = fHash->find(key);
 #else
@@ -282,14 +275,8 @@
 /**
    This private method is the fully general record adder. All other
    record adders should call this funtion. */
-SkScaledImageCache::ID* SkScaledImageCache::addAndLock(SkScaledImageCache::Rec* rec) {
+void 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
@@ -298,7 +285,6 @@
 #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,
@@ -307,7 +293,8 @@
                                                        const SkBitmap& bitmap) {
     Key key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeWH(width, height));
     Rec* rec = SkNEW_ARGS(Rec, (key, bitmap));
-    return this->addAndLock(rec);
+    this->addAndLock(rec);
+    return rec_to_id(rec);
 }
 
 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig,
@@ -324,7 +311,8 @@
     }
     Key key(orig.getGenerationID(), scaleX, scaleY, bounds);
     Rec* rec = SkNEW_ARGS(Rec, (key, scaled));
-    return this->addAndLock(rec);
+    this->addAndLock(rec);
+    return rec_to_id(rec);
 }
 
 SkScaledImageCache::ID* SkScaledImageCache::addAndLockMip(const SkBitmap& orig,
@@ -335,7 +323,8 @@
     }
     Key key(orig.getGenerationID(), 0, 0, bounds);
     Rec* rec = SkNEW_ARGS(Rec, (key, mip));
-    return this->addAndLock(rec);
+    this->addAndLock(rec);
+    return rec_to_id(rec);
 }
 
 void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) {
diff --git a/core/SkScaledImageCache.h b/core/SkScaledImageCache.h
index 44ef1f8..fee69d2 100644
--- a/core/SkScaledImageCache.h
+++ b/core/SkScaledImageCache.h
@@ -126,7 +126,6 @@
 
 public:
     struct Rec;
-    struct Key;
 private:
     Rec*    fHead;
     Rec*    fTail;
@@ -140,8 +139,7 @@
 
     Rec* findAndLock(uint32_t generationID, SkScalar sx, SkScalar sy,
                      const SkIRect& bounds);
-    Rec* findAndLock(const Key& key);
-    ID* addAndLock(Rec* rec);
+    void addAndLock(Rec* rec);
 
     void purgeAsNeeded();
 
diff --git a/core/SkScalerContext.cpp b/core/SkScalerContext.cpp
index 4996a73..1d6c2f7 100644
--- a/core/SkScalerContext.cpp
+++ b/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,54 +523,10 @@
     }
 }
 
-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) {
-    SkPaint paint;
+    SkBitmap::Config config;
+    SkPaint     paint;
 
     int srcW = mask.fBounds.width();
     int srcH = mask.fBounds.height();
@@ -582,25 +538,27 @@
     matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
                         -SkIntToScalar(mask.fBounds.fTop));
 
-    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");
+    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");
+        }
     }
 
     SkRasterClip clip;
@@ -629,9 +587,6 @@
     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/core/SkScalerContext.h b/core/SkScalerContext.h
index e4950ed..2820b5a 100644
--- a/core/SkScalerContext.h
+++ b/core/SkScalerContext.h
@@ -202,57 +202,16 @@
     Rec         fRec;
     unsigned    fBaseGlyphCount;
 
-    /** 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 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;
     virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
                                      SkPaint::FontMetrics* mY) = 0;
-
-    /** 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);
+    // default impl returns 0, indicating failure.
+    virtual SkUnichar generateGlyphToChar(uint16_t);
 
     void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
 
diff --git a/core/SkString.cpp b/core/SkString.cpp
index 643dfb1..e30b89f 100644
--- a/core/SkString.cpp
+++ b/core/SkString.cpp
@@ -634,17 +634,5 @@
     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/core/SkValidatingReadBuffer.cpp b/core/SkValidatingReadBuffer.cpp
index 4a8ac47..a92c1b9 100644
--- a/core/SkValidatingReadBuffer.cpp
+++ b/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 fError ? 0 : *(uint32_t*)fReader.peek();
+    return *(uint32_t*)fReader.peek();
 }
 
 void SkValidatingReadBuffer::readBitmap(SkBitmap* bitmap) {
diff --git a/effects/SkDropShadowImageFilter.cpp b/effects/SkDropShadowImageFilter.cpp
index 5be633e..b4d8689 100644
--- a/effects/SkDropShadowImageFilter.cpp
+++ b/effects/SkDropShadowImageFilter.cpp
@@ -15,21 +15,10 @@
 #include "SkFlattenableBuffers.h"
 
 SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigma, SkColor color, SkImageFilter* input)
-    : INHERITED(input)
+    : SkImageFilter(input)
     , fDx(dx)
     , fDy(dy)
-    , 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)
+    , fSigma(sigma)
     , fColor(color)
 {
 }
@@ -38,13 +27,11 @@
  : INHERITED(1, buffer) {
     fDx = buffer.readScalar();
     fDy = buffer.readScalar();
-    fSigmaX = buffer.readScalar();
-    fSigmaY = buffer.readScalar();
+    fSigma = buffer.readScalar();
     fColor = buffer.readColor();
     buffer.validate(SkScalarIsFinite(fDx) &&
                     SkScalarIsFinite(fDy) &&
-                    SkScalarIsFinite(fSigmaX) &&
-                    SkScalarIsFinite(fSigmaY));
+                    SkScalarIsFinite(fSigma));
 }
 
 void SkDropShadowImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const
@@ -52,8 +39,7 @@
     this->INHERITED::flatten(buffer);
     buffer.writeScalar(fDx);
     buffer.writeScalar(fDy);
-    buffer.writeScalar(fSigmaX);
-    buffer.writeScalar(fSigmaY);
+    buffer.writeScalar(fSigma);
     buffer.writeColor(fColor);
 }
 
@@ -63,26 +49,17 @@
     if (getInput(0) && !getInput(0)->filterImage(proxy, source, matrix, &src, loc))
         return false;
 
-    SkIRect bounds;
-    src.getBounds(&bounds);
-    if (!this->applyCropRect(&bounds, matrix)) {
-        return false;
-    }
-
-    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
+    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(src.width(), src.height()));
     SkCanvas canvas(device.get());
 
-    SkAutoTUnref<SkImageFilter> blurFilter(new SkBlurImageFilter(fSigmaX, fSigmaY));
+    SkAutoTUnref<SkImageFilter> blurFilter(new SkBlurImageFilter(fSigma, fSigma));
     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/effects/SkTransparentShader.cpp b/effects/SkTransparentShader.cpp
index 1d7e808..970e74f 100644
--- a/effects/SkTransparentShader.cpp
+++ b/effects/SkTransparentShader.cpp
@@ -94,6 +94,9 @@
             }
             break;
         }
+        case SkBitmap::kA1_Config:
+            SkDEBUGFAIL("kA1_Config umimplemented at this time");
+            break;
         default:    // to avoid warnings
             break;
     }
diff --git a/fonts/SkGScalerContext.cpp b/fonts/SkGScalerContext.cpp
index 551b01c..f0543c5 100644
--- a/fonts/SkGScalerContext.cpp
+++ b/fonts/SkGScalerContext.cpp
@@ -176,8 +176,6 @@
 
 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/gpu/GrBinHashKey.h b/gpu/GrBinHashKey.h
index 585a1a1..7d4aa0f 100644
--- a/gpu/GrBinHashKey.h
+++ b/gpu/GrBinHashKey.h
@@ -13,19 +13,37 @@
 #include "GrTypes.h"
 
 /**
- *  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).
+ *  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.
  */
-template<size_t KEY_SIZE>
-class GrBinHashKey {
+template<typename ENTRY, size_t KEY_SIZE>
+class GrTBinHashKey {
 public:
     enum { kKeySize = KEY_SIZE };
 
-    GrBinHashKey() {
+    GrTBinHashKey() {
         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
@@ -34,49 +52,39 @@
     }
 
     void setKeyData(const uint32_t* SK_RESTRICT data) {
-        SK_COMPILE_ASSERT(KEY_SIZE % 4 == 0, key_size_mismatch);
+        SkASSERT(GrIsALIGN4(KEY_SIZE));
         memcpy(&fData, data, KEY_SIZE);
 
         uint32_t hash = 0;
         size_t len = KEY_SIZE;
         while (len >= 4) {
             hash += *data++;
-            hash += (hash << 10);
+            hash += (fHash << 10);
             hash ^= (hash >> 6);
             len -= 4;
         }
-        hash += (hash << 3);
-        hash ^= (hash >> 11);
-        hash += (hash << 15);
+        hash += (fHash << 3);
+        hash ^= (fHash >> 11);
+        hash += (fHash << 15);
 #ifdef SK_DEBUG
         fIsValid = true;
 #endif
         fHash = hash;
     }
 
-    bool operator==(const GrBinHashKey<KEY_SIZE>& key) const {
+    int compare(const GrTBinHashKey<ENTRY, KEY_SIZE>& key) const {
         SkASSERT(fIsValid && key.fIsValid);
-        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;
+        return memcmp(fData, key.fData, KEY_SIZE);
     }
 
-    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;
+    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;
     }
 
     uint32_t getHash() const {
@@ -86,12 +94,12 @@
 
     const uint8_t* getData() const {
         SkASSERT(fIsValid);
-        return reinterpret_cast<const uint8_t*>(fData);
+        return fData;
     }
 
 private:
     uint32_t            fHash;
-    uint32_t            fData[KEY_SIZE / sizeof(uint32_t)];  // Buffer for key storage.
+    uint8_t             fData[KEY_SIZE];  // Buffer for key storage
 
 #ifdef SK_DEBUG
 public:
diff --git a/gpu/GrResourceCache.h b/gpu/GrResourceCache.h
index ca30732..38378ac 100644
--- a/gpu/GrResourceCache.h
+++ b/gpu/GrResourceCache.h
@@ -54,7 +54,7 @@
     }
 
     GrResourceKey() {
-        fKey.reset();
+        fKey.fHashedKey.reset();
     }
 
     void reset(const GrCacheID& id, ResourceType type, ResourceFlags flags) {
@@ -63,34 +63,41 @@
 
     //!< returns hash value [0..kHashMask] for the key
     int getHash() const {
-        return fKey.getHash() & kHashMask;
+        return fKey.fHashedKey.getHash() & kHashMask;
     }
 
     bool isScratch() const {
         return ScratchDomain() ==
-            *reinterpret_cast<const GrCacheID::Domain*>(fKey.getData() +
+            *reinterpret_cast<const GrCacheID::Domain*>(fKey.fHashedKey.getData() +
                                                         kCacheIDDomainOffset);
     }
 
     ResourceType getResourceType() const {
-        return *reinterpret_cast<const ResourceType*>(fKey.getData() +
+        return *reinterpret_cast<const ResourceType*>(fKey.fHashedKey.getData() +
                                                       kResourceTypeOffset);
     }
 
     ResourceFlags getResourceFlags() const {
-        return *reinterpret_cast<const ResourceFlags*>(fKey.getData() +
+        return *reinterpret_cast<const ResourceFlags*>(fKey.fHashedKey.getData() +
                                                        kResourceFlagsOffset);
     }
 
-    bool operator==(const GrResourceKey& other) const { return fKey == other.fKey; }
-    bool operator<(const GrResourceKey& other) const { return fKey < other.fKey; }
+    int compare(const GrResourceKey& other) const {
+        return fKey.fHashedKey.compare(other.fKey.fHashedKey);
+    }
 
-    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
+    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);
 
 private:
     enum {
@@ -118,9 +125,21 @@
         memcpy(k + kResourceTypeOffset, &type, sizeof(ResourceType));
         memcpy(k + kResourceFlagsOffset, &flags, sizeof(ResourceFlags));
         memset(k + kPadOffset, 0, kPadSize);
-        fKey.setKeyData(keyData.fKey32);
+        fKey.fHashedKey.setKeyData(keyData.fKey32);
     }
-    GrBinHashKey<kKeySize> fKey;
+
+    struct Key;
+    typedef GrTBinHashKey<Key, kKeySize> HashedKey;
+
+    struct Key {
+        int compare(const HashedKey& hashedKey) const {
+            return fHashedKey.compare(hashedKey);
+        }
+
+        HashedKey fHashedKey;
+    };
+
+    Key fKey;
 };
 
 // The cache listens for these messages to purge junk resources proactively.
@@ -155,23 +174,21 @@
     friend class GrDLinkedList;
 };
 
-inline bool GrResourceKey::LessThan(const GrResourceEntry& entry, const GrResourceKey& key) {
-    return entry.key() < key;
+bool GrResourceKey::LT(const GrResourceEntry& entry, const GrResourceKey& key) {
+    return LT(entry.key(), key);
 }
 
-inline bool GrResourceKey::Equals(const GrResourceEntry& entry, const GrResourceKey& key) {
-    return entry.key() == key;
+bool GrResourceKey::EQ(const GrResourceEntry& entry, const GrResourceKey& key) {
+    return EQ(entry.key(), key);
 }
 
-#ifdef SK_DEBUG
-inline bool GrResourceKey::LessThan(const GrResourceEntry& a, const GrResourceEntry& b) {
-    return a.key() < b.key();
+bool GrResourceKey::LT(const GrResourceEntry& a, const GrResourceEntry& b) {
+    return LT(a.key(), b.key());
 }
 
-inline bool GrResourceKey::Equals(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());
 }
-#endif
 
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gpu/GrTHashTable.h b/gpu/GrTHashTable.h
index 83462c7..3b32977 100644
--- a/gpu/GrTHashTable.h
+++ b/gpu/GrTHashTable.h
@@ -16,10 +16,8 @@
 
 /**
  *  Key needs
- *      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
+ *      static bool EQ(const Entry&, const HashKey&);
+ *      static bool LT(const Entry&, const HashKey&);
  *      uint32_t getHash() const;
  *
  *  Allows duplicate key entries but on find you may get
@@ -92,7 +90,7 @@
     int low = 0;
     while (high > low) {
         int index = (low + high) >> 1;
-        if (Key::LessThan(*array[index], key)) {
+        if (Key::LT(*array[index], key)) {
             low = index + 1;
         } else {
             high = index;
@@ -100,15 +98,15 @@
     }
 
     // check if we found it
-    if (Key::Equals(*array[high], key)) {
+    if (Key::EQ(*array[high], key)) {
         // above search should have found the first occurrence if there
         // are multiple.
-        SkASSERT(0 == high || Key::LessThan(*array[high - 1], key));
+        SkASSERT(0 == high || Key::LT(*array[high - 1], key));
         return high;
     }
 
     // now return the ~ of where we should insert it
-    if (Key::LessThan(*array[high], key)) {
+    if (Key::LT(*array[high], key)) {
         high += 1;
     }
     return ~high;
@@ -121,7 +119,7 @@
     int hashIndex = hash2Index(key.getHash());
     T* elem = fHash[hashIndex];
 
-    if (NULL != elem && Key::Equals(*elem, key) && filter(elem)) {
+    if (NULL != elem && Key::EQ(*elem, key) && filter(elem)) {
         return elem;
     }
 
@@ -135,9 +133,9 @@
 
     // above search should have found the first occurrence if there
     // are multiple.
-    SkASSERT(0 == index || Key::LessThan(*array[index - 1], key));
+    SkASSERT(0 == index || Key::LT(*array[index - 1], key));
 
-    for ( ; index < count() && Key::Equals(*array[index], key); ++index) {
+    for ( ; index < count() && Key::EQ(*array[index], key); ++index) {
         if (filter(fSorted[index])) {
             // update the hash
             fHash[hashIndex] = fSorted[index];
@@ -194,8 +192,8 @@
 void GrTHashTable<T, Key, kHashBits>::validate() const {
     int count = fSorted.count();
     for (int i = 1; i < count; i++) {
-        SkASSERT(Key::LessThan(*fSorted[i - 1], *fSorted[i]) ||
-                 Key::Equals(*fSorted[i - 1], *fSorted[i]));
+        SkASSERT(Key::LT(*fSorted[i - 1], *fSorted[i]) ||
+                 Key::EQ(*fSorted[i - 1], *fSorted[i]));
     }
 }
 
diff --git a/gpu/GrTextStrike_impl.h b/gpu/GrTextStrike_impl.h
index 0691eaa..4297185 100644
--- a/gpu/GrTextStrike_impl.h
+++ b/gpu/GrTextStrike_impl.h
@@ -19,10 +19,10 @@
 
     intptr_t getHash() const { return fFontScalerKey->getHash(); }
 
-    static bool LessThan(const GrTextStrike& strike, const Key& key) {
+    static bool LT(const GrTextStrike& strike, const Key& key) {
         return *strike.getFontScalerKey() < *key.fFontScalerKey;
     }
-    static bool Equals(const GrTextStrike& strike, const Key& key) {
+    static bool EQ(const GrTextStrike& strike, const Key& key) {
         return *strike.getFontScalerKey() == *key.fFontScalerKey;
     }
 
@@ -88,10 +88,10 @@
 
     uint32_t getHash() const { return fPackedID; }
 
-    static bool LessThan(const GrGlyph& glyph, const Key& key) {
+    static bool LT(const GrGlyph& glyph, const Key& key) {
         return glyph.fPackedID < key.fPackedID;
     }
-    static bool Equals(const GrGlyph& glyph, const Key& key) {
+    static bool EQ(const GrGlyph& glyph, const Key& key) {
         return glyph.fPackedID == key.fPackedID;
     }
 
diff --git a/gpu/SkGrFontScaler.cpp b/gpu/SkGrFontScaler.cpp
index 1ca9357..6514866 100644
--- a/gpu/SkGrFontScaler.cpp
+++ b/gpu/SkGrFontScaler.cpp
@@ -85,8 +85,6 @@
             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/gpu/effects/GrTextureStripAtlas.h b/gpu/effects/GrTextureStripAtlas.h
index e06e273..e56e736 100644
--- a/gpu/effects/GrTextureStripAtlas.h
+++ b/gpu/effects/GrTextureStripAtlas.h
@@ -136,15 +136,12 @@
 
     // Hash table entry for atlases
     class AtlasEntry;
-    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);
-    };
+    typedef GrTBinHashKey<AtlasEntry, sizeof(GrTextureStripAtlas::Desc)> AtlasHashKey;
     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;
     };
@@ -181,14 +178,4 @@
     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/gpu/gl/GrGpuGL.cpp b/gpu/gl/GrGpuGL.cpp
index 00d27b3..9cf39b6 100644
--- a/gpu/gl/GrGpuGL.cpp
+++ b/gpu/gl/GrGpuGL.cpp
@@ -1276,7 +1276,6 @@
             return;
         }
     }
-
     this->flushRenderTarget(rect);
     GrAutoTRestore<ScissorState> asr(&fScissorState);
     fScissorState.fEnabled = (NULL != rect);
@@ -1523,16 +1522,10 @@
     if (fHWBoundRenderTarget != rt) {
         GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, rt->renderFBOID()));
 #ifdef SK_DEBUG
-        // 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);
-            }
+        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/gpu/gr_unittests.cpp b/gpu/gr_unittests.cpp
new file mode 100644
index 0000000..ae9f67f
--- /dev/null
+++ b/gpu/gr_unittests.cpp
@@ -0,0 +1,80 @@
+
+/*
+ * 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/opts/SkBlitMask_opts_arm.cpp b/opts/SkBlitMask_opts_arm.cpp
index 2bf7603..0ad0919 100644
--- a/opts/SkBlitMask_opts_arm.cpp
+++ b/opts/SkBlitMask_opts_arm.cpp
@@ -1,39 +1,14 @@
 
-#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) {
-    if (isOpaque) {
-        return SK_ARM_NEON_WRAP(SkBlitLCD16OpaqueRow);
-    } else {
-        return SK_ARM_NEON_WRAP(SkBlitLCD16Row);
-    }
+    return NULL;
 }
 
 SkBlitMask::RowProc SkBlitMask::PlatformRowProcs(SkBitmap::Config dstConfig,
diff --git a/opts/SkColor_opts_neon.h b/opts/SkColor_opts_neon.h
index 85752f5..f812397 100644
--- a/opts/SkColor_opts_neon.h
+++ b/opts/SkColor_opts_neon.h
@@ -2,7 +2,6 @@
 #define SkColor_opts_neon_DEFINED
 
 #include "SkTypes.h"
-#include "SkColorPriv.h"
 
 #include <arm_neon.h>
 
@@ -66,20 +65,4 @@
     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/pdf/SkPDFImage.cpp b/pdf/SkPDFImage.cpp
index 81adcc2..a99c9fe 100644
--- a/pdf/SkPDFImage.cpp
+++ b/pdf/SkPDFImage.cpp
@@ -36,6 +36,7 @@
             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:
@@ -165,6 +166,48 @@
     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,
@@ -240,6 +283,14 @@
             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();
@@ -523,7 +574,8 @@
     insertName("Type", "XObject");
     insertName("Subtype", "Image");
 
-    bool alphaOnly = (config == SkBitmap::kA8_Config);
+    bool alphaOnly = (config == SkBitmap::kA1_Config ||
+                      config == SkBitmap::kA8_Config);
 
     if (!isAlpha && alphaOnly) {
         // For alpha only images, we stretch a single pixel of black for
@@ -549,6 +601,8 @@
     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/utils/debugger/SkObjectParser.cpp b/utils/debugger/SkObjectParser.cpp
index ebbd400..54ae077 100644
--- a/utils/debugger/SkObjectParser.cpp
+++ b/utils/debugger/SkObjectParser.cpp
@@ -26,9 +26,9 @@
     mBitmap->appendS32(bitmap.height());
 
     const char* gConfigStrings[] = {
-        "None", "A8", "Index8", "RGB565", "ARGB4444", "ARGB8888"
+        "None", "A1", "A8", "Index8", "RGB565", "ARGB4444", "ARGB8888"
     };
-    SkASSERT(SkBitmap::kConfigCount == SK_ARRAY_COUNT(gConfigStrings));
+    SkASSERT(SkBitmap::kConfigCount == 7);
 
     mBitmap->append(" Config: ");
     mBitmap->append(gConfigStrings[bitmap.config()]);