Serialize the font index.

BUG=skia:1186
R=reed@google.com

Author: bungeman@google.com

Review URL: https://codereview.chromium.org/567013002
diff --git a/include/core/SkRefCnt.h b/include/core/SkRefCnt.h
index f092e77..459ad25 100644
--- a/include/core/SkRefCnt.h
+++ b/include/core/SkRefCnt.h
@@ -234,7 +234,7 @@
     BlockRefType *operator->() const {
         return static_cast<BlockRefType*>(fObj);
     }
-    operator T*() { return fObj; }
+    operator T*() const { return fObj; }
 
 private:
     T*  fObj;
diff --git a/include/core/SkTypeface.h b/include/core/SkTypeface.h
index 1df467a..cb87a6a 100644
--- a/include/core/SkTypeface.h
+++ b/include/core/SkTypeface.h
@@ -114,13 +114,13 @@
     /** Return a new typeface given a file. If the file does not exist, or is
         not a valid font file, returns null.
     */
-    static SkTypeface* CreateFromFile(const char path[]);
+    static SkTypeface* CreateFromFile(const char path[], int index = 0);
 
     /** Return a new typeface given a stream. If the stream is
         not a valid font file, returns null. Ownership of the stream is
         transferred, so the caller must not reference it again.
     */
-    static SkTypeface* CreateFromStream(SkStream* stream);
+    static SkTypeface* CreateFromStream(SkStream* stream, int index = 0);
 
     /** Write a unique signature to a stream, sufficient to reconstruct a
         typeface referencing the same font when Deserialize is called.
diff --git a/src/core/SkFontDescriptor.cpp b/src/core/SkFontDescriptor.cpp
index 5088ed7..7426894 100644
--- a/src/core/SkFontDescriptor.cpp
+++ b/src/core/SkFontDescriptor.cpp
@@ -7,6 +7,7 @@
 
 #include "SkFontDescriptor.h"
 #include "SkStream.h"
+#include <SkData.h>
 
 enum {
     // these must match the sfnt 'name' enums
@@ -16,13 +17,12 @@
 
     // These count backwards from 0xFF, so as not to collide with the SFNT
     // defines for names in its 'name' table.
+    kFontIndex      = 0xFD,
     kFontFileName   = 0xFE,
     kSentinel       = 0xFF,
 };
 
-SkFontDescriptor::SkFontDescriptor(SkTypeface::Style style) {
-    fStyle = style;
-}
+SkFontDescriptor::SkFontDescriptor(SkTypeface::Style style) : fFontIndex(0), fStyle(style) { }
 
 static void read_string(SkStream* stream, SkString* string) {
     const uint32_t length = SkToU32(stream->readPackedUInt());
@@ -41,11 +41,20 @@
     }
 }
 
-SkFontDescriptor::SkFontDescriptor(SkStream* stream) {
+static size_t read_uint(SkStream* stream) {
+    return stream->readPackedUInt();
+}
+
+static void write_uint(SkWStream* stream, size_t n, uint32_t id) {
+    stream->writePackedUInt(id);
+    stream->writePackedUInt(n);
+}
+
+SkFontDescriptor::SkFontDescriptor(SkStream* stream) : fFontIndex(0) {
     fStyle = (SkTypeface::Style)stream->readPackedUInt();
 
-    for (;;) {
-        switch (stream->readPackedUInt()) {
+    for (size_t id; (id = stream->readPackedUInt()) != kSentinel;) {
+        switch (id) {
             case kFontFamilyName:
                 read_string(stream, &fFamilyName);
                 break;
@@ -55,16 +64,25 @@
             case kPostscriptName:
                 read_string(stream, &fPostscriptName);
                 break;
+            case kFontIndex:
+                fFontIndex = read_uint(stream);
+                break;
             case kFontFileName:
                 read_string(stream, &fFontFileName);
                 break;
-            case kSentinel:
-                return;
             default:
                 SkDEBUGFAIL("Unknown id used by a font descriptor");
                 return;
         }
     }
+
+    size_t length = stream->readPackedUInt();
+    if (length > 0) {
+        SkAutoTUnref<SkData> data(SkData::NewUninitialized(length));
+        if (stream->read(data->writable_data(), length) == length) {
+            fFontData.reset(SkNEW_ARGS(SkMemoryStream, (data)));
+        }
+    }
 }
 
 void SkFontDescriptor::serialize(SkWStream* stream) {
@@ -74,6 +92,17 @@
     write_string(stream, fFullName, kFullName);
     write_string(stream, fPostscriptName, kPostscriptName);
     write_string(stream, fFontFileName, kFontFileName);
+    if (fFontIndex) {
+        write_uint(stream, fFontIndex, kFontIndex);
+    }
 
     stream->writePackedUInt(kSentinel);
+
+    if (fFontData) {
+        size_t length = fFontData->getLength();
+        stream->writePackedUInt(length);
+        stream->writeStream(fFontData, length);
+    } else {
+        stream->writePackedUInt(0);
+    }
 }
diff --git a/src/core/SkFontDescriptor.h b/src/core/SkFontDescriptor.h
index 5febfd8..5a6ddd5 100644
--- a/src/core/SkFontDescriptor.h
+++ b/src/core/SkFontDescriptor.h
@@ -8,10 +8,10 @@
 #ifndef SkFontDescriptor_DEFINED
 #define SkFontDescriptor_DEFINED
 
+#include "SkStream.h"
 #include "SkString.h"
 #include "SkTypeface.h"
 
-class SkStream;
 class SkWStream;
 
 class SkFontDescriptor {
@@ -24,21 +24,30 @@
     SkTypeface::Style getStyle() { return fStyle; }
     void setStyle(SkTypeface::Style style) { fStyle = style; }
 
-    const char* getFamilyName() { return fFamilyName.c_str(); }
-    const char* getFullName() { return fFullName.c_str(); }
-    const char* getPostscriptName() { return fPostscriptName.c_str(); }
-    const char* getFontFileName() { return fFontFileName.c_str(); }
+    const char* getFamilyName() const { return fFamilyName.c_str(); }
+    const char* getFullName() const { return fFullName.c_str(); }
+    const char* getPostscriptName() const { return fPostscriptName.c_str(); }
+    const char* getFontFileName() const { return fFontFileName.c_str(); }
+    SkStream* getFontData() const { return fFontData; }
+    int getFontIndex() const { return fFontIndex; }
 
     void setFamilyName(const char* name) { fFamilyName.set(name); }
     void setFullName(const char* name) { fFullName.set(name); }
     void setPostscriptName(const char* name) { fPostscriptName.set(name); }
     void setFontFileName(const char* name) { fFontFileName.set(name); }
+    /** Set the font data only if it is necessary for serialization.
+     *  This method takes ownership of the stream (both reference and cursor).
+     */
+    void setFontData(SkStream* stream) { fFontData.reset(stream); }
+    void setFontIndex(int index) { fFontIndex = index; }
 
 private:
     SkString fFamilyName;
     SkString fFullName;
     SkString fPostscriptName;
     SkString fFontFileName;
