Add Truetype and Type 1 font embedding support

Sorry this is such a large CL.  It was very exploratory for me to make this
work.

- Add an interface to SkFontHost to retrieve font information and provide NULL implementations on all platforms except Linux.
- Segment large Type 1 fonts into fonts with shared resources with 255 glyphs each.
- Convert the various Type 1 formats to the form PDF wants.
- Update font as we draw text instead of as part of the graphical state.
- Remove built-in font support, we can't really use it.

Other changes I can pull out to a separate CL if you like.

- Add SkTScopedPtr class.
- Fix double free of resources.
- Fix bug in resource unique-ifying code.
- Don't print anything for any empty clip path.
- Fix copy paste error - MiterLimit.
- Fix sign extension bug in SkPDFString
- Fix FlateTest rename that was missed on a previous commit.

Review URL: http://codereview.appspot.com/4082042

git-svn-id: http://skia.googlecode.com/svn/trunk@728 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h
index ca538d1..4363ecd 100644
--- a/include/core/SkFontHost.h
+++ b/include/core/SkFontHost.h
@@ -176,6 +176,11 @@
 
     ///////////////////////////////////////////////////////////////////////////
 
+    /** Retrieve information about the typeface needed for inclusion in a
+        PDF output device. Returns NULL if it is unable to find the font.
+     */
+    static SkPDFTypefaceInfo* GetPDFTypefaceInfo(SkFontID);
+
     /** Return the number of tables in the font
      */
     static int CountTables(SkFontID);
diff --git a/include/core/SkTScopedPtr.h b/include/core/SkTScopedPtr.h
new file mode 100644
index 0000000..1e5d4c4
--- /dev/null
+++ b/include/core/SkTScopedPtr.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SkTScopedPtr_DEFINED
+#define SkTScopedPtr_DEFINED
+
+#include "SkTypes.h"
+
+/** \class SkTScopedPtr
+  A SkTScopedPtr<T> is like a T*, except that the destructor of SkTScopedPtr<T>
+  automatically deletes the pointer it holds (if any).  That is, SkTScopedPtr<T>
+  owns the T object that it points to.  Like a T*, a SkTScopedPtr<T> may hold
+  either NULL or a pointer to a T object.  Also like T*, SkTScopedPtr<T> is
+  thread-compatible, and once you dereference it, you get the threadsafety
+  guarantees of T.
+
+  The size of a SkTScopedPtr is small: sizeof(SkTScopedPtr<T>) == sizeof(T*)
+*/
+template <typename T> class SkTScopedPtr : SkNoncopyable {
+public:
+    explicit SkTScopedPtr(T* o = NULL) : fObj(o) {}
+    ~SkTScopedPtr() {
+        enum { kTypeMustBeComplete = sizeof(T) };
+        delete fObj;
+    }
+
+    /** Delete the current object, if any.  Then take ownership of the
+        passed object.
+     */
+    void reset(T* o = NULL) {
+        if (o != fObj) {
+            enum { kTypeMustBeComplete = sizeof(T) };
+            delete fObj;
+            fObj = o;
+        }
+    }
+
+    /** Without deleting the current object, return it and forget about it.
+        Similar to calling get() and reset(), but the object is not deleted.
+     */
+    T* release() {
+        T* retVal = fObj;
+        fObj = NULL;
+        return retVal;
+    }
+
+    T& operator*() const {
+        SkASSERT(fObj != NULL);
+        return *fObj;
+    }
+    T* operator->() const  {
+        SkASSERT(fObj != NULL);
+        return fObj;
+    }
+    T* get() const { return fObj; }
+
+    bool operator==(T* o) const { return fObj == o; }
+    bool operator!=(T* o) const { return fObj != o; }
+
+private:
+    T* fObj;
+
+    // Forbid comparison of SkTScopedPtr types.  If T2 != T, it doesn't make
+    // sense, and if T2 == T, it still doesn't make sense because the same
+    // object can't be owned by two different scoped_ptrs.
+    template <class T2> bool operator==(SkTScopedPtr<T2> const& o2) const;
+    template <class T2> bool operator!=(SkTScopedPtr<T2> const& o2) const;
+};
+
+#endif
diff --git a/include/core/SkTemplates.h b/include/core/SkTemplates.h
index 27ebd41..eaa812f 100644
--- a/include/core/SkTemplates.h
+++ b/include/core/SkTemplates.h
@@ -59,6 +59,7 @@
     T* fObj;
 };
 
+// See also SkTScopedPtr.
 template <typename T> class SkAutoTDelete : SkNoncopyable {
 public:
     SkAutoTDelete(T* obj) : fObj(obj) {}
diff --git a/include/core/SkTypeface.h b/include/core/SkTypeface.h
index d4af700..b7ccf51 100644
--- a/include/core/SkTypeface.h
+++ b/include/core/SkTypeface.h
@@ -20,6 +20,7 @@
 #include "SkRefCnt.h"
 
 class SkStream;
+class SkPDFTypefaceInfo;
 class SkWStream;
 
 /** \class SkTypeface
@@ -130,6 +131,11 @@
      */
     static SkTypeface* Deserialize(SkStream*);
 
+    /** Retrieve information about the typeface needed for inclusion in a
+        PDF output device.
+     */
+    SkPDFTypefaceInfo* getPDFTypefaceInfo() const;
+
 protected:
     /** uniqueID must be unique (please!) and non-zero
     */
diff --git a/include/pdf/SkPDFDevice.h b/include/pdf/SkPDFDevice.h
index 3ef234a..64e0407 100644
--- a/include/pdf/SkPDFDevice.h
+++ b/include/pdf/SkPDFDevice.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -143,13 +143,14 @@
     // one entry: a transform
     // one entry: a clip
     // two entries: a clip and then a transform
+    // Pointers are owned by the respective Resources list.
     struct GraphicStackEntry {
         SkColor fColor;
         SkScalar fTextSize;
         SkScalar fTextScaleX;
         SkPaint::Style fTextFill;
-        SkRefPtr<SkPDFFont> fFont;
-        SkRefPtr<SkPDFGraphicState> fGraphicState;
+        SkPDFFont* fFont;
+        SkPDFGraphicState* fGraphicState;
         SkRegion fClip;
         SkMatrix fTransform;
     };
@@ -159,7 +160,8 @@
     SkString fContent;
 
     void updateGSFromPaint(const SkPaint& newPaint, bool forText);
-    int getFontResourceIndex(uint32_t fontID);
+    void updateFont(const SkPaint& paint, uint16_t glyphID);
+    int getFontResourceIndex(uint32_t fontID, uint16_t glyphID);
 
     void moveTo(SkScalar x, SkScalar y);
     void appendLine(SkScalar x, SkScalar y);
diff --git a/include/pdf/SkPDFFont.h b/include/pdf/SkPDFFont.h
index 82357ef..d020163 100644
--- a/include/pdf/SkPDFFont.h
+++ b/include/pdf/SkPDFFont.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
 #include "SkThread.h"
 
 class SkPaint;
+class SkPDFTypefaceInfo;
 
 /** \class SkPDFFont
     A PDF Object class representing a font.  The font may have resources
@@ -40,53 +41,95 @@
      */
     uint32_t fontID();
 
-    /** Returns true if this font supports glyph IDs above 255.
+    /** Return true if this font has an encoding for the passed glyph id.
+     */
+    bool hasGlyph(uint16_t glyphID);
+
+    /** Returns true if this font encoding supports glyph IDs above 255.
      */
     bool multiByteGlyphs();
 
-    /** Covert the specified text to glyph IDs, taking into consideration
-     *  PDF encodings and return the number of glyphs IDs written.
+    /** Convert the input glyph IDs into the font encoding.  If the font has
+     *  more glyphs than can be encoded (like a type 1 font with more than
+     *  255 glyphs) this method only converts up to the first out of range
+     *  glyph ID.
+     *  @param glyphIDs       The input text as glyph IDs.
+     *  @param numGlyphs      The number of input glyphs.
+     *  @param encodedValues  The method writes its result to this parameter.
+     *                        multiByteGlyphs() reveals the output format.
+     *  @param encodedLength  The size of encodedValues (in bytes), which is
+     *                        overwritten with how much of encodedValues is
+     *                        used.
+     *  @return               Returns the number of glyphs consumed.
      */
-    int textToPDFGlyphs(const void* text, size_t byteLength,
-                        const SkPaint& paint, uint16_t* glyphs,
-                        size_t glyphsLength) const;
+    size_t glyphsToPDFFontEncoding(const uint16_t* glyphIDs, size_t numGlyphs,
+                                   void* encodedValues, size_t* encodedLength);
 
-    /** Get the font resource for the passed font ID. The reference count of
-     *  the object is incremented and it is the caller's responsibility to
-     *  unreference it when done.  This is needed to accommodate the weak
-     *  reference pattern used when the returned object is new and has no
-     *  other references.
-     *  @param paint  The SkPaint to emulate.
+    /** Get the font resource for the passed font ID and glyphID. The
+     *  reference count of the object is incremented and it is the caller's
+     *  responsibility to unreference it when done.  This is needed to
+     *  accommodate the weak reference pattern used when the returned object
+     *  is new and has no other references.
+     *  @param fontID  The fontId to find.
+     *  @param glyphID Specify which section of a large font is of interest.
      */
-    static SkPDFFont* getFontResouceByID(uint32_t fontID);
+    static SkPDFFont* getFontResource(uint32_t fontID, uint16_t glyphID);
 
 private:
     uint32_t fFontID;
+#ifdef SK_DEBUG
+    bool fDescendant;
+#endif
     bool fMultiByteGlyphs;
 
+    // The glyph IDs accessible with this font.  For Type1 (non CID) fonts,
+    // this will be a subset if the font has more than 255 glyphs.
+    uint16_t fFirstGlyphID;
+    uint16_t fLastGlyphID;
+    // The font info is only kept around after construction for large
+    // Type1 (non CID) fonts that need multiple "fonts" to access all glyphs.
+    SkRefPtr<SkPDFTypefaceInfo> fFontInfo;
     SkTDArray<SkPDFObject*> fResources;
+    SkRefPtr<SkPDFDict> fDescriptor;
 
     class FontRec {
     public:
         SkPDFFont* fFont;
         uint32_t fFontID;
+        uint16_t fGlyphID;
 
+        // A fGlyphID of 0 with no fFont always matches.
         bool operator==(const FontRec& b) const;
-        FontRec(SkPDFFont* font, uint32_t fontID);
+        FontRec(SkPDFFont* font, uint32_t fontID, uint16_t fGlyphID);
     };
 
     // This should be made a hash table if performance is a problem.
     static SkTDArray<FontRec>& canonicalFonts();
     static SkMutex& canonicalFontsMutex();
 
-    SkPDFFont(uint32_t fontID, bool multiByteGlyphs);
+    /** Construct a new font dictionary and support objects.
+     *  @param fontInfo       Information about the to create.
+     *  @param fontID         The font ID of the font.
+     *  @param glyphID        The glyph ID the caller is interested in. This
+     *                        is important only for Type1 fonts, which have
+     *                        more than 255 glyphs.
+     *  @param descendantFont If this is the descendant (true) or root
+     *                        (Type 0 font - false) font dictionary.  Only True
+     *                        Type and CID encoded fonts will use a true value.
+     *  @param fontDescriptor If the font descriptor has already have generated
+     *                        for this font, pass it in here, otherwise pass
+     *                        NULL.
+     */
+    SkPDFFont(class SkPDFTypefaceInfo* fontInfo, uint32_t fontID,
+              uint16_t glyphID, bool descendantFont, SkPDFDict* fontDescriptor);
 
-    void populateBuiltinFont(const char fontName[]);
-    void populateFont(const char subType[], const char fontName[],
-                      int firstChar, int lastChar, int widths[],
-                      SkPDFObject* fontDescriptor);
+    void populateType0Font();
+    void populateCIDFont();
+    bool populateType1Font(uint16_t firstGlyphID, uint16_t lastGlyphID);
+    void populateType3Font();
+    bool addFontDescriptor(int defaultWidth);
 
-    static int find(uint32_t fontID);
+    static bool find(uint32_t fontID, uint16_t glyphID, int* index);
 };
 
 #endif
