Reverting r12427

git-svn-id: http://skia.googlecode.com/svn/trunk@12428 2bbb7eff-a529-9590-31e7-b0007b416f81
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) {