+    SkAutoTUnref<SkStream> fFontData;
+    int fFontIndex;
 
     SkTypeface::Style fStyle;
 };
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 1c2f8e8..88bde22 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -2308,19 +2308,15 @@
 
 #ifndef SK_IGNORE_TO_STRING
 
-static SkFontDescriptor typeface_getDescriptor(const SkTypeface* face) {
-    SkDynamicMemoryWStream ostream;
-    face->serialize(&ostream);
-    SkAutoTUnref<SkStreamAsset> istream(ostream.detachAsStream());
-    return SkFontDescriptor(istream);
-}
-
 void SkPaint::toString(SkString* str) const {
     str->append("<dl><dt>SkPaint:</dt><dd><dl>");
 
     SkTypeface* typeface = this->getTypeface();
     if (typeface) {
-        SkFontDescriptor descriptor(typeface_getDescriptor(typeface));
+        SkDynamicMemoryWStream ostream;
+        typeface->serialize(&ostream);
+        SkAutoTUnref<SkStreamAsset> istream(ostream.detachAsStream());
+        SkFontDescriptor descriptor(istream);
 
         str->append("<dt>Font Family Name:</dt><dd>");
         str->append(descriptor.getFamilyName());
diff --git a/src/core/SkTypeface.cpp b/src/core/SkTypeface.cpp
index 74dd5d9..d7da131 100644
--- a/src/core/SkTypeface.cpp
+++ b/src/core/SkTypeface.cpp
@@ -147,14 +147,14 @@
     return fm->matchFaceStyle(family, newStyle);
 }
 
-SkTypeface* SkTypeface::CreateFromStream(SkStream* stream) {
+SkTypeface* SkTypeface::CreateFromStream(SkStream* stream, int index) {
     SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
-    return fm->createFromStream(stream);
+    return fm->createFromStream(stream, index);
 }
 
-SkTypeface* SkTypeface::CreateFromFile(const char path[]) {
+SkTypeface* SkTypeface::CreateFromFile(const char path[], int index) {
     SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
-    return fm->createFromFile(path);
+    return fm->createFromFile(path, index);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -164,45 +164,24 @@
     SkFontDescriptor desc(this->style());
     this->onGetFontDescriptor(&desc, &isLocal);
 
-    desc.serialize(wstream);
-    if (isLocal) {
-        int ttcIndex;   // TODO: write this to the stream?
-        SkAutoTUnref<SkStream> rstream(this->openStream(&ttcIndex));
-        if (rstream.get()) {
-            size_t length = rstream->getLength();
-            wstream->writePackedUInt(length);
-            wstream->writeStream(rstream, length);
-        } else {
-            wstream->writePackedUInt(0);
-        }
-    } else {
-        wstream->writePackedUInt(0);
+    if (isLocal && NULL == desc.getFontData()) {
+        int ttcIndex;
+        desc.setFontData(this->onOpenStream(&ttcIndex));
+        desc.setFontIndex(ttcIndex);
     }
+
+    desc.serialize(wstream);
 }
 
 SkTypeface* SkTypeface::Deserialize(SkStream* stream) {
     SkFontDescriptor desc(stream);
-    size_t length = stream->readPackedUInt();
-    if (length > 0) {
-        void* addr = sk_malloc_flags(length, 0);
-        if (addr) {
-            SkAutoTUnref<SkMemoryStream> localStream(SkNEW(SkMemoryStream));
-            localStream->setMemoryOwned(addr, length);
-
-            if (stream->read(addr, length) == length) {
-                return SkTypeface::CreateFromStream(localStream.get());
-            } else {
-                // Failed to read the full font data, so fall through and try to create from name.
-                // If this is because of EOF, all subsequent reads from the stream will be EOF.
-                // If this is because of a stream error, the stream is in an error state,
-                // do not attempt to skip any remaining bytes.
-            }
-        } else {
-            // failed to allocate, so just skip and create-from-name
-            stream->skip(length);
+    SkStream* data = desc.getFontData();
+    if (data) {
+        SkTypeface* typeface = SkTypeface::CreateFromStream(data, desc.getFontIndex());
+        if (typeface) {
+            return typeface;
         }
     }
-
     return SkTypeface::CreateFromName(desc.getFamilyName(), desc.getStyle());
 }
 
diff --git a/src/ports/SkFontHost_fontconfig.cpp b/src/ports/SkFontHost_fontconfig.cpp
index 57252d0..b3a893e 100644
--- a/src/ports/SkFontHost_fontconfig.cpp
+++ b/src/ports/SkFontHost_fontconfig.cpp
@@ -169,5 +169,6 @@
 void FontConfigTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
                                              bool* isLocalStream) const {
     desc->setFamilyName(this->getFamilyName());
+    desc->setFontIndex(this->getIdentity().fTTCIndex);
     *isLocalStream = SkToBool(this->getLocalStream());
 }
diff --git a/src/ports/SkFontHost_linux.cpp b/src/ports/SkFontHost_linux.cpp
index 2904cac..a4202aa 100644
--- a/src/ports/SkFontHost_linux.cpp
+++ b/src/ports/SkFontHost_linux.cpp
@@ -30,9 +30,10 @@
 /** The base SkTypeface implementation for the custom font manager. */
 class SkTypeface_Custom : public SkTypeface_FreeType {
 public:
-    SkTypeface_Custom(Style style, bool isFixedPitch, bool sysFont, const SkString familyName)
+    SkTypeface_Custom(Style style, bool isFixedPitch,
+                      bool sysFont, const SkString familyName, int index)
         : INHERITED(style, SkTypefaceCache::NewFontID(), isFixedPitch)
-        , fIsSysFont(sysFont), fFamilyName(familyName)
+        , fIsSysFont(sysFont), fFamilyName(familyName), fIndex(index)
     { }
 
     bool isSysFont() const { return fIsSysFont; }
@@ -47,12 +48,16 @@
     virtual void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const SK_OVERRIDE {
         desc->setFamilyName(fFamilyName.c_str());
         desc->setFontFileName(this->getUniqueString());
+        desc->setFontIndex(fIndex);
         *isLocal = !this->isSysFont();
     }
 
+    int getIndex() const { return fIndex; }
+
 private:
-    bool fIsSysFont;
-    SkString fFamilyName;
+    const bool fIsSysFont;
+    const SkString fFamilyName;
+    const int fIndex;
 
     typedef SkTypeface_FreeType INHERITED;
 };
@@ -62,7 +67,7 @@
  */
 class SkTypeface_Empty : public SkTypeface_Custom {
 public:
-    SkTypeface_Empty() : INHERITED(SkTypeface::kNormal, false, true, SkString()) {}
+    SkTypeface_Empty() : INHERITED(SkTypeface::kNormal, false, true, SkString(), 0) {}
 
     virtual const char* getUniqueString() const SK_OVERRIDE { return NULL; }
 
@@ -78,21 +83,20 @@
 public:
     SkTypeface_Stream(Style style, bool isFixedPitch, bool sysFont, const SkString familyName,
                       SkStream* stream, int ttcIndex)
-        : INHERITED(style, isFixedPitch, sysFont, familyName)
-        , fStream(SkRef(stream)), fTtcIndex(ttcIndex)
+        : INHERITED(style, isFixedPitch, sysFont, familyName, ttcIndex)
+        , fStream(SkRef(stream))
     { }
 
     virtual const char* getUniqueString() const SK_OVERRIDE { return NULL; }
 
 protected:
     virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
-        *ttcIndex = 0;
+        *ttcIndex = this->getIndex();
         return fStream->duplicate();
     }
 
 private:
-    SkAutoTUnref<SkStream> fStream;
-    int fTtcIndex;
+    const SkAutoTUnref<const SkStream> fStream;
 
     typedef SkTypeface_Custom INHERITED;
 };
@@ -101,8 +105,8 @@
 class SkTypeface_File : public SkTypeface_Custom {
 public:
     SkTypeface_File(Style style, bool isFixedPitch, bool sysFont, const SkString familyName,
-                    const char path[])
-        : INHERITED(style, isFixedPitch, sysFont, familyName)
+                    const char path[], int index)
+        : INHERITED(style, isFixedPitch, sysFont, familyName, index)
         , fPath(path)
     { }
 
@@ -116,7 +120,7 @@
 
 protected:
     virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
-        *ttcIndex = 0;
+        *ttcIndex = this->getIndex();
         return SkStream::NewFromFile(fPath.c_str());
     }
 
@@ -343,7 +347,7 @@
                                                 isFixedPitch,
                                                 true,  // system-font (cannot delete)
                                                 realname,
-                                                filename.c_str()));
+                                                filename.c_str(), 0));
 
             SkFontStyleSet_Custom* addTo = this->onMatchFamily(realname.c_str());
             if (NULL == addTo) {
diff --git a/src/ports/SkFontMgr_android.cpp b/src/ports/SkFontMgr_android.cpp
index 2fee735..5e93bf8 100644
--- a/src/ports/SkFontMgr_android.cpp
+++ b/src/ports/SkFontMgr_android.cpp
@@ -81,6 +81,7 @@
         SkASSERT(serialize);
         desc->setFamilyName(fFamilyName.c_str());
         desc->setFontFileName(fPathName.c_str());
+        desc->setFontIndex(fIndex);
         *serialize = false;
     }
     virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