diff --git a/include/pdf/SkPDFTypefaceInfo.h b/include/pdf/SkPDFTypefaceInfo.h
new file mode 100644
index 0000000..2655d14
--- /dev/null
+++ b/include/pdf/SkPDFTypefaceInfo.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SkPDFTypefaceInfo_DEFINED
+#define SkPDFTypefaceInfo_DEFINED
+
+#include "SkRect.h"
+#include "SkRefCnt.h"
+#include "SkString.h"
+#include "SkTDArray.h"
+#include "SkTemplates.h"
+#include "SkTScopedPtr.h"
+
+/** \class SkPDFTypefaceInfo
+
+    The SkPDFTypefaceInfo is used by the PDF backend to correctly embed
+    typefaces.  This class is filled in with information about a given typeface
+    by the SkFontHost class.
+*/
+
+class SkPDFTypefaceInfo : public SkRefCnt {
+public:
+    enum FontType {
+        kType1_Font,
+        kType1CID_Font,
+        kCFF_Font,
+        kTrueType_Font,
+        kOther_Font,
+        kNotEmbeddable_Font,
+    };
+    // The type of the underlying font program.  This field determines which
+    // of the following fields are valid.  If it is kOther_Font or
+    // kNotEmbeddable_Font, fFontName may be valid, but no other fields are
+    // valid.
+    FontType fType;
+
+    // fMultiMaster may be true for Type1_Font or CFF_Font.
+    bool fMultiMaster;
+    SkString fFontName;
+    SkIRect fBBox;  // The bounding box of all glyphs (in font units).
+
+    uint16_t fLastGlyphID;
+
+    template <typename Data>
+    struct AdvanceMetric {
+        enum MetricType {
+            kDefault,  // Default advance: fAdvance.count = 1
+            kRange,    // Advances for a range: fAdvance.count = fEndID-fStartID
+            kRun,      // fStartID-fEndID have same advance: fAdvance.count = 1
+        };
+        MetricType fType;
+        int fStartId;
+        int fEndId;
+        SkTDArray<Data> fAdvance;
+        SkTScopedPtr<AdvanceMetric<Data> > fNext;
+    };
+
+    struct VerticalMetric {
+        int fVerticalAdvance;
+        int fOriginXDisp;  // Horizontal displacement of the secondary origin.
+        int fOriginYDisp;  // Vertical displacement of the secondary origin.
+    };
+    typedef struct VerticalMetric VerticalMetric;
+    typedef AdvanceMetric<int> WidthRange;
+    typedef AdvanceMetric<VerticalMetric> VerticalAdvanceRange;
+
+    // This is indexed by glyph id.
+    SkTScopedPtr<WidthRange> fGlyphWidths;
+    // Only used for Vertical CID fonts.
+    SkTScopedPtr<VerticalAdvanceRange> fVerticalMetrics;
+
+    // The names of each glyph, only populated for postscript fonts.
+    SkTScopedPtr<SkAutoTArray<SkString> > fGlyphNames;
+
+    // Metrics: probably used by the pdf renderer for substitution, which
+    // shouldn't be needed with embedding fonts.  Optional fields with a value
+    // of 0 will be ignored.
+
+    // The enum values match the values used in the PDF file format.
+    enum StyleFlags {
+        kFixedPitch_Style  = 0x00001,
+        kSerif_Style       = 0x00002,
+        kSymbolic_Style    = 0x00004,
+        kScript_Style      = 0x00008,
+        kNonsymbolic_Style = 0x00020,
+        kItalic_Style      = 0x00040,
+        kAllCaps_Style     = 0x10000,
+        kSmallCaps_Style   = 0x20000,
+        kForceBold_Style   = 0x40000,
+    };
+    uint16_t fStyle;        // Font style characteristics.
+    long fItalicAngle;      // Counterclockwise degrees from vertical of the
+                            // dominant vertical stroke for an Italic face.
+    SkScalar fAscent;       // Max height above baseline, not including accents.
+    SkScalar fDescent;      // Max depth below baseline (negative).
+    SkScalar fStemV;        // Thickness of dominant vertical stem.
+    SkScalar fCapHeight;    // Height (from baseline) of top of flat capitals.
+
+    /* Omit the optional entries. Better to let the viewer compute them, since
+     * it has to be able to anyway.
+    SkScalar fLeading;      // Space between lines. Optional.
+    SkScalar fXHeight;      // Height of top of 'x'. Optional.
+    SkScalar fStemH;        // Thickness of dominant horizontal stem. Optional.
+    SkScalar fAvgWidth;     // Average width of glyphs. Optional.
+    SkScalar fMaxWidth;     // Max width of a glyph. Optional.
+    */
+};
+
+#endif
diff --git a/src/core/SkTypeface.cpp b/src/core/SkTypeface.cpp
index 257df27..6306098 100644
--- a/src/core/SkTypeface.cpp
+++ b/src/core/SkTypeface.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #include "SkTypeface.h"
 #include "SkFontHost.h"
 
@@ -59,4 +75,6 @@
     return SkFontHost::Deserialize(stream);
 }
 
-
+SkPDFTypefaceInfo* SkTypeface::getPDFTypefaceInfo() const {
+    return SkFontHost::GetPDFTypefaceInfo(fUniqueID);
+}
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index fec9a4f..fd458e0 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -139,6 +139,8 @@
     fGraphicStack[0].fTextSize = SK_ScalarNaN;  // This has no default value.
     fGraphicStack[0].fTextScaleX = SK_Scalar1;
     fGraphicStack[0].fTextFill = SkPaint::kFill_Style;
+    fGraphicStack[0].fFont = NULL;
+    fGraphicStack[0].fGraphicState = NULL;
     fGraphicStack[0].fClip.setRect(0,0, width, height);
     fGraphicStack[0].fTransform.reset();
 }
@@ -158,17 +160,19 @@
         pushGS();
 
         SkPath clipPath;
-        if (!region.getBoundaryPath(&clipPath))
-            clipPath.moveTo(SkIntToScalar(-1), SkIntToScalar(-1));
-        emitPath(clipPath);
+        if (region.getBoundaryPath(&clipPath)) {
+            emitPath(clipPath);
 
-        SkPath::FillType clipFill = clipPath.getFillType();
-        NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false);
-        NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false);
-        if (clipFill == SkPath::kEvenOdd_FillType)
-            fContent.append("W* n ");
-        else
-            fContent.append("W n ");
+            SkPath::FillType clipFill = clipPath.getFillType();
+            NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType,
+                            false);
+            NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType,
+                            false);
+            if (clipFill == SkPath::kEvenOdd_FillType)
+                fContent.append("W* n ");
+            else
+                fContent.append("W n ");
+        }
 
         fGraphicStack[fGraphicStackIndex].fClip = region;
     }
@@ -298,12 +302,25 @@
                            SkScalar x, SkScalar y, const SkPaint& paint) {
     SkPaint textPaint = calculateTextPaint(paint);
     updateGSFromPaint(textPaint, true);
-    SkPDFFont* font = fGraphicStack[fGraphicStackIndex].fFont.get();
 
-    uint16_t glyphs[len];
-    size_t glyphsLength;
-    glyphsLength = font->textToPDFGlyphs(text, len, textPaint, glyphs, len);
-    textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    // Make sure we have a glyph id encoding.
+    SkAutoFree glyphStorage;
+    uint16_t* glyphIDs;
+    size_t numGlyphs;
+    if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
+        numGlyphs = paint.textToGlyphs(text, len, NULL);
+        glyphIDs = (uint16_t*)sk_malloc_flags(numGlyphs * 2,
+                                              SK_MALLOC_TEMP | SK_MALLOC_THROW);
+        glyphStorage.set(glyphIDs);
+        paint.textToGlyphs(text, len, glyphIDs);
+        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    } else {
+        SkASSERT((len & 1) == 0);
+        numGlyphs = len / 2;
+        glyphIDs = (uint16_t*)text;
+    }
+    SkAutoFree encodedStorage(
+            sk_malloc_flags(numGlyphs * 2, SK_MALLOC_TEMP | SK_MALLOC_THROW));
 
     SkScalar width;
     SkScalar* widthPtr = NULL;
@@ -311,13 +328,26 @@
         widthPtr = &width;
 
     SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
-    alignText(glyphCacheProc, textPaint, glyphs, glyphsLength, &x, &y,
-              widthPtr);
+    alignText(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y, widthPtr);
     fContent.append("BT\n");
     setTextTransform(x, y, textPaint.getTextSkewX());
-    fContent.append(SkPDFString::formatString(glyphs, glyphsLength,
-                                              font->multiByteGlyphs()));
-    fContent.append(" Tj\nET\n");
+    size_t consumedGlyphCount = 0;
+    while (numGlyphs > consumedGlyphCount) {
+        updateFont(textPaint, glyphIDs[consumedGlyphCount]);
+        SkPDFFont* font = fGraphicStack[fGraphicStackIndex].fFont;
+        size_t encodedLength = numGlyphs * 2;
+        consumedGlyphCount += font->glyphsToPDFFontEncoding(
+                glyphIDs + consumedGlyphCount, numGlyphs - consumedGlyphCount,
+                encodedStorage.get(), &encodedLength);
+        if (font->multiByteGlyphs())
+            encodedLength /= 2;
+        fContent.append(
+                SkPDFString::formatString((const uint16_t*)encodedStorage.get(),
+                                          encodedLength,
+                                          font->multiByteGlyphs()));
+        fContent.append(" Tj\n");
+    }
+    fContent.append("ET\n");
 
     // Draw underline and/or strikethrough if the paint has them.
     // drawPosText() and drawTextOnPath() don't draw underline or strikethrough
@@ -346,21 +376,42 @@
     SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos);
     SkPaint textPaint = calculateTextPaint(paint);
     updateGSFromPaint(textPaint, true);
-    SkPDFFont* font = fGraphicStack[fGraphicStackIndex].fFont.get();
 
-    uint16_t glyphs[len];
-    size_t glyphsLength;
-    glyphsLength = font->textToPDFGlyphs(text, len, textPaint, glyphs, len);
-    textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    // Make sure we have a glyph id encoding.
+    SkAutoFree glyphStorage;
+    uint16_t* glyphIDs;
+    size_t numGlyphs;
+    if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
+        numGlyphs = paint.textToGlyphs(text, len, NULL);
+        glyphIDs = (uint16_t*)sk_malloc_flags(numGlyphs * 2,
+                                              SK_MALLOC_TEMP | SK_MALLOC_THROW);
+        glyphStorage.set(glyphIDs);
+        paint.textToGlyphs(text, len, glyphIDs);
+        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    } else {
+        SkASSERT((len & 1) == 0);
+        numGlyphs = len / 2;
+        glyphIDs = (uint16_t*)text;
+    }
 
     SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
     fContent.append("BT\n");
