[PDF] Add font subsetting using the sfntly library.

Patch from Arthur Hsu, original CL: http://codereview.chromium.org/7513003/

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

git-svn-id: http://skia.googlecode.com/svn/trunk@1957 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index f50580a..0191cb1 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -34,6 +34,10 @@
 #include "SkTypes.h"
 #include "SkUtils.h"
 
+#if defined (SK_SFNTLY_SUBSETTER)
+#include SK_SFNTLY_SUBSETTER
+#endif
+
 namespace {
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -427,6 +431,63 @@
     return new SkPDFStream(cmapStream.get());
 }
 
+static void sk_delete_array(const void* ptr, size_t, void*) {
+    // Use C-style cast to cast away const and cast type simultaneously.
+    delete[] (unsigned char*)ptr;
+}
+
+static int get_subset_font_stream(const char* fontName,
+                                  const SkTypeface* typeface,
+                                  const SkPDFGlyphSet* subset,
+                                  SkPDFStream** fontStream) {
+    SkRefPtr<SkStream> fontData =
+            SkFontHost::OpenStream(SkTypeface::UniqueID(typeface));
+    fontData->unref();  // SkRefPtr and OpenStream both took a ref.
+
+    int fontSize = fontData->getLength();
+
+#if defined (SK_SFNTLY_SUBSETTER)
+    // Generate glyph id array.
+    SkTDArray<unsigned int> glyphIDs;
+    glyphIDs.push(0);  // Always include glyph 0.
+    for (int i = 0; i <= SK_MaxU16; ++i) {
+        if (subset->has(i)) {
+            glyphIDs.push(i);
+        }
+    }
+
+    // Read font into buffer.
+    SkPDFStream* subsetFontStream = NULL;
+    SkTDArray<unsigned char> originalFont;
+    originalFont.setCount(fontSize);
+    if (fontData->read(originalFont.begin(), fontSize) == (size_t)fontSize) {
+        unsigned char* subsetFont = NULL;
+        int subsetFontSize = SfntlyWrapper::SubsetFont(fontName,
+                                                       originalFont.begin(),
+                                                       fontSize,
+                                                       glyphIDs.begin(),
+                                                       glyphIDs.count(),
+                                                       &subsetFont);
+        if (subsetFontSize > 0 && subsetFont != NULL) {
+            SkData* data = SkData::NewWithProc(subsetFont,
+                                               subsetFontSize,
+                                               sk_delete_array,
+                                               NULL);
+            subsetFontStream = new SkPDFStream(data);
+            fontSize = subsetFontSize;
+        }
+    }
+    if (subsetFontStream) {
+        *fontStream = subsetFontStream;
+        return fontSize;
+    }
+#endif
+
+    // Fail over: just embed the whole font.
+    *fontStream = new SkPDFStream(fontData.get());
+    return fontSize;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // class SkPDFGlyphSet
 ///////////////////////////////////////////////////////////////////////////////
@@ -858,15 +919,19 @@
 
     switch (getType()) {
         case SkAdvancedTypefaceMetrics::kTrueType_Font: {
-            // TODO(arthurhsu): sfntly font subsetting
-            SkRefPtr<SkStream> fontData =
-                SkFontHost::OpenStream(SkTypeface::UniqueID(typeface()));
-            fontData->unref();  // SkRefPtr and OpenStream both took a ref.
-            SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
+            // Font subsetting
+            SkPDFStream* rawStream = NULL;
+            int fontSize = get_subset_font_stream(fontInfo()->fFontName.c_str(),
+                                                  typeface(),
+                                                  subset,
+                                                  &rawStream);
+            SkASSERT(fontSize);
+            SkASSERT(rawStream);
+            SkRefPtr<SkPDFStream> fontStream = rawStream;
             // SkRefPtr and new both ref()'d fontStream, pass one.
             addResource(fontStream.get());
 
-            fontStream->insertInt("Length1", fontData->getLength());
+            fontStream->insertInt("Length1", fontSize);
             descriptor->insert("FontFile2",
                                 new SkPDFObjRef(fontStream.get()))->unref();
             break;