diff --git a/src/ports/SkFontMgr_fontconfig.cpp b/src/ports/SkFontMgr_fontconfig.cpp
index f4cae23..00b962a 100644
--- a/src/ports/SkFontMgr_fontconfig.cpp
+++ b/src/ports/SkFontMgr_fontconfig.cpp
@@ -394,7 +394,7 @@
     }
 
     virtual void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const SK_OVERRIDE {
-        desc->setStyle(this->style());
+        desc->setFontIndex(fIndex);
         *serialize = true;
     }
 
@@ -425,10 +425,10 @@
     virtual void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const SK_OVERRIDE {
         FCLocker lock;
         desc->setFamilyName(get_string(fPattern, FC_FAMILY));
-        desc->setFontFileName(get_string(fPattern, FC_FILE));
         desc->setFullName(get_string(fPattern, FC_FULLNAME));
         desc->setPostscriptName(get_string(fPattern, FC_POSTSCRIPT_NAME));
-        desc->setStyle(this->style());
+        desc->setFontFileName(get_string(fPattern, FC_FILE));
+        desc->setFontIndex(get_int(fPattern, FC_INDEX, 0));
         *serialize = false;
     }
 
diff --git a/src/ports/SkTypeface_win_dw.cpp b/src/ports/SkTypeface_win_dw.cpp
index 9c2b41d..8b9ed16 100644
--- a/src/ports/SkTypeface_win_dw.cpp
+++ b/src/ports/SkTypeface_win_dw.cpp
@@ -42,6 +42,7 @@
     sk_get_locale_string(familyNames.get(), NULL/*fMgr->fLocaleName.get()*/, &utf8FamilyName);
 
     desc->setFamilyName(utf8FamilyName.c_str());
+    desc->setFontIndex(fDWriteFontFace->GetIndex());
     *isLocalStream = SkToBool(fDWriteFontFileLoader.get());
 }
 
diff --git a/tests/SerializationTest.cpp b/tests/SerializationTest.cpp
index 23cc33d..b6ee978 100644
--- a/tests/SerializationTest.cpp
+++ b/tests/SerializationTest.cpp
@@ -301,7 +301,7 @@
         return;
     }
     SkString filename = SkOSPath::Join(resourcePath.c_str(), "test.ttc");
-    SkTypeface* typeface = SkTypeface::CreateFromFile(filename.c_str());
+    SkTypeface* typeface = SkTypeface::CreateFromFile(filename.c_str(), 1);
     if (!typeface) {
         SkDebugf("Could not run fontstream test because test.ttc not found.");
         return;
@@ -320,7 +320,7 @@
                                                SkIntToScalar(canvasRect.height()), 
                                                NULL, 0);
     canvas->drawColor(SK_ColorWHITE);
-    canvas->drawText("A", 1, 24, 32, paint);
+    canvas->drawText("A!", 2, 24, 32, paint);
     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
     // Serlialize picture and create its clone from stream.