-    for (size_t i = 0; i < glyphsLength; i++) {
+    updateFont(textPaint, glyphIDs[0]);
+    for (size_t i = 0; i < numGlyphs; i++) {
+        SkPDFFont* font = fGraphicStack[fGraphicStackIndex].fFont;
+        uint16_t encodedValue;
+        size_t encodedLength = 2;
+        if (font->glyphsToPDFFontEncoding(glyphIDs + i, 1, &encodedValue,
+                                          &encodedLength) == 0) {
+            updateFont(textPaint, glyphIDs[i]);
+            i--;
+            continue;
+        }
         SkScalar x = pos[i * scalarsPerPos];
         SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1];
-        alignText(glyphCacheProc, textPaint, glyphs + i, 1, &x, &y, NULL);
+        alignText(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y, NULL);
         setTextTransform(x, y, textPaint.getTextSkewX());
-        fContent.append(SkPDFString::formatString(glyphs + i, 1,
+        fContent.append(SkPDFString::formatString(&encodedValue, 1,
                                                   font->multiByteGlyphs()));
         fContent.append(" Tj\n");
     }
@@ -539,7 +590,7 @@
     newGraphicState->unref();  // getGraphicState and SkRefPtr both took a ref.
     // newGraphicState has been canonicalized so we can directly compare
     // pointers.
-    if (fGraphicStack[fGraphicStackIndex].fGraphicState.get() !=
+    if (fGraphicStack[fGraphicStackIndex].fGraphicState !=
             newGraphicState.get()) {
         int resourceIndex = fGraphicStateResources.find(newGraphicState.get());
         if (resourceIndex < 0) {
@@ -550,7 +601,7 @@
         fContent.append("/G");
         fContent.appendS32(resourceIndex);
         fContent.append(" gs\n");
-        fGraphicStack[fGraphicStackIndex].fGraphicState = newGraphicState;
+        fGraphicStack[fGraphicStackIndex].fGraphicState = newGraphicState.get();
     }
 
     SkColor newColor = newPaint.getColor();
@@ -565,22 +616,6 @@
     }
 
     if (forText) {
-        uint32_t fontID = SkTypeface::UniqueID(newPaint.getTypeface());
-        if (fGraphicStack[fGraphicStackIndex].fTextSize !=
-                newPaint.getTextSize() ||
-                fGraphicStack[fGraphicStackIndex].fFont.get() == NULL ||
-                fGraphicStack[fGraphicStackIndex].fFont->fontID() != fontID) {
-            int fontIndex = getFontResourceIndex(fontID);
-            fContent.append("/F");
-            fContent.appendS32(fontIndex);
-            fContent.append(" ");
-            fContent.appendScalar(newPaint.getTextSize());
-            fContent.append(" Tf\n");
-            fGraphicStack[fGraphicStackIndex].fTextSize =
-                newPaint.getTextSize();
-            fGraphicStack[fGraphicStackIndex].fFont = fFontResources[fontIndex];
-        }
-
         if (fGraphicStack[fGraphicStackIndex].fTextScaleX !=
                 newPaint.getTextScaleX()) {
             SkScalar scale = newPaint.getTextScaleX();
@@ -604,9 +639,27 @@
     }
 }
 
-int SkPDFDevice::getFontResourceIndex(uint32_t fontID) {
-    SkRefPtr<SkPDFFont> newFont = SkPDFFont::getFontResouceByID(fontID);
-    newFont->unref();  // getFontResourceByID and SkRefPtr both took a ref.
+void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID) {
+    uint32_t fontID = SkTypeface::UniqueID(paint.getTypeface());
+    if (fGraphicStack[fGraphicStackIndex].fTextSize != paint.getTextSize() ||
+            fGraphicStack[fGraphicStackIndex].fFont == NULL ||
+            fGraphicStack[fGraphicStackIndex].fFont->fontID() != fontID ||
+            !fGraphicStack[fGraphicStackIndex].fFont->hasGlyph(glyphID)) {
+        int fontIndex = getFontResourceIndex(fontID, glyphID);
+        fContent.append("/F");
+        fContent.appendS32(fontIndex);
+        fContent.append(" ");
+        fContent.appendScalar(paint.getTextSize());
+        fContent.append(" Tf\n");
+        fGraphicStack[fGraphicStackIndex].fTextSize = paint.getTextSize();
+        fGraphicStack[fGraphicStackIndex].fFont = fFontResources[fontIndex];
+    }
+}
+
+
+int SkPDFDevice::getFontResourceIndex(uint32_t fontID, uint16_t glyphID) {
+    SkRefPtr<SkPDFFont> newFont = SkPDFFont::getFontResource(fontID, glyphID);
+    newFont->unref();  // getFontResource and SkRefPtr both took a ref.
     int resourceIndex = fFontResources.find(newFont.get());
     if (resourceIndex < 0) {
         resourceIndex = fFontResources.count();
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
index 2b1e3f7..77a9fdb 100644
--- a/src/pdf/SkPDFDocument.cpp
+++ b/src/pdf/SkPDFDocument.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,12 +27,9 @@
     for (int i = firstIndex; i < resourceList->count(); i++) {
         int index = resourceList->find((*resourceList)[i]);
         if (index != i) {
-            // The resource lists themselves should already be unique, so the
-            // first page resources shouldn't have any dups (assuming the first
-            // page resources are handled first).
-            SkASSERT(!firstPage);
             (*resourceList)[i]->unref();
             resourceList->removeShuffle(i);
+            i--;
         } else {
             catalog->addObject((*resourceList)[i], firstPage);
         }
@@ -68,6 +65,23 @@
         SkRefPtr<SkPDFObjRef> pageTreeRootRef = new SkPDFObjRef(pageTreeRoot);
         pageTreeRootRef->unref();  // SkRefPtr and new both took a reference.
         fDocCatalog->insert("Pages", pageTreeRootRef.get());
+
+        /* TODO(vandebo) output intent
+        SkRefPtr<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent");
+        outputIntent->unref();  // SkRefPtr and new both took a reference.
+        SkRefPtr<SkPDFName> intentSubtype = new SkPDFName("GTS_PDFA1");
+        intentSubtype->unref();  // SkRefPtr and new both took a reference.
+        outputIntent->insert("S", intentSubtype.get());
+        SkRefPtr<SkPDFString> intentIdentifier = new SkPDFString("sRGB");
+        intentIdentifier->unref();  // SkRefPtr and new both took a reference.
+        outputIntent->insert("OutputConditionIdentifier",
+                             intentIdentifier.get());
+        SkRefPtr<SkPDFArray> intentArray = new SkPDFArray;
+        intentArray->unref();  // SkRefPtr and new both took a reference.
+        intentArray->append(outputIntent.get());
+        fDocCatalog->insert("OutputIntent", intentArray.get());
+        */
+
         bool first_page = true;
         for (int i = 0; i < fPages.count(); i++) {
             int resourceCount = fPageResources.count();
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index 1bbc53a..e39530c 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,30 +14,296 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+
+#include "SkFontHost.h"
 #include "SkPaint.h"
 #include "SkPDFFont.h"
+#include "SkPDFStream.h"
+#include "SkPDFTypefaceInfo.h"
+#include "SkPDFTypes.h"
+#include "SkStream.h"
+#include "SkTypeface.h"
 #include "SkUtils.h"
 
 namespace {
 
-uint16_t unicharToWinAnsiGlyphID(SkUnichar uniChar) {
-    // TODO(vandebo) Quick hack to get text working.  Either finish the
-    // implementation of this, or remove it and use the encoding built into
-    // the real font.
-    if (uniChar < ' ')
-        return 0;
-    if (uniChar < '~')
-        return uniChar;
-    return 0;
+bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType,
+                     size_t* size) {
+    // PFB sections have a two or six bytes header. 0x80 and a one byte
+    // section type followed by a four byte section length.  Type one is
+    // an ASCII section (includes a length), type two is a binary section
+    // (includes a length) and type three is an EOF marker with no length.
+    const uint8_t* buf = *src;
+    if (*len < 2 || buf[0] != 0x80 || buf[1] != sectionType)
+        return false;
+    if (buf[1] == 3)
+        return true;
+    if (*len < 6)
+        return false;
+
+    *size = buf[2] | (buf[3] << 8) | (buf[4] << 16) | (buf[5] << 24);
+    size_t consumed = *size + 6;
+    if (consumed > *len)
+        return false;
+    *src = *src + consumed;
+    *len = *len - consumed;
+    return true;
 }
 
+bool parsePFB(const uint8_t* src, size_t size, size_t* headerLen,
+              size_t* dataLen, size_t* trailerLen) {
+    const uint8_t* srcPtr = src;
+    size_t remaining = size;
+
+    return parsePFBSection(&srcPtr, &remaining, 1, headerLen) &&
+           parsePFBSection(&srcPtr, &remaining, 2, dataLen) &&
+           parsePFBSection(&srcPtr, &remaining, 1, trailerLen) &&
+           parsePFBSection(&srcPtr, &remaining, 3, NULL);
 }
 
+/* The sections of a PFA file are implicitly defined.  The body starts
+ * after the line containing "eexec," and the trailer starts with 512
+ * literal 0's followed by "cleartomark" (plus arbitrary white space).
+ *
+ * This function assumes that src is NUL terminated, but the NUL
+ * termination is not included in size.
+ *
+ */
+bool parsePFA(const char* src, size_t size, size_t* headerLen,
+              size_t* hexDataLen, size_t* dataLen, size_t* trailerLen) {
+    const char* end = src + size;
+
+    const char* dataPos = strstr(src, "eexec");
+    if (!dataPos)
+        return false;
+    dataPos += strlen("eexec");
+    while ((*dataPos == '\n' || *dataPos == '\r' || *dataPos == ' ') &&
+            dataPos < end)
+        dataPos++;
+    *headerLen = dataPos - src;
+
+    const char* trailerPos = strstr(dataPos, "cleartomark");
+    if (!trailerPos)
+        return false;
+    int zeroCount = 0;
+    for (trailerPos--; trailerPos > dataPos && zeroCount < 512; trailerPos--) {
+        if (*trailerPos == '\n' || *trailerPos == '\r' || *trailerPos == ' ') {
+            continue;
+        } else if (*trailerPos == '0') {
+            zeroCount++;
+        } else {
+            return false;
+        }
+    }
+    if (zeroCount != 512)
+        return false;
+
+    *hexDataLen = trailerPos - src - *headerLen;
+    *trailerLen = size - *headerLen - *hexDataLen;
+
+    // Verify that the data section is hex encoded and count the bytes.
+    int nibbles = 0;
+    for (; dataPos < trailerPos; dataPos++) {
+        if (isspace(*dataPos))
+            continue;
+        if (!isxdigit(*dataPos))
+            return false;
+        nibbles++;
+    }
+    *dataLen = (nibbles + 1) / 2;
+
+    return true;
+}
+
+int8_t hexToBin(uint8_t c) {
+    if (!isxdigit(c))
+        return -1;
+    if (c <= '9') return c - '0';
+    if (c <= 'F') return c - 'A' + 10;
+    if (c <= 'f') return c - 'a' + 10;
+    return -1;
+}
+
+SkStream* handleType1Stream(SkStream* srcStream, size_t* headerLen,
+                            size_t* dataLen, size_t* trailerLen) {
+    // srcStream may be backed by a file or a unseekable fd, so we may not be 
+    // able to use skip(), rewind(), or getMemoryBase().  read()ing through
+    // the input only once is doable, but very ugly. Furthermore, it'd be nice
+    // if the data was NUL terminated so that we can use strstr() to search it.
+    // Make as few copies as possible given these constraints.
+    SkDynamicMemoryWStream dynamicStream;
+    SkRefPtr<SkMemoryStream> staticStream;
+    const uint8_t* src;
+    size_t srcLen;
+    if ((srcLen = srcStream->getLength()) > 0) {
+        staticStream = new SkMemoryStream(srcLen + 1);
+        staticStream->unref();  // new and SkRefPtr both took a ref.
+        src = (const uint8_t*)staticStream->getMemoryBase();
+        if (srcStream->getMemoryBase() != NULL) {
+            memcpy((void *)src, srcStream->getMemoryBase(), srcLen);
+        } else {
+            size_t read = 0;
+            while (read < srcLen) {
+                size_t got = srcStream->read((void *)staticStream->getAtPos(),
+                                             srcLen - read);
+                if (got == 0)
+                    return NULL;
+                read += got;
+                staticStream->seek(read);
+            }
+        }
+        ((uint8_t *)src)[srcLen] = 0;
+    } else {
+        static const size_t bufSize = 4096;
+        uint8_t buf[bufSize];
+        size_t amount;
+        while ((amount = srcStream->read(buf, bufSize)) > 0)
+            dynamicStream.write(buf, amount);
+        amount = 0;
+        dynamicStream.write(&amount, 1);  // NULL terminator.
+        // getStream makes another copy, but we couldn't do any better.
+        src = (const uint8_t*)dynamicStream.getStream();
+        srcLen = dynamicStream.getOffset() - 1;
+    }
+
+    if (parsePFB(src, srcLen, headerLen, dataLen, trailerLen)) {
+        SkMemoryStream* result =
+            new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
+        memcpy((char*)result->getAtPos(), src + 6, *headerLen);
+        result->seek(*headerLen);
+        memcpy((char*)result->getAtPos(), src + 6 + *headerLen + 6, *dataLen);
+        result->seek(*headerLen + *dataLen);
+        memcpy((char*)result->getAtPos(), src + 6 + *headerLen + 6 + *dataLen,
+               *trailerLen);
+        result->rewind();
+        return result;
+    }
+
+    // A PFA has to be converted for PDF.
+    size_t hexDataLen;
+    if (parsePFA((const char*)src, srcLen, headerLen, &hexDataLen, dataLen,
+                 trailerLen)) {
+        SkMemoryStream* result =
+            new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
+        memcpy((char*)result->getAtPos(), src, *headerLen);
+        result->seek(*headerLen);
+
+        const uint8_t* hexData = src + *headerLen;
+        const uint8_t* trailer = hexData + hexDataLen;
+        size_t outputOffset = 0;
+        uint8_t dataByte;
+        bool highNibble = true;
+        for (; hexData < trailer; hexData++) {
+            char curNibble = hexToBin(*hexData);
+            if (curNibble < 0)
+                continue;
+            if (highNibble) {
+                dataByte = curNibble << 4;
+                highNibble = false;
+            } else {
+                dataByte |= curNibble;
+                highNibble = true;
+                ((char *)result->getAtPos())[outputOffset++] = dataByte;
+            }
+        }
+        if (!highNibble)
+            ((char *)result->getAtPos())[outputOffset++] = dataByte;
+        SkASSERT(outputOffset == *dataLen);
+        result->seek(*headerLen + outputOffset);
+
+        memcpy((char *)result->getAtPos(), src + *headerLen + hexDataLen,
+               *trailerLen);
+        result->rewind();
+        return result;
+    }
+
+    return NULL;
+}
+
+void appendWidth(const int& width, SkPDFArray* array) {
+    SkRefPtr<SkPDFInt> widthInt = new SkPDFInt(width);
+    widthInt->unref();  // SkRefPtr and new both took a reference.
+    array->append(widthInt.get());
+}
+
+void appendVerticalAdvance(const SkPDFTypefaceInfo::VerticalMetric& advance,
+                           SkPDFArray* array) {
+    appendWidth(advance.fVerticalAdvance, array);
+    appendWidth(advance.fOriginXDisp, array);
+    appendWidth(advance.fOriginYDisp, array);
+}
+
+template <typename Data>
+SkPDFArray* composeAdvanceData(
+        SkPDFTypefaceInfo::AdvanceMetric<Data>* advanceInfo,
+        void (*appendAdvance)(const Data& advance, SkPDFArray* array),
+        Data* defaultAdvance) {
+    SkPDFArray* result = new SkPDFArray();
+    for (; advanceInfo != NULL; advanceInfo = advanceInfo->fNext.get()) {
+        switch (advanceInfo->fType) {
+            case SkPDFTypefaceInfo::WidthRange::kDefault: {
+                SkASSERT(advanceInfo->fAdvance.count() == 1);
+                *defaultAdvance = advanceInfo->fAdvance[0];
+                break;
+            }
+            case SkPDFTypefaceInfo::WidthRange::kRange: {
+                SkRefPtr<SkPDFArray> advanceArray = new SkPDFArray();
+                advanceArray->unref();  // SkRefPtr and new both took a ref.
+                for (int j = 0; j < advanceInfo->fAdvance.count(); j++)
+                    appendAdvance(advanceInfo->fAdvance[j], advanceArray.get());
+                SkRefPtr<SkPDFInt> rangeStart =
+                    new SkPDFInt(advanceInfo->fStartId);
+                rangeStart->unref();  // SkRefPtr and new both took a reference.
+                result->append(rangeStart.get());
+                result->append(advanceArray.get());
+                break;
+            }
+            case SkPDFTypefaceInfo::WidthRange::kRun: {
+                SkASSERT(advanceInfo->fAdvance.count() == 1);
+                SkRefPtr<SkPDFInt> rangeStart =
+                    new SkPDFInt(advanceInfo->fStartId);
+                rangeStart->unref();  // SkRefPtr and new both took a reference.
+                result->append(rangeStart.get());
+
+                SkRefPtr<SkPDFInt> rangeEnd = new SkPDFInt(advanceInfo->fEndId);
+                rangeEnd->unref();  // SkRefPtr and new both took a reference.
+                result->append(rangeEnd.get());
+
+                appendAdvance(advanceInfo->fAdvance[0], result);
+                break;
+            }
+        }
+    }
+    return result;
+}
+
+}  // namespace
+
+/* Font subset design: It would be nice to be able to subset fonts
+ * (particularly type 3 fonts), but it's a lot of work and not a priority.
+ *
+ * Resources are canonicalized and uniqueified by pointer so there has to be
+ * some additional state indicating which subset of the font is used.  It
+ * must be maintained at the page granularity and then combined at the document
+ * granularity. a) change SkPDFFont to fill in its state on demand, kind of
+ * like SkPDFGraphicState.  b) maintain a per font glyph usage class in each
+ * page/pdf device. c) in the document, retrieve the per font glyph usage
+ * from each page and combine it and ask for a resource with that subset.
+ */
+
 SkPDFFont::~SkPDFFont() {
     SkAutoMutexAcquire lock(canonicalFontsMutex());
-    int index = find(fFontID);
-    SkASSERT(index >= 0);
-    canonicalFonts().removeShuffle(index);
+    int index;
+    if (find(fFontID, fFirstGlyphID, &index)) {
+        canonicalFonts().removeShuffle(index);
+#ifdef SK_DEBUG
+        SkASSERT(!fDescendant);
+    } else {
+        SkASSERT(fDescendant);
+#endif
+    }
+    fResources.unrefAll();
 }
 
 void SkPDFFont::getResources(SkTDArray<SkPDFObject*>* resourceList) {
@@ -53,75 +319,68 @@
     return fFontID;
 }
 
+bool SkPDFFont::hasGlyph(uint16_t id) {
+    return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0;
+}
+
 bool SkPDFFont::multiByteGlyphs() {
     return fMultiByteGlyphs;
 }
 
-// TODO(vandebo) This function goes or stays with unicharToWinAnsiGlyphID.
-int SkPDFFont::textToPDFGlyphs(const void* text, size_t byteLength,
-                               const SkPaint& paint, uint16_t glyphs[],
-                               size_t glyphsLength) const {
-    // For a regular, non built-in font, just ask the paint.
-    if (fResources.count() != 0) {
-        SkASSERT(glyphsLength >= byteLength / 2);
-        if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
-            memcpy(glyphs, text, byteLength / 2 * 2);
-            return byteLength / 2;
-        } else {
-            return paint.textToGlyphs(text, byteLength, glyphs);
+size_t SkPDFFont::glyphsToPDFFontEncoding(const uint16_t* glyphIDs,
+                                          size_t numGlyphs, void* encodedValues,
+                                          size_t* encodedLength) {
+    if (numGlyphs * 2 > *encodedLength)
+        numGlyphs = *encodedLength / 2;
+
+    // A font with multibyte glyphs will support all glyph IDs in a single font,
+    // shortcut if we can.
+    if (fMultiByteGlyphs) {
+        *encodedLength = numGlyphs * 2;
+        memcpy(encodedValues, glyphIDs, *encodedLength);
+    } else {
+        char* output = (char*) encodedValues;
+        for (size_t i = 0; i < numGlyphs; i++) {
+            if (glyphIDs[i] == 0) {
+                output[i] = 0;
+                continue;
+            }
+            if (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID) {
+                numGlyphs = i;
+                break;
+            }
+            output[i] = glyphIDs[i] - fFirstGlyphID + 1;
         }
     }
 
-    const char* data = (const char*)text;
-    const char* stop = data + byteLength;
-    const uint16_t* data16 = (const uint16_t*)data;
-    const uint16_t* stop16 = (const uint16_t*)stop;
-    uint16_t* gPtr = glyphs;
-    uint16_t* gEnd = glyphs + glyphsLength;
-
-    // For a built-in font (no resources), we may have to undo glyph encoding
-    // before converting to the standard pdf encoding.
-    switch(paint.getTextEncoding()) {
-        case SkPaint::kUTF8_TextEncoding:
-            while (data < stop && gPtr < gEnd)
-                *gPtr++ = unicharToWinAnsiGlyphID(SkUTF8_NextUnichar(&data));
-            SkASSERT(data >= stop);
-            break;
-        case SkPaint::kUTF16_TextEncoding:
-            while (data16 < stop16 && gPtr < gEnd)
-                *gPtr++ = unicharToWinAnsiGlyphID(SkUTF16_NextUnichar(&data16));
-            SkASSERT(data16 >= stop16);
-            break;
-        case SkPaint::kGlyphID_TextEncoding:
-            while (data16 < stop16 && gPtr < gEnd) {
-                SkUnichar buf;
-                paint.glyphsToUnichars(data16++, 1, &buf);
-                *gPtr++ = unicharToWinAnsiGlyphID(buf);
-            }
-            SkASSERT(data16 >= stop16);
-            break;
-        default:
-            SkASSERT(!"Unknown text encoding");
-            break;
-    }
-    return gPtr - glyphs;
+    return numGlyphs;
 }
 
 // static
-SkPDFFont* SkPDFFont::getFontResouceByID(uint32_t fontID) {
+SkPDFFont* SkPDFFont::getFontResource(uint32_t fontID, uint16_t glyphID) {
     SkAutoMutexAcquire lock(canonicalFontsMutex());
-    int index = find(fontID);
-    if (index >= 0) {
+    int index;
+    if (find(fontID, glyphID, &index)) {
         canonicalFonts()[index].fFont->ref();
         return canonicalFonts()[index].fFont;
     }
 
-    // TODO(vandebo) Lookup and create the font. For now, just use the built-in
-    // Helevtica.
-    SkPDFFont* font = new SkPDFFont(fontID, false);
-    font->populateBuiltinFont("Helvetica");
+    SkRefPtr<SkPDFTypefaceInfo> fontInfo;
+    SkPDFDict* fontDescriptor = NULL;
+    if (index >= 0) {
+        SkPDFFont* relatedFont = canonicalFonts()[index].fFont;
+        SkASSERT(relatedFont->fFontInfo.get());
+        fontInfo = relatedFont->fFontInfo;
+        fontDescriptor = relatedFont->fDescriptor.get();
+    } else {
+        fontInfo = SkFontHost::GetPDFTypefaceInfo(fontID);
+        fontInfo->unref();  // SkRefPtr and get info both took a reference.
+    }
 
-    FontRec newEntry(font, fontID);
+    SkPDFFont* font = new SkPDFFont(fontInfo.get(), fontID, glyphID, false,
+                                    fontDescriptor);
+    FontRec newEntry(font, fontID, font->fFirstGlyphID);
+    index = canonicalFonts().count();
     canonicalFonts().push(newEntry);
     return font;  // Return the reference new SkPDFFont() created.
 }
@@ -141,59 +400,437 @@
 }
 
 // static
-int SkPDFFont::find(uint32_t fontID) {
-    FontRec search(NULL, fontID);
-    return canonicalFonts().find(search);
+bool SkPDFFont::find(uint32_t fontID, uint16_t glyphID, int* index) {
+    // TODO(vandebo) optimize this, do only one search?
+    FontRec search(NULL, fontID, glyphID);
+    *index = canonicalFonts().find(search);
+    if (*index >= 0)
+        return true;
+    search.fGlyphID = 0;
+    *index = canonicalFonts().find(search);
+    return false;
 }
 
-SkPDFFont::SkPDFFont(uint32_t fontID, bool multiByteGlyphs)
-    : fFontID(fontID),
-      fMultiByteGlyphs(multiByteGlyphs) {
+SkPDFFont::SkPDFFont(class SkPDFTypefaceInfo* fontInfo, uint32_t fontID,
+                     uint16_t glyphID, bool descendantFont,
+                     SkPDFDict* fontDescriptor)
+        : SkPDFDict("Font"),
+          fFontID(fontID),
+#ifdef SK_DEBUG
+          fDescendant(descendantFont),
+#endif
+          fMultiByteGlyphs(false),
+          fFirstGlyphID(1),
+          fLastGlyphID(fontInfo->fLastGlyphID),
+          fFontInfo(fontInfo),
+          fDescriptor(fontDescriptor) {
+
+    if (fontInfo->fMultiMaster) {
+        populateType3Font();
+    } else {
+        switch (fontInfo->fType) {
+            case SkPDFTypefaceInfo::kType1CID_Font:
+            case SkPDFTypefaceInfo::kTrueType_Font:
+                if (descendantFont)
+                    populateCIDFont();
+                else
+                    populateType0Font();
+                break;
+            case SkPDFTypefaceInfo::kType1_Font: {
+                uint16_t firstGlyphID = glyphID - (glyphID - 1) % 255;
+                uint16_t lastGlyphID = firstGlyphID + 255 - 1;
+                if (lastGlyphID > fLastGlyphID)
+                    lastGlyphID = fLastGlyphID;
+                if (populateType1Font(firstGlyphID, lastGlyphID))
+                    break;
+                // else, fall through.
+            }
+            case SkPDFTypefaceInfo::kOther_Font:
+            case SkPDFTypefaceInfo::kNotEmbeddable_Font:
+                populateType3Font();
+                break;
+            case SkPDFTypefaceInfo::kCFF_Font:
+                SkASSERT(false);  // Not supported yet.
+        }
+    }
+
+    // Type1 fonts may hold on to the font info, otherwise we are done with it.
+    if (fontInfo->fType != SkPDFTypefaceInfo::kType1_Font)
+        fFontInfo = NULL;
 }
 
-void SkPDFFont::populateBuiltinFont(const char fontName[]) {
-    SkASSERT(strcmp(fontName, "Time-Roman") == 0 ||
-             strcmp(fontName, "Time-Bold") == 0 ||
-             strcmp(fontName, "Time-Italic") == 0 ||
-             strcmp(fontName, "Time-BoldItalic") == 0 ||
-             strcmp(fontName, "Helvetica") == 0 ||
-             strcmp(fontName, "Helvetica-Bold") == 0 ||
-             strcmp(fontName, "Helvetica-Oblique") == 0 ||
-             strcmp(fontName, "Helvetica-BoldOblique") == 0 ||
-             strcmp(fontName, "Courier") == 0 ||
-             strcmp(fontName, "Courier-Bold") == 0 ||
-             strcmp(fontName, "Courier-Oblique") == 0 ||
-             strcmp(fontName, "Courier-BoldOblique") == 0 ||
-             strcmp(fontName, "Symbol") == 0 ||
-             strcmp(fontName, "ZapfDingbats") == 0);
+void SkPDFFont::populateType0Font() {
+    fMultiByteGlyphs = true;
 
-    SkRefPtr<SkPDFName> type = new SkPDFName("Font");
-    type->unref();  // SkRefPtr and new both took a reference.
-    insert("Type", type.get());
+    SkRefPtr<SkPDFName> subType = new SkPDFName("Type0");
+    subType->unref();  // SkRefPtr and new both took a reference.
+    insert("Subtype", subType.get());
+
+    SkRefPtr<SkPDFName> baseFont = new SkPDFName(fFontInfo.get()->fFontName);
+    baseFont->unref();  // SkRefPtr and new both took a reference.
+    insert("BaseFont", baseFont.get());
+
+    SkRefPtr<SkPDFName> encoding = new SkPDFName("Identity-H");
+    encoding->unref();  // SkRefPtr and new both took a reference.
+    insert("Encoding", encoding.get());
+
+    // TODO(vandebo) add a ToUnicode mapping.
+
+    SkRefPtr<SkPDFFont> cidFont = new SkPDFFont(fFontInfo.get(),
+                                                fFontID, 1, true, NULL);
+    fResources.push(cidFont.get());  // 2 refs: SkRefPtr, new. Pass one.
+
+    SkRefPtr<SkPDFArray> descendantFonts = new SkPDFArray();
+    descendantFonts->unref();  // SkRefPtr and new took a reference.
+    SkRefPtr<SkPDFObjRef> cidFontRef = new SkPDFObjRef(cidFont.get());
+    cidFontRef->unref();  // SkRefPtr and new both took a reference.
+    descendantFonts->append(cidFontRef.get());
+    insert("DescendantFonts", descendantFonts.get());
+}
+
+void SkPDFFont::populateCIDFont() {
+    fMultiByteGlyphs = true;
+
+    SkRefPtr<SkPDFName> subType;
+    if (fFontInfo.get()->fType == SkPDFTypefaceInfo::kType1CID_Font)
+        subType = new SkPDFName("CIDFontType0");
+    else if (fFontInfo.get()->fType == SkPDFTypefaceInfo::kTrueType_Font)
+        subType = new SkPDFName("CIDFontType2");
+    else
+        SkASSERT(false);
+    subType->unref();  // SkRefPtr and new both took a reference.
+    insert("Subtype", subType.get());
+
+    SkRefPtr<SkPDFName> baseFont = new SkPDFName(fFontInfo.get()->fFontName);
+    baseFont->unref();  // SkRefPtr and new both took a reference.
+    insert("BaseFont", baseFont.get());
+
+    SkRefPtr<SkPDFDict> sysInfo = new SkPDFDict;
+    sysInfo->unref();  // SkRefPtr and new both took a reference.
+
+    SkRefPtr<SkPDFString> adobeString = new SkPDFString("Adobe");
+    adobeString->unref();  // SkRefPtr and new both took a reference.
+    sysInfo->insert("Registry", adobeString.get());
+
+    SkRefPtr<SkPDFString> identityString = new SkPDFString("Identity");
+    identityString->unref();  // SkRefPtr and new both took a reference.
+    sysInfo->insert("Ordering", identityString.get());
+
+    SkRefPtr<SkPDFInt> supplement = new SkPDFInt(0);
+    supplement->unref();  // SkRefPtr and new both took a reference.
+    sysInfo->insert("Supplement", supplement.get());
+
+    insert("CIDSystemInfo", sysInfo.get());
+
+    addFontDescriptor(0);
+
+    if (fFontInfo.get()->fGlyphWidths.get()) {
+        int defaultWidth = 0;
+        SkRefPtr<SkPDFArray> widths =
+            composeAdvanceData(fFontInfo.get()->fGlyphWidths.get(),
+                               &appendWidth, &defaultWidth);
+        widths->unref();  // SkRefPtr and compose both took a reference.
+        if (widths->size())
+            insert("W", widths.get());
+        if (defaultWidth != 0) {
+            SkRefPtr<SkPDFInt> defaultWidthInt =
+                new SkPDFInt(defaultWidth);
+            // SkRefPtr and compose both took a reference.
+            defaultWidthInt->unref();
+            insert("DW", defaultWidthInt.get());
+        }
+    }
+    if (fFontInfo.get()->fVerticalMetrics.get()) {
+        struct SkPDFTypefaceInfo::VerticalMetric defaultAdvance;
+        defaultAdvance.fVerticalAdvance = 0;
+        defaultAdvance.fOriginXDisp = 0;
+        defaultAdvance.fOriginYDisp = 0;
+        SkRefPtr<SkPDFArray> advances =
+            composeAdvanceData(fFontInfo.get()->fVerticalMetrics.get(),
+                               &appendVerticalAdvance, &defaultAdvance);
+        advances->unref();  // SkRefPtr and compose both took a ref.
+        if (advances->size())
+            insert("W2", advances.get());
+        if (defaultAdvance.fVerticalAdvance ||
+                defaultAdvance.fOriginXDisp ||
+                defaultAdvance.fOriginYDisp) {
+            SkRefPtr<SkPDFArray> defaultAdvanceArray = new SkPDFArray;
+            // SkRefPtr and compose both took a reference.
+            defaultAdvanceArray->unref();
+            appendVerticalAdvance(defaultAdvance,
+                                  defaultAdvanceArray.get());
+            insert("DW2", defaultAdvanceArray.get());
+        }
+    }
+}
+
+bool SkPDFFont::populateType1Font(uint16_t firstGlyphID, uint16_t lastGlyphID) {
+    SkASSERT(!fFontInfo.get()->fVerticalMetrics.get());
+    SkASSERT(fFontInfo.get()->fGlyphWidths.get());
+
+    int defaultWidth = 0;
+    const SkPDFTypefaceInfo::WidthRange* widthRangeEntry = NULL;
+    const SkPDFTypefaceInfo::WidthRange* widthEntry;
+    for (widthEntry = fFontInfo.get()->fGlyphWidths.get();
+            widthEntry != NULL;
+            widthEntry = widthEntry->fNext.get()) {
+        switch (widthEntry->fType) {
+            case SkPDFTypefaceInfo::WidthRange::kDefault:
+                defaultWidth = widthEntry->fAdvance[0];
+                break;
+            case SkPDFTypefaceInfo::WidthRange::kRun:
+                SkASSERT(false);
+                break;
+            case SkPDFTypefaceInfo::WidthRange::kRange:
+                SkASSERT(widthRangeEntry == NULL);
+                widthRangeEntry = widthEntry;
+                break;
+        }
+    }
+
+    if (!addFontDescriptor(defaultWidth))
+        return false;
+
+    fFirstGlyphID = firstGlyphID;
+    fLastGlyphID = lastGlyphID;
 
     SkRefPtr<SkPDFName> subType = new SkPDFName("Type1");
     subType->unref();  // SkRefPtr and new both took a reference.
     insert("Subtype", subType.get());
 
-    SkRefPtr<SkPDFName> baseFont = new SkPDFName(fontName);
+    SkRefPtr<SkPDFName> baseFont = new SkPDFName(fFontInfo.get()->fFontName);
     baseFont->unref();  // SkRefPtr and new both took a reference.
     insert("BaseFont", baseFont.get());
 
-    SkRefPtr<SkPDFName> encoding = new SkPDFName("WinAnsiEncoding");
+    SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
+    widthArray->unref();  // SkRefPtr and new both took a ref.
+    int firstChar = 0;
+    if (widthRangeEntry) {
+        int startIndex = firstGlyphID - widthRangeEntry->fStartId;
+        int endIndex = startIndex + lastGlyphID - firstGlyphID + 1;
+        if (startIndex < 0)
+            startIndex = 0;
+        if (endIndex > widthRangeEntry->fAdvance.count())
+            endIndex = widthRangeEntry->fAdvance.count();
+        if (widthRangeEntry->fStartId == 0) {
+            appendWidth(widthRangeEntry->fAdvance[0], widthArray.get());
+        } else {
+            firstChar = startIndex + widthRangeEntry->fStartId;
+        }
+        for (int i = startIndex; i < endIndex; i++)
+            appendWidth(widthRangeEntry->fAdvance[i], widthArray.get());
+    } else {
+        appendWidth(defaultWidth, widthArray.get());
+    }
+    insert("Widths", widthArray.get());
+
+    SkRefPtr<SkPDFInt> firstCharInt = new SkPDFInt(firstChar);
+    firstCharInt->unref();  // SkRefPtr and new both took a reference.
+    insert("FirstChar", firstCharInt.get());
+
+    SkRefPtr<SkPDFInt> lastChar =
+        new SkPDFInt(firstChar + widthArray->size() - 1);
+    lastChar->unref();  // SkRefPtr and new both took a reference.
+    insert("LastChar", lastChar.get());
+
+    SkRefPtr<SkPDFDict> encoding = new SkPDFDict("Encoding");
     encoding->unref();  // SkRefPtr and new both took a reference.
     insert("Encoding", encoding.get());
+
+    SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray;
+    encDiffs->unref();  // SkRefPtr and new both took a reference.
+    encoding->insert("Differences", encDiffs.get());
+
+    encDiffs->reserve(fLastGlyphID - fFirstGlyphID + 2);
+    SkRefPtr<SkPDFInt> startID = new SkPDFInt(1);
+    startID->unref();  // SkRefPtr and new both took a reference.
+    encDiffs->append(startID.get());
+    for (int gID = fFirstGlyphID; gID <= fLastGlyphID; gID++) {
+        SkRefPtr<SkPDFName> glyphName =
+            new SkPDFName(fFontInfo.get()->fGlyphNames->get()[gID]);
+        glyphName->unref();  // SkRefPtr and new both took a reference.
+        encDiffs->append(glyphName.get());
+    }
+
+    if (fFontInfo.get()->fLastGlyphID <= 255)
+        fFontInfo = NULL;
+    return true;
 }
 
-void SkPDFFont::populateFont(const char subType[], const char fontName[],
-                             int firstChar, int lastChar, int widths[],
-                             SkPDFObject* fontDescriptor) {
+void SkPDFFont::populateType3Font() {
+    // TODO(vandebo)
+    SkASSERT(false);
 }
 
+bool SkPDFFont::addFontDescriptor(int defaultWidth) {
+    if (fDescriptor.get() != NULL) {
+        fResources.push(fDescriptor.get());
+        fDescriptor->ref();
+        SkRefPtr<SkPDFObjRef> descRef = new SkPDFObjRef(fDescriptor.get());
+        descRef->unref();  // SkRefPtr and new both took a reference.
+        insert("FontDescriptor", descRef.get());
+        return true;
+    }
+
+    fDescriptor = new SkPDFDict("FontDescriptor");
+    fDescriptor->unref();  // SkRefPtr and new both took a ref.
+
+    switch (fFontInfo.get()->fType) {
+        case SkPDFTypefaceInfo::kType1_Font: {
+            size_t header, data, trailer;
+            SkRefPtr<SkStream> rawFontData =
+                SkFontHost::OpenStream(fFontID);
+            rawFontData->unref();  // SkRefPtr and OpenStream both took a ref.
+            SkStream* fontData = handleType1Stream(rawFontData.get(), &header,
+                                                   &data, &trailer);
+            if (fontData == NULL)
+                return false;
+            SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData);
+            // SkRefPtr and new both ref()'d fontStream, pass one.
+            fResources.push(fontStream.get());
+
+            SkRefPtr<SkPDFInt> headerLen = new SkPDFInt(header);
+            headerLen->unref();  // SkRefPtr and new both took a reference.
+            fontStream->insert("Length1", headerLen.get());
+            SkRefPtr<SkPDFInt> dataLen = new SkPDFInt(data);
+            dataLen->unref();  // SkRefPtr and new both took a reference.
+            fontStream->insert("Length2", dataLen.get());
+            SkRefPtr<SkPDFInt> trailerLen = new SkPDFInt(trailer);
+            trailerLen->unref();  // SkRefPtr and new both took a reference.
+            fontStream->insert("Length3", trailerLen.get());
+
+            SkRefPtr<SkPDFObjRef> streamRef = new SkPDFObjRef(fontStream.get());
+            streamRef->unref();  // SkRefPtr and new both took a reference.
+            fDescriptor->insert("FontFile", streamRef.get());
+            break;
+        }
+        case SkPDFTypefaceInfo::kTrueType_Font: {
+            SkRefPtr<SkStream> fontData = SkFontHost::OpenStream(fFontID);
+            fontData->unref();  // SkRefPtr and OpenStream both took a ref.
+            SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
+            // SkRefPtr and new both ref()'d fontStream, pass one.
+            fResources.push(fontStream.get());
+
+            SkRefPtr<SkPDFInt> length = new SkPDFInt(fontData->getLength());
+            length->unref();  // SkRefPtr and new both took a reference.
+            fontStream->insert("Length1", length.get());
+
+            SkRefPtr<SkPDFObjRef> streamRef = new SkPDFObjRef(fontStream.get());
+            streamRef->unref();  // SkRefPtr and new both took a reference.
+            fDescriptor->insert("FontFile2", streamRef.get());
+            break;
+        }
+        case SkPDFTypefaceInfo::kCFF_Font:
+        case SkPDFTypefaceInfo::kType1CID_Font: {
+            SkRefPtr<SkStream> fontData = SkFontHost::OpenStream(fFontID);
+            fontData->unref();  // SkRefPtr and OpenStream both took a ref.
+            SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
+            // SkRefPtr and new both ref()'d fontStream, pass one.
+            fResources.push(fontStream.get());
+
+            SkRefPtr<SkPDFName> subtype;
+            if (fFontInfo.get()->fType == SkPDFTypefaceInfo::kCFF_Font)
+                subtype = new SkPDFName("Type1C");
+            else
+                subtype = new SkPDFName("CIDFontType0c");
+            subtype->unref();  // SkRefPtr and new both took a reference.
+            fontStream->insert("Subtype", subtype.get());
+
+            SkRefPtr<SkPDFObjRef> streamRef = new SkPDFObjRef(fontStream.get());
+            streamRef->unref();  // SkRefPtr and new both took a reference.
+            fDescriptor->insert("FontFile3", streamRef.get());
+            break;
+        }
+        default:
+            SkASSERT(false);
+    }
+
+    fResources.push(fDescriptor.get());
+    fDescriptor->ref();
+    SkRefPtr<SkPDFObjRef> descRef = new SkPDFObjRef(fDescriptor.get());
+    descRef->unref();  // SkRefPtr and new both took a reference.
+    insert("FontDescriptor", descRef.get());
+
+    SkRefPtr<SkPDFName> fontName =
+        new SkPDFName(fFontInfo.get()->fFontName);
+    fontName->unref();  // SkRefPtr and new both took a reference.
+    fDescriptor->insert("FontName", fontName.get());
+
+    SkRefPtr<SkPDFInt> flags = new SkPDFInt(fFontInfo.get()->fStyle);
+    flags->unref();  // SkRefPtr and new both took a reference.
+    fDescriptor->insert("Flags", flags.get());
+
+    SkIRect glyphBBox = fFontInfo.get()->fBBox;
+    SkRefPtr<SkPDFArray> bbox = new SkPDFArray;
+    bbox->unref();  // SkRefPtr and new both took a reference.
+    bbox->reserve(4);
+    SkRefPtr<SkPDFInt> bboxXMin = new SkPDFInt(glyphBBox.fLeft);
+    bboxXMin->unref();  // SkRefPtr and new both took a reference.
+    bbox->append(bboxXMin.get());
+    SkRefPtr<SkPDFInt> bboxYMin = new SkPDFInt(glyphBBox.fBottom);
+    bboxYMin->unref();  // SkRefPtr and new both took a reference.
+    bbox->append(bboxYMin.get());
+    SkRefPtr<SkPDFInt> bboxXMax = new SkPDFInt(glyphBBox.fRight);
+    bboxXMax->unref();  // SkRefPtr and new both took a reference.
+    bbox->append(bboxXMax.get());
+    SkRefPtr<SkPDFInt> bboxYMax = new SkPDFInt(glyphBBox.fTop);
+    bboxYMax->unref();  // SkRefPtr and new both took a reference.
+    bbox->append(bboxYMax.get());
+    fDescriptor->insert("FontBBox", bbox.get());
+
+    SkRefPtr<SkPDFInt> italicAngle =
+        new SkPDFInt(fFontInfo.get()->fItalicAngle);
+    italicAngle->unref();  // SkRefPtr and new both took a reference.
+    fDescriptor->insert("ItalicAngle", italicAngle.get());
+
+    SkRefPtr<SkPDFScalar> ascent = new SkPDFScalar(fFontInfo.get()->fAscent);
+    ascent->unref();  // SkRefPtr and new both took a reference.
+    fDescriptor->insert("Ascent", ascent.get());
+
+    SkRefPtr<SkPDFScalar> descent = new SkPDFScalar(fFontInfo.get()->fDescent);
+    descent->unref();  // SkRefPtr and new both took a reference.
+    fDescriptor->insert("Descent", descent.get());
+
+    SkRefPtr<SkPDFScalar> capHeight =
+        new SkPDFScalar(fFontInfo.get()->fCapHeight);
+    capHeight->unref();  // SkRefPtr and new both took a reference.
+    fDescriptor->insert("CapHeight", capHeight.get());
+
+    SkRefPtr<SkPDFScalar> stemV = new SkPDFScalar(fFontInfo.get()->fStemV);
+    stemV->unref();  // SkRefPtr and new both took a reference.
+    fDescriptor->insert("StemV", stemV.get());
+
+    if (defaultWidth > 0) {
+        SkRefPtr<SkPDFInt> defaultWidthInt = new SkPDFInt(defaultWidth);
+        defaultWidthInt->unref();  // SkRefPtr and new both took a reference.
+        fDescriptor->insert("MissingWidth", defaultWidthInt.get());
+    }
+    return true;
+}
+
+
 bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const {
-    return fFontID == b.fFontID;
+    if (fFontID != b.fFontID)
+        return false;
+    if (fFont != NULL && b.fFont != NULL) {
+        return fFont->fFirstGlyphID == b.fFont->fFirstGlyphID &&
+            fFont->fLastGlyphID == b.fFont->fLastGlyphID;
+    }
+    if (fGlyphID == 0 || b.fGlyphID == 0)
+        return true;
+
+    if (fFont != NULL) {
+        return fFont->fFirstGlyphID <= b.fGlyphID &&
+            b.fGlyphID <= fFont->fLastGlyphID;
+    } else if (b.fFont != NULL) {
+        return b.fFont->fFirstGlyphID <= fGlyphID &&
+            fGlyphID <= b.fFont->fLastGlyphID;
+    }
+    return fGlyphID == b.fGlyphID;
 }
 
-SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID)
+SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID, uint16_t glyphID)
     : fFont(font),
-      fFontID(fontID) {
+      fFontID(fontID),
+      fGlyphID(glyphID) {
 }
diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp
index 1fb62fa..286468b 100644
--- a/src/pdf/SkPDFGraphicState.cpp
+++ b/src/pdf/SkPDFGraphicState.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -114,7 +114,7 @@
         SkRefPtr<SkPDFScalar> strokeMiterLimit = new SkPDFScalar(
             fPaint.getStrokeMiter());
         strokeMiterLimit->unref();  // SkRefPtr and new both took a reference.
-        insert("ML", strokeWidth.get());
+        insert("ML", strokeMiterLimit.get());
 
         // Turn on automatic stroke adjustment.
         SkRefPtr<SkPDFBool> trueVal = new SkPDFBool(true);
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp
index 9649f0b..506b86d 100644
--- a/src/pdf/SkPDFTypes.cpp
+++ b/src/pdf/SkPDFTypes.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -97,7 +97,7 @@
 }
 
 SkPDFString::SkPDFString(const char value[])
-    : fValue(formatString(value, sizeof(value))) {
+    : fValue(formatString(value, strlen(value))) {
 }
 
 SkPDFString::SkPDFString(const SkString& value)
@@ -156,7 +156,7 @@
     for (size_t i = 0; i < len; i++) {
         SkASSERT(!wideInput || !(win[i] & ~0xFF));
         char val = wideInput ? win[i] : cin[i];
-        if (val & 0x80 || val < ' ') {
+        if (val > '~' || val < ' ') {
             sevenBitClean = false;
             break;
         }
@@ -177,7 +177,7 @@
         result.append("<");
         for (size_t i = 0; i < len; i++) {
             SkASSERT(!wideInput || !(win[i] & ~0xFF));
-            char val = wideInput ? win[i] : cin[i];
+            unsigned char val = wideInput ? win[i] : cin[i];
             result.appendHex(val, 2);
         }
         result.append(">");
diff --git a/src/ports/SkFontHost_FONTPATH.cpp b/src/ports/SkFontHost_FONTPATH.cpp
index 308adf8..79e61c0 100644
--- a/src/ports/SkFontHost_FONTPATH.cpp
+++ b/src/ports/SkFontHost_FONTPATH.cpp
@@ -269,6 +269,12 @@
     return SkNEW_ARGS(FontFaceRec_Typeface, (face));
 }
 
+// static
+SkPDFTypefaceInfo* SkFontHost::GetPDFTypefaceInfo(uint32_t fontID) {
+    sk_throw();  // not implemented
+    return NULL;
+}
+
 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
     sk_throw();  // not implemented
     return NULL;
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index 9af21bc..c05e982 100644
--- a/src/ports/SkFontHost_FreeType.cpp
+++ b/src/ports/SkFontHost_FreeType.cpp
@@ -15,27 +15,30 @@
 ** limitations under the License.
 */
 
-#include "SkColorPriv.h"
-#include "SkScalerContext.h"
 #include "SkBitmap.h"
 #include "SkCanvas.h"
+#include "SkColorPriv.h"
 #include "SkDescriptor.h"
 #include "SkFDot6.h"
 #include "SkFontHost.h"
 #include "SkMask.h"
+#include "SkPDFTypefaceInfo.h"
+#include "SkScalerContext.h"
 #include "SkStream.h"
 #include "SkString.h"
-#include "SkThread.h"
 #include "SkTemplates.h"
+#include "SkThread.h"
 
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include FT_OUTLINE_H
 #include FT_SIZES_H
 #include FT_TRUETYPE_TABLES_H
+#include FT_TYPE1_TABLES_H
 #include FT_BITMAP_H
 // In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
 #include FT_SYNTHESIS_H
+#include FT_XFREE86_H
 
 #if defined(SK_SUPPORT_LCDTEXT)
 #include FT_LCD_FILTER_H
@@ -304,6 +307,285 @@
     rec->setHinting(h);
 }
 
+static bool GetLetterCBox(FT_Face face, char letter, FT_BBox* bbox) {
+    const FT_UInt glyph_id = FT_Get_Char_Index(face, letter);
+    if (!glyph_id)
+        return false;
+    FT_Load_Glyph(face, glyph_id, FT_LOAD_NO_SCALE);
+    FT_Outline_Get_CBox(&face->glyph->outline, bbox);
+    return true;
+}
+
+int getWidthAdvance(FT_Face face, int gId, int scaleDivisor) {
+    FT_Fixed unscaledAdvance = 0;
+    SkAssertResult(FT_Get_Advance(face, gId, FT_LOAD_NO_SCALE,
+                   &unscaledAdvance) == 0);
+    return unscaledAdvance * 1000 / scaleDivisor;
+}
+
+template <typename Data>
+void resetRange(SkPDFTypefaceInfo::AdvanceMetric<Data>* range, int startId) {
+    range->fStartId = startId;
+    range->fAdvance.setCount(0);
+}
+
+template <typename Data>
+SkPDFTypefaceInfo::AdvanceMetric<Data>* appendRange(
+        SkTScopedPtr<SkPDFTypefaceInfo::AdvanceMetric<Data> >* nextSlot,
+        int startId) {
+    nextSlot->reset(new SkPDFTypefaceInfo::AdvanceMetric<Data>);
+    resetRange(nextSlot->get(), startId);
+    return nextSlot->get();
+}
+
+template <typename Data>
+void finishRange(
+        SkPDFTypefaceInfo::AdvanceMetric<Data>* range,
+        int endId,
+        typename SkPDFTypefaceInfo::AdvanceMetric<Data>::MetricType type) {
+    range->fEndId = endId;
+    range->fType = type;
+    int newLength;
+    if (type == SkPDFTypefaceInfo::AdvanceMetric<Data>::kRange)
+        newLength = endId - range->fStartId + 1;
+    else
+        newLength = 1;
+    SkASSERT(range->fAdvance.count() >= newLength);
+    range->fAdvance.setCount(newLength);
+}
+
+template <typename Data>
+SkPDFTypefaceInfo::AdvanceMetric<Data>* getAdvanceData(
+        FT_Face face,
+        int scaleDivisor,
+        Data (*getAdvance)(FT_Face face, int gId, int scaleDivisor)) {
+    // Assuming that an ASCII representation of a width or a glyph id is,
+    // on average, 3 characters long gives the following cut offs for
+    // using different range types:
+    // When currently in a range
+    //  - Removing 4 0's is a win
+    //  - Removing 5 repeats is a win
+    // When not currently in a range
+    //  - Removing 1 0 is a win
+    //  - Removing 3 repeats is a win
+
+    SkTScopedPtr<SkPDFTypefaceInfo::AdvanceMetric<Data> > result;
+    SkPDFTypefaceInfo::AdvanceMetric<Data>* curRange;
+    curRange = appendRange(&result, 0);
+    int lastAdvance = INT_MIN;
+    int repeats = 0;
+    for (FT_UInt gId = 0; gId < face->num_glyphs; gId++) {
+        int advance = getAdvance(face, gId, scaleDivisor);
+        if (advance == lastAdvance) {
+            repeats++;
+        } else if (curRange->fAdvance.count() == repeats + 1) {
+            if (lastAdvance == 0 && repeats >= 0) {
+                resetRange(curRange, gId);
+            } else if (repeats >= 2) {
+                finishRange(curRange, gId - 1,
+                            SkPDFTypefaceInfo::WidthRange::kRun);
+                curRange = appendRange(&curRange->fNext, gId);
+            }
+            repeats = 0;
+        } else {
+            if (lastAdvance == 0 && repeats >= 3) {
+                finishRange(curRange, gId - repeats - 2,
+                            SkPDFTypefaceInfo::WidthRange::kRange);
+                curRange = appendRange(&curRange->fNext, gId);
+            } else if (repeats >= 4) {
+                finishRange(curRange, gId - repeats - 2,
+                            SkPDFTypefaceInfo::WidthRange::kRange);
+                curRange = appendRange(&curRange->fNext, gId - repeats - 1);
+                curRange->fAdvance.append(1, &lastAdvance);
+                finishRange(curRange, gId - 1,
+                            SkPDFTypefaceInfo::WidthRange::kRun);
+                curRange = appendRange(&curRange->fNext, gId);
+            }
+            repeats = 0;
+        }
+        curRange->fAdvance.append(1, &advance);
+        lastAdvance = advance;
+    }
+    finishRange(curRange, face->num_glyphs - 1,
+                SkPDFTypefaceInfo::WidthRange::kRange);
+    return result.release();
+}
+
+// static
+SkPDFTypefaceInfo* SkFontHost::GetPDFTypefaceInfo(uint32_t fontID) {
+    SkAutoMutexAcquire ac(gFTMutex);
+    FT_Library libInit = NULL;
+    if (gFTCount == 0) {
+        if (!InitFreetype())
+            sk_throw();
+        libInit = gFTLibrary;
+    }
+    SkAutoTCallIProc<struct FT_LibraryRec_, FT_Done_FreeType> ftLib(libInit);
+    SkFaceRec* rec = ref_ft_face(fontID);
+    if (NULL == rec)
+        return NULL;
+    FT_Face face = rec->fFace;
+
+    SkPDFTypefaceInfo* info = new SkPDFTypefaceInfo;
+    info->fMultiMaster = false;
+    bool cid = false;
+    int scaleDivisor = 1000;
+    const char* fontType = FT_Get_X11_Font_Format(face);
+    if (FT_Get_FSType_Flags(face) & (FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING |
+                                     FT_FSTYPE_BITMAP_EMBEDDING_ONLY)) {
+        info->fType = SkPDFTypefaceInfo::kNotEmbeddable_Font;
+    } else if (FT_HAS_MULTIPLE_MASTERS(face)) {
+        // PDF requires that embedded MM fonts be reduced to a simple font.
+        info->fType = SkPDFTypefaceInfo::kOther_Font;
+    } else if (strcmp(fontType, "Type 1") == 0) {
+        info->fType = SkPDFTypefaceInfo::kType1_Font;
+    } else if (strcmp(fontType, "CID Type 1") == 0) {
+        info->fType = SkPDFTypefaceInfo::kType1CID_Font;
+        cid = true;
+    } else if (strcmp(fontType, "CFF") == 0) {
+        info->fType = SkPDFTypefaceInfo::kCFF_Font;
+    } else if (strcmp(fontType, "TrueType") == 0) {
+        info->fType = SkPDFTypefaceInfo::kTrueType_Font;
+        cid = true;
+        TT_Header* ttHeader;
+        if ((ttHeader = (TT_Header*)FT_Get_Sfnt_Table(face,
+                                                      ft_sfnt_head)) != NULL) {
+            scaleDivisor = ttHeader->Units_Per_EM;
+        }
+    }
+    info->fFontName.set(FT_Get_Postscript_Name(face));
+    SkASSERT(FT_IS_CID_KEYED(face) ==
+             (info->fType == SkPDFTypefaceInfo::kType1CID_Font));
+
+    if (info->fType == SkPDFTypefaceInfo::kOther_Font ||
+            info->fType == SkPDFTypefaceInfo::kNotEmbeddable_Font ||
+            !FT_IS_SCALABLE(face)) {
+        unref_ft_face(face);
+        return info;
+    }
+
+    info->fLastGlyphID = face->num_glyphs - 1;
+
+    SkASSERT(!FT_HAS_VERTICAL(face));
+
+    if (FT_IS_FIXED_WIDTH(face)) {
+        appendRange(&info->fGlyphWidths, 0);
+        int advance = face->max_advance_width * 1000 / scaleDivisor;
+        info->fGlyphWidths->fAdvance.append(1, &advance);
+        finishRange(info->fGlyphWidths.get(), 0,
+                    SkPDFTypefaceInfo::WidthRange::kDefault);
+    } else if(!cid) {
+        appendRange(&info->fGlyphWidths, 0);
+        // So as to not blow out the stack, get advances in batches.
+        for (int gIDStart = 0; gIDStart < face->num_glyphs; gIDStart += 128) {
+            FT_Fixed advances[128];
+            int advanceCount = 128;
+            if (gIDStart + advanceCount > face->num_glyphs)
+                advanceCount = face->num_glyphs - gIDStart + 1;
+            FT_Get_Advances(face, gIDStart, advanceCount, FT_LOAD_NO_SCALE,
+                            advances);
+            for (int i = 0; i < advanceCount; i++) {
+                int advance = advances[gIDStart + i];
+                info->fGlyphWidths->fAdvance.append(1, &advance);
+            }
+        }
+        finishRange(info->fGlyphWidths.get(), face->num_glyphs - 1,
+                    SkPDFTypefaceInfo::WidthRange::kRange);
+    } else {
+        // For CID keyed fonts, an identity pdf-cmap is used, so we iterate and
+        // report on glyph ids, not character ids (tt-cmap indices).
+        info->fGlyphWidths.reset(getAdvanceData(face, scaleDivisor,
+                                                &getWidthAdvance));
+    }
+
+    if (info->fType == SkPDFTypefaceInfo::kType1_Font) {
+        // Postscript fonts may contain more than 255 glyphs, so we end up
+        // using multiple font descriptions with a glyph ordering.  Record
+        // the name of each glyph.
+        info->fGlyphNames.reset(new SkAutoTArray<SkString>(face->num_glyphs));
+        for (FT_UInt gID = 0; gID < face->num_glyphs; gID++) {
+            char glyphName[128];  // Postscript limit for names is 127 bytes.
+            FT_Get_Glyph_Name(face, gID, glyphName, 128);
+            info->fGlyphNames->get()[gID].set(glyphName);
+        }
+    }
+
+    info->fBBox = SkIRect::MakeLTRB(face->bbox.xMin * 1000 / scaleDivisor,
+                                    face->bbox.yMax * 1000 / scaleDivisor,
+                                    face->bbox.xMax * 1000 / scaleDivisor,
+                                    face->bbox.yMin * 1000 / scaleDivisor);
+    info->fStyle = 0;
+    if (FT_IS_FIXED_WIDTH(face))
+        info->fStyle |= SkPDFTypefaceInfo::kFixedPitch_Style;
+    if (face->style_flags & FT_STYLE_FLAG_ITALIC)
+        info->fStyle |= SkPDFTypefaceInfo::kItalic_Style;
+    // We should set either Symbolic or Nonsymbolic; Nonsymbolic if the font's
+    // character set is a subset of 'Adobe standard Latin.'
+    info->fStyle |= SkPDFTypefaceInfo::kSymbolic_Style;
+
+    TT_PCLT* pclt_info;
+    TT_OS2* os2_table;
+    if ((pclt_info = (TT_PCLT*)FT_Get_Sfnt_Table(face, ft_sfnt_pclt)) != NULL) {
+        info->fCapHeight = pclt_info->CapHeight;
+        uint8_t serif_style = pclt_info->SerifStyle & 0x3F;
+        if (serif_style >= 2 && serif_style <= 6)
+            info->fStyle |= SkPDFTypefaceInfo::kSerif_Style;
+        else if (serif_style >= 9 && serif_style <= 12)
+            info->fStyle |= SkPDFTypefaceInfo::kScript_Style;
+    } else if ((os2_table =
+                (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2)) != NULL) {
+        info->fCapHeight = os2_table->sCapHeight;
+    } else {
+        // Figure out a good guess for CapHeight: average the height of M and X.
+        FT_BBox m_bbox, x_bbox;
+        bool got_m, got_x;
+        got_m = GetLetterCBox(face, 'M', &m_bbox);
+        got_x = GetLetterCBox(face, 'X', &x_bbox);
+        if (got_m && got_x) {
+            info->fCapHeight = (m_bbox.yMax - m_bbox.yMin + x_bbox.yMax -
+                    x_bbox.yMin) / 2;
+        } else if (got_m && !got_x) {
+            info->fCapHeight = m_bbox.yMax - m_bbox.yMin;
+        } else if (!got_m && got_x) {
+            info->fCapHeight = x_bbox.yMax - x_bbox.yMin;
+        }
+    }
+    info->fCapHeight = info->fCapHeight * 1000 / scaleDivisor;
+
+    // Figure out a good guess for StemV - Min width of i, I, !, 1.
+    // This probably isn't very good with an italic font.
+    int min_width = INT_MAX;
+    char stem_chars[] = {'i', 'I', '!', '1'};
+    for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
+        FT_BBox bbox;
+        if (GetLetterCBox(face, stem_chars[i], &bbox)) {
+            int width = bbox.xMax - bbox.xMin;
+            if (width > 0 && width < min_width) {
+                min_width = width;
+                info->fStemV = min_width * 1000 / scaleDivisor;
+            }
+        }
+    }
+
+    PS_FontInfoRec ps_info;
+    TT_Postscript* tt_info;
+    if (FT_Get_PS_Font_Info(face, &ps_info) == 0) {
+        info->fItalicAngle = ps_info.italic_angle;
+    } else if ((tt_info =
+                (TT_Postscript*)FT_Get_Sfnt_Table(face,
+                                                  ft_sfnt_post)) != NULL) {
+        info->fItalicAngle = SkFixedToScalar(tt_info->italicAngle);
+    } else {
+        info->fItalicAngle = 0;
+    }
+
+    info->fAscent = face->ascender * 1000 / scaleDivisor;
+    info->fDescent = face->descender * 1000 / scaleDivisor;
+
+    unref_ft_face(face);
+    return info;
+}
+
 SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
         : SkScalerContext(desc) {
     SkAutoMutexAcquire  ac(gFTMutex);
diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp
index 28b9ff2..98e8df5 100644
--- a/src/ports/SkFontHost_android.cpp
+++ b/src/ports/SkFontHost_android.cpp
@@ -584,6 +584,12 @@
     return tf;
 }
 
+// static
+SkPDFTypefaceInfo* SkFontHost::GetPDFTypefaceInfo(uint32_t fontID) {
+    SkASSERT(!"SkFontHost::GetPDFTypefaceInfo unimplemented");
+    return NULL;
+}
+
 bool SkFontHost::ValidFontID(uint32_t fontID) {
     SkAutoMutexAcquire  ac(gFamilyMutex);
 
diff --git a/src/ports/SkFontHost_fontconfig.cpp b/src/ports/SkFontHost_fontconfig.cpp
index d1da8d1..f11c985 100644
--- a/src/ports/SkFontHost_fontconfig.cpp
+++ b/src/ports/SkFontHost_fontconfig.cpp
@@ -301,6 +301,12 @@
 }
 
 // static
+SkPDFTypefaceInfo* SkFontHost::GetPDFTypefaceInfo(uint32_t fontID) {
+    SkASSERT(!"SkFontHost::GetPDFTypefaceInfo unimplemented");
+    return NULL;
+}
+
+// static
 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream)
 {
     SkASSERT(!"SkFontHost::CreateTypefaceFromStream unimplemented");
diff --git a/src/ports/SkFontHost_mac_atsui.cpp b/src/ports/SkFontHost_mac_atsui.cpp
index 9c01dfe..361d5ce 100644
--- a/src/ports/SkFontHost_mac_atsui.cpp
+++ b/src/ports/SkFontHost_mac_atsui.cpp
@@ -479,6 +479,12 @@
     return NULL;
 }
 
+// static
+SkPDFTypefaceInfo* SkFontHost::GetPDFTypefaceInfo(uint32_t fontID) {
+    SkASSERT(!"SkFontHost::GetPDFTypefaceInfo unimplemented");
+    return NULL;
+}
+
 SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
     return new SkScalerContext_Mac(desc);
 }
diff --git a/src/ports/SkFontHost_mac_coretext.cpp b/src/ports/SkFontHost_mac_coretext.cpp
index 2fc5c1d..f6839bc 100644
--- a/src/ports/SkFontHost_mac_coretext.cpp
+++ b/src/ports/SkFontHost_mac_coretext.cpp
@@ -603,6 +603,12 @@
     return SkFontHost::CreateTypeface(NULL, NULL, NULL, NULL, SkTypeface::kNormal);
 }
 
+// static
+SkPDFTypefaceInfo* SkFontHost::GetPDFTypefaceInfo(uint32_t fontID) {
+    SkASSERT(!"SkFontHost::GetPDFTypefaceInfo unimplemented");
+    return NULL;
+}
+
 ///////////////////////////////////////////////////////////////////////////
 
 bool SkFontHost::ValidFontID(SkFontID uniqueID)
diff --git a/src/ports/SkFontHost_none.cpp b/src/ports/SkFontHost_none.cpp
index ae56ae4..d2d0a9f 100644
--- a/src/ports/SkFontHost_none.cpp
+++ b/src/ports/SkFontHost_none.cpp
@@ -33,6 +33,12 @@
     return NULL;
 }
 
+// static
+SkPDFTypefaceInfo* SkFontHost::GetPDFTypefaceInfo(uint32_t fontID) {
+    SkASSERT(!"SkFontHost::GetPDFTypefaceInfo unimplemented");
+    return NULL;
+}
+
 void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
 }
 
diff --git a/src/ports/SkFontHost_simple.cpp b/src/ports/SkFontHost_simple.cpp
index 9e126bc..ccec75b 100644
--- a/src/ports/SkFontHost_simple.cpp
+++ b/src/ports/SkFontHost_simple.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #include "SkFontHost.h"
 #include "SkDescriptor.h"
 #include "SkMMapStream.h"
@@ -566,6 +582,12 @@
     return stream;
 }
 
+// static
+SkPDFTypefaceInfo* SkFontHost::GetPDFTypefaceInfo(uint32_t fontID) {
+    SkASSERT(!"SkFontHost::GetPDFTypefaceInfo unimplemented");
+    return NULL;
+}
+
 size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
                                int32_t* index) {
     SkAutoMutexAcquire  ac(gFamilyMutex);
diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp
index a1114d9..4f3f198 100644
--- a/src/ports/SkFontHost_win.cpp
+++ b/src/ports/SkFontHost_win.cpp
@@ -463,6 +463,12 @@
     return NULL;

 }

 

+// static

+SkPDFTypefaceInfo* SkFontHost::GetPDFTypefaceInfo(uint32_t fontID) {

+    SkASSERT(!"SkFontHost::GetPDFTypefaceInfo unimplemented");

+    return NULL;

+}

+

 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {

 

     //Should not be used on Windows, keep linker happy

diff --git a/tests/FlateTest.cpp b/tests/FlateTest.cpp
index b9befe0..f8e0921 100644
--- a/tests/FlateTest.cpp
+++ b/tests/FlateTest.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
 
 // A memory stream that reports zero size with the standard call, like
 // an unseekable file stream would.
-class SkSimulatedFileStream : public SkMemoryStream {
+class SkZeroSizeMemStream : public SkMemoryStream {
 public:
     virtual size_t read(void* buffer, size_t size) {
         if (buffer == NULL && size == 0)
@@ -55,7 +55,7 @@
     // Check that the input data wasn't changed.
     size_t inputSize = testStream->getLength();
     if (inputSize == 0)
-        inputSize = testStream->read(NULL, SkSimulatedFileStream::kGetSizeKey);
+        inputSize = testStream->read(NULL, SkZeroSizeMemStream::kGetSizeKey);
     REPORTER_ASSERT(reporter, testData.getLength() == inputSize);
     REPORTER_ASSERT(reporter, memcmp(testData.getMemoryBase(),
                                      testStream->getMemoryBase(),
@@ -75,7 +75,7 @@
     // Check that the input data wasn't changed.
     inputSize = testStream->getLength();
     if (inputSize == 0)
-        inputSize = testStream->read(NULL, SkSimulatedFileStream::kGetSizeKey);
+        inputSize = testStream->read(NULL, SkZeroSizeMemStream::kGetSizeKey);
     REPORTER_ASSERT(reporter, compressed.getOffset() == inputSize);
     REPORTER_ASSERT(reporter, memcmp(testStream->getMemoryBase(),
                                      compressed.getStream(),
@@ -97,7 +97,7 @@
     TestFlate(reporter, &memStream, 512);
     TestFlate(reporter, &memStream, 10240);
 
-    SkSimulatedFileStream fileStream;
+    SkZeroSizeMemStream fileStream;
     TestFlate(reporter, &fileStream, 512);
     TestFlate(reporter, &fileStream, 10240);
 #endif