[PDF] Improve efficiency of glyph id collection during font subsetting.

Patch from Arthur Hsu, original CL: http://codereview.appspot.com/4828044/

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

git-svn-id: http://skia.googlecode.com/svn/trunk@1978 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/pdf/SkBitSet.h b/include/pdf/SkBitSet.h
index 01d9c6c..b72a895 100755
--- a/include/pdf/SkBitSet.h
+++ b/include/pdf/SkBitSet.h
@@ -18,6 +18,7 @@
 #define SkBitSet_DEFINED
 
 #include "SkTypes.h"
+#include "SkTDArray.h"
 
 class SkBitSet {
 public:
@@ -47,6 +48,10 @@
      */
     bool orBits(const SkBitSet& source);
 
+    /** Export set bits to unsigned int array. (used in font subsetting)
+     */
+    void exportTo(SkTDArray<uint32_t>* array) const;
+
 private:
     SkAutoFree fBitData;
     // Dword (32-bit) count of the bitset.
diff --git a/include/pdf/SkPDFFont.h b/include/pdf/SkPDFFont.h
index 00dcb95..a37fec1 100644
--- a/include/pdf/SkPDFFont.h
+++ b/include/pdf/SkPDFFont.h
@@ -35,6 +35,7 @@
     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;
diff --git a/src/pdf/SkBitSet.cpp b/src/pdf/SkBitSet.cpp
index c7af832..4f2b335 100755
--- a/src/pdf/SkBitSet.cpp
+++ b/src/pdf/SkBitSet.cpp
@@ -89,3 +89,19 @@
     }
     return true;
 }
+
+void SkBitSet::exportTo(SkTDArray<uint32_t>* array) const {
+    SkASSERT(array);
+    uint32_t* data = (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);
+                }
+            }
+        }
+    }
+}
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index fce1202..5c2c00e 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -448,13 +448,9 @@
 
 #if defined (SK_SFNTLY_SUBSETTER)
     // Generate glyph id array.
-    SkTDArray<unsigned int> glyphIDs;
+    SkTDArray<uint32_t> glyphIDs;
     glyphIDs.push(0);  // Always include glyph 0.
-    for (int i = 0; i <= SK_MaxU16; ++i) {
-        if (subset->has(i)) {
-            glyphIDs.push(i);
-        }
-    }
+    subset->exportTo(&glyphIDs);
 
     // Read font into buffer.
     SkPDFStream* subsetFontStream = NULL;
@@ -462,6 +458,10 @@
     originalFont.setCount(fontSize);
     if (fontData->read(originalFont.begin(), fontSize) == (size_t)fontSize) {
         unsigned char* subsetFont = NULL;
+        // sfntly requires unsigned int* to be passed in, as far as we know,
+        // unsigned int is equivalent to uint32_t on all platforms.
+        SK_COMPILE_ASSERT(sizeof(unsigned int) == sizeof(uint32_t),
+                          unsigned_int_not_32_bits);
         int subsetFontSize = SfntlyWrapper::SubsetFont(fontName,
                                                        originalFont.begin(),
                                                        fontSize,
@@ -509,6 +509,10 @@
     fBitSet.orBits(usage.fBitSet);
 }
 
+void SkPDFGlyphSet::exportTo(SkTDArray<unsigned int>* glyphIDs) const {
+    fBitSet.exportTo(glyphIDs);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // class SkPDFGlyphSetMap
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/tests/BitSetTest.cpp b/tests/BitSetTest.cpp
index 96bf80f..c7f2073 100644
--- a/tests/BitSetTest.cpp
+++ b/tests/BitSetTest.cpp
@@ -21,6 +21,12 @@
     REPORTER_ASSERT(reporter, set0.isBitSet(24) == true);
     REPORTER_ASSERT(reporter, set0.isBitSet(35) == true);
 
+    SkTDArray<unsigned int> data;
+    set0.exportTo(&data);
+    REPORTER_ASSERT(reporter, data.count() == 2);
+    REPORTER_ASSERT(reporter, data[0] == 24);
+    REPORTER_ASSERT(reporter, data[1] == 35);
+
     set1.setBit(12345, true);
     set1.orBits(set0);
     REPORTER_ASSERT(reporter, set0.isBitSet(12345) == false);