[PDF] Move most of the headers to be private.

Compute font stats in SkPDFDocument in order to make more of the headers private.

Previous review: https://codereview.appspot.com/5865048/

Review URL: https://codereview.appspot.com/5868049

git-svn-id: http://skia.googlecode.com/svn/trunk@3457 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pdf/SkBitSet.h b/src/pdf/SkBitSet.h
new file mode 100755
index 0000000..484fc2a
--- /dev/null
+++ b/src/pdf/SkBitSet.h
@@ -0,0 +1,78 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkBitSet_DEFINED
+#define SkBitSet_DEFINED
+
+#include "SkTypes.h"
+#include "SkTDArray.h"
+
+class SkBitSet {
+public:
+    /** NumberOfBits must be greater than zero.
+     */
+    explicit SkBitSet(int numberOfBits);
+    explicit SkBitSet(const SkBitSet& source);
+
+    const SkBitSet& operator=(const SkBitSet& rhs);
+    bool operator==(const SkBitSet& rhs);
+    bool operator!=(const SkBitSet& rhs);
+
+    /** Clear all data.
+     */
+    void clearAll();
+
+    /** Set the value of the index-th bit.
+     */
+    void setBit(int index, bool value);
+
+    /** Test if bit index is set.
+     */
+    bool isBitSet(int index) const;
+
+    /** Or bits from source.  false is returned if this doesn't have the same
+     *  bit count as source.
+     */
+    bool orBits(const SkBitSet& source);
+
+    /** Export indices of set bits to T array.
+     */
+    template<typename T>
+    void exportTo(SkTDArray<T>* array) const {
+        SkASSERT(array);
+        uint32_t* data = reinterpret_cast<uint32_t*>(fBitData.get());
+        for (unsigned int i = 0; i < fDwordCount; ++i) {
+            uint32_t value = data[i];
+            if (value) {  // There are set bits
+                unsigned int index = i * 32;
+                for (unsigned int j = 0; j < 32; ++j) {
+                    if (0x1 & (value >> j)) {
+                        array->push(index + j);
+                    }
+                }
+            }
+        }
+    }
+
+private:
+    SkAutoFree fBitData;
+    // Dword (32-bit) count of the bitset.
+    size_t fDwordCount;
+    size_t fBitCount;
+
+    uint32_t* internalGet(int index) const {
+        SkASSERT((size_t)index < fBitCount);
+        size_t internalIndex = index / 32;
+        SkASSERT(internalIndex < fDwordCount);
+        return reinterpret_cast<uint32_t*>(fBitData.get()) + internalIndex;
+    }
+};
+
+
+#endif
diff --git a/src/pdf/SkPDFCatalog.h b/src/pdf/SkPDFCatalog.h
new file mode 100644
index 0000000..44005c6
--- /dev/null
+++ b/src/pdf/SkPDFCatalog.h
@@ -0,0 +1,137 @@
+
+/*
+ * Copyright 2010 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.
+ */
+
+
+#ifndef SkPDFCatalog_DEFINED
+#define SkPDFCatalog_DEFINED
+
+#include <sys/types.h>
+
+#include "SkPDFDocument.h"
+#include "SkPDFTypes.h"
+#include "SkRefCnt.h"
+#include "SkTDArray.h"
+
+/** \class SkPDFCatalog
+
+    The PDF catalog manages object numbers and file offsets.  It is used
+    to create the PDF cross reference table.
+*/
+class SkPDFCatalog {
+public:
+    /** Create a PDF catalog.
+     */
+    explicit SkPDFCatalog(SkPDFDocument::Flags flags);
+    ~SkPDFCatalog();
+
+    /** Add the passed object to the catalog.  Refs obj.
+     *  @param obj         The object to add.
+     *  @param onFirstPage Is the object on the first page.
+     *  @return The obj argument is returned.
+     */
+    SkPDFObject* addObject(SkPDFObject* obj, bool onFirstPage);
+
+    /** Inform the catalog of the object's position in the final stream.
+     *  The object should already have been added to the catalog.  Returns
+     *  the object's size.
+     *  @param obj         The object to add.
+     *  @param offset      The byte offset in the output stream of this object.
+     */
+    size_t setFileOffset(SkPDFObject* obj, size_t offset);
+
+    /** Output the object number for the passed object.
+     *  @param obj         The object of interest.
+     *  @param stream      The writable output stream to send the output to.
+     */
+    void emitObjectNumber(SkWStream* stream, SkPDFObject* obj);
+
+    /** Return the number of bytes that would be emitted for the passed
+     *  object's object number.
+     *  @param obj         The object of interest
+     */
+    size_t getObjectNumberSize(SkPDFObject* obj);
+
+    /** Return the document flags in effect for this catalog/document.
+     */
+    SkPDFDocument::Flags getDocumentFlags() const { return fDocumentFlags; }
+
+    /** Output the cross reference table for objects in the catalog.
+     *  Returns the total number of objects.
+     *  @param stream      The writable output stream to send the output to.
+     *  @param firstPage   If true, include first page objects only, otherwise
+     *                     include all objects not on the first page.
+     */
+    int32_t emitXrefTable(SkWStream* stream, bool firstPage);
+
+    /** Set substitute object for the passed object.
+     */
+    void setSubstitute(SkPDFObject* original, SkPDFObject* substitute);
+
+    /** Find and return any substitute object set for the passed object. If
+     *  there is none, return the passed object.
+     */
+    SkPDFObject* getSubstituteObject(SkPDFObject* object);
+
+    /** Set file offsets for the resources of substitute objects.
+     *  @param fileOffset Accumulated offset of current document.
+     *  @param firstPage  Indicate whether this is for the first page only.
+     *  @return           Total size of resources of substitute objects.
+     */
+    off_t setSubstituteResourcesOffsets(off_t fileOffset, bool firstPage);
+
+    /** Emit the resources of substitute objects.
+     */
+    void emitSubstituteResources(SkWStream* stream, bool firstPage);
+
+private:
+    struct Rec {
+        Rec(SkPDFObject* object, bool onFirstPage)
+            : fObject(object),
+              fFileOffset(0),
+              fObjNumAssigned(false),
+              fOnFirstPage(onFirstPage) {
+        }
+        SkPDFObject* fObject;
+        off_t fFileOffset;
+        bool fObjNumAssigned;
+        bool fOnFirstPage;
+    };
+
+    struct SubstituteMapping {
+        SubstituteMapping(SkPDFObject* original, SkPDFObject* substitute)
+            : fOriginal(original), fSubstitute(substitute) {
+        }
+        SkPDFObject* fOriginal;
+        SkPDFObject* fSubstitute;
+    };
+
+    // TODO(vandebo): Make this a hash if it's a performance problem.
+    SkTDArray<struct Rec> fCatalog;
+
+    // TODO(arthurhsu): Make this a hash if it's a performance problem.
+    SkTDArray<SubstituteMapping> fSubstituteMap;
+    SkTDArray<SkPDFObject*> fSubstituteResourcesFirstPage;
+    SkTDArray<SkPDFObject*> fSubstituteResourcesRemaining;
+
+    // Number of objects on the first page.
+    uint32_t fFirstPageCount;
+    // Next object number to assign (on page > 1).
+    uint32_t fNextObjNum;
+    // Next object number to assign on the first page.
+    uint32_t fNextFirstPageObjNum;
+
+    SkPDFDocument::Flags fDocumentFlags;
+
+    int findObjectIndex(SkPDFObject* obj) const;
+
+    int assignObjNum(SkPDFObject* obj);
+
+    SkTDArray<SkPDFObject*>* getSubstituteList(bool firstPage);
+};
+
+#endif
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
index cb87d8f..3ec4877 100644
--- a/src/pdf/SkPDFDocument.cpp
+++ b/src/pdf/SkPDFDocument.cpp
@@ -10,8 +10,9 @@
 #include "SkPDFCatalog.h"
 #include "SkPDFDevice.h"
 #include "SkPDFDocument.h"
-#include "SkPDFPage.h"
 #include "SkPDFFont.h"
+#include "SkPDFPage.h"
+#include "SkPDFTypes.h"
 #include "SkStream.h"
 
 // Add the resources, starting at firstIndex to the catalog, removing any dupes.
@@ -222,8 +223,23 @@
     return true;
 }
 
-const SkTDArray<SkPDFPage*>& SkPDFDocument::getPages() {
-    return fPages;
+void SkPDFDocument::getCountOfFontTypes(
+        int counts[SkAdvancedTypefaceMetrics::kNotEmbeddable_Font + 1]) const {
+    memset(counts, 0,
+           sizeof(int)* SkAdvancedTypefaceMetrics::kNotEmbeddable_Font + 1);
+    SkTDArray<SkFontID> seenFonts;
+
+    for (int pageNumber = 0; pageNumber < fPages.count(); pageNumber++) {
+        const SkTDArray<SkPDFFont*>& fontResources =
+                fPages[pageNumber]->getFontResources();
+        for (int font = 0; font < fontResources.count(); font++) {
+            SkFontID fontID = fontResources[font]->typeface()->uniqueID();
+            if (seenFonts.find(fontID) == -1) {
+                counts[fontResources[font]->getType()]++;
+                seenFonts.push(fontID);
+            }
+        }
+    }
 }
 
 void SkPDFDocument::emitHeader(SkWStream* stream) {
diff --git a/src/pdf/SkPDFFont.h b/src/pdf/SkPDFFont.h
new file mode 100644
index 0000000..f463ed7
--- /dev/null
+++ b/src/pdf/SkPDFFont.h
@@ -0,0 +1,202 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkPDFFont_DEFINED
+#define SkPDFFont_DEFINED
+
+#include "SkAdvancedTypefaceMetrics.h"
+#include "SkBitSet.h"
+#include "SkPDFTypes.h"
+#include "SkTDArray.h"
+#include "SkThread.h"
+#include "SkTypeface.h"
+
+class SkPaint;
+class SkPDFCatalog;
+class SkPDFFont;
+
+class SkPDFGlyphSet : public SkNoncopyable {
+public:
+    SkPDFGlyphSet();
+
+    void set(const uint16_t* glyphIDs, int numGlyphs);
+    bool has(uint16_t glyphID) const;
+    void merge(const SkPDFGlyphSet& usage);
+    void exportTo(SkTDArray<uint32_t>* glyphIDs) const;
+
+private:
+    SkBitSet fBitSet;
+};
+
+class SkPDFGlyphSetMap : public SkNoncopyable {
+public:
+    struct FontGlyphSetPair {
+        FontGlyphSetPair(SkPDFFont* font, SkPDFGlyphSet* glyphSet);
+
+        SkPDFFont* fFont;
+        SkPDFGlyphSet* fGlyphSet;
+    };
+
+    SkPDFGlyphSetMap();
+    ~SkPDFGlyphSetMap();
+
+    class F2BIter {
+    public:
+        explicit F2BIter(const SkPDFGlyphSetMap& map);
+        FontGlyphSetPair* next() const;
+        void reset(const SkPDFGlyphSetMap& map);
+
+    private:
+        const SkTDArray<FontGlyphSetPair>* fMap;
+        mutable int fIndex;
+    };
+
+    void merge(const SkPDFGlyphSetMap& usage);
+    void reset();
+
+    void noteGlyphUsage(SkPDFFont* font, const uint16_t* glyphIDs,
+                        int numGlyphs);
+
+private:
+    SkPDFGlyphSet* getGlyphSetForFont(SkPDFFont* font);
+
+    SkTDArray<FontGlyphSetPair> fMap;
+};
+
+
+/** \class SkPDFFont
+    A PDF Object class representing a font.  The font may have resources
+    attached to it in order to embed the font.  SkPDFFonts are canonicalized
+    so that resource deduplication will only include one copy of a font.
+    This class uses the same pattern as SkPDFGraphicState, a static weak
+    reference to each instantiated class.
+*/
+class SkPDFFont : public SkPDFDict {
+public:
+    virtual ~SkPDFFont();
+
+    virtual void getResources(SkTDArray<SkPDFObject*>* resourceList);
+
+    /** Returns the typeface represented by this class. Returns NULL for the
+     *  default typeface.
+     */
+    SkTypeface* typeface();
+
+    /** Returns the font type represented in this font.  For Type0 fonts,
+     *  returns the type of the decendant font.
+     */
+    virtual SkAdvancedTypefaceMetrics::FontType getType();
+
+    /** Returns true if this font encoding supports glyph IDs above 255.
+     */
+    virtual bool multiByteGlyphs() const = 0;
+
+    /** Return true if this font has an encoding for the passed glyph id.
+     */
+    bool hasGlyph(uint16_t glyphID);
+
+    /** Convert (in place) 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.
+     *  @return               Returns the number of glyphs consumed.
+     */
+    size_t glyphsToPDFFontEncoding(uint16_t* glyphIDs, size_t numGlyphs);
+
+    /** Get the font resource for the passed typeface 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 typeface  The typeface to find.
+     *  @param glyphID   Specify which section of a large font is of interest.
+     */
+    static SkPDFFont* GetFontResource(SkTypeface* typeface,
+                                             uint16_t glyphID);
+
+    /** Subset the font based on usage set. Returns a SkPDFFont instance with
+     *  subset.
+     *  @param usage  Glyph subset requested.
+     *  @return       NULL if font does not support subsetting, a new instance
+     *                of SkPDFFont otherwise.
+     */
+    virtual SkPDFFont* getFontSubset(const SkPDFGlyphSet* usage);
+
+protected:
+    // Common constructor to handle common members.
+    SkPDFFont(SkAdvancedTypefaceMetrics* fontInfo, SkTypeface* typeface,
+              uint16_t glyphID, bool descendantFont);
+
+    // Accessors for subclass.
+    SkAdvancedTypefaceMetrics* fontInfo();
+    void setFontInfo(SkAdvancedTypefaceMetrics* info);
+    uint16_t firstGlyphID() const;
+    uint16_t lastGlyphID() const;
+    void setLastGlyphID(uint16_t glyphID);
+
+    // Add object to resource list.
+    void addResource(SkPDFObject* object);
+
+    // Accessors for FontDescriptor associated with this object.
+    SkPDFDict* getFontDescriptor();
+    void setFontDescriptor(SkPDFDict* descriptor);
+
+    // Add common entries to FontDescriptor.
+    bool addCommonFontDescriptorEntries(int16_t defaultWidth);
+
+    /** Set fFirstGlyphID and fLastGlyphID to span at most 255 glyphs,
+     *  including the passed glyphID.
+     */
+    void adjustGlyphRangeForSingleByteEncoding(int16_t glyphID);
+
+    // Generate ToUnicode table according to glyph usage subset.
+    // If subset is NULL, all available glyph ids will be used.
+    void populateToUnicodeTable(const SkPDFGlyphSet* subset);
+
+    // Create instances of derived types based on fontInfo.
+    static SkPDFFont* Create(SkAdvancedTypefaceMetrics* fontInfo,
+                             SkTypeface* typeface, uint16_t glyphID,
+                             SkPDFDict* fontDescriptor);
+
+    static bool Find(uint32_t fontID, uint16_t glyphID, int* index);
+
+private:
+    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, uint16_t fGlyphID);
+    };
+
+    SkRefPtr<SkTypeface> fTypeface;
+
+    // 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<SkAdvancedTypefaceMetrics> fFontInfo;
+    SkTDArray<SkPDFObject*> fResources;
+    SkRefPtr<SkPDFDict> fDescriptor;
+
+    SkAdvancedTypefaceMetrics::FontType fFontType;
+
+    // This should be made a hash table if performance is a problem.
+    static SkTDArray<FontRec>& CanonicalFonts();
+    static SkBaseMutex& CanonicalFontsMutex();
+};
+
+#endif
diff --git a/src/pdf/SkPDFFormXObject.h b/src/pdf/SkPDFFormXObject.h
new file mode 100644
index 0000000..0c49152
--- /dev/null
+++ b/src/pdf/SkPDFFormXObject.h
@@ -0,0 +1,48 @@
+
+/*
+ * Copyright 2010 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.
+ */
+
+
+#ifndef SkPDFFormXObject_DEFINED
+#define SkPDFFormXObject_DEFINED
+
+#include "SkPDFStream.h"
+#include "SkPDFTypes.h"
+#include "SkRefCnt.h"
+#include "SkString.h"
+
+class SkMatrix;
+class SkPDFDevice;
+class SkPDFCatalog;
+
+/** \class SkPDFFormXObject
+
+    A form XObject; a self contained description of graphics objects.  A form
+    XObject is basically a page object with slightly different syntax, that
+    can be drawn onto a page.
+*/
+
+// The caller could keep track of the form XObjects it creates and
+// canonicalize them, but the Skia API doesn't provide enough context to
+// automatically do it (trivially).
+class SkPDFFormXObject : public SkPDFStream {
+public:
+    /** Create a PDF form XObject. Entries for the dictionary entries are
+     *  automatically added.
+     *  @param device      The set of graphical elements on this form.
+     */
+    explicit SkPDFFormXObject(SkPDFDevice* device);
+    virtual ~SkPDFFormXObject();
+
+    // The SkPDFObject interface.
+    virtual void getResources(SkTDArray<SkPDFObject*>* resourceList);
+
+private:
+    SkTDArray<SkPDFObject*> fResources;
+};
+
+#endif
diff --git a/src/pdf/SkPDFGraphicState.h b/src/pdf/SkPDFGraphicState.h
new file mode 100644
index 0000000..af01737
--- /dev/null
+++ b/src/pdf/SkPDFGraphicState.h
@@ -0,0 +1,101 @@
+
+/*
+ * Copyright 2010 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.
+ */
+
+
+#ifndef SkPDFGraphicState_DEFINED
+#define SkPDFGraphicState_DEFINED
+
+#include "SkPaint.h"
+#include "SkPDFTypes.h"
+#include "SkTemplates.h"
+#include "SkThread.h"
+
+class SkPDFFormXObject;
+
+/** \class SkPDFGraphicState
+    SkPaint objects roughly correspond to graphic state dictionaries that can
+    be installed. So that a given dictionary is only output to the pdf file
+    once, we want to canonicalize them. Static methods in this class manage
+    a weakly referenced set of SkPDFGraphicState objects: when the last
+    reference to a SkPDFGraphicState is removed, it removes itself from the
+    static set of objects.
+
+*/
+class SkPDFGraphicState : public SkPDFDict {
+public:
+    virtual ~SkPDFGraphicState();
+
+    virtual void getResources(SkTDArray<SkPDFObject*>* resourceList);
+
+    // Override emitObject and getOutputSize so that we can populate
+    // the dictionary on demand.
+    virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+                            bool indirect);
+    virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
+
+    /** Get the graphic state for the passed SkPaint. 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.
+     */
+    static SkPDFGraphicState* GetGraphicStateForPaint(const SkPaint& paint);
+
+    /** Make a graphic state that only sets the passed soft mask. The
+     *  reference count of the object is incremented and it is the caller's
+     *  responsibility to unreference it when done.
+     *  @param sMask  The form xobject to use as a soft mask.
+     *  @param invert Indicates if the alpha of the sMask should be inverted.
+     */
+    static SkPDFGraphicState* GetSMaskGraphicState(SkPDFFormXObject* sMask,
+                                                   bool invert);
+
+    /** Get a graphic state that only unsets the soft mask. 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.
+     */
+    static SkPDFGraphicState* GetNoSMaskGraphicState();
+
+private:
+    const SkPaint fPaint;
+    SkTDArray<SkPDFObject*> fResources;
+    bool fPopulated;
+    bool fSMask;
+
+    class GSCanonicalEntry {
+    public:
+        SkPDFGraphicState* fGraphicState;
+        const SkPaint* fPaint;
+
+        bool operator==(const GSCanonicalEntry& b) const;
+        explicit GSCanonicalEntry(SkPDFGraphicState* gs)
+            : fGraphicState(gs),
+              fPaint(&gs->fPaint) {}
+        explicit GSCanonicalEntry(const SkPaint* paint)
+            : fGraphicState(NULL),
+              fPaint(paint) {}
+    };
+
+    // This should be made a hash table if performance is a problem.
+    static SkTDArray<GSCanonicalEntry>& CanonicalPaints();
+    static SkBaseMutex& CanonicalPaintsMutex();
+
+    SkPDFGraphicState();
+    explicit SkPDFGraphicState(const SkPaint& paint);
+
+    void populateDict();
+
+    static SkPDFObject* GetInvertFunction();
+
+    static int Find(const SkPaint& paint);
+};
+
+#endif
diff --git a/src/pdf/SkPDFImage.h b/src/pdf/SkPDFImage.h
new file mode 100644
index 0000000..48b0157
--- /dev/null
+++ b/src/pdf/SkPDFImage.h
@@ -0,0 +1,70 @@
+
+/*
+ * Copyright 2010 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.
+ */
+
+
+#ifndef SkPDFImage_DEFINED
+#define SkPDFImage_DEFINED
+
+#include "SkPDFStream.h"
+#include "SkPDFTypes.h"
+#include "SkRefCnt.h"
+
+class SkBitmap;
+class SkPaint;
+class SkPDFCatalog;
+struct SkIRect;
+
+/** \class SkPDFImage
+
+    An image XObject.
+*/
+
+// We could play the same trick here as is done in SkPDFGraphicState, storing
+// a copy of the Bitmap object (not the pixels), the pixel generation number,
+// and settings used from the paint to canonicalize image objects.
+class SkPDFImage : public SkPDFStream {
+public:
+    /** Create a new Image XObject to represent the passed bitmap.
+     *  @param bitmap   The image to encode.
+     *  @param srcRect  The rectangle to cut out of bitmap.
+     *  @param paint    Used to calculate alpha, masks, etc.
+     *  @return  The image XObject or NUll if there is nothing to draw for
+     *           the given parameters.
+     */
+    static SkPDFImage* CreateImage(const SkBitmap& bitmap,
+                                   const SkIRect& srcRect,
+                                   const SkPaint& paint);
+
+    virtual ~SkPDFImage();
+
+    /** Add a Soft Mask (alpha or shape channel) to the image.  Refs mask.
+     *  @param mask A gray scale image representing the mask.
+     *  @return The mask argument is returned.
+     */
+    SkPDFImage* addSMask(SkPDFImage* mask);
+
+    // The SkPDFObject interface.
+    virtual void getResources(SkTDArray<SkPDFObject*>* resourceList);
+
+private:
+    SkTDArray<SkPDFObject*> fResources;
+
+    /** Create a PDF image XObject. Entries for the image properties are
+     *  automatically added to the stream dictionary.
+     *  @param imageData  The final raw bits representing the image.
+     *  @param bitmap     The image parameters to use (Config, etc).
+     *  @param srcRect    The clipping applied to bitmap before generating
+     *                    imageData.
+     *  @param alpha      Is this the alpha channel of the bitmap.
+     *  @param paint      Used to calculate alpha, masks, etc.
+     */
+    SkPDFImage(SkStream* imageData, const SkBitmap& bitmap,
+               const SkIRect& srcRect, bool alpha, const SkPaint& paint);
+};
+
+#endif
diff --git a/src/pdf/SkPDFPage.h b/src/pdf/SkPDFPage.h
new file mode 100644
index 0000000..8ef909e
--- /dev/null
+++ b/src/pdf/SkPDFPage.h
@@ -0,0 +1,100 @@
+
+/*
+ * Copyright 2010 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.
+ */
+
+
+#ifndef SkPDFPage_DEFINED
+#define SkPDFPage_DEFINED
+
+#include "SkPDFTypes.h"
+#include "SkPDFStream.h"
+#include "SkRefCnt.h"
+#include "SkTDArray.h"
+
+class SkPDFCatalog;
+class SkPDFDevice;
+class SkWStream;
+
+/** \class SkPDFPage
+
+    A SkPDFPage contains meta information about a page, is used in the page
+    tree and points to the content of the page.
+*/
+class SkPDFPage : public SkPDFDict {
+public:
+    /** Create a PDF page with the passed PDF device.  The device need not
+     *  have content on it yet.
+     *  @param content    The page content.
+     */
+    explicit SkPDFPage(SkPDFDevice* content);
+    ~SkPDFPage();
+
+    /** Before a page and its contents can be sized and emitted, it must
+     *  be finalized.  No changes to the PDFDevice will be honored after
+     *  finalizePage has been called.  This function adds the page content
+     *  to the passed catalog, so it must be called for each document
+     *  that the page is part of.
+     *  @param catalog         The catalog to add page content objects to.
+     *  @param firstPage       Indicate if this is the first page of a document.
+     *  @param resourceObjects All the resource objects (recursively) used on
+     *                         the page are added to this array.  This gives
+     *                         the caller a chance to deduplicate resources
+     *                         across pages.
+     */
+    void finalizePage(SkPDFCatalog* catalog, bool firstPage,
+                      SkTDArray<SkPDFObject*>* resourceObjects);
+
+    /** Determine the size of the page content and store to the catalog
+     *  the offsets of all nonresource-indirect objects that make up the page
+     *  content.  This must be called before emitPage(), but after finalizePage.
+     *  @param catalog    The catalog to add the object offsets to.
+     *  @param fileOffset The file offset where the page content will be
+     *                    emitted.
+     */
+    off_t getPageSize(SkPDFCatalog* catalog, off_t fileOffset);
+
+    /** Output the page content to the passed stream.
+     *  @param stream     The writable output stream to send the content to.
+     *  @param catalog    The active object catalog.
+     */
+    void emitPage(SkWStream* stream, SkPDFCatalog* catalog);
+
+    /** Generate a page tree for the passed vector of pages.  New objects are
+     *  added to the catalog.  The pageTree vector is populated with all of
+     *  the 'Pages' dictionaries as well as the 'Page' objects.  Page trees
+     *  have both parent and children links, creating reference cycles, so
+     *  it must be torn down explicitly.  The first page is not added to
+     *  the pageTree dictionary array so the caller can handle it specially.
+     *  @param pages      The ordered vector of page objects.
+     *  @param catalog    The catalog to add new objects into.
+     *  @param pageTree   An output vector with all of the internal and leaf
+     *                    nodes of the pageTree.
+     *  @param rootNode   An output parameter set to the root node.
+     */
+    static void GeneratePageTree(const SkTDArray<SkPDFPage*>& pages,
+                                 SkPDFCatalog* catalog,
+                                 SkTDArray<SkPDFDict*>* pageTree,
+                                 SkPDFDict** rootNode);
+
+    /** Get the fonts used on this page.
+     */
+    const SkTDArray<SkPDFFont*>& getFontResources() const;
+
+    /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font
+     *  that shows on this page.
+     */
+    const SkPDFGlyphSetMap& getFontGlyphUsage() const;
+
+private:
+    // Multiple pages may reference the content.
+    SkRefPtr<SkPDFDevice> fDevice;
+
+    // Once the content is finalized, put it into a stream for output.
+    SkRefPtr<SkPDFStream> fContentStream;
+};
+
+#endif
diff --git a/src/pdf/SkPDFShader.h b/src/pdf/SkPDFShader.h
new file mode 100644
index 0000000..439d83b
--- /dev/null
+++ b/src/pdf/SkPDFShader.h
@@ -0,0 +1,65 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkPDFShader_DEFINED
+#define SkPDFShader_DEFINED
+
+#include "SkPDFStream.h"
+#include "SkPDFTypes.h"
+#include "SkMatrix.h"
+#include "SkRefCnt.h"
+#include "SkShader.h"
+
+class SkObjRef;
+class SkPDFCatalog;
+
+/** \class SkPDFShader
+
+    In PDF parlance, this is a pattern, used in place of a color when the
+    pattern color space is selected.
+*/
+
+class SkPDFShader {
+public:
+    /** Get the PDF shader for the passed SkShader. If the SkShader is
+     *  invalid in some way, returns NULL. 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 shader     The SkShader to emulate.
+     *  @param matrix     The current transform. (PDF shaders are absolutely
+     *                    positioned, relative to where the page is drawn.)
+     *  @param surfceBBox The bounding box of the drawing surface (with matrix
+     *                    already applied).
+     */
+    static SkPDFObject* GetPDFShader(const SkShader& shader,
+                                     const SkMatrix& matrix,
+                                     const SkIRect& surfaceBBox);
+
+protected:
+    class State;
+
+    class ShaderCanonicalEntry {
+    public:
+        ShaderCanonicalEntry(SkPDFObject* pdfShader, const State* state);
+        bool operator==(const ShaderCanonicalEntry& b) const;
+
+        SkPDFObject* fPDFShader;
+        const State* fState;
+    };
+    // This should be made a hash table if performance is a problem.
+    static SkTDArray<ShaderCanonicalEntry>& CanonicalShaders();
+    static SkBaseMutex& CanonicalShadersMutex();
+    static void RemoveShader(SkPDFObject* shader);
+
+    SkPDFShader();
+};
+
+#endif
diff --git a/src/pdf/SkPDFStream.h b/src/pdf/SkPDFStream.h
new file mode 100644
index 0000000..b3a7ad3
--- /dev/null
+++ b/src/pdf/SkPDFStream.h
@@ -0,0 +1,75 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkPDFStream_DEFINED
+#define SkPDFStream_DEFINED
+
+#include "SkPDFTypes.h"
+#include "SkRefCnt.h"
+#include "SkStream.h"
+#include "SkTemplates.h"
+
+class SkPDFCatalog;
+
+/** \class SkPDFStream
+
+    A stream object in a PDF.  Note, all streams must be indirect objects (via
+    SkObjRef).
+*/
+class SkPDFStream : public SkPDFDict {
+public:
+    /** Create a PDF stream. A Length entry is automatically added to the
+     *  stream dictionary. The stream may be retained (stream->ref() may be
+     *  called) so its contents must not be changed after calling this.
+     *  @param data  The data part of the stream.
+     */
+    explicit SkPDFStream(SkData* data);
+    /** Deprecated constructor. */
+    explicit SkPDFStream(SkStream* stream);
+    /** Create a PDF stream with the same content and dictionary entries
+     *  as the passed one.
+     */
+    explicit SkPDFStream(const SkPDFStream& pdfStream);
+    virtual ~SkPDFStream();
+
+    // The SkPDFObject interface.
+    virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+                            bool indirect);
+    virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
+
+protected:
+    /* Create a PDF stream with no data.  The setData method must be called to
+     * set the data.
+     */
+    SkPDFStream();
+
+    void setData(SkStream* stream);
+
+private:
+    enum State {
+        kUnused_State,         //!< The stream hasn't been requested yet.
+        kNoCompression_State,  //!< The stream's been requested in an
+                               //   uncompressed form.
+        kCompressed_State,     //!< The stream's already been compressed.
+    };
+    // Indicates what form (or if) the stream has been requested.
+    State fState;
+
+    // TODO(vandebo): Use SkData (after removing deprecated constructor).
+    SkRefPtr<SkStream> fData;
+    SkRefPtr<SkPDFStream> fSubstitute;
+
+    typedef SkPDFDict INHERITED;
+
+    // Populate the stream dictionary.  This method returns false if
+    // fSubstitute should be used.
+    bool populate(SkPDFCatalog* catalog);
+};
+
+#endif
diff --git a/src/pdf/SkPDFTypes.h b/src/pdf/SkPDFTypes.h
new file mode 100644
index 0000000..6334938
--- /dev/null
+++ b/src/pdf/SkPDFTypes.h
@@ -0,0 +1,403 @@
+
+/*
+ * Copyright 2010 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.
+ */
+
+
+#ifndef SkPDFTypes_DEFINED
+#define SkPDFTypes_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkScalar.h"
+#include "SkString.h"
+#include "SkTDArray.h"
+#include "SkTypes.h"
+
+class SkPDFCatalog;
+class SkWStream;
+
+/** \class SkPDFObject
+
+    A PDF Object is the base class for primitive elements in a PDF file.  A
+    common subtype is used to ease the use of indirect object references,
+    which are common in the PDF format.
+*/
+class SkPDFObject : public SkRefCnt {
+public:
+    /** Create a PDF object.
+     */
+    SkPDFObject();
+    virtual ~SkPDFObject();
+
+    /** Return the size (number of bytes) of this object in the final output
+     *  file. Compound objects or objects that are computationally intensive
+     *  to output should override this method.
+     *  @param catalog  The object catalog to use.
+     *  @param indirect If true, output an object identifier with the object.
+     */
+    virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
+
+    /** For non-primitive objects (i.e. objects defined outside this file),
+     *  this method will add to resourceList any objects that this method
+     *  depends on.  This operates recursively so if this object depends on
+     *  another object and that object depends on two more, all three objects
+     *  will be added.
+     *  @param resourceList  The list to append dependant resources to.
+     */
+    virtual void getResources(SkTDArray<SkPDFObject*>* resourceList);
+
+    /** Emit this object unless the catalog has a substitute object, in which
+     *  case emit that.
+     *  @see emitObject
+     */
+    void emit(SkWStream* stream, SkPDFCatalog* catalog, bool indirect);
+
+    /** Helper function to output an indirect object.
+     *  @param catalog The object catalog to use.
+     *  @param stream  The writable output stream to send the output to.
+     */
+    void emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog);
+
+    /** Helper function to find the size of an indirect object.
+     *  @param catalog The object catalog to use.
+     */
+    size_t getIndirectOutputSize(SkPDFCatalog* catalog);
+
+    /** Static helper function to add a resource to a list.  The list takes
+     *  a reference.
+     * @param resource  The resource to add.
+     * @param list      The list to add the resource to.
+     */
+    static void AddResourceHelper(SkPDFObject* resource,
+                                  SkTDArray<SkPDFObject*>* list);
+
+    /** Static helper function to copy and reference the resources (and all
+     *   their subresources) into a new list.
+     * @param resources The resource list.
+     * @param result    The list to add to.
+     */
+    static void GetResourcesHelper(SkTDArray<SkPDFObject*>* resources,
+                                   SkTDArray<SkPDFObject*>* result);
+
+protected:
+    /** Subclasses must implement this method to print the object to the
+     *  PDF file.
+     *  @param catalog  The object catalog to use.
+     *  @param indirect If true, output an object identifier with the object.
+     *  @param stream   The writable output stream to send the output to.
+     */
+    virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+                            bool indirect) = 0;
+};
+
+/** \class SkPDFObjRef
+
+    An indirect reference to a PDF object.
+*/
+class SkPDFObjRef : public SkPDFObject {
+public:
+    /** Create a reference to an existing SkPDFObject.
+     *  @param obj The object to reference.
+     */
+    explicit SkPDFObjRef(SkPDFObject* obj);
+    virtual ~SkPDFObjRef();
+
+    // The SkPDFObject interface.
+    virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+                            bool indirect);
+    virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
+
+private:
+    SkRefPtr<SkPDFObject> fObj;
+};
+
+/** \class SkPDFInt
+
+    An integer object in a PDF.
+*/
+class SkPDFInt : public SkPDFObject {
+public:
+    /** Create a PDF integer (usually for indirect reference purposes).
+     *  @param value An integer value between 2^31 - 1 and -2^31.
+     */
+    explicit SkPDFInt(int32_t value);
+    virtual ~SkPDFInt();
+
+    // The SkPDFObject interface.
+    virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+                            bool indirect);
+
+private:
+    int32_t fValue;
+};
+
+/** \class SkPDFBool
+
+    An boolean value in a PDF.
+*/
+class SkPDFBool : public SkPDFObject {
+public:
+    /** Create a PDF boolean.
+     *  @param value true or false.
+     */
+    explicit SkPDFBool(bool value);
+    virtual ~SkPDFBool();
+
+    // The SkPDFObject interface.
+    virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+                            bool indirect);
+    virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
+
+private:
+    bool fValue;
+};
+
+/** \class SkPDFScalar
+
+    A real number object in a PDF.
+*/
+class SkPDFScalar : public SkPDFObject {
+public:
+    /** Create a PDF real number.
+     *  @param value A real value.
+     */
+    explicit SkPDFScalar(SkScalar value);
+    virtual ~SkPDFScalar();
+
+    static void Append(SkScalar value, SkWStream* stream);
+
+    // The SkPDFObject interface.
+    virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+                            bool indirect);
+
+private:
+    SkScalar fValue;
+};
+
+/** \class SkPDFString
+
+    A string object in a PDF.
+*/
+class SkPDFString : public SkPDFObject {
+public:
+    /** Create a PDF string. Maximum length (in bytes) is 65,535.
+     *  @param value A string value.
+     */
+    explicit SkPDFString(const char value[]);
+    explicit SkPDFString(const SkString& value);
+
+    /** Create a PDF string. Maximum length (in bytes) is 65,535.
+     *  @param value     A string value.
+     *  @param len       The length of value.
+     *  @param wideChars Indicates if the top byte in value is significant and
+     *                   should be encoded (true) or not (false).
+     */
+    SkPDFString(const uint16_t* value, size_t len, bool wideChars);
+    virtual ~SkPDFString();
+
+    // The SkPDFObject interface.
+    virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+                            bool indirect);
+    virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
+
+    static SkString FormatString(const char* input, size_t len);
+    static SkString FormatString(const uint16_t* input, size_t len,
+                                 bool wideChars);
+private:
+    static const size_t kMaxLen = 65535;
+
+    const SkString fValue;
+
+    static SkString DoFormatString(const void* input, size_t len,
+                                 bool wideInput, bool wideOutput);
+};
+
+/** \class SkPDFName
+
+    A name object in a PDF.
+*/
+class SkPDFName : public SkPDFObject {
+public:
+    /** Create a PDF name object. Maximum length is 127 bytes.
+     *  @param value The name.
+     */
+    explicit SkPDFName(const char name[]);
+    explicit SkPDFName(const SkString& name);
+    virtual ~SkPDFName();
+
+    bool operator==(const SkPDFName& b) const;
+
+    // The SkPDFObject interface.
+    virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+                            bool indirect);
+    virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
+
+private:
+    static const size_t kMaxLen = 127;
+
+    const SkString fValue;
+
+    static SkString FormatName(const SkString& input);
+};
+
+/** \class SkPDFArray
+
+    An array object in a PDF.
+*/
+class SkPDFArray : public SkPDFObject {
+public:
+    /** Create a PDF array. Maximum length is 8191.
+     */
+    SkPDFArray();
+    virtual ~SkPDFArray();
+
+    // The SkPDFObject interface.
+    virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+                            bool indirect);
+    virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
+
+    /** The size of the array.
+     */
+    int size() { return fValue.count(); }
+
+    /** Preallocate space for the given number of entries.
+     *  @param length The number of array slots to preallocate.
+     */
+    void reserve(int length);
+
+    /** Returns the object at the given offset in the array.
+     *  @param index The index into the array to retrieve.
+     */
+    SkPDFObject* getAt(int index) { return fValue[index]; }
+
+    /** Set the object at the given offset in the array. Ref's value.
+     *  @param index The index into the array to set.
+     *  @param value The value to add to the array.
+     *  @return The value argument is returned.
+     */
+    SkPDFObject* setAt(int index, SkPDFObject* value);
+
+    /** Append the object to the end of the array and increments its ref count.
+     *  @param value The value to add to the array.
+     *  @return The value argument is returned.
+     */
+    SkPDFObject* append(SkPDFObject* value);
+
+    /** Creates a SkPDFInt object and appends it to the array.
+     *  @param value The value to add to the array.
+     */
+    void appendInt(int32_t value);
+
+    /** Creates a SkPDFScalar object and appends it to the array.
+     *  @param value The value to add to the array.
+     */
+    void appendScalar(SkScalar value);
+
+    /** Creates a SkPDFName object and appends it to the array.
+     *  @param value The value to add to the array.
+     */
+    void appendName(const char name[]);
+
+private:
+    static const int kMaxLen = 8191;
+    SkTDArray<SkPDFObject*> fValue;
+};
+
+/** \class SkPDFDict
+
+    A dictionary object in a PDF.
+*/
+class SkPDFDict : public SkPDFObject {
+public:
+    /** Create a PDF dictionary. Maximum number of entries is 4095.
+     */
+    SkPDFDict();
+
+    /** Create a PDF dictionary with a Type entry.
+     *  @param type   The value of the Type entry.
+     */
+    explicit SkPDFDict(const char type[]);
+
+    virtual ~SkPDFDict();
+
+    // The SkPDFObject interface.
+    virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+                            bool indirect);
+    virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
+
+    /** The size of the dictionary.
+     */
+    int size() { return fValue.count(); }
+
+    /** Add the value to the dictionary with the given key.  Refs value.
+     *  @param key   The key for this dictionary entry.
+     *  @param value The value for this dictionary entry.
+     *  @return The value argument is returned.
+     */
+    SkPDFObject* insert(SkPDFName* key, SkPDFObject* value);
+
+    /** Add the value to the dictionary with the given key.  Refs value.  The
+     *  method will create the SkPDFName object.
+     *  @param key   The text of the key for this dictionary entry.
+     *  @param value The value for this dictionary entry.
+     *  @return The value argument is returned.
+     */
+    SkPDFObject* insert(const char key[], SkPDFObject* value);
+
+    /** Add the int to the dictionary with the given key.
+     *  @param key   The text of the key for this dictionary entry.
+     *  @param value The int value for this dictionary entry.
+     */
+    void insertInt(const char key[], int32_t value);
+
+    /** Add the scalar to the dictionary with the given key.
+     *  @param key   The text of the key for this dictionary entry.
+     *  @param value The scalar value for this dictionary entry.
+     */
+    void insertScalar(const char key[], SkScalar value);
+
+    /** Add the name to the dictionary with the given key.
+     *  @param key   The text of the key for this dictionary entry.
+     *  @param name  The name for this dictionary entry.
+     */
+    void insertName(const char key[], const char name[]);
+
+    /** Add the name to the dictionary with the given key.
+     *  @param key   The text of the key for this dictionary entry.
+     *  @param name  The name for this dictionary entry.
+     */
+    void insertName(const char key[], const SkString& name) {
+        this->insertName(key, name.c_str());
+    }
+
+    /** Remove all entries from the dictionary.
+     */
+    void clear();
+
+private:
+    struct Rec {
+      SkPDFName* key;
+      SkPDFObject* value;
+    };
+
+public:
+    class Iter {
+    public:
+        explicit Iter(const SkPDFDict& dict);
+        SkPDFName* next(SkPDFObject** value);
+
+    private:
+        Rec* fIter;
+        Rec* fStop;
+    };
+
+private:
+    static const int kMaxLen = 4095;
+
+    SkTDArray<struct Rec> fValue;
+};
+
+#endif
diff --git a/src/pdf/SkPDFUtils.h b/src/pdf/SkPDFUtils.h
new file mode 100644
index 0000000..5b9d74e
--- /dev/null
+++ b/src/pdf/SkPDFUtils.h
@@ -0,0 +1,54 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkPDFUtils_DEFINED
+#define SkPDFUtils_DEFINED
+
+#include "SkPath.h"
+
+class SkMatrix;
+class SkPath;
+class SkPDFArray;
+struct SkRect;
+
+#if 0
+#define PRINT_NOT_IMPL(str) fprintf(stderr, str)
+#else
+#define PRINT_NOT_IMPL(str)
+#endif
+
+#define NOT_IMPLEMENTED(condition, assert)                         \
+    do {                                                           \
+        if (condition) {                                           \
+            PRINT_NOT_IMPL("NOT_IMPLEMENTED: " #condition "\n");   \
+            SkDEBUGCODE(SkASSERT(!assert);)                        \
+        }                                                          \
+    } while (0)
+
+class SkPDFUtils {
+public:
+    static SkPDFArray* MatrixToArray(const SkMatrix& matrix);
+    static void AppendTransform(const SkMatrix& matrix, SkWStream* content);
+
+    static void MoveTo(SkScalar x, SkScalar y, SkWStream* content);
+    static void AppendLine(SkScalar x, SkScalar y, SkWStream* content);
+    static void AppendCubic(SkScalar ctl1X, SkScalar ctl1Y,
+                            SkScalar ctl2X, SkScalar ctl2Y,
+                            SkScalar dstX, SkScalar dstY, SkWStream* content);
+    static void AppendRectangle(const SkRect& rect, SkWStream* content);
+    static void EmitPath(const SkPath& path, SkWStream* content);
+    static void ClosePath(SkWStream* content);
+    static void PaintPath(SkPaint::Style style, SkPath::FillType fill,
+                          SkWStream* content);
+    static void StrokePath(SkWStream* content);
+    static void DrawFormXObject(int objectIndex, SkWStream* content);
+    static void ApplyGraphicState(int objectIndex, SkWStream* content);
+};
+
+#endif