Merge from Chromium at DEPS revision 237746

This commit was generated by merge_to_master.py.

Change-Id: If4ff821474cc985d0bc16bc22c8180c8bec48014
diff --git a/sample/chromium/chrome_subsetter.cc b/sample/chromium/chrome_subsetter.cc
new file mode 100644
index 0000000..df15c18
--- /dev/null
+++ b/sample/chromium/chrome_subsetter.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 <stdio.h>
+
+#include <vector>
+#include <string>
+#include <sstream>
+
+#include "sfntly/port/type.h"
+#include "font_subsetter.h"
+
+template <typename T>
+class HexTo {
+ public:
+  explicit HexTo(const char* in) {
+    std::stringstream ss;
+    ss << std::hex << in;
+    ss >> value_;
+  }
+  operator T() const { return value_; }
+
+ private:
+  T value_;
+};
+
+bool LoadFile(const char* input_file_path, sfntly::ByteVector* input_buffer) {
+  assert(input_file_path);
+  assert(input_buffer);
+
+  FILE* input_file = NULL;
+#if defined WIN32
+  fopen_s(&input_file, input_file_path, "rb");
+#else
+  input_file = fopen(input_file_path, "rb");
+#endif
+  if (input_file == NULL) {
+    return false;
+  }
+  fseek(input_file, 0, SEEK_END);
+  size_t file_size = ftell(input_file);
+  fseek(input_file, 0, SEEK_SET);
+  input_buffer->resize(file_size);
+  size_t bytes_read = fread(&((*input_buffer)[0]), 1, file_size, input_file);
+  fclose(input_file);
+  return bytes_read == file_size;
+}
+
+bool SaveFile(const char* output_file_path, const unsigned char* output_buffer,
+              int buffer_length) {
+  int byte_count = 0;
+  if (buffer_length > 0) {
+    FILE* output_file = NULL;
+#if defined WIN32
+    fopen_s(&output_file, output_file_path, "wb");
+#else
+    output_file = fopen(output_file_path, "wb");
+#endif
+    if (output_file) {
+      byte_count = fwrite(output_buffer, 1, buffer_length, output_file);
+      fflush(output_file);
+      fclose(output_file);
+    }
+    return buffer_length == byte_count;
+  }
+  return false;
+}
+
+bool StringToGlyphId(const char* input, std::vector<unsigned int>* glyph_ids) {
+  assert(input);
+  std::string hex_csv = input;
+  size_t start = 0;
+  size_t end = hex_csv.find_first_of(",");
+  while (end != std::string::npos) {
+    glyph_ids->push_back(
+        HexTo<unsigned int>(hex_csv.substr(start, end - start).c_str()));
+    start = end + 1;
+    end = hex_csv.find_first_of(",", start);
+  }
+  glyph_ids->push_back(HexTo<unsigned int>(hex_csv.substr(start).c_str()));
+  return glyph_ids->size() > 0;
+}
+
+int main(int argc, char** argv) {
+  if (argc < 5) {
+    fprintf(stderr,
+        "Usage: %s <input path> <output path> <font name> <glyph ids>\n",
+        argv[0]);
+    fprintf(stderr, "\tGlyph ids are comma separated hex values\n");
+    fprintf(stderr, "\te.g. 20,1a,3b,4f\n");
+    return 0;
+  }
+
+  sfntly::ByteVector input_buffer;
+  if (!LoadFile(argv[1], &input_buffer)) {
+    fprintf(stderr, "ERROR: unable to load font file %s\n", argv[1]);
+    return 0;
+  }
+
+  std::vector<unsigned int> glyph_ids;
+  if (!StringToGlyphId(argv[4], &glyph_ids)) {
+    fprintf(stderr, "ERROR: unable to parse input glyph id\n");
+    return 0;
+  }
+
+  unsigned char* output_buffer = NULL;
+  int output_length =
+      SfntlyWrapper::SubsetFont(argv[3],
+                                &(input_buffer[0]),
+                                input_buffer.size(),
+                                &(glyph_ids[0]),
+                                glyph_ids.size(),
+                                &output_buffer);
+
+  int result = SaveFile(argv[2], output_buffer, output_length) ? 1 : 0;
+  delete[] output_buffer;
+  return result;
+}
diff --git a/sample/chromium/font_subsetter.cc b/sample/chromium/font_subsetter.cc
new file mode 100644
index 0000000..14f5494
--- /dev/null
+++ b/sample/chromium/font_subsetter.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "font_subsetter.h"
+
+#include "subsetter_impl.h"
+
+int SfntlyWrapper::SubsetFont(const char* font_name,
+                              const unsigned char* original_font,
+                              size_t font_size,
+                              const unsigned int* glyph_ids,
+                              size_t glyph_count,
+                              unsigned char** output_buffer) {
+  if (output_buffer == NULL ||
+      original_font == NULL || font_size == 0 ||
+      glyph_ids == NULL || glyph_count == 0) {
+    return 0;
+  }
+
+  sfntly::SubsetterImpl subsetter;
+  if (!subsetter.LoadFont(font_name, original_font, font_size)) {
+    return -1;  // Load error or font not found.
+  }
+
+  return subsetter.SubsetFont(glyph_ids, glyph_count, output_buffer);
+}
diff --git a/sample/chromium/font_subsetter.h b/sample/chromium/font_subsetter.h
new file mode 100644
index 0000000..07b1b5b
--- /dev/null
+++ b/sample/chromium/font_subsetter.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+// File is originally from Chromium third_party/sfntly/src/subsetter.
+// Use as test case in sfntly so that problems can be caught in upstream early.
+#ifndef SFNTLY_CPP_SRC_TEST_FONT_SUBSETTER_H_
+#define SFNTLY_CPP_SRC_TEST_FONT_SUBSETTER_H_
+
+#include <cstddef>
+
+class SfntlyWrapper {
+ public:
+
+  // Font subsetting API
+  //
+  // Input TTF/TTC/OTF fonts, specify the glyph IDs to subset, and the subset
+  // font is returned in |output_buffer| (caller to delete[]).  Return value is
+  // the length of output_buffer allocated.
+  //
+  // If subsetting fails, a negative value is returned.  If none of the glyph
+  // IDs specified is found, the function will return 0.
+  //
+  // |font_name|      Font name, required for TTC files.  If specified NULL,
+  //                  the first available font is selected.
+  // |original_font|  Original font file contents.
+  // |font_size|      Size of |original_font| in bytes.
+  // |glyph_ids|      Glyph IDs to subset.  If the specified glyph ID is not
+  //                  found in the font file, it will be ignored silently.
+  // |glyph_count|    Number of glyph IDs in |glyph_ids|
+  // |output_buffer|  Generated subset font.  Caller to delete[].
+  static int SubsetFont(const char* font_name,
+                        const unsigned char* original_font,
+                        size_t font_size,
+                        const unsigned int* glyph_ids,
+                        size_t glyph_count,
+                        unsigned char** output_buffer);
+};
+
+#endif  // SFNTLY_CPP_SRC_TEST_FONT_SUBSETTER_H_
diff --git a/sample/chromium/subsetter_impl.cc b/sample/chromium/subsetter_impl.cc
new file mode 100644
index 0000000..528e336
--- /dev/null
+++ b/sample/chromium/subsetter_impl.cc
@@ -0,0 +1,785 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "subsetter_impl.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <iterator>
+#include <map>
+#include <set>
+
+#include "sfntly/table/bitmap/eblc_table.h"
+#include "sfntly/table/bitmap/ebdt_table.h"
+#include "sfntly/table/bitmap/index_sub_table.h"
+#include "sfntly/table/bitmap/index_sub_table_format1.h"
+#include "sfntly/table/bitmap/index_sub_table_format2.h"
+#include "sfntly/table/bitmap/index_sub_table_format3.h"
+#include "sfntly/table/bitmap/index_sub_table_format4.h"
+#include "sfntly/table/bitmap/index_sub_table_format5.h"
+#include "sfntly/table/core/name_table.h"
+#include "sfntly/tag.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/port/memory_input_stream.h"
+#include "sfntly/port/memory_output_stream.h"
+
+#if defined U_USING_ICU_NAMESPACE
+  U_NAMESPACE_USE
+#endif
+
+namespace {
+
+using namespace sfntly;
+
+// The bitmap tables must be greater than 16KB to trigger bitmap subsetter.
+static const int BITMAP_SIZE_THRESHOLD = 16384;
+
+void ConstructName(UChar* name_part, UnicodeString* name, int32_t name_id) {
+  switch (name_id) {
+    case NameId::kFullFontName:
+      *name = name_part;
+      break;
+    case NameId::kFontFamilyName:
+    case NameId::kPreferredFamily:
+    case NameId::kWWSFamilyName: {
+      UnicodeString original = *name;
+      *name = name_part;
+      *name += original;
+      break;
+    }
+    case NameId::kFontSubfamilyName:
+    case NameId::kPreferredSubfamily:
+    case NameId::kWWSSubfamilyName:
+      *name += name_part;
+      break;
+    default:
+      // This name part is not used to construct font name (e.g. copyright).
+      // Simply ignore it.
+      break;
+  }
+}
+
+int32_t HashCode(int32_t platform_id, int32_t encoding_id, int32_t language_id,
+                 int32_t name_id) {
+  int32_t result = platform_id << 24 | encoding_id << 16 | language_id << 8;
+  if (name_id == NameId::kFullFontName) {
+    result |= 0xff;
+  } else if (name_id == NameId::kPreferredFamily ||
+             name_id == NameId::kPreferredSubfamily) {
+    result |= 0xf;
+  } else if (name_id == NameId::kWWSFamilyName ||
+             name_id == NameId::kWWSSubfamilyName) {
+    result |= 1;
+  }
+  return result;
+}
+
+bool HasName(const char* font_name, Font* font) {
+  UnicodeString font_string = UnicodeString::fromUTF8(font_name);
+  if (font_string.isEmpty())
+    return false;
+  UnicodeString regular_suffix = UnicodeString::fromUTF8(" Regular");
+  UnicodeString alt_font_string = font_string;
+  alt_font_string += regular_suffix;
+
+  typedef std::map<int32_t, UnicodeString> NameMap;
+  NameMap names;
+  NameTablePtr name_table = down_cast<NameTable*>(font->GetTable(Tag::name));
+  if (name_table == NULL) {
+    return false;
+  }
+
+  for (int32_t i = 0; i < name_table->NameCount(); ++i) {
+    switch (name_table->NameId(i)) {
+      case NameId::kFontFamilyName:
+      case NameId::kFontSubfamilyName:
+      case NameId::kFullFontName:
+      case NameId::kPreferredFamily:
+      case NameId::kPreferredSubfamily:
+      case NameId::kWWSFamilyName:
+      case NameId::kWWSSubfamilyName: {
+        UChar* name_part = name_table->Name(i);
+        if (name_part == NULL) {
+          continue;
+        }
+        int32_t hash_code = HashCode(name_table->PlatformId(i),
+                                     name_table->EncodingId(i),
+                                     name_table->LanguageId(i),
+                                     name_table->NameId(i));
+        ConstructName(name_part, &(names[hash_code]), name_table->NameId(i));
+        delete[] name_part;
+        break;
+      }
+      default:
+        break;
+    }
+  }
+
+  if (!names.empty()) {
+    for (NameMap::iterator i = names.begin(), e = names.end(); i != e; ++i) {
+      if (i->second.caseCompare(font_string, 0) == 0 ||
+          i->second.caseCompare(alt_font_string, 0) == 0) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+Font* FindFont(const char* font_name, const FontArray& font_array) {
+  if (font_array.empty() || font_array[0] == NULL) {
+    return NULL;
+  }
+
+  if (font_name && strlen(font_name)) {
+    for (FontArray::const_iterator i = font_array.begin(), e = font_array.end();
+         i != e; ++i) {
+      if (HasName(font_name, i->p_)) {
+        return i->p_;
+      }
+    }
+  }
+
+  return font_array[0].p_;
+}
+
+bool ResolveCompositeGlyphs(GlyphTable* glyph_table,
+                            LocaTable* loca_table,
+                            const unsigned int* glyph_ids,
+                            size_t glyph_count,
+                            IntegerSet* glyph_id_processed) {
+  if (glyph_table == NULL || loca_table == NULL ||
+      glyph_ids == NULL || glyph_count == 0 || glyph_id_processed == NULL) {
+    return false;
+  }
+
+  // Sort and uniquify glyph ids.
+  IntegerSet glyph_id_remaining;
+  glyph_id_remaining.insert(0);  // Always include glyph id 0.
+  for (size_t i = 0; i < glyph_count; ++i) {
+    glyph_id_remaining.insert(glyph_ids[i]);
+  }
+
+  // Identify if any given glyph id maps to a composite glyph.  If so, include
+  // the glyphs referenced by that composite glyph.
+  while (!glyph_id_remaining.empty()) {
+    IntegerSet comp_glyph_id;
+    for (IntegerSet::iterator i = glyph_id_remaining.begin(),
+                              e = glyph_id_remaining.end(); i != e; ++i) {
+      if (*i < 0 || *i >= loca_table->num_glyphs()) {
+        // Invalid glyph id, ignore.
+        continue;
+      }
+
+      int32_t length = loca_table->GlyphLength(*i);
+      if (length == 0) {
+        // Empty glyph, ignore.
+        continue;
+      }
+      int32_t offset = loca_table->GlyphOffset(*i);
+
+      GlyphPtr glyph;
+      glyph.Attach(glyph_table->GetGlyph(offset, length));
+      if (glyph == NULL) {
+        // Error finding glyph, ignore.
+        continue;
+      }
+
+      if (glyph->GlyphType() == GlyphType::kComposite) {
+        Ptr<GlyphTable::CompositeGlyph> comp_glyph =
+            down_cast<GlyphTable::CompositeGlyph*>(glyph.p_);
+        for (int32_t j = 0; j < comp_glyph->NumGlyphs(); ++j) {
+          int32_t glyph_id = comp_glyph->GlyphIndex(j);
+          if (glyph_id_processed->find(glyph_id) == glyph_id_processed->end() &&
+              glyph_id_remaining.find(glyph_id) == glyph_id_remaining.end()) {
+            comp_glyph_id.insert(comp_glyph->GlyphIndex(j));
+          }
+        }
+      }
+
+      glyph_id_processed->insert(*i);
+    }
+
+    glyph_id_remaining.clear();
+    glyph_id_remaining = comp_glyph_id;
+  }
+
+  return true;
+}
+
+bool SetupGlyfBuilders(Font::Builder* font_builder,
+                       GlyphTable* glyph_table,
+                       LocaTable* loca_table,
+                       const IntegerSet& glyph_ids) {
+  if (!font_builder || !glyph_table || !loca_table) {
+    return false;
+  }
+
+  GlyphTableBuilderPtr glyph_table_builder =
+      down_cast<GlyphTable::Builder*>(font_builder->NewTableBuilder(Tag::glyf));
+  LocaTableBuilderPtr loca_table_builder =
+      down_cast<LocaTable::Builder*>(font_builder->NewTableBuilder(Tag::loca));
+  if (glyph_table_builder == NULL || loca_table_builder == NULL) {
+    // Out of memory.
+    return false;
+  }
+
+  // Extract glyphs and setup loca list.
+  IntegerList loca_list;
+  loca_list.resize(loca_table->num_glyphs());
+  loca_list.push_back(0);
+  int32_t last_glyph_id = 0;
+  int32_t last_offset = 0;
+  GlyphTable::GlyphBuilderList* glyph_builders =
+      glyph_table_builder->GlyphBuilders();
+  for (IntegerSet::const_iterator i = glyph_ids.begin(), e = glyph_ids.end();
+                                  i != e; ++i) {
+    int32_t length = loca_table->GlyphLength(*i);
+    int32_t offset = loca_table->GlyphOffset(*i);
+
+    GlyphPtr glyph;
+    glyph.Attach(glyph_table->GetGlyph(offset, length));
+
+    // Add glyph to new glyf table.
+    ReadableFontDataPtr data = glyph->ReadFontData();
+    WritableFontDataPtr copy_data;
+    copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length()));
+    data->CopyTo(copy_data);
+    GlyphBuilderPtr glyph_builder;
+    glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data));
+    glyph_builders->push_back(glyph_builder);
+
+    // Configure loca list.
+    for (int32_t j = last_glyph_id + 1; j <= *i; ++j) {
+      loca_list[j] = last_offset;
+    }
+    last_offset += length;
+    loca_list[*i + 1] = last_offset;
+    last_glyph_id = *i;
+  }
+  for (int32_t j = last_glyph_id + 1; j <= loca_table->num_glyphs(); ++j) {
+    loca_list[j] = last_offset;
+  }
+  loca_table_builder->SetLocaList(&loca_list);
+
+  return true;
+}
+
+bool HasOverlap(int32_t range_begin, int32_t range_end,
+                const IntegerSet& glyph_ids) {
+  if (range_begin == range_end) {
+    return glyph_ids.find(range_begin) != glyph_ids.end();
+  } else if (range_end > range_begin) {
+    IntegerSet::const_iterator left = glyph_ids.lower_bound(range_begin);
+    IntegerSet::const_iterator right = glyph_ids.lower_bound(range_end);
+    return right != left;
+  }
+  return false;
+}
+
+// Initialize builder, returns false if glyph_id subset is not covered.
+// Not thread-safe, caller to ensure object life-time.
+bool InitializeBitmapBuilder(EbdtTable::Builder* ebdt, EblcTable::Builder* eblc,
+                             const IntegerSet& glyph_ids) {
+  BitmapLocaList loca_list;
+  BitmapSizeTableBuilderList* strikes = eblc->BitmapSizeBuilders();
+
+  // Note: Do not call eblc_builder->GenerateLocaList(&loca_list) and then
+  //       ebdt_builder->SetLoca(loca_list).  For fonts like SimSun, there are
+  //       >28K glyphs inside, where a typical usage will be <1K glyphs.  Doing
+  //       the calls improperly will result in creation of >100K objects that
+  //       will be destroyed immediately, inducing significant slowness.
+  IntegerList removed_strikes;
+  for (size_t i = 0; i < strikes->size(); i++) {
+    if (!HasOverlap((*strikes)[i]->StartGlyphIndex(),
+                    (*strikes)[i]->EndGlyphIndex(), glyph_ids)) {
+      removed_strikes.push_back(i);
+      continue;
+    }
+
+    IndexSubTableBuilderList* index_builders =
+        (*strikes)[i]->IndexSubTableBuilders();
+    IntegerList removed_indexes;
+    BitmapGlyphInfoMap info_map;
+    for (size_t j = 0; j < index_builders->size(); ++j) {
+      if ((*index_builders)[j] == NULL) {
+        // Subtable is malformed, let's just skip it.
+        removed_indexes.push_back(j);
+        continue;
+      }
+      int32_t first_glyph_id = (*index_builders)[j]->first_glyph_index();
+      int32_t last_glyph_id = (*index_builders)[j]->last_glyph_index();
+      if (!HasOverlap(first_glyph_id, last_glyph_id, glyph_ids)) {
+        removed_indexes.push_back(j);
+        continue;
+      }
+      for (IntegerSet::const_iterator gid = glyph_ids.begin(),
+                                      gid_end = glyph_ids.end();
+                                      gid != gid_end; gid++) {
+        if (*gid < first_glyph_id) {
+          continue;
+        }
+        if (*gid > last_glyph_id) {
+          break;
+        }
+        BitmapGlyphInfoPtr info;
+        info.Attach((*index_builders)[j]->GlyphInfo(*gid));
+        if (info && info->length()) {  // Do not include gid without bitmap
+          info_map[*gid] = info;
+        }
+      }
+    }
+    if (!info_map.empty()) {
+      loca_list.push_back(info_map);
+    } else {
+      removed_strikes.push_back(i);  // Detected null entries.
+    }
+
+    // Remove unused index sub tables
+    for (IntegerList::reverse_iterator j = removed_indexes.rbegin(),
+                                       e = removed_indexes.rend();
+                                       j != e; j++) {
+      index_builders->erase(index_builders->begin() + *j);
+    }
+  }
+  if (removed_strikes.size() == strikes->size() || loca_list.empty()) {
+    return false;
+  }
+
+  for (IntegerList::reverse_iterator i = removed_strikes.rbegin(),
+                                     e = removed_strikes.rend(); i != e; i++) {
+    strikes->erase(strikes->begin() + *i);
+  }
+
+  if (strikes->empty()) {  // no glyph covered, can safely drop the builders.
+    return false;
+  }
+
+  ebdt->SetLoca(&loca_list);
+  ebdt->GlyphBuilders();  // Initialize the builder.
+  return true;
+}
+
+void CopyBigGlyphMetrics(BigGlyphMetrics::Builder* source,
+                         BigGlyphMetrics::Builder* target) {
+  target->SetHeight(static_cast<byte_t>(source->Height()));
+  target->SetWidth(static_cast<byte_t>(source->Width()));
+  target->SetHoriBearingX(static_cast<byte_t>(source->HoriBearingX()));
+  target->SetHoriBearingY(static_cast<byte_t>(source->HoriBearingY()));
+  target->SetHoriAdvance(static_cast<byte_t>(source->HoriAdvance()));
+  target->SetVertBearingX(static_cast<byte_t>(source->VertBearingX()));
+  target->SetVertBearingY(static_cast<byte_t>(source->VertBearingY()));
+  target->SetVertAdvance(static_cast<byte_t>(source->VertAdvance()));
+}
+
+CALLER_ATTACH IndexSubTable::Builder*
+ConstructIndexFormat4(IndexSubTable::Builder* b, const BitmapGlyphInfoMap& loca,
+                      int32_t* image_data_offset) {
+  IndexSubTableFormat4BuilderPtr builder4;
+  builder4.Attach(IndexSubTableFormat4::Builder::CreateBuilder());
+  CodeOffsetPairBuilderList offset_pairs;
+
+  size_t offset = 0;
+  int32_t lower_bound = b->first_glyph_index();
+  int32_t upper_bound = b->last_glyph_index();
+  int32_t last_gid = -1;
+  BitmapGlyphInfoMap::const_iterator i = loca.lower_bound(lower_bound);
+  BitmapGlyphInfoMap::const_iterator end = loca.end();
+  if (i != end) {
+    last_gid = i->first;
+    builder4->set_first_glyph_index(last_gid);
+    builder4->set_image_format(b->image_format());
+    builder4->set_image_data_offset(*image_data_offset);
+  }
+  for (; i != end; i++) {
+    int32_t gid = i->first;
+    if (gid > upper_bound) {
+      break;
+    }
+    offset_pairs.push_back(
+        IndexSubTableFormat4::CodeOffsetPairBuilder(gid, offset));
+    offset += i->second->length();
+    last_gid = gid;
+  }
+  offset_pairs.push_back(
+      IndexSubTableFormat4::CodeOffsetPairBuilder(-1, offset));
+  builder4->set_last_glyph_index(last_gid);
+  *image_data_offset += offset;
+  builder4->SetOffsetArray(offset_pairs);
+
+  return builder4.Detach();
+}
+
+CALLER_ATTACH IndexSubTable::Builder*
+ConstructIndexFormat5(IndexSubTable::Builder* b, const BitmapGlyphInfoMap& loca,
+                      int32_t* image_data_offset) {
+  IndexSubTableFormat5BuilderPtr new_builder;
+  new_builder.Attach(IndexSubTableFormat5::Builder::CreateBuilder());
+
+  // Copy BigMetrics
+  int32_t image_size = 0;
+  if (b->index_format() == IndexSubTable::Format::FORMAT_2) {
+    IndexSubTableFormat2BuilderPtr builder2 =
+      down_cast<IndexSubTableFormat2::Builder*>(b);
+    CopyBigGlyphMetrics(builder2->BigMetrics(), new_builder->BigMetrics());
+    image_size = builder2->ImageSize();
+  } else {
+    IndexSubTableFormat5BuilderPtr builder5 =
+      down_cast<IndexSubTableFormat5::Builder*>(b);
+    BigGlyphMetricsBuilderPtr metrics_builder;
+    CopyBigGlyphMetrics(builder5->BigMetrics(), new_builder->BigMetrics());
+    image_size = builder5->ImageSize();
+  }
+
+  IntegerList* glyph_array = new_builder->GlyphArray();
+  size_t offset = 0;
+  int32_t lower_bound = b->first_glyph_index();
+  int32_t upper_bound = b->last_glyph_index();
+  int32_t last_gid = -1;
+  BitmapGlyphInfoMap::const_iterator i = loca.lower_bound(lower_bound);
+  BitmapGlyphInfoMap::const_iterator end = loca.end();
+  if (i != end) {
+    last_gid = i->first;
+    new_builder->set_first_glyph_index(last_gid);
+    new_builder->set_image_format(b->image_format());
+    new_builder->set_image_data_offset(*image_data_offset);
+    new_builder->SetImageSize(image_size);
+  }
+  for (; i != end; i++) {
+    int32_t gid = i->first;
+    if (gid > upper_bound) {
+      break;
+    }
+    glyph_array->push_back(gid);
+    offset += i->second->length();
+    last_gid = gid;
+  }
+  new_builder->set_last_glyph_index(last_gid);
+  *image_data_offset += offset;
+  return new_builder.Detach();
+}
+
+CALLER_ATTACH IndexSubTable::Builder*
+SubsetIndexSubTable(IndexSubTable::Builder* builder,
+                    const BitmapGlyphInfoMap& loca,
+                    int32_t* image_data_offset) {
+  switch (builder->index_format()) {
+    case IndexSubTable::Format::FORMAT_1:
+    case IndexSubTable::Format::FORMAT_3:
+    case IndexSubTable::Format::FORMAT_4:
+      return ConstructIndexFormat4(builder, loca, image_data_offset);
+    case IndexSubTable::Format::FORMAT_2:
+    case IndexSubTable::Format::FORMAT_5:
+      return ConstructIndexFormat5(builder, loca, image_data_offset);
+    default:
+      assert(false);
+      break;
+  }
+  return NULL;
+}
+
+}
+
+namespace sfntly {
+
+// Not thread-safe, caller to ensure object life-time.
+void SubsetEBLC(EblcTable::Builder* eblc, const BitmapLocaList& new_loca) {
+  BitmapSizeTableBuilderList* size_builders = eblc->BitmapSizeBuilders();
+  if (size_builders == NULL) {
+    return;
+  }
+
+  int32_t image_data_offset = EbdtTable::Offset::kHeaderLength;
+  for (size_t strike = 0; strike < size_builders->size(); ++strike) {
+    IndexSubTableBuilderList* index_builders =
+        (*size_builders)[strike]->IndexSubTableBuilders();
+    for (size_t index = 0; index < index_builders->size(); ++index) {
+      IndexSubTable::Builder* new_builder_raw =
+          SubsetIndexSubTable((*index_builders)[index], new_loca[strike],
+                              &image_data_offset);
+      if (NULL != new_builder_raw) {
+        (*index_builders)[index].Attach(new_builder_raw);
+      }
+    }
+  }
+}
+
+// EBLC structure (from stuartg)
+//  header
+//  bitmapSizeTable[]
+//    one per strike
+//    holds strike metrics - sbitLineMetrics
+//    holds info about indexSubTableArray
+//  indexSubTableArray[][]
+//    one per strike and then one per indexSubTable for that strike
+//    holds info about the indexSubTable
+//    the indexSubTable entries pointed to can be of different formats
+//  indexSubTable
+//    one per indexSubTableArray entry
+//    tells how to get the glyphs
+//    may hold the glyph metrics if they are uniform for all the glyphs in range
+// Please note that the structure can also be
+//  {indexSubTableArray[], indexSubTables[]}[]
+//  This way is also legal and in fact how Microsoft fonts are laid out.
+//
+// There is nothing that says that the indexSubTableArray entries and/or the
+// indexSubTable items need to be unique. They may be shared between strikes.
+//
+// EBDT structure:
+//  header
+//  glyphs
+//    amorphous blob of data
+//    different glyphs that are only able to be figured out from the EBLC table
+//    may hold metrics - depends on the EBLC entry that pointed to them
+
+// Subsetting EBLC table (from arthurhsu)
+//  Most pages use only a fraction (hundreds or less) glyphs out of a given font
+//  (which can have >20K glyphs for CJK).  It's safe to assume that the subset
+//  font will have sparse bitmap glyphs.  So we reconstruct the EBLC table as
+//  format 4 or 5 here.
+
+enum BuildersToRemove {
+  kRemoveNone,
+  kRemoveBDAT,
+  kRemoveBDATAndEBDT,
+  kRemoveEBDT
+};
+
+int SetupBitmapBuilders(Font* font, Font::Builder* font_builder,
+                        const IntegerSet& glyph_ids) {
+  if (!font || !font_builder) {
+    return false;
+  }
+
+  // Check if bitmap table exists.
+  EbdtTablePtr ebdt_table = down_cast<EbdtTable*>(font->GetTable(Tag::EBDT));
+  EblcTablePtr eblc_table = down_cast<EblcTable*>(font->GetTable(Tag::EBLC));
+  bool use_ebdt = (ebdt_table != NULL && eblc_table != NULL);
+  if (!use_ebdt) {
+    ebdt_table = down_cast<EbdtTable*>(font->GetTable(Tag::bdat));
+    eblc_table = down_cast<EblcTable*>(font->GetTable(Tag::bloc));
+    if (ebdt_table == NULL || eblc_table == NULL) {
+      return kRemoveNone;
+    }
+  }
+
+  // If the bitmap table's size is too small, skip subsetting.
+  if (ebdt_table->DataLength() + eblc_table->DataLength() <
+      BITMAP_SIZE_THRESHOLD) {
+    return use_ebdt ? kRemoveBDAT : kRemoveNone;
+  }
+
+  // Get the builders.
+  EbdtTableBuilderPtr ebdt_table_builder = down_cast<EbdtTable::Builder*>(
+      font_builder->NewTableBuilder(use_ebdt ? Tag::EBDT : Tag::bdat,
+                                    ebdt_table->ReadFontData()));
+  EblcTableBuilderPtr eblc_table_builder = down_cast<EblcTable::Builder*>(
+      font_builder->NewTableBuilder(use_ebdt ? Tag::EBLC : Tag::bloc,
+                                    eblc_table->ReadFontData()));
+  if (ebdt_table_builder == NULL || eblc_table_builder == NULL) {
+    // Out of memory.
+    return use_ebdt ? kRemoveBDAT : kRemoveNone;
+  }
+
+  if (!InitializeBitmapBuilder(ebdt_table_builder, eblc_table_builder,
+                               glyph_ids)) {
+    // Bitmap tables do not cover the glyphs in our subset.
+    font_builder->RemoveTableBuilder(use_ebdt ? Tag::EBLC : Tag::bloc);
+    font_builder->RemoveTableBuilder(use_ebdt ? Tag::EBDT : Tag::bdat);
+    return use_ebdt ? kRemoveBDATAndEBDT : kRemoveEBDT;
+  }
+
+  BitmapLocaList new_loca;
+  ebdt_table_builder->GenerateLocaList(&new_loca);
+  SubsetEBLC(eblc_table_builder, new_loca);
+
+  return use_ebdt ? kRemoveBDAT : kRemoveNone;
+}
+
+SubsetterImpl::SubsetterImpl() {
+}
+
+SubsetterImpl::~SubsetterImpl() {
+}
+
+bool SubsetterImpl::LoadFont(const char* font_name,
+                             const unsigned char* original_font,
+                             size_t font_size) {
+  MemoryInputStream mis;
+  mis.Attach(original_font, font_size);
+  if (factory_ == NULL) {
+    factory_.Attach(FontFactory::GetInstance());
+  }
+
+  FontArray font_array;
+  factory_->LoadFonts(&mis, &font_array);
+  font_ = FindFont(font_name, font_array);
+  if (font_ == NULL) {
+    return false;
+  }
+
+  return true;
+}
+
+int SubsetterImpl::SubsetFont(const unsigned int* glyph_ids,
+                              size_t glyph_count,
+                              unsigned char** output_buffer) {
+  if (factory_ == NULL || font_ == NULL) {
+    return -1;
+  }
+
+  // Find glyf and loca table.
+  GlyphTablePtr glyph_table =
+      down_cast<GlyphTable*>(font_->GetTable(Tag::glyf));
+  LocaTablePtr loca_table = down_cast<LocaTable*>(font_->GetTable(Tag::loca));
+  if (glyph_table == NULL || loca_table == NULL) {
+    // We are not able to subset the font.
+    return 0;
+  }
+
+  IntegerSet glyph_id_processed;
+  if (!ResolveCompositeGlyphs(glyph_table, loca_table,
+                              glyph_ids, glyph_count, &glyph_id_processed) ||
+      glyph_id_processed.empty()) {
+    return 0;
+  }
+
+  FontPtr new_font;
+  new_font.Attach(Subset(glyph_id_processed, glyph_table, loca_table));
+  if (new_font == NULL) {
+    return 0;
+  }
+
+  MemoryOutputStream output_stream;
+  factory_->SerializeFont(new_font, &output_stream);
+  int length = static_cast<int>(output_stream.Size());
+  if (length > 0) {
+    *output_buffer = new unsigned char[length];
+    memcpy(*output_buffer, output_stream.Get(), length);
+  }
+
+  return length;
+}
+
+// Long comments regarding TTF tables and PDF (from stuartg)
+//
+// According to PDF spec 1.4 (section 5.8), the following tables must be
+// present:
+//  head, hhea, loca, maxp, cvt, prep, glyf, hmtx, fpgm
+//  cmap if font is used with a simple font dict and not a CIDFont dict
+//
+// Other tables we need to keep for PDF rendering to support zoom in/out:
+//  bdat, bloc, ebdt, eblc, ebsc, gasp
+//
+// Special table:
+//  CFF - if you have this table then you shouldn't have a glyf table and this
+//        is the table with all the glyphs.  Shall skip subsetting completely
+//        since sfntly is not capable of subsetting it for now.
+//  post - extra info here for printing on PostScript printers but maybe not
+//         enough to outweigh the space taken by the names
+//
+// Tables to break apart:
+//  name - could throw away all but one language and one platform strings/ might
+//         throw away some of the name entries
+//  cmap - could strip out non-needed cmap subtables
+//       - format 4 subtable can be subsetted as well using sfntly
+//
+// Graphite tables:
+//  silf, glat, gloc, feat - should be okay to strip out
+//
+// Tables that can be discarded:
+//  OS/2 - everything here is for layout and description of the font that is
+//         elsewhere (some in the PDF objects)
+//  BASE, GDEF, GSUB, GPOS, JSTF - all used for layout
+//  kern - old style layout
+//  DSIG - this will be invalid after subsetting
+//  hdmx - layout
+//  PCLT - metadata that's not needed
+//  vmtx - layout
+//  vhea - layout
+//  VDMX
+//  VORG - not used by TT/OT - used by CFF
+//  hsty - would be surprised to see one of these - used on the Newton
+//  AAT tables - mort, morx, feat, acnt, bsin, just, lcar, fdsc, fmtx, prop,
+//               Zapf, opbd, trak, fvar, gvar, avar, cvar
+//             - these are all layout tables and once layout happens are not
+//               needed anymore
+//  LTSH - layout
+
+CALLER_ATTACH
+Font* SubsetterImpl::Subset(const IntegerSet& glyph_ids, GlyphTable* glyf,
+                            LocaTable* loca) {
+  // The const is initialized here to workaround VC bug of rendering all Tag::*
+  // as 0.  These tags represents the TTF tables that we will embed in subset
+  // font.
+  const int32_t TABLES_IN_SUBSET[] = {
+    Tag::head, Tag::hhea, Tag::loca, Tag::maxp, Tag::cvt,
+    Tag::prep, Tag::glyf, Tag::hmtx, Tag::fpgm, Tag::EBDT,
+    Tag::EBLC, Tag::EBSC, Tag::bdat, Tag::bloc, Tag::bhed,
+    Tag::cmap,  // Keep here for future tagged PDF development.
+    Tag::name,  // Keep here due to legal concerns: copyright info inside.
+  };
+
+  // Setup font builders we need.
+  FontBuilderPtr font_builder;
+  font_builder.Attach(factory_->NewFontBuilder());
+  IntegerSet remove_tags;
+
+  if (SetupGlyfBuilders(font_builder, glyf, loca, glyph_ids)) {
+    remove_tags.insert(Tag::glyf);
+    remove_tags.insert(Tag::loca);
+  }
+
+  // For old Apple bitmap fonts, they have only bdats and bhed is identical
+  // to head.  As a result, we can't remove bdat tables for those fonts.
+  int setup_result = SetupBitmapBuilders(font_, font_builder, glyph_ids);
+  if (setup_result == kRemoveBDATAndEBDT || setup_result == kRemoveEBDT) {
+    remove_tags.insert(Tag::EBDT);
+    remove_tags.insert(Tag::EBLC);
+    remove_tags.insert(Tag::EBSC);
+  }
+
+  if (setup_result == kRemoveBDAT || setup_result == kRemoveBDATAndEBDT) {
+    remove_tags.insert(Tag::bdat);
+    remove_tags.insert(Tag::bloc);
+    remove_tags.insert(Tag::bhed);
+  }
+
+  IntegerSet allowed_tags;
+  for (size_t i = 0; i < sizeof(TABLES_IN_SUBSET) / sizeof(int32_t); ++i) {
+    allowed_tags.insert(TABLES_IN_SUBSET[i]);
+  }
+
+  IntegerSet result;
+  std::set_difference(allowed_tags.begin(), allowed_tags.end(),
+                      remove_tags.begin(), remove_tags.end(),
+                      std::inserter(result, result.end()));
+  allowed_tags = result;
+
+  // Setup remaining builders.
+  for (IntegerSet::iterator i = allowed_tags.begin(), e = allowed_tags.end();
+                            i != e; ++i) {
+    Table* table = font_->GetTable(*i);
+    if (table) {
+      font_builder->NewTableBuilder(*i, table->ReadFontData());
+    }
+  }
+
+  return font_builder->Build();
+}
+
+}  // namespace sfntly
diff --git a/sample/chromium/subsetter_impl.h b/sample/chromium/subsetter_impl.h
new file mode 100644
index 0000000..ffbf408
--- /dev/null
+++ b/sample/chromium/subsetter_impl.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+// File is originally from Chromium third_party/sfntly/src/subsetter.
+// Use as test case in sfntly so that problems can be caught in upstream early.
+
+#ifndef SFNTLY_CPP_SRC_TEST_SUBSETTER_IMPL_H_
+#define SFNTLY_CPP_SRC_TEST_SUBSETTER_IMPL_H_
+
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/truetype/glyph_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+#include "sfntly/tag.h"
+
+namespace sfntly {
+
+// Smart pointer usage in sfntly:
+//
+// sfntly carries a smart pointer implementation like COM.  Ref-countable object
+// type inherits from RefCounted<>, which have AddRef and Release just like
+// IUnknown (but no QueryInterface).  Use a Ptr<> based smart pointer to hold
+// the object so that the object ref count is handled correctly.
+//
+// class Foo : public RefCounted<Foo> {
+//  public:
+//   static Foo* CreateInstance() {
+//     Ptr<Foo> obj = new Foo();  // ref count = 1
+//     return obj.detach();
+//   }
+// };
+// typedef Ptr<Foo> FooPtr;  // common short-hand notation
+// FooPtr obj;
+// obj.attach(Foo::CreatedInstance());  // ref count = 1
+// {
+//   FooPtr obj2 = obj;  // ref count = 2
+// }  // ref count = 1, obj2 out of scope
+// obj.release();  // ref count = 0, object destroyed
+
+class SubsetterImpl {
+ public:
+  SubsetterImpl();
+  ~SubsetterImpl();
+
+  bool LoadFont(const char* font_name,
+                const unsigned char* original_font,
+                size_t font_size);
+  int SubsetFont(const unsigned int* glyph_ids,
+                 size_t glyph_count,
+                 unsigned char** output_buffer);
+
+ private:
+  CALLER_ATTACH Font* Subset(const IntegerSet& glyph_ids,
+                             GlyphTable* glyf, LocaTable* loca);
+
+  FontFactoryPtr factory_;
+  FontPtr font_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_TEST_SUBSETTER_IMPL_H_
diff --git a/sample/subsetter/main.cc b/sample/subsetter/main.cc
new file mode 100644
index 0000000..19a3e0e
--- /dev/null
+++ b/sample/subsetter/main.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 <stdio.h>
+#if _MSC_VER > 12
+  #define _CRTDBG_MAP_ALLOC
+  #include <stdlib.h>
+  #include <crtdbg.h>
+#endif
+
+#include "sample/subsetter/subset_util.h"
+
+int main(int argc, char** argv) {
+#ifdef _CRTDBG_MAP_ALLOC
+  _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+  if (argc < 3) {
+    printf("Usage: subsetter <font file> <output file>\n");
+    return 0;
+  }
+
+  sfntly::SubsetUtil subset_util;
+  subset_util.Subset(argv[1], argv[2]);
+
+#ifdef _CRTDBG_MAP_ALLOC
+  _CrtDumpMemoryLeaks();
+#endif
+
+  return 0;
+}
diff --git a/sample/subsetter/subset_util.cc b/sample/subsetter/subset_util.cc
new file mode 100644
index 0000000..f35eb25
--- /dev/null
+++ b/sample/subsetter/subset_util.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+// Remove VC++ nag on fopen.
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "sample/subsetter/subset_util.h"
+
+#include <stdio.h>
+
+#include <vector>
+#include <memory>
+
+#include "sfntly/font.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/port/memory_output_stream.h"
+#include "sfntly/port/type.h"
+#include "sfntly/tag.h"
+#include "sfntly/tools/subsetter/subsetter.h"
+
+namespace sfntly {
+
+SubsetUtil::SubsetUtil() {
+}
+
+SubsetUtil::~SubsetUtil() {
+}
+
+void SubsetUtil::Subset(const char *input_file_path,
+                        const char *output_file_path) {
+  UNREFERENCED_PARAMETER(output_file_path);
+  ByteVector input_buffer;
+  FILE* input_file = fopen(input_file_path, "rb");
+  if (input_file == NULL) {
+    fprintf(stderr, "file not found\n");
+    return;
+  }
+  fseek(input_file, 0, SEEK_END);
+  size_t file_size = ftell(input_file);
+  fseek(input_file, 0, SEEK_SET);
+  input_buffer.resize(file_size);
+  size_t bytes_read = fread(&(input_buffer[0]), 1, file_size, input_file);
+  UNREFERENCED_PARAMETER(bytes_read);
+  fclose(input_file);
+
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+
+  FontArray font_array;
+  factory->LoadFonts(&input_buffer, &font_array);
+  if (font_array.empty() || font_array[0] == NULL)
+    return;
+
+  IntegerList glyphs;
+  for (int32_t i = 0; i < 10; i++) {
+    glyphs.push_back(i);
+  }
+  glyphs.push_back(11);
+  glyphs.push_back(10);
+
+  Ptr<Subsetter> subsetter = new Subsetter(font_array[0], factory);
+  subsetter->SetGlyphs(&glyphs);
+  IntegerSet remove_tables;
+  remove_tables.insert(Tag::DSIG);
+  subsetter->SetRemoveTables(&remove_tables);
+
+  FontBuilderPtr font_builder;
+  font_builder.Attach(subsetter->Subset());
+
+  FontPtr new_font;
+  new_font.Attach(font_builder->Build());
+
+  // TODO(arthurhsu): glyph renumbering/Loca table
+  // TODO(arthurhsu): alter CMaps
+
+  MemoryOutputStream output_stream;
+  factory->SerializeFont(new_font, &output_stream);
+
+  FILE* output_file = fopen(output_file_path, "wb");
+  fwrite(output_stream.Get(), 1, output_stream.Size(), output_file);
+  fflush(output_file);
+  fclose(output_file);
+}
+
+}  // namespace sfntly
diff --git a/sample/subsetter/subset_util.h b/sample/subsetter/subset_util.h
new file mode 100644
index 0000000..5eb4fe4
--- /dev/null
+++ b/sample/subsetter/subset_util.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SAMPLE_SUBSETTER_SUBSET_UTIL_H_
+#define SFNTLY_CPP_SRC_SAMPLE_SUBSETTER_SUBSET_UTIL_H_
+
+namespace sfntly {
+
+class SubsetUtil {
+ public:
+  SubsetUtil();
+  virtual ~SubsetUtil();
+
+  void Subset(const char* input_file_path, const char* output_file_path);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SAMPLE_SUBSETTER_SUBSET_UTIL_H_
diff --git a/sample/subtly/character_predicate.cc b/sample/subtly/character_predicate.cc
new file mode 100644
index 0000000..b9c6cc7
--- /dev/null
+++ b/sample/subtly/character_predicate.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/port/refcount.h"
+#include "subtly/character_predicate.h"
+
+namespace subtly {
+using namespace sfntly;
+
+// AcceptRange predicate
+AcceptRange::AcceptRange(int32_t start, int32_t end)
+    : start_(start),
+      end_(end) {
+}
+
+AcceptRange::~AcceptRange() {}
+
+bool AcceptRange::operator()(int32_t character) const {
+  return start_ <= character && character <= end_;
+}
+
+// AcceptSet predicate
+AcceptSet::AcceptSet(IntegerSet* characters)
+    : characters_(characters) {
+}
+
+AcceptSet::~AcceptSet() {
+  delete characters_;
+}
+
+bool AcceptSet::operator()(int32_t character) const {
+  return characters_->find(character) != characters_->end();
+}
+
+// AcceptAll predicate
+bool AcceptAll::operator()(int32_t character) const {
+  UNREFERENCED_PARAMETER(character);
+  return true;
+}
+}
diff --git a/sample/subtly/character_predicate.h b/sample/subtly/character_predicate.h
new file mode 100644
index 0000000..a6e3ea3
--- /dev/null
+++ b/sample/subtly/character_predicate.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_CHARACTER_PREDICATE_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_CHARACTER_PREDICATE_H_
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/port/type.h"
+
+namespace subtly {
+class CharacterPredicate : virtual public sfntly::RefCount {
+ public:
+  CharacterPredicate() {}
+  virtual ~CharacterPredicate() {}
+  virtual bool operator()(int32_t character) const = 0;
+};
+
+// All characters except for those between [start, end] are rejected
+class AcceptRange : public CharacterPredicate,
+                    public sfntly::RefCounted<AcceptRange> {
+ public:
+  AcceptRange(int32_t start, int32_t end);
+  ~AcceptRange();
+  virtual bool operator()(int32_t character) const;
+
+ private:
+  int32_t start_;
+  int32_t end_;
+};
+
+// All characters in IntegerSet
+// The set is OWNED by the predicate! Do not modify it.
+// It will be freed when the predicate is destroyed.
+class AcceptSet : public CharacterPredicate,
+                  public sfntly::RefCounted<AcceptSet> {
+ public:
+  explicit AcceptSet(sfntly::IntegerSet* characters);
+  ~AcceptSet();
+  virtual bool operator()(int32_t character) const;
+
+ private:
+  sfntly::IntegerSet* characters_;
+};
+
+// All characters
+class AcceptAll : public CharacterPredicate,
+                  public sfntly::RefCounted<AcceptAll> {
+ public:
+  AcceptAll() {}
+  ~AcceptAll() {}
+  virtual bool operator()(int32_t character) const;
+};
+}
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_CHARACTER_PREDICATE_H_
diff --git a/sample/subtly/debug_main.cc b/sample/subtly/debug_main.cc
new file mode 100644
index 0000000..8324cde
--- /dev/null
+++ b/sample/subtly/debug_main.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+#include <map>
+#include <utility>
+
+#include "sfntly/font.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/tag.h"
+#include "subtly/stats.h"
+#include "subtly/subsetter.h"
+#include "subtly/utils.h"
+
+using namespace subtly;
+
+void PrintUsage(const char* program_name) {
+  fprintf(stdout, "Usage: %s <input_font_file>\n", program_name);
+}
+
+int main(int argc, const char** argv) {
+  const char* program_name = argv[0];
+  if (argc < 2) {
+    PrintUsage(program_name);
+    exit(1);
+  }
+
+  const char* input_font_path = argv[1];
+  const char* output_font_path = argv[2];
+  FontPtr font;
+  font.Attach(subtly::LoadFont(input_font_path));
+
+  int32_t original_size = TotalFontSize(font);
+  Ptr<Subsetter> subsetter = new Subsetter(font, NULL);
+  Ptr<Font> new_font;
+  new_font.Attach(subsetter->Subset());
+  if (!new_font) {
+    fprintf(stdout, "Cannot create subset.\n");
+    return 0;
+  }
+
+  subtly::SerializeFont(output_font_path, new_font);
+  subtly::PrintComparison(stdout, font, new_font);
+  int32_t new_size = TotalFontSize(new_font);
+  fprintf(stdout, "Went from %d to %d: %lf%% of original\n",
+          original_size, new_size,
+          static_cast<double>(new_size) / original_size * 100);
+  return 0;
+}
diff --git a/sample/subtly/font_assembler.cc b/sample/subtly/font_assembler.cc
new file mode 100644
index 0000000..2f7cd11
--- /dev/null
+++ b/sample/subtly/font_assembler.cc
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "subtly/font_assembler.h"
+
+#include <stdio.h>
+
+#include <set>
+#include <map>
+
+#include "sfntly/tag.h"
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+#include "sfntly/table/truetype/glyph_table.h"
+#include "sfntly/table/core/maximum_profile_table.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/refcount.h"
+#include "subtly/font_info.h"
+
+namespace subtly {
+using namespace sfntly;
+
+FontAssembler::FontAssembler(FontInfo* font_info,
+                             IntegerSet* table_blacklist)
+    : table_blacklist_(table_blacklist) {
+  font_info_ = font_info;
+  Initialize();
+}
+
+FontAssembler::FontAssembler(FontInfo* font_info)
+    : table_blacklist_(NULL) {
+  font_info_ = font_info;
+  Initialize();
+}
+
+void FontAssembler::Initialize() {
+  font_factory_.Attach(sfntly::FontFactory::GetInstance());
+  font_builder_.Attach(font_factory_->NewFontBuilder());
+}
+
+CALLER_ATTACH Font* FontAssembler::Assemble() {
+  // Assemble tables we can subset.
+  if (!AssembleCMapTable() || !AssembleGlyphAndLocaTables()) {
+    return NULL;
+  }
+  // For all other tables, either include them unmodified or don't at all.
+  const TableMap* common_table_map =
+      font_info_->GetTableMap(font_info_->fonts()->begin()->first);
+  for (TableMap::const_iterator it = common_table_map->begin(),
+           e = common_table_map->end(); it != e; ++it) {
+    if (table_blacklist_
+        && table_blacklist_->find(it->first) != table_blacklist_->end()) {
+      continue;
+    }
+    font_builder_->NewTableBuilder(it->first, it->second->ReadFontData());
+  }
+  return font_builder_->Build();
+}
+
+bool FontAssembler::AssembleCMapTable() {
+  // Creating the new CMapTable and the new format 4 CMap
+  Ptr<CMapTable::Builder> cmap_table_builder =
+      down_cast<CMapTable::Builder*>
+      (font_builder_->NewTableBuilder(Tag::cmap));
+  if (!cmap_table_builder)
+    return false;
+  Ptr<CMapTable::CMapFormat4::Builder> cmap_builder =
+      down_cast<CMapTable::CMapFormat4::Builder*>
+      (cmap_table_builder->NewCMapBuilder(CMapFormat::kFormat4,
+                                          CMapTable::WINDOWS_BMP));
+  if (!cmap_builder)
+    return false;
+  // Creating the segments and the glyph id array
+  CharacterMap* chars_to_glyph_ids = font_info_->chars_to_glyph_ids();
+  SegmentList* segment_list = new SegmentList;
+  IntegerList* glyph_id_array = new IntegerList;
+  int32_t last_chararacter = -2;
+  int32_t last_offset = 0;
+  Ptr<CMapTable::CMapFormat4::Builder::Segment> current_segment;
+
+  // For simplicity, we will have one segment per contiguous range.
+  // To test the algorithm, we've replaced the original CMap with the CMap
+  // generated by this code without removing any character.
+  // Tuffy.ttf: CMap went from 3146 to 3972 bytes (1.7% to 2.17% of file)
+  // AnonymousPro.ttf: CMap went from 1524 to 1900 bytes (0.96% to 1.2%)
+  for (CharacterMap::iterator it = chars_to_glyph_ids->begin(),
+           e = chars_to_glyph_ids->end(); it != e; ++it) {
+    int32_t character = it->first;
+    int32_t glyph_id = it->second.glyph_id();
+    if (character != last_chararacter + 1) {  // new segment
+      if (current_segment != NULL) {
+        current_segment->set_end_count(last_chararacter);
+        segment_list->push_back(current_segment);
+      }
+      // start_code = character
+      // end_code = -1 (unknown for now)
+      // id_delta = 0 (we don't use id_delta for this representation)
+      // id_range_offset = last_offset (offset into the glyph_id_array)
+      current_segment =
+          new CMapTable::CMapFormat4::Builder::
+          Segment(character, -1, 0, last_offset);
+    }
+    glyph_id_array->push_back(glyph_id);
+    last_offset += DataSize::kSHORT;
+    last_chararacter = character;
+  }
+  // The last segment is still open.
+  current_segment->set_end_count(last_chararacter);
+  segment_list->push_back(current_segment);
+  // Updating the id_range_offset for every segment.
+  for (int32_t i = 0, num_segs = segment_list->size(); i < num_segs; ++i) {
+    Ptr<CMapTable::CMapFormat4::Builder::Segment> segment = segment_list->at(i);
+    segment->set_id_range_offset(segment->id_range_offset()
+                                 + (num_segs - i + 1) * DataSize::kSHORT);
+  }
+  // Adding the final, required segment.
+  current_segment =
+      new CMapTable::CMapFormat4::Builder::Segment(0xffff, 0xffff, 1, 0);
+  segment_list->push_back(current_segment);
+  // Writing the segments and glyph id array to the CMap
+  cmap_builder->set_segments(segment_list);
+  cmap_builder->set_glyph_id_array(glyph_id_array);
+  delete segment_list;
+  delete glyph_id_array;
+  return true;
+}
+
+bool FontAssembler::AssembleGlyphAndLocaTables() {
+  Ptr<LocaTable::Builder> loca_table_builder =
+      down_cast<LocaTable::Builder*>
+      (font_builder_->NewTableBuilder(Tag::loca));
+  Ptr<GlyphTable::Builder> glyph_table_builder =
+      down_cast<GlyphTable::Builder*>
+      (font_builder_->NewTableBuilder(Tag::glyf));
+
+  GlyphIdSet* resolved_glyph_ids = font_info_->resolved_glyph_ids();
+  IntegerList loca_list;
+  // Basic sanity check: all LOCA tables are of the same size
+  // This is necessary but not suficient!
+  int32_t previous_size = -1;
+  for (FontIdMap::iterator it = font_info_->fonts()->begin();
+       it != font_info_->fonts()->end(); ++it) {
+    Ptr<LocaTable> loca_table =
+        down_cast<LocaTable*>(font_info_->GetTable(it->first, Tag::loca));
+    int32_t current_size = loca_table->header_length();
+    if (previous_size != -1 && current_size != previous_size) {
+      return false;
+    }
+    previous_size = current_size;
+  }
+
+  // Assuming all fonts referenced by the FontInfo are the subsets of the same
+  // font, their loca tables should all have the same sizes.
+  // We'll just get the size of the first font's LOCA table for simplicty.
+  Ptr<LocaTable> first_loca_table =
+    down_cast<LocaTable*>
+    (font_info_->GetTable(font_info_->fonts()->begin()->first, Tag::loca));
+  int32_t num_loca_glyphs = first_loca_table->num_glyphs();
+  loca_list.resize(num_loca_glyphs);
+  loca_list.push_back(0);
+  int32_t last_glyph_id = 0;
+  int32_t last_offset = 0;
+  GlyphTable::GlyphBuilderList* glyph_builders =
+      glyph_table_builder->GlyphBuilders();
+
+  for (GlyphIdSet::iterator it = resolved_glyph_ids->begin(),
+           e = resolved_glyph_ids->end(); it != e; ++it) {
+    // Get the glyph for this resolved_glyph_id.
+    int32_t resolved_glyph_id = it->glyph_id();
+    int32_t font_id = it->font_id();
+    // Get the LOCA table for the current glyph id.
+    Ptr<LocaTable> loca_table =
+        down_cast<LocaTable*>
+        (font_info_->GetTable(font_id, Tag::loca));
+    int32_t length = loca_table->GlyphLength(resolved_glyph_id);
+    int32_t offset = loca_table->GlyphOffset(resolved_glyph_id);
+
+    // Get the GLYF table for the current glyph id.
+    Ptr<GlyphTable> glyph_table =
+        down_cast<GlyphTable*>
+        (font_info_->GetTable(font_id, Tag::glyf));
+    GlyphPtr glyph;
+    glyph.Attach(glyph_table->GetGlyph(offset, length));
+
+    // The data reference by the glyph is copied into a new glyph and
+    // added to the glyph_builders belonging to the glyph_table_builder.
+    // When Build gets called, all the glyphs will be built.
+    Ptr<ReadableFontData> data = glyph->ReadFontData();
+    Ptr<WritableFontData> copy_data;
+    copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length()));
+    data->CopyTo(copy_data);
+    GlyphBuilderPtr glyph_builder;
+    glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data));
+    glyph_builders->push_back(glyph_builder);
+
+    // If there are missing glyphs between the last glyph_id and the
+    // current resolved_glyph_id, since the LOCA table needs to have the same
+    // size, the offset is kept the same.
+    for (int32_t i = last_glyph_id + 1; i <= resolved_glyph_id; ++i)
+      loca_list[i] = last_offset;
+    last_offset += length;
+    loca_list[resolved_glyph_id + 1] = last_offset;
+    last_glyph_id = resolved_glyph_id + 1;
+  }
+  // If there are missing glyph ids, their loca entries must all point
+  // to the same offset as the last valid glyph id making them all zero length.
+  for (int32_t i = last_glyph_id + 1; i <= num_loca_glyphs; ++i)
+    loca_list[i] = last_offset;
+  loca_table_builder->SetLocaList(&loca_list);
+  return true;
+}
+}
diff --git a/sample/subtly/font_assembler.h b/sample/subtly/font_assembler.h
new file mode 100644
index 0000000..c53c21f
--- /dev/null
+++ b/sample/subtly/font_assembler.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_ASSEMBLER_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_ASSEMBLER_H_
+
+#include <set>
+#include <map>
+
+#include "subtly/font_info.h"
+
+#include "sfntly/tag.h"
+#include "sfntly/font.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/refcount.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/table/truetype/glyph_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+
+namespace subtly {
+// Assembles FontInfo into font builders.
+// Does not take ownership of data passed to it.
+class FontAssembler : public sfntly::RefCounted<FontAssembler> {
+ public:
+  // font_info is the FontInfo which will be used for the new font
+  // table_blacklist is used to decide which tables to exclude from the
+  // final font.
+  FontAssembler(FontInfo* font_info, sfntly::IntegerSet* table_blacklist);
+  explicit FontAssembler(FontInfo* font_info);
+  ~FontAssembler() { }
+
+  // Assemble a new font from the font info object.
+  virtual CALLER_ATTACH sfntly::Font* Assemble();
+
+  sfntly::IntegerSet* table_blacklist() const { return table_blacklist_; }
+  void set_table_blacklist(sfntly::IntegerSet* table_blacklist) {
+    table_blacklist_ = table_blacklist;
+  }
+
+ protected:
+  virtual bool AssembleCMapTable();
+  virtual bool AssembleGlyphAndLocaTables();
+
+  virtual void Initialize();
+
+ private:
+  sfntly::Ptr<FontInfo> font_info_;
+  sfntly::Ptr<sfntly::FontFactory> font_factory_;
+  sfntly::Ptr<sfntly::Font::Builder> font_builder_;
+  sfntly::IntegerSet* table_blacklist_;
+};
+}
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_ASSEMBLER_H_
diff --git a/sample/subtly/font_info.cc b/sample/subtly/font_info.cc
new file mode 100644
index 0000000..6eb6a38
--- /dev/null
+++ b/sample/subtly/font_info.cc
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "subtly/font_info.h"
+
+#include <stdio.h>
+
+#include <set>
+#include <map>
+
+#include "subtly/character_predicate.h"
+
+#include "sfntly/tag.h"
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+#include "sfntly/table/truetype/glyph_table.h"
+#include "sfntly/table/core/maximum_profile_table.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/refcount.h"
+
+namespace subtly {
+using namespace sfntly;
+/******************************************************************************
+ * GlyphId class
+ ******************************************************************************/
+GlyphId::GlyphId(int32_t glyph_id, FontId font_id)
+    : glyph_id_(glyph_id),
+      font_id_(font_id) {
+}
+
+bool GlyphId::operator==(const GlyphId& other) const {
+  return glyph_id_ == other.glyph_id();
+}
+
+bool GlyphId::operator<(const GlyphId& other) const {
+  return glyph_id_ < other.glyph_id();
+}
+
+/******************************************************************************
+ * FontInfo class
+ ******************************************************************************/
+FontInfo::FontInfo()
+    : chars_to_glyph_ids_(new CharacterMap),
+      resolved_glyph_ids_(new GlyphIdSet),
+      fonts_(new FontIdMap) {
+}
+
+FontInfo::FontInfo(CharacterMap* chars_to_glyph_ids,
+                   GlyphIdSet* resolved_glyph_ids,
+                   FontIdMap* fonts) {
+  chars_to_glyph_ids_ = new CharacterMap(chars_to_glyph_ids->begin(),
+                                         chars_to_glyph_ids->end());
+  resolved_glyph_ids_ = new GlyphIdSet(resolved_glyph_ids->begin(),
+                                       resolved_glyph_ids->end());
+  fonts_ = new FontIdMap(fonts->begin(), fonts->end());
+}
+
+FontInfo::~FontInfo() {
+  delete chars_to_glyph_ids_;
+  delete resolved_glyph_ids_;
+  delete fonts_;
+}
+
+FontDataTable* FontInfo::GetTable(FontId font_id, int32_t tag) {
+  if (!fonts_)
+    return NULL;
+  FontIdMap::iterator it = fonts_->find(font_id);
+  if (it == fonts_->end())
+    return NULL;
+  return it->second->GetTable(tag);
+}
+
+const TableMap* FontInfo::GetTableMap(FontId font_id) {
+  if (!fonts_)
+    return NULL;
+  FontIdMap::iterator it = fonts_->find(font_id);
+  if (it == fonts_->end())
+    return NULL;
+  return it->second->GetTableMap();
+}
+
+void FontInfo::set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids) {
+  *chars_to_glyph_ids_ = *chars_to_glyph_ids;
+}
+
+void FontInfo::set_resolved_glyph_ids(GlyphIdSet* resolved_glyph_ids) {
+  *resolved_glyph_ids_ = *resolved_glyph_ids;
+}
+
+void FontInfo::set_fonts(FontIdMap* fonts) {
+  *fonts_ = *fonts;
+}
+
+/******************************************************************************
+ * FontSourcedInfoBuilder class
+ ******************************************************************************/
+FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, FontId font_id)
+    : font_(font),
+      font_id_(font_id),
+      predicate_(NULL) {
+  Initialize();
+}
+
+FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font,
+                                               FontId font_id,
+                                               CharacterPredicate* predicate)
+    : font_(font),
+      font_id_(font_id),
+      predicate_(predicate) {
+  Initialize();
+}
+
+void FontSourcedInfoBuilder::Initialize() {
+  Ptr<CMapTable> cmap_table = down_cast<CMapTable*>(font_->GetTable(Tag::cmap));
+  // We prefer Windows BMP format 4 cmaps.
+  cmap_.Attach(cmap_table->GetCMap(CMapTable::WINDOWS_BMP));
+  // But if none is found,
+  if (!cmap_) {
+    return;
+  }
+  loca_table_ = down_cast<LocaTable*>(font_->GetTable(Tag::loca));
+  glyph_table_ = down_cast<GlyphTable*>(font_->GetTable(Tag::glyf));
+}
+
+CALLER_ATTACH FontInfo* FontSourcedInfoBuilder::GetFontInfo() {
+  CharacterMap* chars_to_glyph_ids = new CharacterMap;
+  bool success = GetCharacterMap(chars_to_glyph_ids);
+  if (!success) {
+    delete chars_to_glyph_ids;
+#if defined (SUBTLY_DEBUG)
+    fprintf(stderr, "Error creating character map.\n");
+#endif
+    return NULL;
+  }
+  GlyphIdSet* resolved_glyph_ids = new GlyphIdSet;
+  success = ResolveCompositeGlyphs(chars_to_glyph_ids, resolved_glyph_ids);
+  if (!success) {
+    delete chars_to_glyph_ids;
+    delete resolved_glyph_ids;
+#if defined (SUBTLY_DEBUG)
+    fprintf(stderr, "Error resolving composite glyphs.\n");
+#endif
+    return NULL;
+  }
+  Ptr<FontInfo> font_info = new FontInfo;
+  font_info->set_chars_to_glyph_ids(chars_to_glyph_ids);
+  font_info->set_resolved_glyph_ids(resolved_glyph_ids);
+  FontIdMap* font_id_map = new FontIdMap;
+  font_id_map->insert(std::make_pair(font_id_, font_));
+  font_info->set_fonts(font_id_map);
+  delete chars_to_glyph_ids;
+  delete resolved_glyph_ids;
+  delete font_id_map;
+  return font_info.Detach();
+}
+
+bool FontSourcedInfoBuilder::GetCharacterMap(CharacterMap* chars_to_glyph_ids) {
+  if (!cmap_ || !chars_to_glyph_ids)
+    return false;
+  chars_to_glyph_ids->clear();
+  CMapTable::CMap::CharacterIterator* character_iterator = cmap_->Iterator();
+  if (!character_iterator)
+    return false;
+  while (character_iterator->HasNext()) {
+    int32_t character = character_iterator->Next();
+    if (!predicate_ || (*predicate_)(character)) {
+      chars_to_glyph_ids->insert
+          (std::make_pair(character,
+                          GlyphId(cmap_->GlyphId(character), font_id_)));
+    }
+  }
+  delete character_iterator;
+  return true;
+}
+
+bool
+FontSourcedInfoBuilder::ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids,
+                                               GlyphIdSet* resolved_glyph_ids) {
+  if (!chars_to_glyph_ids || !resolved_glyph_ids)
+    return false;
+  resolved_glyph_ids->clear();
+  resolved_glyph_ids->insert(GlyphId(0, font_id_));
+  IntegerSet* unresolved_glyph_ids = new IntegerSet;
+  // Since composite glyph elements might themselves be composite, we would need
+  // to recursively resolve the elements too. To avoid the recursion we
+  // create two sets, |unresolved_glyph_ids| for the unresolved glyphs,
+  // initially containing all the ids and |resolved_glyph_ids|, initially empty.
+  // We'll remove glyph ids from |unresolved_glyph_ids| until it is empty and,
+  // if the glyph is composite, add its elements to the unresolved set.
+  for (CharacterMap::iterator it = chars_to_glyph_ids->begin(),
+           e = chars_to_glyph_ids->end(); it != e; ++it) {
+    unresolved_glyph_ids->insert(it->second.glyph_id());
+  }
+  // As long as there are unresolved glyph ids.
+  while (!unresolved_glyph_ids->empty()) {
+    // Get the corresponding glyph.
+    int32_t glyph_id = *(unresolved_glyph_ids->begin());
+    unresolved_glyph_ids->erase(unresolved_glyph_ids->begin());
+    if (glyph_id < 0 || glyph_id > loca_table_->num_glyphs()) {
+#if defined (SUBTLY_DEBUG)
+      fprintf(stderr, "%d larger than %d or smaller than 0\n", glyph_id,
+              loca_table_->num_glyphs());
+#endif
+      continue;
+    }
+    int32_t length = loca_table_->GlyphLength(glyph_id);
+    if (length == 0) {
+#if defined (SUBTLY_DEBUG)
+      fprintf(stderr, "Zero length glyph %d\n", glyph_id);
+#endif
+      continue;
+    }
+    int32_t offset = loca_table_->GlyphOffset(glyph_id);
+    GlyphPtr glyph;
+    glyph.Attach(glyph_table_->GetGlyph(offset, length));
+    if (glyph == NULL) {
+#if defined (SUBTLY_DEBUG)
+      fprintf(stderr, "GetGlyph returned NULL for %d\n", glyph_id);
+#endif
+      continue;
+    }
+    // Mark the glyph as resolved.
+    resolved_glyph_ids->insert(GlyphId(glyph_id, font_id_));
+    // If it is composite, add all its components to the unresolved glyph set.
+    if (glyph->GlyphType() == GlyphType::kComposite) {
+      Ptr<GlyphTable::CompositeGlyph> composite_glyph =
+          down_cast<GlyphTable::CompositeGlyph*>(glyph.p_);
+      int32_t num_glyphs = composite_glyph->NumGlyphs();
+      for (int32_t i = 0; i < num_glyphs; ++i) {
+        int32_t glyph_id = composite_glyph->GlyphIndex(i);
+        if (resolved_glyph_ids->find(GlyphId(glyph_id, -1))
+            == resolved_glyph_ids->end()) {
+          unresolved_glyph_ids->insert(glyph_id);
+        }
+      }
+    }
+  }
+  delete unresolved_glyph_ids;
+  return true;
+}
+}
diff --git a/sample/subtly/font_info.h b/sample/subtly/font_info.h
new file mode 100644
index 0000000..6f42d73
--- /dev/null
+++ b/sample/subtly/font_info.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_INFO_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_INFO_H_
+
+#include <map>
+#include <set>
+
+#include "sfntly/font.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/refcount.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/table/truetype/glyph_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+
+namespace subtly {
+class CharacterPredicate;
+
+typedef int32_t FontId;
+typedef std::map<FontId, sfntly::Ptr<sfntly::Font> > FontIdMap;
+
+// Glyph id pair that contains the loca table glyph id as well as the
+// font id that has the glyph table this glyph belongs to.
+class GlyphId {
+ public:
+  GlyphId(int32_t glyph_id, FontId font_id);
+  ~GlyphId() {}
+
+  bool operator==(const GlyphId& other) const;
+  bool operator<(const GlyphId& other) const;
+
+  int32_t glyph_id() const { return glyph_id_; }
+  void set_glyph_id(const int32_t glyph_id) { glyph_id_ = glyph_id; }
+  FontId font_id() const { return font_id_; }
+  void set_font_id(const FontId font_id) { font_id_ = font_id; }
+
+ private:
+  int32_t glyph_id_;
+  FontId font_id_;
+};
+
+typedef std::map<int32_t, GlyphId> CharacterMap;
+typedef std::set<GlyphId> GlyphIdSet;
+
+// Font information used for FontAssembler in the construction of a new font.
+// Will make copies of character map, glyph id set and font id map.
+class FontInfo : public sfntly::RefCounted<FontInfo> {
+ public:
+  // Empty FontInfo object.
+  FontInfo();
+  // chars_to_glyph_ids maps characters to GlyphIds for CMap construction
+  // resolved_glyph_ids defines GlyphIds which should be in the final font
+  // fonts is a map of font ids to fonts to reference any needed table
+  FontInfo(CharacterMap* chars_to_glyph_ids,
+           GlyphIdSet* resolved_glyph_ids,
+           FontIdMap* fonts);
+  virtual ~FontInfo();
+
+  // Gets the table with the specified tag from the font corresponding to
+  // font_id or NULL if there is no such font/table.
+  // font_id is the id of the font that contains the table
+  // tag identifies the table to be obtained
+  virtual sfntly::FontDataTable* GetTable(FontId font_id, int32_t tag);
+  // Gets the table map of the font whose id is font_id
+  virtual const sfntly::TableMap* GetTableMap(FontId);
+
+  CharacterMap* chars_to_glyph_ids() const { return chars_to_glyph_ids_; }
+  // Takes ownership of the chars_to_glyph_ids CharacterMap.
+  void set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids);
+  GlyphIdSet* resolved_glyph_ids() const { return resolved_glyph_ids_; }
+  // Takes ownership of the glyph_ids GlyphIdSet.
+  void set_resolved_glyph_ids(GlyphIdSet* glyph_ids);
+  FontIdMap* fonts() const { return fonts_; }
+  // Takes ownership of the fonts FontIdMap.
+  void set_fonts(FontIdMap* fonts);
+
+ private:
+  CharacterMap* chars_to_glyph_ids_;
+  GlyphIdSet* resolved_glyph_ids_;
+  FontIdMap* fonts_;
+};
+
+// FontSourcedInfoBuilder is used to create a FontInfo object from a Font
+// optionally specifying a CharacterPredicate to filter out some of
+// the font's characters.
+// It does not take ownership or copy the values its constructor receives.
+class FontSourcedInfoBuilder :
+      public sfntly::RefCounted<FontSourcedInfoBuilder> {
+ public:
+  FontSourcedInfoBuilder(sfntly::Font* font, FontId font_id);
+  FontSourcedInfoBuilder(sfntly::Font* font,
+                         FontId font_id,
+                         CharacterPredicate* predicate);
+  virtual ~FontSourcedInfoBuilder() { }
+
+  virtual CALLER_ATTACH FontInfo* GetFontInfo();
+
+ protected:
+  bool GetCharacterMap(CharacterMap* chars_to_glyph_ids);
+  bool ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids,
+                              GlyphIdSet* resolved_glyph_ids);
+  void Initialize();
+
+ private:
+  sfntly::Ptr<sfntly::Font> font_;
+  FontId font_id_;
+  CharacterPredicate* predicate_;
+
+  sfntly::Ptr<sfntly::CMapTable::CMap> cmap_;
+  sfntly::Ptr<sfntly::LocaTable> loca_table_;
+  sfntly::Ptr<sfntly::GlyphTable> glyph_table_;
+};
+}
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_INFO_H_
diff --git a/sample/subtly/merger.cc b/sample/subtly/merger.cc
new file mode 100644
index 0000000..7875c2d
--- /dev/null
+++ b/sample/subtly/merger.cc
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "subtly/merger.h"
+
+#include <stdio.h>
+
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "subtly/character_predicate.h"
+#include "subtly/font_assembler.h"
+#include "subtly/font_info.h"
+#include "subtly/utils.h"
+
+namespace subtly {
+using namespace sfntly;
+
+/******************************************************************************
+ * Merger class
+ ******************************************************************************/
+Merger::Merger(FontArray* fonts) {
+  if (!fonts) {
+    return;
+  }
+  int32_t num_fonts = fonts->size();
+  for (int32_t i = 0; i < num_fonts; ++i) {
+    fonts_.insert(std::make_pair(i, fonts->at(i)));
+  }
+}
+
+CALLER_ATTACH Font* Merger::Merge() {
+  Ptr<FontInfo> merged_info;
+  merged_info.Attach(MergeFontInfos());
+  if (!merged_info) {
+#if defined (SUBTLY_DEBUG)
+    fprintf(stderr, "Could not create merged font info\n");
+#endif
+    return NULL;
+  }
+  Ptr<FontAssembler> font_assembler = new FontAssembler(merged_info);
+  return font_assembler->Assemble();
+}
+
+CALLER_ATTACH FontInfo* Merger::MergeFontInfos() {
+  Ptr<FontInfo> font_info = new FontInfo;
+  font_info->set_fonts(&fonts_);
+  for (FontIdMap::iterator it = fonts_.begin(),
+           e = fonts_.end(); it != e; ++it) {
+    Ptr<FontSourcedInfoBuilder> info_builder =
+        new FontSourcedInfoBuilder(it->second, it->first, NULL);
+    Ptr<FontInfo> current_font_info;
+    current_font_info.Attach(info_builder->GetFontInfo());
+    if (!current_font_info) {
+#if defined (SUBTLY_DEBUG)
+      fprintf(stderr, "Couldn't create font info. "
+              "No subset will be generated.\n");
+#endif
+      return NULL;
+    }
+    font_info->chars_to_glyph_ids()->insert(
+        current_font_info->chars_to_glyph_ids()->begin(),
+        current_font_info->chars_to_glyph_ids()->end());
+    font_info->resolved_glyph_ids()->insert(
+        current_font_info->resolved_glyph_ids()->begin(),
+        current_font_info->resolved_glyph_ids()->end());
+#if defined (SUBTLY_DEBUG)
+    fprintf(stderr, "Counts: chars_to_glyph_ids: %d; resoved_glyph_ids: %d\n",
+            font_info->chars_to_glyph_ids()->size(),
+            font_info->resolved_glyph_ids()->size());
+#endif
+  }
+  return font_info.Detach();
+}
+}
diff --git a/sample/subtly/merger.h b/sample/subtly/merger.h
new file mode 100644
index 0000000..43764a8
--- /dev/null
+++ b/sample/subtly/merger.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_MERGER_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_MERGER_H_
+
+#include "subtly/character_predicate.h"
+#include "subtly/font_info.h"
+
+namespace sfntly {
+class Font;
+}
+
+namespace subtly {
+// Merges the subsets in the font array into a single font.
+class Merger : public sfntly::RefCounted<Merger> {
+ public:
+  explicit Merger(sfntly::FontArray* fonts);
+  virtual ~Merger() { }
+
+  // Performs merging returning the subsetted font.
+  virtual CALLER_ATTACH sfntly::Font* Merge();
+
+ protected:
+  virtual CALLER_ATTACH FontInfo* MergeFontInfos();
+
+ private:
+  FontIdMap fonts_;
+};
+}
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_MERGER_H_
diff --git a/sample/subtly/merger_main.cc b/sample/subtly/merger_main.cc
new file mode 100644
index 0000000..a977aa7
--- /dev/null
+++ b/sample/subtly/merger_main.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+#include <map>
+#include <utility>
+
+#include "sfntly/font.h"
+#include "subtly/merger.h"
+#include "subtly/stats.h"
+#include "subtly/utils.h"
+
+using namespace subtly;
+
+void PrintUsage(const char* program_name) {
+  fprintf(stdout, "Usage: %s <input_font_file1> <input_font_file2> ..."
+          "<input_font_filen> <output_font_file>\n",
+          program_name);
+}
+
+void CheckLoading(const char* font_path, Font* font) {
+  if (!font || font->num_tables() == 0) {
+    fprintf(stderr, "Could not load font %s. Terminating.\n", font_path);
+    exit(1);
+  }
+}
+
+int main(int argc, const char** argv) {
+  if (argc < 3) {
+    PrintUsage(argv[0]);
+    exit(1);
+  }
+
+  FontArray fonts;
+  for (int32_t i = 1; i < argc - 1; ++i) {
+    Ptr<Font> font;
+    font.Attach(LoadFont(argv[i]));
+    CheckLoading(argv[i], font);
+    fonts.push_back(font);
+  }
+
+  Ptr<Merger> merger = new Merger(&fonts);
+  FontPtr new_font;
+  new_font.Attach(merger->Merge());
+
+  fprintf(stderr, "Serializing font to %s\n", argv[argc - 1]);
+  SerializeFont(argv[argc - 1], new_font);
+  if (!new_font) {
+    fprintf(stdout, "Cannot create merged font.\n");
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/sample/subtly/stats.cc b/sample/subtly/stats.cc
new file mode 100644
index 0000000..769f691
--- /dev/null
+++ b/sample/subtly/stats.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 <stdio.h>
+
+#include "sfntly/font.h"
+#include "sfntly/table/table.h"
+#include "sfntly/tag.h"
+#include "subtly/stats.h"
+
+namespace subtly {
+using namespace sfntly;
+
+int32_t TotalFontSize(Font* font) {
+  int32_t size = 0;
+  const TableMap* table_map = font->GetTableMap();
+  for (TableMap::const_iterator it = table_map->begin(),
+           e = table_map->end(); it != e; ++it) {
+    size += it->second->DataLength();
+  }
+  return size;
+}
+
+double TableSizePercent(Font* font, int32_t tag) {
+  TablePtr table = font->GetTable(tag);
+  return static_cast<double>(table->DataLength()) / TotalFontSize(font) * 100;
+}
+
+void PrintComparison(FILE* out, Font* font, Font* new_font) {
+  fprintf(out, "====== Table Comparison (original v. subset) ======\n");
+  const TableMap* tables = font->GetTableMap();
+  for (TableMap::const_iterator it = tables->begin(),
+           e = tables->end(); it != e; ++it) {
+    char *name = TagToString(it->first);
+    int32_t size = it->second->DataLength();
+    fprintf(out, "-- %s: %d (%lf%%) ", name, size,
+            TableSizePercent(font, it->first));
+    delete[] name;
+
+    Ptr<FontDataTable> new_table = new_font->GetTable(it->first);
+    int32_t new_size = 0;
+    double size_percent = 0;
+    if (new_table) {
+      new_size = new_table->DataLength();
+      size_percent = subtly::TableSizePercent(new_font, it->first);
+    }
+
+    if (new_size == size) {
+      fprintf(out, "| same size\n");
+    } else {
+      fprintf(out, "-> %d (%lf%%) | %lf%% of original\n", new_size,
+              size_percent, static_cast<double>(new_size) / size * 100);
+    }
+  }
+}
+
+void PrintStats(FILE* out, Font* font) {
+  fprintf(out, "====== Table Stats ======\n");
+  const TableMap* tables = font->GetTableMap();
+  for (TableMap::const_iterator it = tables->begin(),
+           e = tables->end(); it != e; ++it) {
+    char *name = TagToString(it->first);
+    int32_t size = it->second->DataLength();
+    fprintf(out, "-- %s: %d (%lf%%)\n", name, size,
+            TableSizePercent(font, it->first));
+    delete[] name;
+  }
+}
+}
diff --git a/sample/subtly/stats.h b/sample/subtly/stats.h
new file mode 100644
index 0000000..89ef2ae
--- /dev/null
+++ b/sample/subtly/stats.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_STATS_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_STATS_H_
+
+#include <stdio.h>
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+class Font;
+}
+
+namespace subtly {
+using namespace sfntly;
+
+int32_t TotalFontSize(Font* font);
+
+double TableSizePercent(Font* font, int32_t tag);
+
+void PrintComparison(FILE* out, Font* font, Font* new_font);
+
+void PrintStats(FILE* out, Font* font);
+}
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_STATS_H_
diff --git a/sample/subtly/subsetter.cc b/sample/subtly/subsetter.cc
new file mode 100644
index 0000000..d09627c
--- /dev/null
+++ b/sample/subtly/subsetter.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "subtly/subsetter.h"
+
+#include <stdio.h>
+
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/tag.h"
+#include "subtly/character_predicate.h"
+#include "subtly/font_assembler.h"
+#include "subtly/font_info.h"
+#include "subtly/utils.h"
+
+namespace subtly {
+using namespace sfntly;
+
+/******************************************************************************
+ * Subsetter class
+ ******************************************************************************/
+Subsetter::Subsetter(Font* font, CharacterPredicate* predicate)
+    : font_(font),
+      predicate_(predicate) {
+}
+
+Subsetter::Subsetter(const char* font_path, CharacterPredicate* predicate)
+    : predicate_(predicate) {
+  font_.Attach(LoadFont(font_path));
+}
+
+CALLER_ATTACH Font* Subsetter::Subset() {
+  Ptr<FontSourcedInfoBuilder> info_builder =
+      new FontSourcedInfoBuilder(font_, 0, predicate_);
+
+  Ptr<FontInfo> font_info;
+  font_info.Attach(info_builder->GetFontInfo());
+  if (!font_info) {
+#if defined (SUBTLY_DEBUG)
+    fprintf(stderr,
+            "Couldn't create font info. No subset will be generated.\n");
+#endif
+    return NULL;
+  }
+  IntegerSet* table_blacklist = new IntegerSet;
+  table_blacklist->insert(Tag::DSIG);
+  Ptr<FontAssembler> font_assembler = new FontAssembler(font_info,
+                                                        table_blacklist);
+  Ptr<Font> font_subset;
+  font_subset.Attach(font_assembler->Assemble());
+  delete table_blacklist;
+  return font_subset.Detach();
+}
+}
diff --git a/sample/subtly/subsetter.h b/sample/subtly/subsetter.h
new file mode 100644
index 0000000..a93747f
--- /dev/null
+++ b/sample/subtly/subsetter.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_SUBSETTER_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_SUBSETTER_H_
+
+#include "sfntly/font.h"
+// Cannot remove this header due to Ptr<T> instantiation issue
+#include "subtly/character_predicate.h"
+
+namespace subtly {
+// Subsets a given font using a character predicate.
+class Subsetter : public sfntly::RefCounted<Subsetter> {
+ public:
+  Subsetter(sfntly::Font* font, CharacterPredicate* predicate);
+  Subsetter(const char* font_path, CharacterPredicate* predicate);
+  virtual ~Subsetter() { }
+
+  // Performs subsetting returning the subsetted font.
+  virtual CALLER_ATTACH sfntly::Font* Subset();
+
+ private:
+  sfntly::Ptr<sfntly::Font> font_;
+  sfntly::Ptr<CharacterPredicate> predicate_;
+};
+}
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_SUBSETTER_H_
diff --git a/sample/subtly/subsetter_main.cc b/sample/subtly/subsetter_main.cc
new file mode 100644
index 0000000..d438148
--- /dev/null
+++ b/sample/subtly/subsetter_main.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+#include <map>
+#include <utility>
+
+#include "sfntly/font.h"
+#include "subtly/character_predicate.h"
+#include "subtly/stats.h"
+#include "subtly/subsetter.h"
+#include "subtly/utils.h"
+
+using namespace subtly;
+
+void PrintUsage(const char* program_name) {
+  fprintf(stdout, "Usage: %s <input_font_file> <output_font_file>"
+          "<start_char> <end_char>\n", program_name);
+}
+
+int main(int argc, const char** argv) {
+  const char* program_name = argv[0];
+  if (argc < 5) {
+    PrintUsage(program_name);
+    exit(1);
+  }
+
+  const char* input_font_path = argv[1];
+  const char* output_font_path = argv[2];
+  FontPtr font;
+  font.Attach(subtly::LoadFont(input_font_path));
+  if (font->num_tables() == 0) {
+    fprintf(stderr, "Could not load font %s.\n", input_font_path);
+    exit(1);
+  }
+
+  const char* start_char = argv[3];
+  const char* end_char = argv[4];
+  if (start_char[1] != 0) {
+    fprintf(stderr, "Start character %c invalid.\n", start_char[0]);
+    exit(1);
+  }
+  if (end_char[1] != 0) {
+    fprintf(stderr, "Start character %c invalid.\n", end_char[0]);
+    exit(1);
+  }
+  int32_t original_size = TotalFontSize(font);
+
+
+  Ptr<CharacterPredicate> range_predicate =
+      new AcceptRange(start_char[0], end_char[0]);
+  Ptr<Subsetter> subsetter = new Subsetter(font, range_predicate);
+  Ptr<Font> new_font;
+  new_font.Attach(subsetter->Subset());
+  if (!new_font) {
+    fprintf(stdout, "Cannot create subset.\n");
+    return 0;
+  }
+
+  subtly::SerializeFont(output_font_path, new_font);
+  subtly::PrintComparison(stdout, font, new_font);
+  int32_t new_size = TotalFontSize(new_font);
+  fprintf(stdout, "Went from %d to %d: %lf%% of original\n",
+          original_size, new_size,
+          static_cast<double>(new_size) / original_size * 100);
+  return 0;
+}
diff --git a/sample/subtly/utils.cc b/sample/subtly/utils.cc
new file mode 100644
index 0000000..3c204d3
--- /dev/null
+++ b/sample/subtly/utils.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "subtly/utils.h"
+
+#include "sfntly/data/growable_memory_byte_array.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/port/file_input_stream.h"
+#include "sfntly/port/memory_output_stream.h"
+
+namespace subtly {
+using namespace sfntly;
+
+CALLER_ATTACH Font* LoadFont(const char* font_path) {
+  Ptr<FontFactory> font_factory;
+  font_factory.Attach(FontFactory::GetInstance());
+  FontArray fonts;
+  LoadFonts(font_path, font_factory, &fonts);
+  return fonts[0].Detach();
+}
+
+CALLER_ATTACH Font::Builder* LoadFontBuilder(const char* font_path) {
+  FontFactoryPtr font_factory;
+  font_factory.Attach(FontFactory::GetInstance());
+  FontBuilderArray builders;
+  LoadFontBuilders(font_path, font_factory, &builders);
+  return builders[0].Detach();
+}
+
+void LoadFonts(const char* font_path, FontFactory* factory, FontArray* fonts) {
+  FileInputStream input_stream;
+  input_stream.Open(font_path);
+  factory->LoadFonts(&input_stream, fonts);
+  input_stream.Close();
+}
+
+void LoadFontBuilders(const char* font_path,
+                      FontFactory* factory,
+                      FontBuilderArray* builders) {
+  FileInputStream input_stream;
+  input_stream.Open(font_path);
+  factory->LoadFontsForBuilding(&input_stream, builders);
+  input_stream.Close();
+}
+
+bool SerializeFont(const char* font_path, Font* font) {
+  if (!font_path)
+    return false;
+  FontFactoryPtr font_factory;
+  font_factory.Attach(FontFactory::GetInstance());
+  return SerializeFont(font_path, font_factory, font);
+}
+
+bool SerializeFont(const char* font_path, FontFactory* factory, Font* font) {
+  if (!font_path || !factory || !font)
+    return false;
+  // Serializing the font to a stream.
+  MemoryOutputStream output_stream;
+  factory->SerializeFont(font, &output_stream);
+  // Serializing the stream to a file.
+  FILE* output_file = NULL;
+#if defined WIN32
+  fopen_s(&output_file, font_path, "wb");
+#else
+  output_file = fopen(font_path, "wb");
+#endif
+  if (output_file == reinterpret_cast<FILE*>(NULL))
+    return false;
+  for (size_t i = 0; i < output_stream.Size(); ++i) {
+    fwrite(&(output_stream.Get()[i]), 1, 1, output_file);
+  }
+  fflush(output_file);
+  fclose(output_file);
+  return true;
+}
+};
diff --git a/sample/subtly/utils.h b/sample/subtly/utils.h
new file mode 100644
index 0000000..ba9f0d4
--- /dev/null
+++ b/sample/subtly/utils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_UTILS_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_UTILS_H_
+
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+
+namespace subtly {
+CALLER_ATTACH sfntly::Font* LoadFont(const char* font_path);
+CALLER_ATTACH sfntly::Font::Builder* LoadFontBuilder(const char* font_path);
+
+void LoadFonts(const char* font_path, sfntly::FontFactory* factory,
+               sfntly::FontArray* fonts);
+void LoadFontBuilders(const char* font_path,
+                      sfntly::FontFactory* factory,
+                      sfntly::FontBuilderArray* builders);
+
+bool SerializeFont(const char* font_path, sfntly::Font* font);
+bool SerializeFont(const char* font_path, sfntly::FontFactory* factory,
+                   sfntly::Font* font);
+}
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_UTILS_H_
diff --git a/sfntly/data/byte_array.cc b/sfntly/data/byte_array.cc
new file mode 100644
index 0000000..915a40c
--- /dev/null
+++ b/sfntly/data/byte_array.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/data/byte_array.h"
+
+#include <algorithm>
+
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+
+const int32_t ByteArray::COPY_BUFFER_SIZE = 8192;
+
+ByteArray::~ByteArray() {}
+
+int32_t ByteArray::Length() { return filled_length_; }
+int32_t ByteArray::Size() { return storage_length_; }
+
+int32_t ByteArray::SetFilledLength(int32_t filled_length) {
+  filled_length_ = std::min<int32_t>(filled_length, storage_length_);
+  return filled_length_;
+}
+
+int32_t ByteArray::Get(int32_t index) {
+  return InternalGet(index) & 0xff;
+}
+
+int32_t ByteArray::Get(int32_t index, ByteVector* b) {
+  assert(b);
+  return Get(index, &((*b)[0]), 0, b->size());
+}
+
+int32_t ByteArray::Get(int32_t index,
+                       byte_t* b,
+                       int32_t offset,
+                       int32_t length) {
+  assert(b);
+  if (index < 0 || index >= filled_length_) {
+    return 0;
+  }
+  int32_t actual_length = std::min<int32_t>(length, filled_length_ - index);
+  return InternalGet(index, b, offset, actual_length);
+}
+
+void ByteArray::Put(int32_t index, byte_t b) {
+  if (index < 0 || index >= Size()) {
+#if defined (SFNTLY_NO_EXCEPTION)
+    return;
+#else
+    throw IndexOutOfBoundException(
+        "Attempt to write outside the bounds of the data");
+#endif
+  }
+  InternalPut(index, b);
+  filled_length_ = std::max<int32_t>(filled_length_, index + 1);
+}
+
+int32_t ByteArray::Put(int index, ByteVector* b) {
+  assert(b);
+  return Put(index, &((*b)[0]), 0, b->size());
+}
+
+int32_t ByteArray::Put(int32_t index,
+                       byte_t* b,
+                       int32_t offset,
+                       int32_t length) {
+  assert(b);
+  if (index < 0 || index >= Size()) {
+#if defined (SFNTLY_NO_EXCEPTION)
+    return 0;
+#else
+    throw IndexOutOfBoundException(
+        "Attempt to write outside the bounds of the data");
+#endif
+  }
+  int32_t actual_length = std::min<int32_t>(length, Size() - index);
+  int32_t bytes_written = InternalPut(index, b, offset, actual_length);
+  filled_length_ = std::max<int32_t>(filled_length_, index + bytes_written);
+  return bytes_written;
+}
+
+int32_t ByteArray::CopyTo(ByteArray* array) {
+  return CopyTo(array, 0, Length());
+}
+
+int32_t ByteArray::CopyTo(ByteArray* array, int32_t offset, int32_t length) {
+  return CopyTo(0, array, offset, length);
+}
+
+int32_t ByteArray::CopyTo(int32_t dst_offset, ByteArray* array,
+                          int32_t src_offset, int32_t length) {
+  assert(array);
+  if (array->Size() < dst_offset + length) {  // insufficient space
+    return -1;
+  }
+
+  ByteVector b(COPY_BUFFER_SIZE);
+  int32_t bytes_read = 0;
+  int32_t index = 0;
+  int32_t remaining_length = length;
+  int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length);
+  while ((bytes_read =
+              Get(index + src_offset, &(b[0]), 0, buffer_length)) > 0) {
+    int bytes_written = array->Put(index + dst_offset, &(b[0]), 0, bytes_read);
+    UNREFERENCED_PARAMETER(bytes_written);
+    index += bytes_read;
+    remaining_length -= bytes_read;
+    buffer_length = std::min<int32_t>(b.size(), remaining_length);
+  }
+  return index;
+}
+
+int32_t ByteArray::CopyTo(OutputStream* os) {
+    return CopyTo(os, 0, Length());
+}
+
+int32_t ByteArray::CopyTo(OutputStream* os, int32_t offset, int32_t length) {
+  ByteVector b(COPY_BUFFER_SIZE);
+  int32_t bytes_read = 0;
+  int32_t index = 0;
+  int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length);
+  while ((bytes_read = Get(index + offset, &(b[0]), 0, buffer_length)) > 0) {
+    os->Write(&b, 0, bytes_read);
+    index += bytes_read;
+    buffer_length = std::min<int32_t>(b.size(), length - index);
+  }
+  return index;
+}
+
+bool ByteArray::CopyFrom(InputStream* is, int32_t length) {
+  ByteVector b(COPY_BUFFER_SIZE);
+  int32_t bytes_read = 0;
+  int32_t index = 0;
+  int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length);
+  while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) {
+    if (Put(index, &(b[0]), 0, bytes_read) != bytes_read) {
+#if defined (SFNTLY_NO_EXCEPTION)
+      return 0;
+#else
+      throw IOException("Error writing bytes.");
+#endif
+    }
+    index += bytes_read;
+    length -= bytes_read;
+    buffer_length = std::min<int32_t>(b.size(), length);
+  }
+  return true;
+}
+
+bool ByteArray::CopyFrom(InputStream* is) {
+  ByteVector b(COPY_BUFFER_SIZE);
+  int32_t bytes_read = 0;
+  int32_t index = 0;
+  int32_t buffer_length = COPY_BUFFER_SIZE;
+  while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) {
+    if (Put(index, &b[0], 0, bytes_read) != bytes_read) {
+#if defined (SFNTLY_NO_EXCEPTION)
+      return 0;
+#else
+      throw IOException("Error writing bytes.");
+#endif
+    }
+    index += bytes_read;
+  }
+  return true;
+}
+
+ByteArray::ByteArray(int32_t filled_length,
+                     int32_t storage_length,
+                     bool growable) {
+  Init(filled_length, storage_length, growable);
+}
+
+ByteArray::ByteArray(int32_t filled_length, int32_t storage_length) {
+  Init(filled_length, storage_length, false);
+}
+
+void ByteArray::Init(int32_t filled_length,
+                     int32_t storage_length,
+                     bool growable) {
+  storage_length_ = storage_length;
+  growable_ = growable;
+  SetFilledLength(filled_length);
+}
+
+}  // namespace sfntly
diff --git a/sfntly/data/byte_array.h b/sfntly/data/byte_array.h
new file mode 100644
index 0000000..70dc92f
--- /dev/null
+++ b/sfntly/data/byte_array.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2011 The sfntly 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.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/input_stream.h"
+#include "sfntly/port/output_stream.h"
+
+namespace sfntly {
+
+// An abstraction to a contiguous array of bytes.
+// C++ port of this class assumes that the data are stored in a linear region
+// like std::vector.
+class ByteArray : virtual public RefCount {
+ public:
+  virtual ~ByteArray();
+
+  // Gets the current filled and readable length of the array.
+  int32_t Length();
+
+  // Gets the maximum size of the array. This is the maximum number of bytes that
+  // the array can hold and all of it may not be filled with data or even fully
+  // allocated yet.
+  int32_t Size();
+
+  // Determines whether or not this array is growable or of fixed size.
+  bool growable() { return growable_; }
+
+  int32_t SetFilledLength(int32_t filled_length);
+
+  // Gets the byte from the given index.
+  // @param index the index into the byte array
+  // @return the byte or -1 if reading beyond the bounds of the data
+  virtual int32_t Get(int32_t index);
+
+  // Gets the bytes from the given index and fill the buffer with them. As many
+  // bytes as will fit into the buffer are read unless that would go past the
+  // end of the array.
+  // @param index the index into the byte array
+  // @param b the buffer to put the bytes read into
+  // @return the number of bytes read from the buffer
+  virtual int32_t Get(int32_t index, ByteVector* b);
+
+  // Gets the bytes from the given index and fill the buffer with them starting
+  // at the offset given. As many bytes as the specified length are read unless
+  // that would go past the end of the array.
+  // @param index the index into the byte array
+  // @param b the buffer to put the bytes read into
+  // @param offset the location in the buffer to start putting the bytes
+  // @param length the number of bytes to put into the buffer
+  // @return the number of bytes read from the buffer
+  virtual int32_t Get(int32_t index,
+                      byte_t* b,
+                      int32_t offset,
+                      int32_t length);
+
+  // Puts the specified byte into the array at the given index unless that would
+  // be beyond the length of the array and it isn't growable.
+  virtual void Put(int32_t index, byte_t b);
+
+  // Puts the specified bytes into the array at the given index. The entire
+  // buffer is put into the array unless that would extend beyond the length and
+  // the array isn't growable.
+  virtual int32_t Put(int32_t index, ByteVector* b);
+
+  // Puts the specified bytes into the array at the given index. All of the bytes
+  // specified are put into the array unless that would extend beyond the length
+  // and the array isn't growable. The bytes to be put into the array are those
+  // in the buffer from the given offset and for the given length.
+  // @param index the index into the ByteArray
+  // @param b the bytes to put into the array
+  // @param offset the offset in the bytes to start copying from
+  // @param length the number of bytes to copy into the array
+  // @return the number of bytes actually written
+  virtual int32_t Put(int32_t index,
+                      byte_t* b,
+                      int32_t offset,
+                      int32_t length);
+
+  // Fully copies this ByteArray to another ByteArray to the extent that the
+  // destination array has storage for the data copied.
+  virtual int32_t CopyTo(ByteArray* array);
+
+  // Copies a segment of this ByteArray to another ByteArray.
+  // @param array the destination
+  // @param offset the offset in this ByteArray to start copying from
+  // @param length the maximum length in bytes to copy
+  // @return the number of bytes copied
+  virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length);
+
+  // Copies this ByteArray to another ByteArray.
+  // @param dstOffset the offset in the destination array to start copying to
+  // @param array the destination
+  // @param srcOffset the offset in this ByteArray to start copying from
+  // @param length the maximum length in bytes to copy
+  // @return the number of bytes copied
+  virtual int32_t CopyTo(int32_t dst_offset,
+                         ByteArray* array,
+                         int32_t src_offset,
+                         int32_t length);
+
+  // Copies this ByteArray to an OutputStream.
+  // @param os the destination
+  // @return the number of bytes copied
+  virtual int32_t CopyTo(OutputStream* os);
+
+  // Copies this ByteArray to an OutputStream.
+  // @param os the destination
+  // @param offset
+  // @param length
+  // @return the number of bytes copied
+  virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length);
+
+  // Copies from the InputStream into this ByteArray.
+  // @param is the source
+  // @param length the number of bytes to copy
+  virtual bool CopyFrom(InputStream* is, int32_t length);
+
+  // Copies everything from the InputStream into this ByteArray.
+  // @param is the source
+  virtual bool CopyFrom(InputStream* is);
+
+ protected:
+  // filledLength the length that is "filled" and readable counting from offset.
+  // storageLength the maximum storage size of the underlying data.
+  // growable is the storage growable - storageLength is the max growable size.
+  ByteArray(int32_t filled_length, int32_t storage_length, bool growable);
+  ByteArray(int32_t filled_length, int32_t storage_length);
+  void Init(int32_t filled_length, int32_t storage_length, bool growable);
+
+  // Internal subclass API
+
+  // Stores the byte at the index given.
+  // @param index the location to store at
+  // @param b the byte to store
+  virtual void InternalPut(int32_t index, byte_t b) = 0;
+
+  // Stores the array of bytes at the given index.
+  // @param index the location to store at
+  // @param b the bytes to store
+  // @param offset the offset to start from in the byte array
+  // @param length the length of the byte array to store from the offset
+  // @return the number of bytes actually stored
+  virtual int32_t InternalPut(int32_t index,
+                              byte_t* b,
+                              int32_t offset,
+                              int32_t length) = 0;
+
+  // Gets the byte at the index given.
+  // @param index the location to get from
+  // @return the byte stored at the index
+  virtual byte_t InternalGet(int32_t index) = 0;
+
+  // Gets the bytes at the index given of the given length.
+  // @param index the location to start getting from
+  // @param b the array to put the bytes into
+  // @param offset the offset in the array to put the bytes into
+  // @param length the length of bytes to read
+  // @return the number of bytes actually ready
+  virtual int32_t InternalGet(int32_t index,
+                              byte_t* b,
+                              int32_t offset,
+                              int32_t length) = 0;
+
+  // Close this instance of the ByteArray.
+  virtual void Close() = 0;
+
+  // C++ port only, raw pointer to the first element of storage.
+  virtual byte_t* Begin() = 0;
+
+  // Java toString() not ported.
+
+  static const int32_t COPY_BUFFER_SIZE;
+
+ private:
+  //bool bound_;  // unused, comment out
+  int32_t filled_length_;
+  int32_t storage_length_;
+  bool growable_;
+};
+typedef Ptr<ByteArray> ByteArrayPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_
diff --git a/sfntly/data/font_data.cc b/sfntly/data/font_data.cc
new file mode 100644
index 0000000..d2b95ea
--- /dev/null
+++ b/sfntly/data/font_data.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 <limits.h>
+#include <algorithm>
+#include <functional>
+
+#include "sfntly/data/font_data.h"
+
+namespace sfntly {
+
+int32_t FontData::Size() const {
+  return std::min<int32_t>(array_->Size() - bound_offset_, bound_length_);
+}
+
+bool FontData::Bound(int32_t offset, int32_t length) {
+  if (offset + length > Size() || offset < 0 || length < 0)
+    return false;
+
+  bound_offset_ += offset;
+  bound_length_ = length;
+  return true;
+}
+
+bool FontData::Bound(int32_t offset) {
+if (offset > Size() || offset < 0)
+    return false;
+
+  bound_offset_ += offset;
+  return true;
+}
+
+int32_t FontData::Length() const {
+  return std::min<int32_t>(array_->Length() - bound_offset_, bound_length_);
+}
+
+FontData::FontData(ByteArray* ba) {
+  Init(ba);
+}
+
+FontData::FontData(FontData* data, int32_t offset, int32_t length) {
+  Init(data->array_);
+  Bound(data->bound_offset_ + offset, length);
+}
+
+FontData::FontData(FontData* data, int32_t offset) {
+  Init(data->array_);
+  Bound(data->bound_offset_ + offset,
+        (data->bound_length_ == GROWABLE_SIZE)
+            ? GROWABLE_SIZE : data->bound_length_ - offset);
+}
+
+FontData::~FontData() {}
+
+void FontData::Init(ByteArray* ba) {
+  array_ = ba;
+  bound_offset_ = 0;
+  bound_length_ = GROWABLE_SIZE;
+}
+
+int32_t FontData::BoundOffset(int32_t offset) {
+  return offset + bound_offset_;
+}
+
+int32_t FontData::BoundLength(int32_t offset, int32_t length) {
+  return std::min<int32_t>(length, bound_length_ - offset);
+}
+
+}  // namespace sfntly
diff --git a/sfntly/data/font_data.h b/sfntly/data/font_data.h
new file mode 100644
index 0000000..d02e8b7
--- /dev/null
+++ b/sfntly/data/font_data.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_
+
+#include <limits.h>
+
+#include <vector>
+
+#include "sfntly/port/type.h"
+#include "sfntly/data/byte_array.h"
+#include "sfntly/port/refcount.h"
+
+namespace sfntly {
+
+struct DataSize {
+  enum {
+    kBYTE = 1,
+    kCHAR = 1,
+    kUSHORT = 2,
+    kSHORT = 2,
+    kUINT24 = 3,
+    kULONG = 4,
+    kLONG = 4,
+    kFixed = 4,
+    kFUNIT = 4,
+    kFWORD = 2,
+    kUFWORD = 2,
+    kF2DOT14 = 2,
+    kLONGDATETIME = 8,
+    kTag = 4,
+    kGlyphID = 2,
+    kOffset = 2
+  };
+};
+
+class FontData : virtual public RefCount {
+ public:
+  // Gets the maximum size of the FontData. This is the maximum number of bytes
+  // that the font data can hold and all of it may not be filled with data or
+  // even fully allocated yet.
+  // @return the maximum size of this font data
+  virtual int32_t Size() const;
+
+  // Sets limits on the size of the FontData. The FontData is then only
+  // visible within the bounds set.
+  // @param offset the start of the new bounds
+  // @param length the number of bytes in the bounded array
+  // @return true if the bounding range was successful; false otherwise
+  virtual bool Bound(int32_t offset, int32_t length);
+
+  // Sets limits on the size of the FontData. This is a offset bound only so if
+  // the FontData is writable and growable then there is no limit to that growth
+  // from the bounding operation.
+  // @param offset the start of the new bounds which must be within the current
+  //        size of the FontData
+  // @return true if the bounding range was successful; false otherwise
+  virtual bool Bound(int32_t offset);
+
+  // Makes a slice of this FontData. The returned slice will share the data with
+  // the original <code>FontData</code>.
+  // @param offset the start of the slice
+  // @param length the number of bytes in the slice
+  // @return a slice of the original FontData
+  virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length) = 0;
+
+  // Makes a bottom bound only slice of this array. The returned slice will
+  // share the data with the original <code>FontData</code>.
+  // @param offset the start of the slice
+  // @return a slice of the original FontData
+  virtual CALLER_ATTACH FontData* Slice(int32_t offset) = 0;
+
+  // Gets the length of the data.
+  virtual int32_t Length() const;
+
+ protected:
+  // Constructor.
+  // @param ba the byte array to use for the backing data
+  explicit FontData(ByteArray* ba);
+
+  // Constructor.
+  // @param data the data to wrap
+  // @param offset the offset to start the wrap from
+  // @param length the length of the data wrapped
+  FontData(FontData* data, int32_t offset, int32_t length);
+
+  // Constructor.
+  // @param data the data to wrap
+  // @param offset the offset to start the wrap from
+  FontData(FontData* data, int32_t offset);
+  virtual ~FontData();
+
+  void Init(ByteArray* ba);
+
+  // Gets the offset in the underlying data taking into account any bounds on
+  // the data.
+  // @param offset the offset to get the bound compensated offset for
+  // @return the bound compensated offset
+  int32_t BoundOffset(int32_t offset);
+
+  // Gets the length in the underlying data taking into account any bounds on
+  // the data.
+  // @param offset the offset that the length is being used at
+  // @param length the length to get the bound compensated length for
+  // @return the bound compensated length
+  int32_t BoundLength(int32_t offset, int32_t length);
+
+  static const int32_t GROWABLE_SIZE = INT_MAX;
+
+  // TODO(arthurhsu): style guide violation: refactor this protected member
+  ByteArrayPtr array_;
+
+ private:
+  int32_t bound_offset_;
+  int32_t bound_length_;
+};
+typedef Ptr<FontData> FontDataPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_
diff --git a/sfntly/data/font_input_stream.cc b/sfntly/data/font_input_stream.cc
new file mode 100644
index 0000000..dcf8be3
--- /dev/null
+++ b/sfntly/data/font_input_stream.cc
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/data/font_input_stream.h"
+
+#include <algorithm>
+
+namespace sfntly {
+
+FontInputStream::FontInputStream(InputStream* is)
+    : stream_(is), position_(0), length_(0), bounded_(false) {
+}
+
+FontInputStream::FontInputStream(InputStream* is, size_t length)
+    : stream_(is), position_(0), length_(length), bounded_(true) {
+}
+
+FontInputStream::~FontInputStream() {
+  // Do not close here, underlying InputStream will close themselves.
+}
+
+int32_t FontInputStream::Available() {
+  if (stream_) {
+    return stream_->Available();
+  }
+  return 0;
+}
+
+void FontInputStream::Close() {
+  if (stream_) {
+    stream_->Close();
+  }
+}
+
+void FontInputStream::Mark(int32_t readlimit) {
+  if (stream_) {
+    stream_->Mark(readlimit);
+  }
+}
+
+bool FontInputStream::MarkSupported() {
+  if (stream_) {
+    return stream_->MarkSupported();
+  }
+  return false;
+}
+
+void FontInputStream::Reset() {
+  if (stream_) {
+    stream_->Reset();
+  }
+}
+
+int32_t FontInputStream::Read() {
+  if (!stream_ || (bounded_ && position_ >= length_)) {
+    return -1;
+  }
+  int32_t b = stream_->Read();
+  if (b >= 0) {
+    position_++;
+  }
+  return b;
+}
+
+int32_t FontInputStream::Read(ByteVector* b, int32_t offset, int32_t length) {
+  if (!stream_ || offset < 0 || length < 0 ||
+      (bounded_ && position_ >= length_)) {
+    return -1;
+  }
+  int32_t bytes_to_read =
+      bounded_ ? std::min<int32_t>(length, (int32_t)(length_ - position_)) :
+                 length;
+  int32_t bytes_read = stream_->Read(b, offset, bytes_to_read);
+  position_ += bytes_read;
+  return bytes_read;
+}
+
+int32_t FontInputStream::Read(ByteVector* b) {
+  return Read(b, 0, b->size());
+}
+
+int32_t FontInputStream::ReadChar() {
+  return Read();
+}
+
+int32_t FontInputStream::ReadUShort() {
+  return 0xffff & (Read() << 8 | Read());
+}
+
+int32_t FontInputStream::ReadShort() {
+  return ((Read() << 8 | Read()) << 16) >> 16;
+}
+
+int32_t FontInputStream::ReadUInt24() {
+  return 0xffffff & (Read() << 16 | Read() << 8 | Read());
+}
+
+int64_t FontInputStream::ReadULong() {
+  return 0xffffffffL & ReadLong();
+}
+
+int32_t FontInputStream::ReadULongAsInt() {
+  int64_t ulong = ReadULong();
+  return ((int32_t)ulong) & ~0x80000000;
+}
+
+int32_t FontInputStream::ReadLong() {
+  return Read() << 24 | Read() << 16 | Read() << 8 | Read();
+}
+
+int32_t FontInputStream::ReadFixed() {
+  return ReadLong();
+}
+
+int64_t FontInputStream::ReadDateTimeAsLong() {
+  return (int64_t)ReadULong() << 32 | ReadULong();
+}
+
+int64_t FontInputStream::Skip(int64_t n) {
+  if (stream_) {
+    int64_t skipped = stream_->Skip(n);
+    position_ += skipped;
+    return skipped;
+  }
+  return 0;
+}
+
+}  // namespace sfntly
diff --git a/sfntly/data/font_input_stream.h b/sfntly/data/font_input_stream.h
new file mode 100644
index 0000000..9992b07
--- /dev/null
+++ b/sfntly/data/font_input_stream.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_
+
+#include "sfntly/port/type.h"
+#include "sfntly/port/input_stream.h"
+
+namespace sfntly {
+
+// An input stream for reading font data.
+// The data types used are as listed:
+// BYTE       8-bit unsigned integer.
+// CHAR       8-bit signed integer.
+// USHORT     16-bit unsigned integer.
+// SHORT      16-bit signed integer.
+// UINT24     24-bit unsigned integer.
+// ULONG      32-bit unsigned integer.
+// LONG       32-bit signed integer.
+// Fixed      32-bit signed fixed-point number (16.16)
+// FUNIT      Smallest measurable distance in the em space.
+// FWORD      16-bit signed integer (SHORT) that describes a quantity in FUnits.
+// UFWORD     16-bit unsigned integer (USHORT) that describes a quantity in
+//            FUnits.
+// F2DOT14    16-bit signed fixed number with the low 14 bits of fraction (2.14)
+// LONGDATETIME  Date represented in number of seconds since 12:00 midnight,
+//               January 1, 1904. The value is represented as a signed 64-bit
+//               integer.
+
+// Note: Original class inherits from Java's FilterOutputStream, which wraps
+//       an InputStream within.  In C++, we directly do the wrapping without
+//       defining another layer of abstraction.  The wrapped output stream is
+//       *NOT* reference counted (because it's meaningless to ref-count an I/O
+//       stream).
+class FontInputStream : public InputStream {
+ public:
+  // Constructor.
+  // @param is input stream to wrap
+  explicit FontInputStream(InputStream* is);
+
+  // Constructor for a bounded font input stream.
+  // @param is input stream to wrap
+  // @param length the maximum length of bytes to read
+  FontInputStream(InputStream* is, size_t length);
+
+  virtual ~FontInputStream();
+
+
+  virtual int32_t Available();
+  virtual void Close();
+  virtual void Mark(int32_t readlimit);
+  virtual bool MarkSupported();
+  virtual void Reset();
+
+  virtual int32_t Read();
+  virtual int32_t Read(ByteVector* buffer);
+  virtual int32_t Read(ByteVector* buffer, int32_t offset, int32_t length);
+
+  // Get the current position in the stream in bytes.
+  // @return the current position in bytes
+  virtual int64_t position() { return position_; }
+
+  virtual int32_t ReadChar();
+  virtual int32_t ReadUShort();
+  virtual int32_t ReadShort();
+  virtual int32_t ReadUInt24();
+  virtual int64_t ReadULong();
+  virtual int32_t ReadULongAsInt();
+  virtual int32_t ReadLong();
+  virtual int32_t ReadFixed();
+  virtual int64_t ReadDateTimeAsLong();
+  virtual int64_t Skip(int64_t n);  // n can be negative.
+
+ private:
+  InputStream* stream_;
+  int64_t position_;
+  int64_t length_;  // Bound on length of data to read.
+  bool bounded_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_
diff --git a/sfntly/data/font_output_stream.cc b/sfntly/data/font_output_stream.cc
new file mode 100644
index 0000000..3422a22
--- /dev/null
+++ b/sfntly/data/font_output_stream.cc
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/data/font_output_stream.h"
+
+#include <algorithm>
+
+namespace sfntly {
+
+FontOutputStream::FontOutputStream(OutputStream* os)
+    : stream_(os),
+      position_(0) {
+}
+
+FontOutputStream::~FontOutputStream() {
+  // Do not close, underlying stream shall clean up themselves.
+}
+
+void FontOutputStream::Write(byte_t b) {
+  if (stream_) {
+    stream_->Write(b);
+    position_++;
+  }
+}
+
+void FontOutputStream::Write(ByteVector* b) {
+  if (b) {
+    Write(b, 0, b->size());
+    position_ += b->size();
+  }
+}
+
+void FontOutputStream::Write(ByteVector* b, int32_t off, int32_t len) {
+  assert(b);
+  assert(stream_);
+  if (off < 0 || len < 0 || off + len < 0 ||
+      static_cast<size_t>(off + len) > b->size()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException();
+#else
+    return;
+#endif
+  }
+
+  stream_->Write(b, off, len);
+  position_ += len;
+}
+
+void FontOutputStream::Write(byte_t* b, int32_t off, int32_t len) {
+  assert(b);
+  assert(stream_);
+  if (off < 0 || len < 0 || off + len < 0) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException();
+#else
+    return;
+#endif
+  }
+
+  stream_->Write(b, off, len);
+  position_ += len;
+}
+
+void FontOutputStream::WriteChar(byte_t c) {
+  Write(c);
+}
+
+void FontOutputStream::WriteUShort(int32_t us) {
+  Write((byte_t)((us >> 8) & 0xff));
+  Write((byte_t)(us & 0xff));
+}
+
+void FontOutputStream::WriteShort(int32_t s) {
+  WriteUShort(s);
+}
+
+void FontOutputStream::WriteUInt24(int32_t ui) {
+  Write((byte_t)(ui >> 16) & 0xff);
+  Write((byte_t)(ui >> 8) & 0xff);
+  Write((byte_t)ui & 0xff);
+}
+
+void FontOutputStream::WriteULong(int64_t ul) {
+  Write((byte_t)((ul >> 24) & 0xff));
+  Write((byte_t)((ul >> 16) & 0xff));
+  Write((byte_t)((ul >> 8) & 0xff));
+  Write((byte_t)(ul & 0xff));
+}
+
+void FontOutputStream::WriteLong(int64_t l) {
+  WriteULong(l);
+}
+
+void FontOutputStream::WriteFixed(int32_t f) {
+  WriteULong(f);
+}
+
+void FontOutputStream::WriteDateTime(int64_t date) {
+  WriteULong((date >> 32) & 0xffffffff);
+  WriteULong(date & 0xffffffff);
+}
+
+void FontOutputStream::Flush() {
+  if (stream_) {
+    stream_->Flush();
+  }
+}
+
+void FontOutputStream::Close() {
+  if (stream_) {
+    stream_->Flush();
+    stream_->Close();
+    position_ = 0;
+  }
+}
+
+}  // namespace sfntly
diff --git a/sfntly/data/font_output_stream.h b/sfntly/data/font_output_stream.h
new file mode 100644
index 0000000..fcd48e8
--- /dev/null
+++ b/sfntly/data/font_output_stream.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_
+
+#include "sfntly/port/type.h"
+#include "sfntly/port/output_stream.h"
+
+namespace sfntly {
+
+// An output stream for writing font data.
+// The data types used are as listed:
+// BYTE       8-bit unsigned integer.
+// CHAR       8-bit signed integer.
+// USHORT     16-bit unsigned integer.
+// SHORT      16-bit signed integer.
+// UINT24     24-bit unsigned integer.
+// ULONG      32-bit unsigned integer.
+// LONG       32-bit signed integer.
+// Fixed      32-bit signed fixed-point number (16.16)
+// FUNIT      Smallest measurable distance in the em space.
+// FWORD      16-bit signed integer (SHORT) that describes a quantity in FUnits.
+// UFWORD     16-bit unsigned integer (USHORT) that describes a quantity in
+//            FUnits.
+// F2DOT14    16-bit signed fixed number with the low 14 bits of fraction (2.14)
+// LONGDATETIME  Date represented in number of seconds since 12:00 midnight,
+//               January 1, 1904. The value is represented as a signed 64-bit
+//               integer.
+
+// Note: The wrapped output stream is *NOT* reference counted (because it's
+//       meaningless to ref-count an I/O stream).
+class FontOutputStream : public OutputStream {
+ public:
+  explicit FontOutputStream(OutputStream* os);
+  virtual ~FontOutputStream();
+
+  virtual size_t position() { return position_; }
+
+  virtual void Write(byte_t b);
+  virtual void Write(ByteVector* b);
+  virtual void Write(ByteVector* b, int32_t off, int32_t len);
+  virtual void Write(byte_t* b, int32_t off, int32_t len);
+  virtual void WriteChar(byte_t c);
+  virtual void WriteUShort(int32_t us);
+  virtual void WriteShort(int32_t s);
+  virtual void WriteUInt24(int32_t ui);
+  virtual void WriteULong(int64_t ul);
+  virtual void WriteLong(int64_t l);
+  virtual void WriteFixed(int32_t l);
+  virtual void WriteDateTime(int64_t date);
+
+  // Note: C++ port only.
+  virtual void Flush();
+  virtual void Close();
+
+ private:
+  // Note: we do not use the variable name out as in Java because it has
+  //       special meaning in VC++ and will be very confusing.
+  OutputStream* stream_;
+  size_t position_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_
diff --git a/sfntly/data/growable_memory_byte_array.cc b/sfntly/data/growable_memory_byte_array.cc
new file mode 100644
index 0000000..c335614
--- /dev/null
+++ b/sfntly/data/growable_memory_byte_array.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/data/growable_memory_byte_array.h"
+
+#include <limits.h>
+#include <string.h>
+
+#include <algorithm>
+
+namespace sfntly {
+
+GrowableMemoryByteArray::GrowableMemoryByteArray()
+    : ByteArray(0, INT_MAX, true) {
+  // Note: We did not set an initial size of array like Java because STL
+  //       implementation will determine the best strategy.
+}
+
+GrowableMemoryByteArray::~GrowableMemoryByteArray() {}
+
+int32_t GrowableMemoryByteArray::CopyTo(OutputStream* os,
+                                        int32_t offset,
+                                        int32_t length) {
+  assert(os);
+  os->Write(&b_, offset, length);
+  return length;
+}
+
+void GrowableMemoryByteArray::InternalPut(int32_t index, byte_t b) {
+  if ((size_t)index >= b_.size()) {
+    b_.resize((size_t)(index + 1));
+  }
+  b_[index] = b;
+}
+
+int32_t GrowableMemoryByteArray::InternalPut(int32_t index,
+                                             byte_t* b,
+                                             int32_t offset,
+                                             int32_t length) {
+  if ((size_t)index + length >= b_.size()) {
+    // Note: We grow one byte more than Java version. VC debuggers shows
+    //       data better this way.
+    b_.resize((size_t)(index + length + 1));
+  }
+  std::copy(b + offset, b + offset + length, b_.begin() + index);
+  return length;
+}
+
+byte_t GrowableMemoryByteArray::InternalGet(int32_t index) {
+  return b_[index];
+}
+
+int32_t GrowableMemoryByteArray::InternalGet(int32_t index,
+                                             byte_t* b,
+                                             int32_t offset,
+                                             int32_t length) {
+  memcpy(b + offset, &(b_[0]) + index, length);
+  return length;
+}
+
+void GrowableMemoryByteArray::Close() {
+  b_.clear();
+}
+
+byte_t* GrowableMemoryByteArray::Begin() {
+  return &(b_[0]);
+}
+
+}  // namespace sfntly
diff --git a/sfntly/data/growable_memory_byte_array.h b/sfntly/data/growable_memory_byte_array.h
new file mode 100644
index 0000000..8583a0d
--- /dev/null
+++ b/sfntly/data/growable_memory_byte_array.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_
+
+#include "sfntly/data/byte_array.h"
+
+namespace sfntly {
+
+// Note: This is not really a port of Java version. Instead, this wraps a
+//       std::vector inside and let it grow by calling resize().
+class GrowableMemoryByteArray : public ByteArray,
+                                public RefCounted<GrowableMemoryByteArray> {
+ public:
+  GrowableMemoryByteArray();
+  virtual ~GrowableMemoryByteArray();
+  virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length);
+
+  // Make gcc -Woverloaded-virtual happy.
+  virtual int32_t CopyTo(ByteArray* array) { return ByteArray::CopyTo(array); }
+  virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length) {
+    return ByteArray::CopyTo(array, offset, length);
+  }
+  virtual int32_t CopyTo(int32_t dst_offset,
+                         ByteArray* array,
+                         int32_t src_offset,
+                         int32_t length) {
+    return ByteArray::CopyTo(dst_offset, array, src_offset, length);
+  }
+  virtual int32_t CopyTo(OutputStream* os) { return ByteArray::CopyTo(os); }
+
+ protected:
+  virtual void InternalPut(int32_t index, byte_t b);
+  virtual int32_t InternalPut(int32_t index,
+                              byte_t* b,
+                              int32_t offset,
+                              int32_t length);
+  virtual byte_t InternalGet(int32_t index);
+  virtual int32_t InternalGet(int32_t index,
+                              byte_t* b,
+                              int32_t offset,
+                              int32_t length);
+  virtual void Close();
+  virtual byte_t* Begin();
+
+ private:
+  ByteVector b_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_
diff --git a/sfntly/data/memory_byte_array.cc b/sfntly/data/memory_byte_array.cc
new file mode 100644
index 0000000..d6c9c48
--- /dev/null
+++ b/sfntly/data/memory_byte_array.cc
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/data/memory_byte_array.h"
+
+#include <string.h>
+
+namespace sfntly {
+
+MemoryByteArray::MemoryByteArray(int32_t length)
+    : ByteArray(0, length), b_(NULL), allocated_(true) {
+}
+
+MemoryByteArray::MemoryByteArray(byte_t* b, int32_t filled_length)
+    : ByteArray(filled_length, filled_length), b_(b), allocated_(false) {
+  assert(b);
+}
+
+MemoryByteArray::~MemoryByteArray() {
+  Close();
+}
+
+int32_t MemoryByteArray::CopyTo(OutputStream* os,
+                                int32_t offset,
+                                int32_t length) {
+  assert(os);
+  os->Write(b_, offset, length);
+  return length;
+}
+
+void MemoryByteArray::Init() {
+  if (allocated_ && b_ == NULL) {
+    b_ = new byte_t[Size()];
+    memset(b_, 0, Size());
+  }
+}
+
+void MemoryByteArray::InternalPut(int32_t index, byte_t b) {
+  Init();
+  b_[index] = b;
+}
+
+int32_t MemoryByteArray::InternalPut(int32_t index,
+                                     byte_t* b,
+                                     int32_t offset,
+                                     int32_t length) {
+  assert(b);
+  Init();
+  memcpy(b_ + index, b + offset, length);
+  return length;
+}
+
+byte_t MemoryByteArray::InternalGet(int32_t index) {
+  Init();
+  return b_[index];
+}
+
+int32_t MemoryByteArray::InternalGet(int32_t index,
+                                     byte_t* b,
+                                     int32_t offset,
+                                     int32_t length) {
+  assert(b);
+  Init();
+  memcpy(b + offset, b_ + index, length);
+  return length;
+}
+
+void MemoryByteArray::Close() {
+  if (allocated_ && b_) {
+    delete[] b_;
+  }
+  b_ = NULL;
+}
+
+byte_t* MemoryByteArray::Begin() {
+  Init();
+  return b_;
+}
+
+}  // namespace sfntly
diff --git a/sfntly/data/memory_byte_array.h b/sfntly/data/memory_byte_array.h
new file mode 100644
index 0000000..838fd1a
--- /dev/null
+++ b/sfntly/data/memory_byte_array.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_
+
+#include "sfntly/data/byte_array.h"
+
+namespace sfntly {
+
+class MemoryByteArray : public ByteArray, public RefCounted<MemoryByteArray> {
+ public:
+  // Construct a new MemoryByteArray with a new array of the size given. It is
+  // assumed that none of the array is filled and readable.
+  explicit MemoryByteArray(int32_t length);
+
+  // Note: not implemented due to dangerous operations in constructor.
+  //explicit MemoryByteArray(ByteVector* b);
+
+  // Construct a new MemoryByteArray using byte array.
+  // @param b the byte array that provides the actual storage
+  // @param filled_length the index of the last byte in the array has data
+  // Note: This is different from Java version, it does not take over the
+  //       ownership of b.  Caller is responsible for handling the lifetime
+  //       of b.  C++ port also assumes filled_length is buffer_length since
+  //       there is not a reliable way to identify the actual size of buffer.
+  MemoryByteArray(byte_t* b, int32_t filled_length);
+
+  virtual ~MemoryByteArray();
+  virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length);
+
+  // Make gcc -Woverloaded-virtual happy.
+  virtual int32_t CopyTo(ByteArray* array) { return ByteArray::CopyTo(array); }
+  virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length) {
+    return ByteArray::CopyTo(array, offset, length);
+  }
+  virtual int32_t CopyTo(int32_t dst_offset,
+                         ByteArray* array,
+                         int32_t src_offset,
+                         int32_t length) {
+    return ByteArray::CopyTo(dst_offset, array, src_offset, length);
+  }
+  virtual int32_t CopyTo(OutputStream* os) { return ByteArray::CopyTo(os); }
+
+ protected:
+  virtual void InternalPut(int32_t index, byte_t b);
+  virtual int32_t InternalPut(int32_t index,
+                              byte_t* b,
+                              int32_t offset,
+                              int32_t length);
+  virtual byte_t InternalGet(int32_t index);
+  virtual int32_t InternalGet(int32_t index,
+                              byte_t* b,
+                              int32_t offset,
+                              int32_t length);
+  virtual void Close();
+  virtual byte_t* Begin();
+
+ private:
+  void Init();  // C++ port only, used to allocate memory outside constructor.
+
+  byte_t* b_;
+  bool allocated_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_
diff --git a/sfntly/data/readable_font_data.cc b/sfntly/data/readable_font_data.cc
new file mode 100644
index 0000000..06d783f
--- /dev/null
+++ b/sfntly/data/readable_font_data.cc
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/data/readable_font_data.h"
+
+#include <stdio.h>
+
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/data/writable_font_data.h"
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+
+ReadableFontData::ReadableFontData(ByteArray* array)
+    : FontData(array),
+      checksum_set_(false),
+      checksum_(0) {
+}
+
+ReadableFontData::~ReadableFontData() {}
+
+// TODO(arthurhsu): re-investigate the memory model of this function.  It's
+//                  not too useful without copying, but it's not performance
+//                  savvy to do copying.
+CALLER_ATTACH
+ReadableFontData* ReadableFontData::CreateReadableFontData(ByteVector* b) {
+  assert(b);
+  ByteArrayPtr ba = new MemoryByteArray(b->size());
+  ba->Put(0, b);
+  ReadableFontDataPtr wfd = new ReadableFontData(ba);
+  return wfd.Detach();
+}
+
+int64_t ReadableFontData::Checksum() {
+  AutoLock lock(checksum_lock_);
+  if (!checksum_set_) {
+    ComputeChecksum();
+  }
+  return checksum_;
+}
+
+void ReadableFontData::SetCheckSumRanges(const IntegerList& ranges) {
+  checksum_range_ = ranges;
+  checksum_set_ = false;  // UNIMPLEMENTED: atomicity
+}
+
+int32_t ReadableFontData::ReadUByte(int32_t index) {
+  int32_t b = array_->Get(BoundOffset(index));
+#if !defined (SFNTLY_NO_EXCEPTION)
+  if (b < 0) {
+    throw IndexOutOfBoundException(
+        "Index attempted to be read from is out of bounds", index);
+  }
+#endif
+  return b;
+}
+
+int32_t ReadableFontData::ReadByte(int32_t index) {
+  int32_t b = array_->Get(BoundOffset(index));
+#if !defined (SFNTLY_NO_EXCEPTION)
+  if (b < 0) {
+    throw IndexOutOfBoundException(
+        "Index attempted to be read from is out of bounds", index);
+  }
+#endif
+  return (b << 24) >> 24;
+}
+
+int32_t ReadableFontData::ReadBytes(int32_t index,
+                                    byte_t* b,
+                                    int32_t offset,
+                                    int32_t length) {
+  return array_->Get(BoundOffset(index), b, offset, BoundLength(index, length));
+}
+
+int32_t ReadableFontData::ReadChar(int32_t index) {
+  return ReadUByte(index);
+}
+
+int32_t ReadableFontData::ReadUShort(int32_t index) {
+  return 0xffff & (ReadUByte(index) << 8 | ReadUByte(index + 1));
+}
+
+int32_t ReadableFontData::ReadShort(int32_t index) {
+  return ((ReadByte(index) << 8 | ReadUByte(index + 1)) << 16) >> 16;
+}
+
+int32_t ReadableFontData::ReadUInt24(int32_t index) {
+  return 0xffffff & (ReadUByte(index) << 16 |
+                     ReadUByte(index + 1) << 8 |
+                     ReadUByte(index + 2));
+}
+
+int64_t ReadableFontData::ReadULong(int32_t index) {
+  return 0xffffffffL & (ReadUByte(index) << 24 |
+                        ReadUByte(index + 1) << 16 |
+                        ReadUByte(index + 2) << 8 |
+                        ReadUByte(index + 3));
+}
+
+int32_t ReadableFontData::ReadULongAsInt(int32_t index) {
+  int64_t ulong = ReadULong(index);
+#if !defined (SFNTLY_NO_EXCEPTION)
+  if ((ulong & 0x80000000) == 0x80000000) {
+    throw ArithmeticException("Long value too large to fit into an integer.");
+  }
+#endif
+  return static_cast<int32_t>(ulong);
+}
+
+int64_t ReadableFontData::ReadULongLE(int32_t index) {
+  return 0xffffffffL & (ReadUByte(index) |
+                        ReadUByte(index + 1) << 8 |
+                        ReadUByte(index + 2) << 16 |
+                        ReadUByte(index + 3) << 24);
+}
+
+int32_t ReadableFontData::ReadLong(int32_t index) {
+  return ReadByte(index) << 24 |
+         ReadUByte(index + 1) << 16 |
+         ReadUByte(index + 2) << 8 |
+         ReadUByte(index + 3);
+}
+
+int32_t ReadableFontData::ReadFixed(int32_t index) {
+  return ReadLong(index);
+}
+
+int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) {
+  return (int64_t)ReadULong(index) << 32 | ReadULong(index + 4);
+}
+
+int32_t ReadableFontData::ReadFWord(int32_t index) {
+  return ReadShort(index);
+}
+
+int32_t ReadableFontData::ReadFUFWord(int32_t index) {
+  return ReadUShort(index);
+}
+
+int32_t ReadableFontData::CopyTo(OutputStream* os) {
+  return array_->CopyTo(os, BoundOffset(0), Length());
+}
+
+int32_t ReadableFontData::CopyTo(WritableFontData* wfd) {
+  return array_->CopyTo(wfd->BoundOffset(0),
+                        wfd->array_,
+                        BoundOffset(0),
+                        Length());
+}
+
+int32_t ReadableFontData::CopyTo(ByteArray* ba) {
+  return array_->CopyTo(ba, BoundOffset(0), Length());
+}
+
+int32_t ReadableFontData::SearchUShort(int32_t start_index,
+                                       int32_t start_offset,
+                                       int32_t end_index,
+                                       int32_t end_offset,
+                                       int32_t length,
+                                       int32_t key) {
+  int32_t location = 0;
+  int32_t bottom = 0;
+  int32_t top = length;
+  while (top != bottom) {
+    location = (top + bottom) / 2;
+    int32_t location_start = ReadUShort(start_index + location * start_offset);
+    if (key < location_start) {
+      // location is below current location
+      top = location;
+    } else {
+      // is key below the upper bound?
+      int32_t location_end = ReadUShort(end_index + location * end_offset);
+#if defined (SFNTLY_DEBUG_FONTDATA)
+      fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
+#endif
+      if (key <= location_end) {
+        return location;
+      } else {
+        // location is above the current location
+        bottom = location + 1;
+      }
+    }
+  }
+  return -1;
+}
+
+int32_t ReadableFontData::SearchUShort(int32_t start_index,
+                                       int32_t start_offset,
+                                       int32_t length,
+                                       int32_t key) {
+  int32_t location = 0;
+  int32_t bottom = 0;
+  int32_t top = length;
+  while (top != bottom) {
+    location = (top + bottom) / 2;
+    int32_t location_start = ReadUShort(start_index + location * start_offset);
+    if (key < location_start) {
+      // location is below current location
+      top = location;
+    } else if (key > location_start) {
+      // location is above current location
+      bottom = location + 1;
+    } else {
+      return location;
+    }
+  }
+  return -1;
+}
+
+int32_t ReadableFontData::SearchULong(int32_t start_index,
+                                      int32_t start_offset,
+                                      int32_t end_index,
+                                      int32_t end_offset,
+                                      int32_t length,
+                                      int32_t key) {
+  int32_t location = 0;
+  int32_t bottom = 0;
+  int32_t top = length;
+  while (top != bottom) {
+    location = (top + bottom) / 2;
+    int32_t location_start = ReadULongAsInt(start_index
+                                            + location * start_offset);
+    if (key < location_start) {
+      // location is below current location
+      top = location;
+    } else {
+      // is key below the upper bound?
+      int32_t location_end = ReadULongAsInt(end_index + location * end_offset);
+#if defined (SFNTLY_DEBUG_FONTDATA)
+      fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
+#endif
+      if (key <= location_end) {
+        return location;
+      } else {
+        // location is above the current location
+        bottom = location + 1;
+      }
+    }
+  }
+  return -1;
+}
+
+CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset,
+                                                int32_t length) {
+  if (offset < 0 || offset + length > Size()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundsException(
+        "Attempt to bind data outside of its limits");
+#endif
+    return NULL;
+  }
+  FontDataPtr slice = new ReadableFontData(this, offset, length);
+  return slice.Detach();
+}
+
+CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) {
+  if (offset < 0 || offset > Size()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundsException(
+        "Attempt to bind data outside of its limits");
+#endif
+    return NULL;
+  }
+  FontDataPtr slice = new ReadableFontData(this, offset);
+  return slice.Detach();
+}
+
+ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset)
+    : FontData(data, offset),
+      checksum_set_(false),
+      checksum_(0) {
+}
+
+ReadableFontData::ReadableFontData(ReadableFontData* data,
+                                   int32_t offset,
+                                   int32_t length)
+    : FontData(data, offset, length),
+      checksum_set_(false),
+      checksum_(0) {
+}
+
+void ReadableFontData::ComputeChecksum() {
+  // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity
+  int64_t sum = 0;
+  if (checksum_range_.empty()) {
+    sum = ComputeCheckSum(0, Length());
+  } else {
+    for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size();
+         low_bound_index += 2) {
+      int32_t low_bound = checksum_range_[low_bound_index];
+      int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ?
+                                Length() :
+                                checksum_range_[low_bound_index + 1];
+      sum += ComputeCheckSum(low_bound, high_bound);
+    }
+  }
+
+  checksum_ = sum & 0xffffffffL;
+  checksum_set_ = true;
+}
+
+int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound,
+                                          int32_t high_bound) {
+  int64_t sum = 0;
+  // Checksum all whole 4-byte chunks.
+  for (int32_t i = low_bound; i <= high_bound - 4; i += 4) {
+    sum += ReadULong(i);
+  }
+
+  // Add last fragment if not 4-byte multiple
+  int32_t off = high_bound & -4;
+  if (off < high_bound) {
+    int32_t b3 = ReadUByte(off);
+    int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0;
+    int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0;
+    int32_t b0 = 0;
+    sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
+  }
+  return sum;
+}
+
+}  // namespace sfntly
diff --git a/sfntly/data/readable_font_data.h b/sfntly/data/readable_font_data.h
new file mode 100644
index 0000000..b43c626
--- /dev/null
+++ b/sfntly/data/readable_font_data.h
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_
+
+#include "sfntly/data/font_data.h"
+#include "sfntly/port/lock.h"
+
+namespace sfntly {
+
+class WritableFontData;
+class OutputStream;
+
+// Writable font data wrapper. Supports reading of data primitives in the
+// TrueType / OpenType spec.
+// The data types used are as listed:
+// BYTE       8-bit unsigned integer.
+// CHAR       8-bit signed integer.
+// USHORT     16-bit unsigned integer.
+// SHORT      16-bit signed integer.
+// UINT24     24-bit unsigned integer.
+// ULONG      32-bit unsigned integer.
+// LONG       32-bit signed integer.
+// Fixed      32-bit signed fixed-point number (16.16)
+// FUNIT      Smallest measurable distance in the em space.
+// FWORD      16-bit signed integer (SHORT) that describes a quantity in FUnits.
+// UFWORD     16-bit unsigned integer (USHORT) that describes a quantity in
+//            FUnits.
+// F2DOT14    16-bit signed fixed number with the low 14 bits of fraction (2.14)
+// LONGDATETIME  Date represented in number of seconds since 12:00 midnight,
+//               January 1, 1904. The value is represented as a signed 64-bit
+//               integer.
+
+class ReadableFontData : public FontData,
+                         public RefCounted<ReadableFontData> {
+ public:
+  explicit ReadableFontData(ByteArray* array);
+  virtual ~ReadableFontData();
+
+  static CALLER_ATTACH ReadableFontData* CreateReadableFontData(ByteVector* b);
+
+  // Gets a computed checksum for the data. This checksum uses the OpenType spec
+  // calculation. Every ULong value (32 bit unsigned) in the data is summed and
+  // the resulting value is truncated to 32 bits. If the data length in bytes is
+  // not an integral multiple of 4 then any remaining bytes are treated as the
+  // start of a 4 byte sequence whose remaining bytes are zero.
+  // @return the checksum
+  int64_t Checksum();
+
+  // Sets the bounds to use for computing the checksum. These bounds are in
+  // begin and end pairs. If an odd number is given then the final range is
+  // assumed to extend to the end of the data. The lengths of each range must be
+  // a multiple of 4.
+  // @param ranges the range bounds to use for the checksum
+  void SetCheckSumRanges(const IntegerList& ranges);
+
+  // Read the UBYTE at the given index.
+  // @param index index into the font data
+  // @return the UBYTE; -1 if outside the bounds of the font data
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadUByte(int32_t index);
+
+  // Read the BYTE at the given index.
+  // @param index index into the font data
+  // @return the BYTE
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadByte(int32_t index);
+
+  // Read the bytes at the given index into the array.
+  // @param index index into the font data
+  // @param b the destination for the bytes read
+  // @param offset offset in the byte array to place the bytes
+  // @param length the length of bytes to read
+  // @return the number of bytes actually read; -1 if the index is outside the
+  //         bounds of the font data
+  virtual int32_t ReadBytes(int32_t index,
+                            byte_t* b,
+                            int32_t offset,
+                            int32_t length);
+
+  // Read the CHAR at the given index.
+  // @param index index into the font data
+  // @return the CHAR
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadChar(int32_t index);
+
+  // Read the USHORT at the given index.
+  // @param index index into the font data
+  // @return the USHORT
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadUShort(int32_t index);
+
+  // Read the SHORT at the given index.
+  // @param index index into the font data
+  // @return the SHORT
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadShort(int32_t index);
+
+  // Read the UINT24 at the given index.
+  // @param index index into the font data
+  // @return the UINT24
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadUInt24(int32_t index);
+
+  // Read the ULONG at the given index.
+  // @param index index into the font data
+  // @return the ULONG
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int64_t ReadULong(int32_t index);
+
+  // Read the ULONG at the given index as int32_t.
+  // @param index index into the font data
+  // @return the ULONG
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadULongAsInt(int32_t index);
+
+  // Read the ULONG at the given index, little-endian variant
+  // @param index index into the font data
+  // @return the ULONG
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int64_t ReadULongLE(int32_t index);
+
+  // Read the LONG at the given index.
+  // @param index index into the font data
+  // @return the LONG
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadLong(int32_t index);
+
+  // Read the Fixed at the given index.
+  // @param index index into the font data
+  // @return the Fixed
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadFixed(int32_t index);
+
+  // Read the LONGDATETIME at the given index.
+  // @param index index into the font data
+  // @return the LONGDATETIME
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int64_t ReadDateTimeAsLong(int32_t index);
+
+  // Read the FWORD at the given index.
+  // @param index index into the font data
+  // @return the FWORD
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadFWord(int32_t index);
+
+  // Read the UFWORD at the given index.
+  // @param index index into the font data
+  // @return the UFWORD
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadFUFWord(int32_t index);
+
+  // Note: Not ported because they just throw UnsupportedOperationException()
+  //       in Java.
+  /*
+  virtual int32_t ReadFUnit(int32_t index);
+  virtual int64_t ReadF2Dot14(int32_t index);
+  */
+
+  // Copy the FontData to an OutputStream.
+  // @param os the destination
+  // @return number of bytes copied
+  // @throws IOException
+  virtual int32_t CopyTo(OutputStream* os);
+
+  // Copy the FontData to a WritableFontData.
+  // @param wfd the destination
+  // @return number of bytes copied
+  // @throws IOException
+  virtual int32_t CopyTo(WritableFontData* wfd);
+
+  // Make gcc -Woverloaded-virtual happy.
+  virtual int32_t CopyTo(ByteArray* ba);
+
+  // Search for the key value in the range tables provided.
+  // The search looks through the start-end pairs looking for the key value. It
+  // is assumed that the start-end pairs are both represented by UShort values,
+  // ranges do not overlap, and are monotonically increasing.
+  // @param startIndex the position to read the first start value from
+  // @param startOffset the offset between subsequent start values
+  // @param endIndex the position to read the first end value from
+  // @param endOffset the offset between subsequent end values
+  // @param length the number of start-end pairs
+  // @param key the value to search for
+  // @return the index of the start-end pairs in which the key was found; -1
+  //         otherwise
+  int32_t SearchUShort(int32_t start_index,
+                       int32_t start_offset,
+                       int32_t end_index,
+                       int32_t end_offset,
+                       int32_t length,
+                       int32_t key);
+
+  // Search for the key value in the table provided.
+  // The search looks through the values looking for the key value. It is
+  // assumed that the are represented by UShort values and are monotonically
+  // increasing.
+  // @param startIndex the position to read the first start value from
+  // @param startOffset the offset between subsequent start values
+  // @param length the number of start-end pairs
+  // @param key the value to search for
+  // @return the index of the start-end pairs in which the key was found; -1
+  //         otherwise
+  int32_t SearchUShort(int32_t start_index,
+                       int32_t start_offset,
+                       int32_t length,
+                       int32_t key);
+
+  // Search for the key value in the range tables provided.
+  // The search looks through the start-end pairs looking for the key value. It
+  // is assumed that the start-end pairs are both represented by ULong values
+  // that can be represented within 31 bits, ranges do not overlap, and are
+  // monotonically increasing.
+  // @param startIndex the position to read the first start value from
+  // @param startOffset the offset between subsequent start values
+  // @param endIndex the position to read the first end value from
+  // @param endOffset the offset between subsequent end values
+  // @param length the number of start-end pairs
+  // @param key the value to search for
+  // @return the index of the start-end pairs in which the key was found; -1
+  //         otherwise
+  int32_t SearchULong(int32_t start_index,
+                      int32_t start_offset,
+                      int32_t end_index,
+                      int32_t end_offset,
+                      int32_t length,
+                      int32_t key);
+
+
+  // TODO(arthurhsu): IMPLEMENT
+  /*
+  virtual int32_t ReadFUnit(int32_t index);
+  virtual int64_t ReadF2Dot14(int32_t index);
+  virtual int64_t ReadLongDateTime(int32_t index);
+  */
+
+  // Makes a slice of this FontData. The returned slice will share the data with
+  // the original FontData.
+  // @param offset the start of the slice
+  // @param length the number of bytes in the slice
+  // @return a slice of the original FontData
+  // Note: C++ polymorphism requires return type to be consistent
+  virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length);
+
+  // Makes a bottom bound only slice of this array. The returned slice will
+  // share the data with the original FontData.
+  // @param offset the start of the slice
+  // @return a slice of the original FontData
+  // Note: C++ polymorphism requires return type to be consistent
+  virtual CALLER_ATTACH FontData* Slice(int32_t offset);
+
+  // Not Ported: toString()
+
+ protected:
+  // Constructor. Creates a bounded wrapper of another ReadableFontData from the
+  // given offset until the end of the original ReadableFontData.
+  // @param data data to wrap
+  // @param offset the start of this data's view of the original data
+  ReadableFontData(ReadableFontData* data, int32_t offset);
+
+  // Constructor. Creates a bounded wrapper of another ReadableFontData from the
+  // given offset until the end of the original ReadableFontData.
+  // @param data data to wrap
+  // @param offset the start of this data's view of the original data
+  // @param length the length of the other FontData to use
+  ReadableFontData(ReadableFontData* data, int32_t offset, int32_t length);
+
+ private:
+  // Compute the checksum for the font data using any ranges set for the
+  // calculation.
+  void ComputeChecksum();
+
+  // Do the actual computation of the checksum for a range using the
+  // TrueType/OpenType checksum algorithm. The range used is from the low bound
+  // to the high bound in steps of four bytes. If any of the bytes within that 4
+  // byte segment are not readable then it will considered a zero for
+  // calculation.
+  // Only called from within a synchronized method so it does not need to be
+  // synchronized itself.
+  // @param lowBound first position to start a 4 byte segment on
+  // @param highBound last possible position to start a 4 byte segment on
+  // @return the checksum for the total range
+  int64_t ComputeCheckSum(int32_t low_bound, int32_t high_bound);
+
+  Lock checksum_lock_;
+  bool checksum_set_;
+  int64_t checksum_;
+  IntegerList checksum_range_;
+};
+typedef Ptr<ReadableFontData> ReadableFontDataPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_
diff --git a/sfntly/data/writable_font_data.cc b/sfntly/data/writable_font_data.cc
new file mode 100644
index 0000000..4b3b440
--- /dev/null
+++ b/sfntly/data/writable_font_data.cc
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/data/writable_font_data.h"
+
+#include <algorithm>
+
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/data/growable_memory_byte_array.h"
+
+namespace sfntly {
+
+WritableFontData::WritableFontData(ByteArray* ba) : ReadableFontData(ba) {
+}
+
+WritableFontData::~WritableFontData() {}
+
+// static
+CALLER_ATTACH
+WritableFontData* WritableFontData::CreateWritableFontData(int32_t length) {
+  ByteArrayPtr ba;
+  if (length > 0) {
+    ba = new MemoryByteArray(length);
+    ba->SetFilledLength(length);
+  } else {
+    ba = new GrowableMemoryByteArray();
+  }
+  WritableFontDataPtr wfd = new WritableFontData(ba);
+  return wfd.Detach();
+}
+
+// TODO(arthurhsu): re-investigate the memory model of this function.  It's
+//                  not too useful without copying, but it's not performance
+//                  savvy to do copying.
+CALLER_ATTACH
+WritableFontData* WritableFontData::CreateWritableFontData(ByteVector* b) {
+  ByteArrayPtr ba = new GrowableMemoryByteArray();
+  ba->Put(0, b);
+  WritableFontDataPtr wfd = new WritableFontData(ba);
+  return wfd.Detach();
+}
+
+int32_t WritableFontData::WriteByte(int32_t index, byte_t b) {
+  array_->Put(BoundOffset(index), b);
+  return 1;
+}
+
+int32_t WritableFontData::WriteBytes(int32_t index,
+                                     byte_t* b,
+                                     int32_t offset,
+                                     int32_t length) {
+  return array_->Put(BoundOffset(index),
+                     b,
+                     offset,
+                     BoundLength(index, length));
+}
+
+int32_t WritableFontData::WriteBytes(int32_t index, ByteVector* b) {
+  assert(b);
+  return WriteBytes(index, &((*b)[0]), 0, b->size());
+}
+
+int32_t WritableFontData::WriteBytesPad(int32_t index,
+                                        ByteVector* b,
+                                        int32_t offset,
+                                        int32_t length,
+                                        byte_t pad) {
+  int32_t written =
+      array_->Put(BoundOffset(index),
+                  &((*b)[0]),
+                  offset,
+                  BoundLength(index,
+                              std::min<int32_t>(length, b->size() - offset)));
+  written += WritePadding(written + index, length - written, pad);
+  return written;
+}
+
+int32_t WritableFontData::WritePadding(int32_t index, int32_t count) {
+  return WritePadding(index, count, (byte_t)0);
+}
+
+int32_t WritableFontData::WritePadding(int32_t index, int32_t count,
+                                       byte_t pad) {
+  for (int32_t i = 0; i < count; ++i) {
+    array_->Put(index + i, pad);
+  }
+  return count;
+}
+
+int32_t WritableFontData::WriteChar(int32_t index, byte_t c) {
+  return WriteByte(index, c);
+}
+
+int32_t WritableFontData::WriteUShort(int32_t index, int32_t us) {
+  WriteByte(index, (byte_t)((us >> 8) & 0xff));
+  WriteByte(index + 1, (byte_t)(us & 0xff));
+  return 2;
+}
+
+int32_t WritableFontData::WriteUShortLE(int32_t index, int32_t us) {
+  WriteByte(index, (byte_t)(us & 0xff));
+  WriteByte(index + 1, (byte_t)((us >> 8) & 0xff));
+  return 2;
+}
+
+int32_t WritableFontData::WriteShort(int32_t index, int32_t s) {
+  return WriteUShort(index, s);
+}
+
+int32_t WritableFontData::WriteUInt24(int32_t index, int32_t ui) {
+  WriteByte(index, (byte_t)((ui >> 16) & 0xff));
+  WriteByte(index + 1, (byte_t)((ui >> 8) & 0xff));
+  WriteByte(index + 2, (byte_t)(ui & 0xff));
+  return 3;
+}
+
+int32_t WritableFontData::WriteULong(int32_t index, int64_t ul) {
+  WriteByte(index, (byte_t)((ul >> 24) & 0xff));
+  WriteByte(index + 1, (byte_t)((ul >> 16) & 0xff));
+  WriteByte(index + 2, (byte_t)((ul >> 8) & 0xff));
+  WriteByte(index + 3, (byte_t)(ul & 0xff));
+  return 4;
+}
+
+int32_t WritableFontData::WriteULongLE(int32_t index, int64_t ul) {
+  WriteByte(index, (byte_t)(ul & 0xff));
+  WriteByte(index + 1, (byte_t)((ul >> 8) & 0xff));
+  WriteByte(index + 2, (byte_t)((ul >> 16) & 0xff));
+  WriteByte(index + 3, (byte_t)((ul >> 24) & 0xff));
+  return 4;
+}
+
+int32_t WritableFontData::WriteLong(int32_t index, int64_t l) {
+  return WriteULong(index, l);
+}
+
+int32_t WritableFontData::WriteFixed(int32_t index, int32_t f) {
+  return WriteLong(index, f);
+}
+
+int32_t WritableFontData::WriteDateTime(int32_t index, int64_t date) {
+  WriteULong(index, (date >> 32) & 0xffffffff);
+  WriteULong(index + 4, date & 0xffffffff);
+  return 8;
+}
+
+void WritableFontData::CopyFrom(InputStream* is, int32_t length) {
+  array_->CopyFrom(is, length);
+}
+
+void WritableFontData::CopyFrom(InputStream* is) {
+  array_->CopyFrom(is);
+}
+
+CALLER_ATTACH FontData* WritableFontData::Slice(int32_t offset,
+                                                int32_t length) {
+  if (offset < 0 || offset + length > Size()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundsException(
+        "Attempt to bind data outside of its limits");
+#endif
+    return NULL;
+  }
+  FontDataPtr slice = new WritableFontData(this, offset, length);
+  return slice.Detach();
+}
+
+CALLER_ATTACH FontData* WritableFontData::Slice(int32_t offset) {
+  if (offset > Size()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundsException(
+        "Attempt to bind data outside of its limits");
+#endif
+    return NULL;
+  }
+  FontDataPtr slice = new WritableFontData(this, offset);
+  return slice.Detach();
+}
+
+WritableFontData::WritableFontData(WritableFontData* data, int32_t offset)
+    : ReadableFontData(data, offset) {
+}
+
+WritableFontData::WritableFontData(WritableFontData* data,
+                                   int32_t offset,
+                                   int32_t length)
+    : ReadableFontData(data, offset, length) {
+}
+
+}  // namespace sfntly
diff --git a/sfntly/data/writable_font_data.h b/sfntly/data/writable_font_data.h
new file mode 100644
index 0000000..d2a049e
--- /dev/null
+++ b/sfntly/data/writable_font_data.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_
+
+#include "sfntly/data/readable_font_data.h"
+
+namespace sfntly {
+
+// Writable font data wrapper. Supports writing of data primitives in the
+// TrueType / OpenType spec.
+class WritableFontData : public ReadableFontData {
+ public:
+  explicit WritableFontData(ByteArray* ba);
+  virtual ~WritableFontData();
+
+  // Constructs a writable font data object. If the length is specified as
+  // positive then a fixed size font data object will be created. If the length
+  // is zero or less then a growable font data object will be created and the
+  // size will be used as an estimate to help in allocating the original space.
+  // @param length if length > 0 create a fixed length font data; otherwise
+  //        create a growable font data
+  // @return a new writable font data
+  static CALLER_ATTACH WritableFontData* CreateWritableFontData(int32_t length);
+
+  // Constructs a writable font data object. The new font data object will wrap
+  // the bytes passed in to the factory and it will take make a copy of those
+  // bytes.
+  // @param b the byte vector to wrap
+  // @return a new writable font data
+  static CALLER_ATTACH WritableFontData* CreateWritableFontData(ByteVector* b);
+
+  // Write a byte at the given index.
+  // @param index index into the font data
+  // @param b the byte to write
+  // @return the number of bytes written
+  virtual int32_t WriteByte(int32_t index, byte_t b);
+
+  // Write the bytes from the array.
+  // @param index index into the font data
+  // @param b the source for the bytes to be written
+  // @param offset offset in the byte array
+  // @param length the length of the bytes to be written
+  // @return the number of bytes actually written; -1 if the index is outside
+  //         the FontData's range
+  virtual int32_t WriteBytes(int32_t index,
+                             byte_t* b,
+                             int32_t offset,
+                             int32_t length);
+
+  // Write the bytes from the array.
+  // @param index index into the font data
+  // @param b the source for the bytes to be written
+  // @return the number of bytes actually written; -1 if the index is outside
+  //         the FontData's range
+  virtual int32_t WriteBytes(int32_t index, ByteVector* b);
+
+  // Write the bytes from the array and pad if necessary.
+  // Write to the length given using the byte array provided and if there are
+  // not enough bytes in the array then pad to the requested length using the
+  // pad byte specified.
+  // @param index index into the font data
+  // @param b the source for the bytes to be written
+  // @param offset offset in the byte array
+  // @param length the length of the bytes to be written
+  // @param pad the padding byte to be used if necessary
+  // @return the number of bytes actually written
+  virtual int32_t WriteBytesPad(int32_t index,
+                                ByteVector* b,
+                                int32_t offset,
+                                int32_t length,
+                                byte_t pad);
+
+  // Writes padding to the FontData. The padding byte written is 0x00.
+  // @param index index into the font data
+  // @param count the number of pad bytes to write
+  // @return the number of pad bytes written
+  virtual int32_t WritePadding(int32_t index, int32_t count);
+
+  // Writes padding to the FontData.
+  // @param index index into the font data
+  // @param count the number of pad bytes to write
+  // @param pad the byte value to use as padding
+  // @return the number of pad bytes written
+  virtual int32_t WritePadding(int32_t index, int32_t count, byte_t pad);
+
+  // Write the CHAR at the given index.
+  // @param index index into the font data
+  // @param c the CHAR
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteChar(int32_t index, byte_t c);
+
+  // Write the USHORT at the given index.
+  // @param index index into the font data
+  // @param us the USHORT
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteUShort(int32_t index, int32_t us);
+
+  // Write the USHORT at the given index in little endian format.
+  // @param index index into the font data
+  // @param us the USHORT
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteUShortLE(int32_t index, int32_t us);
+
+  // Write the SHORT at the given index.
+  // @param index index into the font data
+  // @param s the SHORT
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteShort(int32_t index, int32_t s);
+
+  // Write the UINT24 at the given index.
+  // @param index index into the font data
+  // @param ui the UINT24
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteUInt24(int32_t index, int32_t ui);
+
+  // Write the ULONG at the given index.
+  // @param index index into the font data
+  // @param ul the ULONG
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteULong(int32_t index, int64_t ul);
+
+  // Write the ULONG at the given index in little endian format.
+  // @param index index into the font data
+  // @param ul the ULONG
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteULongLE(int32_t index, int64_t ul);
+
+  // Write the LONG at the given index.
+  // @param index index into the font data
+  // @param l the LONG
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteLong(int32_t index, int64_t l);
+
+  // Write the Fixed at the given index.
+  // @param index index into the font data
+  // @param f the Fixed
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteFixed(int32_t index, int32_t f);
+
+  // Write the LONGDATETIME at the given index.
+  // @param index index into the font data
+  // @param date the LONGDATETIME
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteDateTime(int32_t index, int64_t date);
+
+  // Copy from the InputStream into this FontData.
+  // @param is the source
+  // @param length the number of bytes to copy
+  // @throws IOException
+  virtual void CopyFrom(InputStream* is, int32_t length);
+
+  // Copy everything from the InputStream into this FontData.
+  // @param is the source
+  // @throws IOException
+  virtual void CopyFrom(InputStream* is);
+
+  // Makes a slice of this FontData. The returned slice will share the data with
+  // the original FontData.
+  // @param offset the start of the slice
+  // @param length the number of bytes in the slice
+  // @return a slice of the original FontData
+  virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length);
+
+  // Makes a bottom bound only slice of this array. The returned slice will
+  // share the data with the original FontData.
+  // @param offset the start of the slice
+  // @return a slice of the original FontData
+  virtual CALLER_ATTACH FontData* Slice(int32_t offset);
+
+ private:
+  // Constructor with a lower bound.
+  // @param data other WritableFontData object to share data with
+  // @param offset offset from the other WritableFontData's data
+  WritableFontData(WritableFontData* data, int32_t offset);
+
+  // Constructor with lower bound and a length bound.
+  // @param data other WritableFontData object to share data with
+  // @param offset offset from the other WritableFontData's data
+  // @param length length of other WritableFontData's data to use
+  WritableFontData(WritableFontData* data, int32_t offset, int32_t length);
+};
+typedef Ptr<WritableFontData> WritableFontDataPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_
diff --git a/sfntly/font.cc b/sfntly/font.cc
new file mode 100644
index 0000000..347e0c1
--- /dev/null
+++ b/sfntly/font.cc
@@ -0,0 +1,557 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/font.h"
+
+#include <stdio.h>
+
+#include <functional>
+#include <algorithm>
+#include <map>
+#include <string>
+#include <typeinfo>
+#include <iterator>
+
+#include "sfntly/data/font_input_stream.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/math/fixed1616.h"
+#include "sfntly/math/font_math.h"
+#include "sfntly/port/exception_type.h"
+#include "sfntly/table/core/font_header_table.h"
+#include "sfntly/table/core/horizontal_device_metrics_table.h"
+#include "sfntly/table/core/horizontal_header_table.h"
+#include "sfntly/table/core/horizontal_metrics_table.h"
+#include "sfntly/table/core/maximum_profile_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+#include "sfntly/tag.h"
+
+namespace sfntly {
+
+const int32_t SFNTVERSION_MAJOR = 1;
+const int32_t SFNTVERSION_MINOR = 0;
+
+/******************************************************************************
+ * Font class
+ ******************************************************************************/
+Font::~Font() {}
+
+bool Font::HasTable(int32_t tag) {
+  TableMap::const_iterator result = tables_.find(tag);
+  TableMap::const_iterator end = tables_.end();
+  return (result != end);
+}
+
+Table* Font::GetTable(int32_t tag) {
+  if (!HasTable(tag)) {
+    return NULL;
+  }
+  return tables_[tag];
+}
+
+const TableMap* Font::GetTableMap() {
+  return &tables_;
+}
+
+void Font::Serialize(OutputStream* os, IntegerList* table_ordering) {
+  assert(table_ordering);
+  IntegerList final_table_ordering;
+  GenerateTableOrdering(table_ordering, &final_table_ordering);
+  TableHeaderList table_records;
+  BuildTableHeadersForSerialization(&final_table_ordering, &table_records);
+
+  FontOutputStream fos(os);
+  SerializeHeader(&fos, &table_records);
+  SerializeTables(&fos, &table_records);
+}
+
+Font::Font(int32_t sfnt_version, ByteVector* digest)
+    : sfnt_version_(sfnt_version) {
+  // non-trivial assignments that makes debugging hard if placed in
+  // initialization list
+  digest_ = *digest;
+}
+
+void Font::BuildTableHeadersForSerialization(IntegerList* table_ordering,
+                                             TableHeaderList* table_headers) {
+  assert(table_headers);
+  assert(table_ordering);
+
+  IntegerList final_table_ordering;
+  GenerateTableOrdering(table_ordering, &final_table_ordering);
+  int32_t table_offset = Offset::kTableRecordBegin + num_tables() *
+                         Offset::kTableRecordSize;
+  for (IntegerList::iterator tag = final_table_ordering.begin(),
+                             tag_end = final_table_ordering.end();
+                             tag != tag_end; ++tag) {
+    if (tables_.find(*tag) == tables_.end()) {
+      continue;
+    }
+    TablePtr table = tables_[*tag];
+    if (table != NULL) {
+      HeaderPtr header =
+          new Header(*tag, table->CalculatedChecksum(), table_offset,
+                     table->header()->length());
+      table_headers->push_back(header);
+      table_offset += (table->DataLength() + 3) & ~3;
+    }
+  }
+}
+
+void Font::SerializeHeader(FontOutputStream* fos,
+                           TableHeaderList* table_headers) {
+  fos->WriteFixed(sfnt_version_);
+  fos->WriteUShort(table_headers->size());
+  int32_t log2_of_max_power_of_2 = FontMath::Log2(table_headers->size());
+  int32_t search_range = 2 << (log2_of_max_power_of_2 - 1 + 4);
+  fos->WriteUShort(search_range);
+  fos->WriteUShort(log2_of_max_power_of_2);
+  fos->WriteUShort((table_headers->size() * 16) - search_range);
+
+  HeaderTagSortedSet sorted_headers;
+  std::copy(table_headers->begin(),
+            table_headers->end(),
+            std::inserter(sorted_headers, sorted_headers.end()));
+
+  for (HeaderTagSortedSet::iterator record = sorted_headers.begin(),
+                                    record_end = sorted_headers.end();
+                                    record != record_end; ++record) {
+    fos->WriteULong((*record)->tag());
+    fos->WriteULong((int32_t)((*record)->checksum()));
+    fos->WriteULong((*record)->offset());
+    fos->WriteULong((*record)->length());
+  }
+}
+
+void Font::SerializeTables(FontOutputStream* fos,
+                           TableHeaderList* table_headers) {
+  assert(fos);
+  assert(table_headers);
+  for (TableHeaderList::iterator record = table_headers->begin(),
+                                 end_of_headers = table_headers->end();
+                                 record != end_of_headers; ++record) {
+    TablePtr target_table = GetTable((*record)->tag());
+    if (target_table == NULL) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+      throw IOException("Table out of sync with font header.");
+#endif
+      return;
+    }
+    int32_t table_size = target_table->Serialize(fos);
+    if (table_size != (*record)->length()) {
+      assert(false);
+    }
+    int32_t filler_size = ((table_size + 3) & ~3) - table_size;
+    for (int32_t i = 0; i < filler_size; ++i) {
+      fos->Write(static_cast<byte_t>(0));
+    }
+  }
+}
+
+void Font::GenerateTableOrdering(IntegerList* default_table_ordering,
+                                 IntegerList* table_ordering) {
+  assert(default_table_ordering);
+  assert(table_ordering);
+  table_ordering->clear();
+  if (default_table_ordering->empty()) {
+    DefaultTableOrdering(default_table_ordering);
+  }
+
+  typedef std::map<int32_t, bool> Int2Bool;
+  typedef std::pair<int32_t, bool> Int2BoolEntry;
+  Int2Bool tables_in_font;
+  for (TableMap::iterator table = tables_.begin(), table_end = tables_.end();
+                          table != table_end; ++table) {
+    tables_in_font.insert(Int2BoolEntry(table->first, false));
+  }
+  for (IntegerList::iterator tag = default_table_ordering->begin(),
+                             tag_end = default_table_ordering->end();
+                             tag != tag_end; ++tag) {
+    if (HasTable(*tag)) {
+      table_ordering->push_back(*tag);
+      tables_in_font[*tag] = true;
+    }
+  }
+  for (Int2Bool::iterator table = tables_in_font.begin(),
+                          table_end = tables_in_font.end();
+                          table != table_end; ++table) {
+    if (table->second == false)
+      table_ordering->push_back(table->first);
+  }
+}
+
+void Font::DefaultTableOrdering(IntegerList* default_table_ordering) {
+  assert(default_table_ordering);
+  default_table_ordering->clear();
+  if (HasTable(Tag::CFF)) {
+    default_table_ordering->resize(CFF_TABLE_ORDERING_SIZE);
+    std::copy(CFF_TABLE_ORDERING, CFF_TABLE_ORDERING + CFF_TABLE_ORDERING_SIZE,
+              default_table_ordering->begin());
+    return;
+  }
+  default_table_ordering->resize(TRUE_TYPE_TABLE_ORDERING_SIZE);
+  std::copy(TRUE_TYPE_TABLE_ORDERING,
+            TRUE_TYPE_TABLE_ORDERING + TRUE_TYPE_TABLE_ORDERING_SIZE,
+            default_table_ordering->begin());
+}
+
+/******************************************************************************
+ * Font::Builder class
+ ******************************************************************************/
+Font::Builder::~Builder() {}
+
+CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(FontFactory* factory,
+                                                          InputStream* is) {
+  FontBuilderPtr builder = new Builder(factory);
+  builder->LoadFont(is);
+  return builder.Detach();
+}
+
+CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(
+    FontFactory* factory,
+    WritableFontData* wfd,
+    int32_t offset_to_offset_table) {
+  FontBuilderPtr builder = new Builder(factory);
+  builder->LoadFont(wfd, offset_to_offset_table);
+  return builder.Detach();
+}
+
+CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(
+    FontFactory* factory) {
+  FontBuilderPtr builder = new Builder(factory);
+  return builder.Detach();
+}
+
+bool Font::Builder::ReadyToBuild() {
+  // just read in data with no manipulation
+  if (table_builders_.empty() && !data_blocks_.empty()) {
+    return true;
+  }
+
+  // TODO(stuartg): font level checks - required tables etc?
+  for (TableBuilderMap::iterator table_builder = table_builders_.begin(),
+                                 table_builder_end = table_builders_.end();
+                                 table_builder != table_builder_end;
+                                 ++table_builder) {
+    if (!table_builder->second->ReadyToBuild())
+      return false;
+  }
+  return true;
+}
+
+CALLER_ATTACH Font* Font::Builder::Build() {
+  FontPtr font = new Font(sfnt_version_, &digest_);
+
+  if (!table_builders_.empty()) {
+    // Note: Different from Java. Directly use font->tables_ here to avoid
+    //       STL container copying.
+    BuildTablesFromBuilders(font, &table_builders_, &font->tables_);
+  }
+
+  table_builders_.clear();
+  data_blocks_.clear();
+  return font.Detach();
+}
+
+void Font::Builder::SetDigest(ByteVector* digest) {
+  digest_.clear();
+  digest_ = *digest;
+}
+
+void Font::Builder::ClearTableBuilders() {
+  table_builders_.clear();
+}
+
+bool Font::Builder::HasTableBuilder(int32_t tag) {
+  return (table_builders_.find(tag) != table_builders_.end());
+}
+
+Table::Builder* Font::Builder::GetTableBuilder(int32_t tag) {
+  if (HasTableBuilder(tag))
+    return table_builders_[tag];
+  return NULL;
+}
+
+Table::Builder* Font::Builder::NewTableBuilder(int32_t tag) {
+  HeaderPtr header = new Header(tag);
+  TableBuilderPtr builder;
+  builder.Attach(Table::Builder::GetBuilder(header, NULL));
+  table_builders_.insert(TableBuilderEntry(header->tag(), builder));
+  return builder;
+}
+
+Table::Builder* Font::Builder::NewTableBuilder(int32_t tag,
+                                               ReadableFontData* src_data) {
+  assert(src_data);
+  WritableFontDataPtr data;
+  data.Attach(WritableFontData::CreateWritableFontData(src_data->Length()));
+  // TODO(stuarg): take over original data instead?
+  src_data->CopyTo(data);
+
+  HeaderPtr header = new Header(tag, data->Length());
+  TableBuilderPtr builder;
+  builder.Attach(Table::Builder::GetBuilder(header, data));
+  table_builders_.insert(TableBuilderEntry(tag, builder));
+  return builder;
+}
+
+void Font::Builder::RemoveTableBuilder(int32_t tag) {
+  TableBuilderMap::iterator target = table_builders_.find(tag);
+  if (target != table_builders_.end()) {
+    table_builders_.erase(target);
+  }
+}
+
+Font::Builder::Builder(FontFactory* factory)
+    : factory_(factory),
+      sfnt_version_(Fixed1616::Fixed(SFNTVERSION_MAJOR, SFNTVERSION_MINOR)) {
+}
+
+void Font::Builder::LoadFont(InputStream* is) {
+  // Note: we do not throw exception here for is.  This is more of an assertion.
+  assert(is);
+  FontInputStream font_is(is);
+  HeaderOffsetSortedSet records;
+  ReadHeader(&font_is, &records);
+  LoadTableData(&records, &font_is, &data_blocks_);
+  BuildAllTableBuilders(&data_blocks_, &table_builders_);
+  font_is.Close();
+}
+
+void Font::Builder::LoadFont(WritableFontData* wfd,
+                             int32_t offset_to_offset_table) {
+  // Note: we do not throw exception here for is.  This is more of an assertion.
+  assert(wfd);
+  HeaderOffsetSortedSet records;
+  ReadHeader(wfd, offset_to_offset_table, &records);
+  LoadTableData(&records, wfd, &data_blocks_);
+  BuildAllTableBuilders(&data_blocks_, &table_builders_);
+}
+
+int32_t Font::Builder::SfntWrapperSize() {
+  return Offset::kSfntHeaderSize +
+         (Offset::kTableRecordSize * table_builders_.size());
+}
+
+void Font::Builder::BuildAllTableBuilders(DataBlockMap* table_data,
+                                          TableBuilderMap* builder_map) {
+  for (DataBlockMap::iterator record = table_data->begin(),
+                              record_end = table_data->end();
+                              record != record_end; ++record) {
+    TableBuilderPtr builder;
+    builder.Attach(GetTableBuilder(record->first.p_, record->second.p_));
+    builder_map->insert(TableBuilderEntry(record->first->tag(), builder));
+  }
+  InterRelateBuilders(&table_builders_);
+}
+
+CALLER_ATTACH
+Table::Builder* Font::Builder::GetTableBuilder(Header* header,
+                                               WritableFontData* data) {
+  return Table::Builder::GetBuilder(header, data);
+}
+
+void Font::Builder::BuildTablesFromBuilders(Font* font,
+                                            TableBuilderMap* builder_map,
+                                            TableMap* table_map) {
+  UNREFERENCED_PARAMETER(font);
+  InterRelateBuilders(builder_map);
+
+  // Now build all the tables.
+  for (TableBuilderMap::iterator builder = builder_map->begin(),
+                                 builder_end = builder_map->end();
+                                 builder != builder_end; ++builder) {
+    TablePtr table;
+    if (builder->second && builder->second->ReadyToBuild()) {
+      table.Attach(down_cast<Table*>(builder->second->Build()));
+    }
+    if (table == NULL) {
+      table_map->clear();
+#if !defined (SFNTLY_NO_EXCEPTION)
+      std::string builder_string = "Unable to build table - ";
+      char* table_name = TagToString(builder->first);
+      builder_string += table_name;
+      delete[] table_name;
+      throw RuntimeException(builder_string.c_str());
+#endif
+      return;
+    }
+    table_map->insert(TableMapEntry(table->header()->tag(), table));
+  }
+}
+
+static Table::Builder* GetBuilder(TableBuilderMap* builder_map, int32_t tag) {
+  if (builder_map) {
+    TableBuilderMap::iterator target = builder_map->find(tag);
+    if (target != builder_map->end()) {
+      return target->second.p_;
+    }
+  }
+
+  return NULL;
+}
+
+void Font::Builder::InterRelateBuilders(TableBuilderMap* builder_map) {
+  Table::Builder* raw_head_builder = GetBuilder(builder_map, Tag::head);
+  FontHeaderTableBuilderPtr header_table_builder;
+  if (raw_head_builder != NULL) {
+      header_table_builder =
+          down_cast<FontHeaderTable::Builder*>(raw_head_builder);
+  }
+
+  Table::Builder* raw_hhea_builder = GetBuilder(builder_map, Tag::hhea);
+  HorizontalHeaderTableBuilderPtr horizontal_header_builder;
+  if (raw_head_builder != NULL) {
+      horizontal_header_builder =
+          down_cast<HorizontalHeaderTable::Builder*>(raw_hhea_builder);
+  }
+
+  Table::Builder* raw_maxp_builder = GetBuilder(builder_map, Tag::maxp);
+  MaximumProfileTableBuilderPtr max_profile_builder;
+  if (raw_maxp_builder != NULL) {
+      max_profile_builder =
+          down_cast<MaximumProfileTable::Builder*>(raw_maxp_builder);
+  }
+
+  Table::Builder* raw_loca_builder = GetBuilder(builder_map, Tag::loca);
+  LocaTableBuilderPtr loca_table_builder;
+  if (raw_loca_builder != NULL) {
+      loca_table_builder = down_cast<LocaTable::Builder*>(raw_loca_builder);
+  }
+
+  Table::Builder* raw_hmtx_builder = GetBuilder(builder_map, Tag::hmtx);
+  HorizontalMetricsTableBuilderPtr horizontal_metrics_builder;
+  if (raw_hmtx_builder != NULL) {
+      horizontal_metrics_builder =
+          down_cast<HorizontalMetricsTable::Builder*>(raw_hmtx_builder);
+  }
+
+#if defined (SFNTLY_EXPERIMENTAL)
+  Table::Builder* raw_hdmx_builder = GetBuilder(builder_map, Tag::hdmx);
+  HorizontalDeviceMetricsTableBuilderPtr hdmx_table_builder;
+  if (raw_hdmx_builder != NULL) {
+      hdmx_table_builder =
+          down_cast<HorizontalDeviceMetricsTable::Builder*>(raw_hdmx_builder);
+  }
+#endif
+
+  // set the inter table data required to build certain tables
+  if (horizontal_metrics_builder != NULL) {
+    if (max_profile_builder != NULL) {
+      horizontal_metrics_builder->SetNumGlyphs(
+          max_profile_builder->NumGlyphs());
+    }
+    if (horizontal_header_builder != NULL) {
+      horizontal_metrics_builder->SetNumberOfHMetrics(
+          horizontal_header_builder->NumberOfHMetrics());
+    }
+  }
+
+  if (loca_table_builder != NULL) {
+    if (max_profile_builder != NULL) {
+      loca_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs());
+    }
+    if (header_table_builder != NULL) {
+      loca_table_builder->set_format_version(
+          header_table_builder->IndexToLocFormat());
+    }
+  }
+
+#if defined (SFNTLY_EXPERIMENTAL)
+  // Note: In C++, hdmx_table_builder can be NULL in a subsetter.
+  if (max_profile_builder != NULL && hdmx_table_builder != NULL) {
+    hdmx_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs());
+  }
+#endif
+}
+
+void Font::Builder::ReadHeader(FontInputStream* is,
+                               HeaderOffsetSortedSet* records) {
+  assert(records);
+  sfnt_version_ = is->ReadFixed();
+  num_tables_ = is->ReadUShort();
+  search_range_ = is->ReadUShort();
+  entry_selector_ = is->ReadUShort();
+  range_shift_ = is->ReadUShort();
+
+  for (int32_t table_number = 0; table_number < num_tables_; ++table_number) {
+    // Need to use temporary vars here.  C++ evaluates function parameters from
+    // right to left and thus breaks the order of input stream.
+    int32_t tag = is->ReadULongAsInt();
+    int64_t checksum = is->ReadULong();
+    int32_t offset = is->ReadULongAsInt();
+    int32_t length = is->ReadULongAsInt();
+    HeaderPtr table = new Header(tag, checksum, offset, length);
+    records->insert(table);
+  }
+}
+
+void Font::Builder::ReadHeader(ReadableFontData* fd,
+                               int32_t offset,
+                               HeaderOffsetSortedSet* records) {
+  assert(records);
+  sfnt_version_ = fd->ReadFixed(offset + Offset::kSfntVersion);
+  num_tables_ = fd->ReadUShort(offset + Offset::kNumTables);
+  search_range_ = fd->ReadUShort(offset + Offset::kSearchRange);
+  entry_selector_ = fd->ReadUShort(offset + Offset::kEntrySelector);
+  range_shift_ = fd->ReadUShort(offset + Offset::kRangeShift);
+
+  int32_t table_offset = offset + Offset::kTableRecordBegin;
+  for (int32_t table_number = 0;
+       table_number < num_tables_;
+       table_number++, table_offset += Offset::kTableRecordSize) {
+    int32_t tag = fd->ReadULongAsInt(table_offset + Offset::kTableTag);
+    int64_t checksum = fd->ReadULong(table_offset + Offset::kTableCheckSum);
+    int32_t offset = fd->ReadULongAsInt(table_offset + Offset::kTableOffset);
+    int32_t length = fd->ReadULongAsInt(table_offset + Offset::kTableLength);
+    HeaderPtr table = new Header(tag, checksum, offset, length);
+    records->insert(table);
+  }
+}
+
+void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers,
+                                  FontInputStream* is,
+                                  DataBlockMap* table_data) {
+  assert(table_data);
+  for (HeaderOffsetSortedSet::iterator table_header = headers->begin(),
+                                       table_end = headers->end();
+                                       table_header != table_end;
+                                       ++table_header) {
+    is->Skip((*table_header)->offset() - is->position());
+    FontInputStream table_is(is, (*table_header)->length());
+    WritableFontDataPtr data;
+    data.Attach(
+        WritableFontData::CreateWritableFontData((*table_header)->length()));
+    data->CopyFrom(&table_is, (*table_header)->length());
+    table_data->insert(DataBlockEntry(*table_header, data));
+  }
+}
+
+void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers,
+                                  WritableFontData* fd,
+                                  DataBlockMap* table_data) {
+  for (HeaderOffsetSortedSet::iterator table_header = headers->begin(),
+                                       table_end = headers->end();
+                                       table_header != table_end;
+                                       ++table_header) {
+    FontDataPtr sliced_data;
+    sliced_data.Attach(
+        fd->Slice((*table_header)->offset(), (*table_header)->length()));
+    WritableFontDataPtr data = down_cast<WritableFontData*>(sliced_data.p_);
+    table_data->insert(DataBlockEntry(*table_header, data));
+  }
+}
+
+}  // namespace sfntly
diff --git a/sfntly/font.h b/sfntly/font.h
new file mode 100644
index 0000000..975e8cc
--- /dev/null
+++ b/sfntly/font.h
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_FONT_H_
+#define SFNTLY_CPP_SRC_SFNTLY_FONT_H_
+
+#include <vector>
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/endian.h"
+#include "sfntly/data/font_input_stream.h"
+#include "sfntly/data/font_output_stream.h"
+#include "sfntly/data/writable_font_data.h"
+#include "sfntly/table/table.h"
+
+namespace sfntly {
+
+// Note: following constants are embedded in Font class in Java.  They are
+//       extracted out for easier reference from other classes.  Offset is the
+//       one that is kept within class.
+// Platform ids. These are used in a number of places within the font whenever
+// the platform needs to be specified.
+struct PlatformId {
+  enum {
+    kUnknown = -1,
+    kUnicode = 0,
+    kMacintosh = 1,
+    kISO = 2,
+    kWindows = 3,
+    kCustom = 4
+  };
+};
+
+// Unicode encoding ids. These are used in a number of places within the font
+// whenever character encodings need to be specified.
+struct UnicodeEncodingId {
+  enum {
+    kUnknown = -1,
+    kUnicode1_0 = 0,
+    kUnicode1_1 = 1,
+    kISO10646 = 2,
+    kUnicode2_0_BMP = 3,
+    kUnicode2_0 = 4,
+    kUnicodeVariationSequences = 5
+  };
+};
+
+// Windows encoding ids. These are used in a number of places within the font
+// whenever character encodings need to be specified.
+struct WindowsEncodingId {
+  enum {
+    kUnknown = 0xffffffff,
+    kSymbol = 0,
+    kUnicodeUCS2 = 1,
+    kShiftJIS = 2,
+    kPRC = 3,
+    kBig5 = 4,
+    kWansung = 5,
+    kJohab = 6,
+    kUnicodeUCS4 = 10
+  };
+};
+
+// Macintosh encoding ids. These are used in a number of places within the
+// font whenever character encodings need to be specified.
+struct MacintoshEncodingId {
+  // Macintosh Platform Encodings
+  enum {
+    kUnknown = -1,
+    kRoman = 0,
+    kJapanese = 1,
+    kChineseTraditional = 2,
+    kKorean = 3,
+    kArabic = 4,
+    kHebrew = 5,
+    kGreek = 6,
+    kRussian = 7,
+    kRSymbol = 8,
+    kDevanagari = 9,
+    kGurmukhi = 10,
+    kGujarati = 11,
+    kOriya = 12,
+    kBengali = 13,
+    kTamil = 14,
+    kTelugu = 15,
+    kKannada = 16,
+    kMalayalam = 17,
+    kSinhalese = 18,
+    kBurmese = 19,
+    kKhmer = 20,
+    kThai = 21,
+    kLaotian = 22,
+    kGeorgian = 23,
+    kArmenian = 24,
+    kChineseSimplified = 25,
+    kTibetan = 26,
+    kMongolian = 27,
+    kGeez = 28,
+    kSlavic = 29,
+    kVietnamese = 30,
+    kSindhi = 31,
+    kUninterpreted = 32
+  };
+};
+
+class FontFactory;
+
+// An sfnt container font object. This object is immutable and thread safe. To
+// construct one use an instance of Font::Builder.
+class Font : public RefCounted<Font> {
+ public:
+  // A builder for a font object. The builder allows the for the creation of
+  // immutable Font objects. The builder is a one use non-thread safe object and
+  // once the Font object has been created it is no longer usable. To create a
+  // further Font object new builder will be required.
+  class Builder : public RefCounted<Builder> {
+   public:
+    virtual ~Builder();
+
+    static CALLER_ATTACH Builder*
+        GetOTFBuilder(FontFactory* factory, InputStream* is);
+    static CALLER_ATTACH Builder*
+        GetOTFBuilder(FontFactory* factory,
+                      WritableFontData* ba,
+                      int32_t offset_to_offset_table);
+    static CALLER_ATTACH Builder* GetOTFBuilder(FontFactory* factory);
+
+    // Get the font factory that created this font builder.
+    FontFactory* GetFontFactory() { return factory_; }
+
+    // Is the font ready to build?
+    bool ReadyToBuild();
+
+    // Build the Font. After this call this builder will no longer be usable.
+    CALLER_ATTACH Font* Build();
+
+    // Set a unique fingerprint for the font object.
+    void SetDigest(ByteVector* digest);
+
+    // Clear all table builders.
+    void ClearTableBuilders();
+
+    // Does this font builder have the specified table builder.
+    bool HasTableBuilder(int32_t tag);
+
+    // Get the table builder for the given tag. If there is no builder for that
+    // tag then return a null.
+    Table::Builder* GetTableBuilder(int32_t tag);
+
+    // Creates a new table builder for the table type given by the table id tag.
+    // This new table has been added to the font and will replace any existing
+    // builder for that table.
+    // @return new empty table of the type specified by tag; if tag is not known
+    //         then a generic OpenTypeTable is returned
+    virtual Table::Builder* NewTableBuilder(int32_t tag);
+
+    // Creates a new table builder for the table type given by the table id tag.
+    // It makes a copy of the data provided and uses that copy for the table.
+    // This new table has been added to the font and will replace any existing
+    // builder for that table.
+    virtual Table::Builder* NewTableBuilder(int32_t tag,
+                                            ReadableFontData* src_data);
+
+    // Get a map of the table builders in this font builder accessed by table
+    // tag.
+    virtual TableBuilderMap* table_builders() { return &table_builders_; }
+
+    // Remove the specified table builder from the font builder.
+    // Note: different from Java: we don't return object in removeTableBuilder
+    virtual void RemoveTableBuilder(int32_t tag);
+
+    // Get the number of table builders in the font builder.
+    virtual int32_t number_of_table_builders() {
+      return (int32_t)table_builders_.size();
+    }
+
+   private:
+    explicit Builder(FontFactory* factory);
+    virtual void LoadFont(InputStream* is);
+    virtual void LoadFont(WritableFontData* wfd,
+                          int32_t offset_to_offset_table);
+    int32_t SfntWrapperSize();
+    void BuildAllTableBuilders(DataBlockMap* table_data,
+                               TableBuilderMap* builder_map);
+    CALLER_ATTACH Table::Builder*
+        GetTableBuilder(Header* header, WritableFontData* data);
+    void BuildTablesFromBuilders(Font* font,
+                                 TableBuilderMap* builder_map,
+                                 TableMap* tables);
+    static void InterRelateBuilders(TableBuilderMap* builder_map);
+
+    void ReadHeader(FontInputStream* is,
+                    HeaderOffsetSortedSet* records);
+
+    void ReadHeader(ReadableFontData* fd,
+                    int32_t offset,
+                    HeaderOffsetSortedSet* records);
+
+    void LoadTableData(HeaderOffsetSortedSet* headers,
+                       FontInputStream* is,
+                       DataBlockMap* table_data);
+
+    void LoadTableData(HeaderOffsetSortedSet* headers,
+                       WritableFontData* fd,
+                       DataBlockMap* table_data);
+
+    TableBuilderMap table_builders_;
+    FontFactory* factory_;  // dumb pointer, avoid circular refcounting
+    int32_t sfnt_version_;
+    int32_t num_tables_;
+    int32_t search_range_;
+    int32_t entry_selector_;
+    int32_t range_shift_;
+    DataBlockMap data_blocks_;
+    ByteVector digest_;
+  };
+
+  virtual ~Font();
+
+  // Gets the sfnt version set in the sfnt wrapper of the font.
+  int32_t sfnt_version() { return sfnt_version_; }
+
+  // Gets a copy of the fonts digest that was created when the font was read. If
+  // no digest was set at creation time then the return result will be null.
+  ByteVector* digest() { return &digest_; }
+
+  // Get the checksum for this font.
+  int64_t checksum() { return checksum_; }
+
+  // Get the number of tables in this font.
+  int32_t num_tables() { return (int32_t)tables_.size(); }
+
+  // Whether the font has a particular table.
+  bool HasTable(int32_t tag);
+
+  // UNIMPLEMENTED: public Iterator<? extends Table> iterator
+
+  // Get the table in this font with the specified id.
+  // @param tag the identifier of the table
+  // @return the table specified if it exists; null otherwise
+  // C++ port: rename table() to GetTable()
+  Table* GetTable(int32_t tag);
+
+  // Get a map of the tables in this font accessed by table tag.
+  // @return an unmodifiable view of the tables in this font
+  // Note: renamed tableMap() to GetTableMap()
+  const TableMap* GetTableMap();
+
+  // UNIMPLEMENTED: toString()
+
+  // Serialize the font to the output stream.
+  // @param os the destination for the font serialization
+  // @param tableOrdering the table ordering to apply
+  void Serialize(OutputStream* os, IntegerList* table_ordering);
+
+ private:
+  // Offsets to specific elements in the underlying data. These offsets are
+  // relative to the start of the table or the start of sub-blocks within the
+  // table.
+  struct Offset {
+    enum {
+      // Offsets within the main directory
+      kSfntVersion = 0,
+      kNumTables = 4,
+      kSearchRange = 6,
+      kEntrySelector = 8,
+      kRangeShift = 10,
+      kTableRecordBegin = 12,
+      kSfntHeaderSize = 12,
+
+      // Offsets within a specific table record
+      kTableTag = 0,
+      kTableCheckSum = 4,
+      kTableOffset = 8,
+      kTableLength = 12,
+      kTableRecordSize = 16
+    };
+  };
+
+  // Note: the two constants are moved to tag.h to avoid VC++ bug.
+//  static const int32_t CFF_TABLE_ORDERING[];
+//  static const int32_t TRUE_TYPE_TABLE_ORDERING[];
+
+  // Constructor.
+  // @param sfntVersion the sfnt version
+  // @param digest the computed digest for the font; null if digest was not
+  //        computed
+  // Note: Current C++ port does not support SHA digest validation.
+  Font(int32_t sfnt_version, ByteVector* digest);
+
+  // Build the table headers to be used for serialization. These headers will be
+  // filled out with the data required for serialization. The headers will be
+  // sorted in the order specified and only those specified will have headers
+  // generated.
+  // @param tableOrdering the tables to generate headers for and the order to
+  //        sort them
+  // @return a list of table headers ready for serialization
+  void BuildTableHeadersForSerialization(IntegerList* table_ordering,
+                                         TableHeaderList* table_headers);
+
+  // Searialize the headers.
+  // @param fos the destination stream for the headers
+  // @param tableHeaders the headers to serialize
+  // @throws IOException
+  void SerializeHeader(FontOutputStream* fos, TableHeaderList* table_headers);
+
+  // Serialize the tables.
+  // @param fos the destination stream for the headers
+  // @param tableHeaders the headers for the tables to serialize
+  // @throws IOException
+  void SerializeTables(FontOutputStream* fos, TableHeaderList* table_headers);
+
+  // Generate the full table ordering to used for serialization. The full
+  // ordering uses the partial ordering as a seed and then adds all remaining
+  // tables in the font in an undefined order.
+  // @param defaultTableOrdering the partial ordering to be used as a seed for
+  //        the full ordering
+  // @param (out) table_ordering the full ordering for serialization
+  void GenerateTableOrdering(IntegerList* default_table_ordering,
+                             IntegerList* table_ordering);
+
+  // Get the default table ordering based on the type of the font.
+  // @param (out) default_table_ordering the default table ordering
+  void DefaultTableOrdering(IntegerList* default_table_ordering);
+
+  int32_t sfnt_version_;
+  ByteVector digest_;
+  int64_t checksum_;
+  TableMap tables_;
+};
+typedef Ptr<Font> FontPtr;
+typedef std::vector<FontPtr> FontArray;
+typedef Ptr<Font::Builder> FontBuilderPtr;
+typedef std::vector<FontBuilderPtr> FontBuilderArray;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_FONT_H_
diff --git a/sfntly/font_factory.cc b/sfntly/font_factory.cc
new file mode 100644
index 0000000..c162a77
--- /dev/null
+++ b/sfntly/font_factory.cc
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/font_factory.h"
+
+#include <string.h>
+
+#include "sfntly/tag.h"
+
+namespace sfntly {
+
+FontFactory::~FontFactory() {
+}
+
+CALLER_ATTACH FontFactory* FontFactory::GetInstance() {
+  FontFactoryPtr instance = new FontFactory();
+  return instance.Detach();
+}
+
+void FontFactory::FingerprintFont(bool fingerprint) {
+  fingerprint_ = fingerprint;
+}
+
+bool FontFactory::FingerprintFont() {
+  return fingerprint_;
+}
+
+void FontFactory::LoadFonts(InputStream* is, FontArray* output) {
+  assert(output);
+  PushbackInputStream* pbis = down_cast<PushbackInputStream*>(is);
+  if (IsCollection(pbis)) {
+    LoadCollection(pbis, output);
+    return;
+  }
+  FontPtr font;
+  font.Attach(LoadSingleOTF(pbis));
+  if (font) {
+    output->push_back(font);
+  }
+}
+
+void FontFactory::LoadFonts(ByteVector* b, FontArray* output) {
+  WritableFontDataPtr wfd;
+  wfd.Attach(WritableFontData::CreateWritableFontData(b));
+  if (IsCollection(wfd)) {
+    LoadCollection(wfd, output);
+    return;
+  }
+  FontPtr font;
+  font.Attach(LoadSingleOTF(wfd));
+  if (font) {
+    output->push_back(font);
+  }
+}
+
+void FontFactory::LoadFontsForBuilding(InputStream* is,
+                                       FontBuilderArray* output) {
+  PushbackInputStream* pbis = down_cast<PushbackInputStream*>(is);
+  if (IsCollection(pbis)) {
+    LoadCollectionForBuilding(pbis, output);
+    return;
+  }
+  FontBuilderPtr builder;
+  builder.Attach(LoadSingleOTFForBuilding(pbis));
+  if (builder) {
+    output->push_back(builder);
+  }
+}
+
+void FontFactory::LoadFontsForBuilding(ByteVector* b,
+                                       FontBuilderArray* output) {
+  WritableFontDataPtr wfd;
+  wfd.Attach(WritableFontData::CreateWritableFontData(b));
+  if (IsCollection(wfd)) {
+    LoadCollectionForBuilding(wfd, output);
+    return;
+  }
+  FontBuilderPtr builder;
+  builder.Attach(LoadSingleOTFForBuilding(wfd, 0));
+  if (builder) {
+    output->push_back(builder);
+  }
+}
+
+void FontFactory::SerializeFont(Font* font, OutputStream* os) {
+  font->Serialize(os, &table_ordering_);
+}
+
+void FontFactory::SetSerializationTableOrdering(
+    const IntegerList& table_ordering) {
+  table_ordering_ = table_ordering;
+}
+
+CALLER_ATTACH Font::Builder* FontFactory::NewFontBuilder() {
+  return Font::Builder::GetOTFBuilder(this);
+}
+
+CALLER_ATTACH Font* FontFactory::LoadSingleOTF(InputStream* is) {
+  FontBuilderPtr builder;
+  builder.Attach(LoadSingleOTFForBuilding(is));
+  return builder->Build();
+}
+
+CALLER_ATTACH Font* FontFactory::LoadSingleOTF(WritableFontData* wfd) {
+  FontBuilderPtr builder;
+  builder.Attach(LoadSingleOTFForBuilding(wfd, 0));
+  return builder->Build();
+}
+
+void FontFactory::LoadCollection(InputStream* is, FontArray* output) {
+  FontBuilderArray ba;
+  LoadCollectionForBuilding(is, &ba);
+  output->reserve(ba.size());
+  for (FontBuilderArray::iterator builder = ba.begin(), builders_end = ba.end();
+                                  builder != builders_end; ++builder) {
+      FontPtr font;
+      font.Attach((*builder)->Build());
+      output->push_back(font);
+  }
+}
+
+void FontFactory::LoadCollection(WritableFontData* wfd, FontArray* output) {
+  FontBuilderArray builders;
+  LoadCollectionForBuilding(wfd, &builders);
+  output->reserve(builders.size());
+  for (FontBuilderArray::iterator builder = builders.begin(),
+                                  builders_end = builders.end();
+                                  builder != builders_end; ++builder) {
+    FontPtr font;
+    font.Attach((*builder)->Build());
+    output->push_back(font);
+  }
+}
+
+CALLER_ATTACH
+Font::Builder* FontFactory::LoadSingleOTFForBuilding(InputStream* is) {
+  // UNIMPLEMENTED: SHA-1 hash checking via Java DigestStream
+  Font::Builder* builder = Font::Builder::GetOTFBuilder(this, is);
+  // UNIMPLEMENTED: setDigest
+  return builder;
+}
+
+CALLER_ATTACH Font::Builder*
+    FontFactory::LoadSingleOTFForBuilding(WritableFontData* wfd,
+                                          int32_t offset_to_offset_table) {
+  // UNIMPLEMENTED: SHA-1 hash checking via Java DigestStream
+  Font::Builder* builder =
+      Font::Builder::GetOTFBuilder(this, wfd, offset_to_offset_table);
+  // UNIMPLEMENTED: setDigest
+  return builder;
+}
+
+void FontFactory::LoadCollectionForBuilding(InputStream* is,
+                                            FontBuilderArray* builders) {
+  assert(is);
+  assert(builders);
+  WritableFontDataPtr wfd;
+  wfd.Attach(WritableFontData::CreateWritableFontData(is->Available()));
+  wfd->CopyFrom(is);
+  LoadCollectionForBuilding(wfd, builders);
+}
+
+void FontFactory::LoadCollectionForBuilding(WritableFontData* wfd,
+                                            FontBuilderArray* builders) {
+  int32_t ttc_tag = wfd->ReadULongAsInt(Offset::kTTCTag);
+  UNREFERENCED_PARAMETER(ttc_tag);
+  int32_t version = wfd->ReadFixed(Offset::kVersion);
+  UNREFERENCED_PARAMETER(version);
+  int32_t num_fonts = wfd->ReadULongAsInt(Offset::kNumFonts);
+
+  builders->reserve(num_fonts);
+  int32_t offset_table_offset = Offset::kOffsetTable;
+  for (int32_t font_number = 0;
+               font_number < num_fonts;
+               font_number++, offset_table_offset += DataSize::kULONG) {
+    int32_t offset = wfd->ReadULongAsInt(offset_table_offset);
+    FontBuilderPtr builder;
+    builder.Attach(LoadSingleOTFForBuilding(wfd, offset));
+    builders->push_back(builder);
+  }
+}
+
+bool FontFactory::IsCollection(PushbackInputStream* pbis) {
+  ByteVector tag(4);
+  pbis->Read(&tag);
+  pbis->Unread(&tag);
+  return Tag::ttcf == GenerateTag(tag[0], tag[1], tag[2], tag[3]);
+}
+
+bool FontFactory::IsCollection(ReadableFontData* rfd) {
+  ByteVector tag(4);
+  rfd->ReadBytes(0, &(tag[0]), 0, tag.size());
+  return Tag::ttcf ==
+         GenerateTag(tag[0], tag[1], tag[2], tag[3]);
+}
+
+FontFactory::FontFactory()
+    : fingerprint_(false) {
+}
+
+}  // namespace sfntly
diff --git a/sfntly/font_factory.h b/sfntly/font_factory.h
new file mode 100644
index 0000000..63deff4
--- /dev/null
+++ b/sfntly/font_factory.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_
+#define SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_
+
+#include <vector>
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/port/type.h"
+#include "sfntly/font.h"
+
+namespace sfntly {
+
+class FontFactory : public RefCounted<FontFactory> {
+ public:
+  virtual ~FontFactory();
+
+  // Factory method for the construction of a font factory.
+  static CALLER_ATTACH FontFactory* GetInstance();
+
+  // Toggle whether fonts that are loaded are fingerprinted with a SHA-1 hash.
+  // If a font is fingerprinted then a SHA-1 hash is generated at load time and
+  // stored in the font. This is useful for uniquely identifying fonts. By
+  // default this is turned on.
+  // @param fingerprint whether fingerprinting should be turned on or off
+  // TODO(arthurhsu): IMPLEMENT: C++ port currently don't do any SHA-1
+  void FingerprintFont(bool fingerprint);
+  bool FingerprintFont();
+
+  // Load the font(s) from the input stream. The current settings on the factory
+  // are used during the loading process. One or more fonts are returned if the
+  // stream contains valid font data. Some font container formats may have more
+  // than one font and in this case multiple font objects will be returned. If
+  // the data in the stream cannot be parsed or is invalid an array of size zero
+  // will be returned.
+  void LoadFonts(InputStream* is, FontArray* output);
+
+  // ByteArray font loading
+  // Load the font(s) from the byte array. The current settings on the factory
+  // are used during the loading process. One or more fonts are returned if the
+  // stream contains valid font data. Some font container formats may have more
+  // than one font and in this case multiple font objects will be returned. If
+  // the data in the stream cannot be parsed or is invalid an array of size zero
+  // will be returned.
+  void LoadFonts(ByteVector* b, FontArray* output);
+
+  // Load the font(s) from the input stream into font builders. The current
+  // settings on the factory are used during the loading process. One or more
+  // font builders are returned if the stream contains valid font data. Some
+  // font container formats may have more than one font and in this case
+  // multiple font builder objects will be returned. If the data in the stream
+  // cannot be parsed or is invalid an array of size zero will be returned.
+  void LoadFontsForBuilding(InputStream* is, FontBuilderArray* output);
+
+  // Load the font(s) from the byte array into font builders. The current
+  // settings on the factory are used during the loading process. One or more
+  // font builders are returned if the stream contains valid font data. Some
+  // font container formats may have more than one font and in this case
+  // multiple font builder objects will be returned. If the data in the stream
+  // cannot be parsed or is invalid an array of size zero will be returned.
+  void LoadFontsForBuilding(ByteVector* b, FontBuilderArray* output);
+
+  // Font serialization
+  // Serialize the font to the output stream.
+  // NOTE: in this port we attempted not to implement I/O stream because dealing
+  //       with cross-platform I/O stream itself is big enough as a project.
+  //       Byte buffer it is.
+  void SerializeFont(Font* font, OutputStream* os);
+
+  // Set the table ordering to be used in serializing a font. The table ordering
+  // is an ordered list of table ids and tables will be serialized in the order
+  // given. Any tables whose id is not listed in the ordering will be placed in
+  // an unspecified order following those listed.
+  void SetSerializationTableOrdering(const IntegerList& table_ordering);
+
+  // Get an empty font builder for creating a new font from scratch.
+  CALLER_ATTACH Font::Builder* NewFontBuilder();
+
+ private:
+  // Offsets to specific elements in the underlying data. These offsets are
+  // relative to the start of the table or the start of sub-blocks within the
+  // table.
+  struct Offset {
+    enum {
+      // Offsets within the main directory.
+      kTTCTag = 0,
+      kVersion = 4,
+      kNumFonts = 8,
+      kOffsetTable = 12,
+
+      // TTC Version 2.0 extensions.
+      // Offsets from end of OffsetTable.
+      kulDsigTag = 0,
+      kulDsigLength = 4,
+      kulDsigOffset = 8
+    };
+  };
+
+  FontFactory();
+
+  CALLER_ATTACH Font* LoadSingleOTF(InputStream* is);
+  CALLER_ATTACH Font* LoadSingleOTF(WritableFontData* wfd);
+
+  void LoadCollection(InputStream* is, FontArray* output);
+  void LoadCollection(WritableFontData* wfd, FontArray* output);
+
+  CALLER_ATTACH Font::Builder* LoadSingleOTFForBuilding(InputStream* is);
+  CALLER_ATTACH Font::Builder*
+      LoadSingleOTFForBuilding(WritableFontData* wfd,
+                               int32_t offset_to_offset_table);
+
+  void LoadCollectionForBuilding(InputStream* is, FontBuilderArray* builders);
+  void LoadCollectionForBuilding(WritableFontData* ba,
+                                 FontBuilderArray* builders);
+
+  static bool IsCollection(PushbackInputStream* pbis);
+  static bool IsCollection(ReadableFontData* wfd);
+
+  bool fingerprint_;
+  IntegerList table_ordering_;
+};
+typedef Ptr<FontFactory> FontFactoryPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_
diff --git a/sfntly/math/fixed1616.h b/sfntly/math/fixed1616.h
new file mode 100644
index 0000000..4abbe18
--- /dev/null
+++ b/sfntly/math/fixed1616.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_
+#define SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+class Fixed1616 {
+ public:
+  static inline int32_t Integral(int32_t fixed) {
+    return (fixed >> 16);
+  }
+
+  static inline int32_t Fractional(int32_t fixed) {
+    return (fixed & 0xffff);
+  }
+
+  static inline int32_t Fixed(int32_t integral, int32_t fractional) {
+    return ((integral & 0xffff) << 16) | (fractional & 0xffff);
+  }
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_
diff --git a/sfntly/math/font_math.h b/sfntly/math/font_math.h
new file mode 100644
index 0000000..f1cd2d2
--- /dev/null
+++ b/sfntly/math/font_math.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_
+#define SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+class FontMath {
+ public:
+  static int32_t Log2(int32_t a) {
+    int r = 0;  // r will be lg(a)
+    while (a != 0) {
+      a >>= 1;
+      r++;
+    }
+    return r - 1;
+  }
+
+  // Calculates the amount of padding needed. The values provided need to be in
+  // the same units. So, if the size is given as the number of bytes then the
+  // alignment size must also be specified as byte size to align to.
+  // @param size the size of the data that may need padding
+  // @param alignmentSize the number of units to align to
+  // @return the number of units needing to be added for alignment
+  static int32_t PaddingRequired(int32_t size, int32_t alignment_size) {
+    int32_t padding = alignment_size - (size % alignment_size);
+    return padding == alignment_size ? 0 : padding;
+  }
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_
diff --git a/sfntly/port/atomic.h b/sfntly/port/atomic.h
new file mode 100644
index 0000000..b381a52
--- /dev/null
+++ b/sfntly/port/atomic.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_
+
+#if defined (WIN32)
+
+#include <windows.h>
+
+static inline size_t AtomicIncrement(size_t* address) {
+#if defined (_WIN64)
+  return InterlockedIncrement64(reinterpret_cast<LONGLONG*>(address));
+#else
+  return InterlockedIncrement(reinterpret_cast<LONG*>(address));
+#endif
+}
+
+static inline size_t AtomicDecrement(size_t* address) {
+#if defined (_WIN64)
+  return InterlockedDecrement64(reinterpret_cast<LONGLONG*>(address));
+#else
+  return InterlockedDecrement(reinterpret_cast<LONG*>(address));
+#endif
+}
+
+#elif defined (__APPLE__)
+
+#include <libkern/OSAtomic.h>
+
+static inline size_t AtomicIncrement(size_t* address) {
+  return OSAtomicIncrement32Barrier(reinterpret_cast<int32_t*>(address));
+}
+
+static inline size_t AtomicDecrement(size_t* address) {
+  return OSAtomicDecrement32Barrier(reinterpret_cast<int32_t*>(address));
+}
+
+// Originally we check __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4, however, there are
+// issues that clang not carring over this definition.  Therefore we boldly
+// assume it's gcc or gcc-compatible here.  Compilation shall still fail since
+// the intrinsics used are GCC-specific.
+
+#else
+
+#include <stddef.h>
+
+static inline size_t AtomicIncrement(size_t* address) {
+  return __sync_add_and_fetch(address, 1);
+}
+
+static inline size_t AtomicDecrement(size_t* address) {
+  return __sync_sub_and_fetch(address, 1);
+}
+
+#endif  // WIN32
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_
diff --git a/sfntly/port/config.h b/sfntly/port/config.h
new file mode 100644
index 0000000..0fcdffe
--- /dev/null
+++ b/sfntly/port/config.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_
+
+#if !defined(SFNTLY_BIG_ENDIAN) && !defined(SFNTLY_LITTLE_ENDIAN)
+  #if defined (__ppc__) || defined (__ppc64__)
+    #define SFNTLY_BIG_ENDIAN
+  #else
+    #define SFNTLY_LITTLE_ENDIAN
+  #endif
+#endif
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_
diff --git a/sfntly/port/endian.h b/sfntly/port/endian.h
new file mode 100644
index 0000000..db58f0a
--- /dev/null
+++ b/sfntly/port/endian.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_
+
+#include "sfntly/port/config.h"
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+static inline uint16_t EndianSwap16(uint16_t value) {
+  return (uint16_t)((value >> 8) | (value << 8));
+}
+
+static inline int32_t EndianSwap32(int32_t value) {
+  return (((value & 0x000000ff) << 24) |
+          ((value & 0x0000ff00) <<  8) |
+          ((value & 0x00ff0000) >>  8) |
+          ((value & 0xff000000) >> 24));
+}
+
+static inline uint64_t EndianSwap64(uint64_t value) {
+  return (((value & 0x00000000000000ffLL) << 56) |
+          ((value & 0x000000000000ff00LL) << 40) |
+          ((value & 0x0000000000ff0000LL) << 24) |
+          ((value & 0x00000000ff000000LL) << 8)  |
+          ((value & 0x000000ff00000000LL) >> 8)  |
+          ((value & 0x0000ff0000000000LL) >> 24) |
+          ((value & 0x00ff000000000000LL) >> 40) |
+          ((value & 0xff00000000000000LL) >> 56));
+}
+
+#ifdef SFNTLY_LITTLE_ENDIAN
+  #define ToBE16(n) EndianSwap16(n)
+  #define ToBE32(n) EndianSwap32(n)
+  #define ToBE64(n) EndianSwap64(n)
+  #define ToLE16(n) (n)
+  #define ToLE32(n) (n)
+  #define ToLE64(n) (n)
+  #define FromBE16(n) EndianSwap16(n)
+  #define FromBE32(n) EndianSwap32(n)
+  #define FromBE64(n) EndianSwap64(n)
+  #define FromLE16(n) (n)
+  #define FromLE32(n) (n)
+  #define FromLE64(n) (n)
+#else  // SFNTLY_BIG_ENDIAN
+  #define ToBE16(n) (n)
+  #define ToBE32(n) (n)
+  #define ToBE64(n) (n)
+  #define ToLE16(n) EndianSwap16(n)
+  #define ToLE32(n) EndianSwap32(n)
+  #define ToLE64(n) EndianSwap64(n)
+  #define FromBE16(n) (n)
+  #define FromBE32(n) (n)
+  #define FromBE64(n) (n)
+  #define FromLE16(n) EndianSwap16(n)
+  #define FromLE32(n) EndianSwap32(n)
+  #define FromLE64(n) EndianSwap64(n)
+#endif
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_
diff --git a/sfntly/port/exception_type.h b/sfntly/port/exception_type.h
new file mode 100644
index 0000000..b96efcb
--- /dev/null
+++ b/sfntly/port/exception_type.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+// Exceptions used in sfntly
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_
+
+#if !defined (SFNTLY_NO_EXCEPTION)
+
+#include <exception>
+#include <string>
+#include <sstream>
+
+namespace sfntly {
+
+class Exception : public std::exception {
+ public:
+  Exception() : what_("Unknown exception") {}
+  explicit Exception(const char* message) throw() { SetMessage(message); }
+  virtual ~Exception() throw() {}
+  virtual const char* what() const throw() { return what_.c_str(); }
+
+ protected:
+  void SetMessage(const char* message) throw() {
+    try {
+      what_ = message;
+    } catch (...) {}
+  }
+
+ private:
+  std::string what_;
+};
+
+class IndexOutOfBoundException : public Exception {
+ public:
+  IndexOutOfBoundException() throw() : Exception("Index out of bound") {}
+  explicit IndexOutOfBoundException(const char* message) throw()
+      : Exception(message) {}
+  IndexOutOfBoundException(const char* message, int32_t index) throw() {
+    try {
+      std::ostringstream msg;
+      msg << message;
+      msg << ":";
+      msg << index;
+      SetMessage(msg.str().c_str());
+    } catch (...) {}
+  }
+  virtual ~IndexOutOfBoundException() throw() {}
+};
+
+class IOException : public Exception {
+ public:
+  IOException() throw() : Exception("I/O exception") {}
+  explicit IOException(const char* message) throw() : Exception(message) {}
+  virtual ~IOException() throw() {}
+};
+
+class ArithmeticException : public Exception {
+ public:
+  ArithmeticException() throw() : Exception("Arithmetic exception") {}
+  explicit ArithmeticException(const char* message) throw()
+      : Exception(message) {}
+  virtual ~ArithmeticException() throw() {}
+};
+
+class UnsupportedOperationException : public Exception {
+ public:
+  UnsupportedOperationException() throw() :
+      Exception("Operation not supported") {}
+  explicit UnsupportedOperationException(const char* message) throw()
+      : Exception(message) {}
+  virtual ~UnsupportedOperationException() throw() {}
+};
+
+class RuntimeException : public Exception {
+ public:
+  RuntimeException() throw() : Exception("Runtime exception") {}
+  explicit RuntimeException(const char* message) throw()
+      : Exception(message) {}
+  virtual ~RuntimeException() throw() {}
+};
+
+class NoSuchElementException : public Exception {
+ public:
+  NoSuchElementException() throw() : Exception("No such element") {}
+  explicit NoSuchElementException(const char* message) throw()
+      : Exception(message) {}
+  virtual ~NoSuchElementException() throw() {}
+};
+
+class IllegalArgumentException : public Exception {
+ public:
+  IllegalArgumentException() throw() : Exception("Illegal argument") {}
+  explicit IllegalArgumentException(const char* message) throw()
+      : Exception(message) {}
+  virtual ~IllegalArgumentException() throw() {}
+};
+
+class IllegalStateException : public Exception {
+ public:
+  IllegalStateException() throw() : Exception("Illegal state") {}
+  explicit IllegalStateException(const char* message) throw()
+      : Exception(message) {}
+  virtual ~IllegalStateException() throw() {}
+};
+
+}  // namespace sfntly
+
+#endif  // #if !defined (SFNTLY_NO_EXCEPTION)
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_
diff --git a/sfntly/port/file_input_stream.cc b/sfntly/port/file_input_stream.cc
new file mode 100644
index 0000000..dfe9a7b
--- /dev/null
+++ b/sfntly/port/file_input_stream.cc
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+#if defined (WIN32)
+#include <windows.h>
+#endif
+
+#include <algorithm>
+
+#include "sfntly/port/file_input_stream.h"
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+
+FileInputStream::FileInputStream()
+    : file_(NULL),
+      position_(0),
+      length_(0) {
+}
+
+FileInputStream::~FileInputStream() {
+  Close();
+}
+
+int32_t FileInputStream::Available() {
+  return length_ - position_;
+}
+
+void FileInputStream::Close() {
+  if (file_) {
+    fclose(file_);
+    length_ = 0;
+    position_ = 0;
+    file_ = NULL;
+  }
+}
+
+void FileInputStream::Mark(int32_t readlimit) {
+  // NOP
+  UNREFERENCED_PARAMETER(readlimit);
+}
+
+bool FileInputStream::MarkSupported() {
+  return false;
+}
+
+int32_t FileInputStream::Read() {
+  if (!file_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no opened file");
+#endif
+    return 0;
+  }
+  if (feof(file_)) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("eof reached");
+#endif
+    return 0;
+  }
+  byte_t value;
+  size_t length = fread(&value, 1, 1, file_);
+  position_ += length;
+  return value;
+}
+
+int32_t FileInputStream::Read(ByteVector* b) {
+  return Read(b, 0, b->size());
+}
+
+int32_t FileInputStream::Read(ByteVector* b, int32_t offset, int32_t length) {
+  assert(b);
+  if (!file_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no opened file");
+#endif
+    return 0;
+  }
+  if (feof(file_)) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("eof reached");
+#endif
+    return 0;
+  }
+  size_t read_count = std::min<size_t>(length_ - position_, length);
+  if (b->size() < (size_t)(offset + read_count)) {
+    b->resize((size_t)(offset + read_count));
+  }
+  int32_t actual_read = fread(&((*b)[offset]), 1, read_count, file_);
+  position_ += actual_read;
+  return actual_read;
+}
+
+void FileInputStream::Reset() {
+  // NOP
+}
+
+int64_t FileInputStream::Skip(int64_t n) {
+  if (!file_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no opened file");
+#endif
+    return 0;
+  }
+  int64_t skip_count = 0;
+  if (n < 0) {  // move backwards
+    skip_count = std::max<int64_t>(0 - (int64_t)position_, n);
+    position_ -= (size_t)(0 - skip_count);
+    fseek(file_, position_, SEEK_SET);
+  } else {
+    skip_count = std::min<size_t>(length_ - position_, (size_t)n);
+    position_ += (size_t)skip_count;
+    fseek(file_, (size_t)skip_count, SEEK_CUR);
+  }
+  return skip_count;
+}
+
+void FileInputStream::Unread(ByteVector* b) {
+  Unread(b, 0, b->size());
+}
+
+void FileInputStream::Unread(ByteVector* b, int32_t offset, int32_t length) {
+  assert(b);
+  assert(b->size() >= size_t(offset + length));
+  if (!file_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no opened file");
+#endif
+    return;
+  }
+  size_t unread_count = std::min<size_t>(position_, length);
+  fseek(file_, position_ - unread_count, SEEK_SET);
+  position_ -= unread_count;
+  Read(b, offset, length);
+  fseek(file_, position_ - unread_count, SEEK_SET);
+  position_ -= unread_count;
+}
+
+bool FileInputStream::Open(const char* file_path) {
+  assert(file_path);
+  if (file_) {
+    Close();
+  }
+#if defined (WIN32)
+  fopen_s(&file_, file_path, "rb");
+#else
+  file_ = fopen(file_path, "rb");
+#endif
+  if (file_ == NULL) {
+    return false;
+  }
+
+  fseek(file_, 0, SEEK_END);
+  length_ = ftell(file_);
+  fseek(file_, 0, SEEK_SET);
+  return true;
+}
+
+}  // namespace sfntly
diff --git a/sfntly/port/file_input_stream.h b/sfntly/port/file_input_stream.h
new file mode 100644
index 0000000..cbca25f
--- /dev/null
+++ b/sfntly/port/file_input_stream.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_
+
+#include <stdio.h>
+
+#include "sfntly/port/input_stream.h"
+
+namespace sfntly {
+
+class FileInputStream : public PushbackInputStream {
+ public:
+  FileInputStream();
+  virtual ~FileInputStream();
+
+  // InputStream methods
+  virtual int32_t Available();
+  virtual void Close();
+  virtual void Mark(int32_t readlimit);
+  virtual bool MarkSupported();
+  virtual int32_t Read();
+  virtual int32_t Read(ByteVector* b);
+  virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length);
+  virtual void Reset();
+  virtual int64_t Skip(int64_t n);
+
+  // PushbackInputStream methods
+  virtual void Unread(ByteVector* b);
+  virtual void Unread(ByteVector* b, int32_t offset, int32_t length);
+
+  // Own methods
+  virtual bool Open(const char* file_path);
+
+ private:
+  FILE* file_;
+  size_t position_;
+  size_t length_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_
diff --git a/sfntly/port/input_stream.h b/sfntly/port/input_stream.h
new file mode 100644
index 0000000..5d24036
--- /dev/null
+++ b/sfntly/port/input_stream.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+// C++ equivalent to Java's OutputStream class
+class InputStream {
+ public:
+  // Make gcc -Wnon-virtual-dtor happy.
+  virtual ~InputStream() {}
+
+  virtual int32_t Available() = 0;
+  virtual void Close() = 0;
+  virtual void Mark(int32_t readlimit) = 0;
+  virtual bool MarkSupported() = 0;
+  virtual int32_t Read() = 0;
+  virtual int32_t Read(ByteVector* b) = 0;
+  virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length) = 0;
+  virtual void Reset() = 0;
+  virtual int64_t Skip(int64_t n) = 0;
+};
+
+class PushbackInputStream : public InputStream {
+ public:
+  virtual void Unread(ByteVector* b) = 0;
+  virtual void Unread(ByteVector* b, int32_t offset, int32_t length) = 0;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_
diff --git a/sfntly/port/java_iterator.h b/sfntly/port/java_iterator.h
new file mode 100644
index 0000000..0a99bca
--- /dev/null
+++ b/sfntly/port/java_iterator.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_
+
+#include "sfntly/port/refcount.h"
+
+// Interface of Java iterator.
+// This is a forward read-only iterator that represents java.util.Iterator<E>
+
+namespace sfntly {
+
+template <typename ReturnType, typename ContainerBase>
+class Iterator : public virtual RefCount {
+ public:
+  virtual ~Iterator() {}
+  virtual ContainerBase* container_base() = 0;
+
+ protected:
+  Iterator() {}
+  NO_COPY_AND_ASSIGN(Iterator);
+};
+
+template <typename ReturnType, typename Container,
+          typename ContainerBase = Container>
+class PODIterator : public Iterator<ReturnType, ContainerBase>,
+                    public RefCounted< PODIterator<ReturnType, Container> > {
+ public:
+  explicit PODIterator(Container* container) : container_(container) {}
+  virtual ~PODIterator() {}
+  virtual ContainerBase* container_base() {
+    return static_cast<ContainerBase*>(container_);
+  }
+
+  virtual bool HasNext() = 0;
+  virtual ReturnType Next() = 0;
+  virtual void Remove() {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    // Default to no support.
+    throw UnsupportedOperationException();
+#endif
+  }
+
+ protected:
+  Container* container() { return container_; }
+
+ private:
+  Container* container_;  // Dumb pointer is used to avoid circular ref-counting
+};
+
+template <typename ReturnType, typename Container,
+          typename ContainerBase = Container>
+class RefIterator : public Iterator<ReturnType, ContainerBase>,
+                    public RefCounted< RefIterator<ReturnType, Container> > {
+ public:
+  explicit RefIterator(Container* container) : container_(container) {}
+  virtual ~RefIterator() {}
+  virtual ContainerBase* container_base() {
+    return static_cast<ContainerBase*>(container_);
+  }
+
+  virtual bool HasNext() = 0;
+  CALLER_ATTACH virtual ReturnType* Next() = 0;
+  virtual void Remove() {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    // Default to no support.
+    throw UnsupportedOperationException();
+#endif
+  }
+
+ protected:
+  Container* container() { return container_; }
+
+ private:
+  Container* container_;  // Dumb pointer is used to avoid circular ref-counting
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_
diff --git a/sfntly/port/lock.cc b/sfntly/port/lock.cc
new file mode 100644
index 0000000..6c0c309
--- /dev/null
+++ b/sfntly/port/lock.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/port/lock.h"
+
+namespace sfntly {
+
+#if defined (WIN32)
+
+Lock::Lock() {
+  // The second parameter is the spin count, for short-held locks it avoid the
+  // contending thread from going to sleep which helps performance greatly.
+  ::InitializeCriticalSectionAndSpinCount(&os_lock_, 2000);
+}
+
+Lock::~Lock() {
+  ::DeleteCriticalSection(&os_lock_);
+}
+
+bool Lock::Try() {
+  if (::TryEnterCriticalSection(&os_lock_) != FALSE) {
+    return true;
+  }
+  return false;
+}
+
+void Lock::Acquire() {
+  ::EnterCriticalSection(&os_lock_);
+}
+
+void Lock::Unlock() {
+  ::LeaveCriticalSection(&os_lock_);
+}
+
+#else  // We assume it's pthread
+
+Lock::Lock() {
+  pthread_mutex_init(&os_lock_, NULL);
+}
+
+Lock::~Lock() {
+  pthread_mutex_destroy(&os_lock_);
+}
+
+bool Lock::Try() {
+  return (pthread_mutex_trylock(&os_lock_) == 0);
+}
+
+void Lock::Acquire() {
+  pthread_mutex_lock(&os_lock_);
+}
+
+void Lock::Unlock() {
+  pthread_mutex_unlock(&os_lock_);
+}
+
+#endif
+
+}  // namespace sfntly
diff --git a/sfntly/port/lock.h b/sfntly/port/lock.h
new file mode 100644
index 0000000..b2e29bf
--- /dev/null
+++ b/sfntly/port/lock.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_
+
+#if defined (WIN32)
+#include <windows.h>
+#else  // Assume pthread.
+#include <pthread.h>
+#include <errno.h>
+#endif
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+#if defined (WIN32)
+  typedef CRITICAL_SECTION OSLockType;
+#else  // Assume pthread.
+  typedef pthread_mutex_t OSLockType;
+#endif
+
+class Lock {
+ public:
+  Lock();
+  ~Lock();
+
+  // If the lock is not held, take it and return true.  If the lock is already
+  // held by something else, immediately return false.
+  bool Try();
+
+  // Take the lock, blocking until it is available if necessary.
+  void Acquire();
+
+  // Release the lock.  This must only be called by the lock's holder: after
+  // a successful call to Try, or a call to Lock.
+  void Unlock();
+
+ private:
+  OSLockType os_lock_;
+  NO_COPY_AND_ASSIGN(Lock);
+};
+
+// A helper class that acquires the given Lock while the AutoLock is in scope.
+class AutoLock {
+ public:
+  explicit AutoLock(Lock& lock) : lock_(lock) {
+    lock_.Acquire();
+  }
+
+  ~AutoLock() {
+    lock_.Unlock();
+  }
+
+ private:
+  Lock& lock_;
+  NO_COPY_AND_ASSIGN(AutoLock);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_
diff --git a/sfntly/port/memory_input_stream.cc b/sfntly/port/memory_input_stream.cc
new file mode 100755
index 0000000..f6f2b9b
--- /dev/null
+++ b/sfntly/port/memory_input_stream.cc
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+#if defined (WIN32)
+#include <windows.h>
+#endif
+
+#include <string.h>
+
+#include <algorithm>
+
+#include "sfntly/port/memory_input_stream.h"
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+
+MemoryInputStream::MemoryInputStream()
+    : buffer_(NULL),
+      position_(0),
+      length_(0) {
+}
+
+MemoryInputStream::~MemoryInputStream() {
+  Close();
+}
+
+int32_t MemoryInputStream::Available() {
+  return length_ - position_;
+}
+
+void MemoryInputStream::Close() {
+}
+
+void MemoryInputStream::Mark(int32_t readlimit) {
+  // NOP
+  UNREFERENCED_PARAMETER(readlimit);
+}
+
+bool MemoryInputStream::MarkSupported() {
+  return false;
+}
+
+int32_t MemoryInputStream::Read() {
+  if (!buffer_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no memory attached");
+#endif
+    return 0;
+  }
+  if (position_ >= length_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("eof reached");
+#endif
+    return 0;
+  }
+  byte_t value = buffer_[position_++];
+  return value;
+}
+
+int32_t MemoryInputStream::Read(ByteVector* b) {
+  return Read(b, 0, b->size());
+}
+
+int32_t MemoryInputStream::Read(ByteVector* b, int32_t offset, int32_t length) {
+  assert(b);
+  if (!buffer_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no memory attached");
+#endif
+    return 0;
+  }
+  if (position_ >= length_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("eof reached");
+#endif
+    return 0;
+  }
+  size_t read_count = std::min<size_t>(length_ - position_, length);
+  if (b->size() < (size_t)(offset + read_count)) {
+    b->resize((size_t)(offset + read_count));
+  }
+  memcpy(&((*b)[offset]), buffer_ + position_, read_count);
+  position_ += read_count;
+  return read_count;
+}
+
+void MemoryInputStream::Reset() {
+  // NOP
+}
+
+int64_t MemoryInputStream::Skip(int64_t n) {
+  if (!buffer_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no memory attached");
+#endif
+    return 0;
+  }
+  int64_t skip_count = 0;
+  if (n < 0) {  // move backwards
+    skip_count = std::max<int64_t>(0 - (int64_t)position_, n);
+    position_ -= (size_t)(0 - skip_count);
+  } else {
+    skip_count = std::min<size_t>(length_ - position_, (size_t)n);
+    position_ += (size_t)skip_count;
+  }
+  return skip_count;
+}
+
+void MemoryInputStream::Unread(ByteVector* b) {
+  Unread(b, 0, b->size());
+}
+
+void MemoryInputStream::Unread(ByteVector* b, int32_t offset, int32_t length) {
+  assert(b);
+  assert(b->size() >= size_t(offset + length));
+  if (!buffer_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no memory attached");
+#endif
+    return;
+  }
+  size_t unread_count = std::min<size_t>(position_, length);
+  position_ -= unread_count;
+  Read(b, offset, length);
+  position_ -= unread_count;
+}
+
+bool MemoryInputStream::Attach(const byte_t* buffer, size_t length) {
+  assert(buffer);
+  assert(length);
+  buffer_ = buffer;
+  length_ = length;
+  return true;
+}
+
+}  // namespace sfntly
diff --git a/sfntly/port/memory_input_stream.h b/sfntly/port/memory_input_stream.h
new file mode 100755
index 0000000..bc861c3
--- /dev/null
+++ b/sfntly/port/memory_input_stream.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_
+
+#include <stdio.h>
+
+#include "sfntly/port/input_stream.h"
+
+namespace sfntly {
+
+class MemoryInputStream : public PushbackInputStream {
+ public:
+  MemoryInputStream();
+  virtual ~MemoryInputStream();
+
+  // InputStream methods
+  virtual int32_t Available();
+  virtual void Close();
+  virtual void Mark(int32_t readlimit);
+  virtual bool MarkSupported();
+  virtual int32_t Read();
+  virtual int32_t Read(ByteVector* b);
+  virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length);
+  virtual void Reset();
+  virtual int64_t Skip(int64_t n);
+
+  // PushbackInputStream methods
+  virtual void Unread(ByteVector* b);
+  virtual void Unread(ByteVector* b, int32_t offset, int32_t length);
+
+  // Own methods
+  virtual bool Attach(const byte_t* buffer, size_t length);
+
+ private:
+  const byte_t* buffer_;
+  size_t position_;
+  size_t length_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_
diff --git a/sfntly/port/memory_output_stream.cc b/sfntly/port/memory_output_stream.cc
new file mode 100644
index 0000000..f2ff2e3
--- /dev/null
+++ b/sfntly/port/memory_output_stream.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/port/memory_output_stream.h"
+
+namespace sfntly {
+
+MemoryOutputStream::MemoryOutputStream() {
+}
+
+MemoryOutputStream::~MemoryOutputStream() {
+}
+
+void MemoryOutputStream::Write(ByteVector* buffer) {
+  store_.insert(store_.end(), buffer->begin(), buffer->end());
+}
+
+void MemoryOutputStream::Write(ByteVector* buffer,
+                               int32_t offset,
+                               int32_t length) {
+  assert(buffer);
+  if (offset >= 0 && length > 0) {
+    store_.insert(store_.end(),
+                  buffer->begin() + offset,
+                  buffer->begin() + offset + length);
+  } else {
+#if !defined(SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException();
+#endif
+  }
+}
+
+void MemoryOutputStream::Write(byte_t* buffer, int32_t offset, int32_t length) {
+  assert(buffer);
+  if (offset >= 0 && length > 0) {
+    store_.insert(store_.end(), buffer + offset, buffer + offset + length);
+  } else {
+#if !defined(SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException();
+#endif
+  }
+}
+
+void MemoryOutputStream::Write(byte_t b) {
+  store_.push_back(b);
+}
+
+byte_t* MemoryOutputStream::Get() {
+  if (store_.empty()) {
+    return NULL;
+  }
+  return &(store_[0]);
+}
+
+size_t MemoryOutputStream::Size() {
+  return store_.size();
+}
+
+}  // namespace sfntly
diff --git a/sfntly/port/memory_output_stream.h b/sfntly/port/memory_output_stream.h
new file mode 100644
index 0000000..d1eda7f
--- /dev/null
+++ b/sfntly/port/memory_output_stream.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_
+
+#include <cstddef>
+#include <vector>
+
+#include "sfntly/port/type.h"
+#include "sfntly/port/output_stream.h"
+
+namespace sfntly {
+
+// OutputStream backed by STL vector
+
+class MemoryOutputStream : public OutputStream {
+ public:
+  MemoryOutputStream();
+  virtual ~MemoryOutputStream();
+
+  virtual void Close() {}  // no-op
+  virtual void Flush() {}  // no-op
+  virtual void Write(ByteVector* buffer);
+  virtual void Write(ByteVector* buffer, int32_t offset, int32_t length);
+  virtual void Write(byte_t* buffer, int32_t offset, int32_t length);
+  virtual void Write(byte_t b);
+
+  byte_t* Get();
+  size_t Size();
+
+ private:
+  std::vector<byte_t> store_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_
diff --git a/sfntly/port/output_stream.h b/sfntly/port/output_stream.h
new file mode 100644
index 0000000..64a6024
--- /dev/null
+++ b/sfntly/port/output_stream.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+// C++ equivalent to Java's OutputStream class
+class OutputStream {
+ public:
+  // Make gcc -Wnon-virtual-dtor happy.
+  virtual ~OutputStream() {}
+
+  virtual void Close() = 0;
+  virtual void Flush() = 0;
+  virtual void Write(ByteVector* buffer) = 0;
+  virtual void Write(byte_t b) = 0;
+
+  // Note: C++ port offered both versions of Write() here.  The first one is
+  //       better because it does check bounds.  The second one is there for
+  //       performance concerns.
+  virtual void Write(ByteVector* buffer, int32_t offset, int32_t length) = 0;
+
+  // Note: Caller is responsible for the boundary of buffer.
+  virtual void Write(byte_t* buffer, int32_t offset, int32_t length) = 0;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_
diff --git a/sfntly/port/refcount.h b/sfntly/port/refcount.h
new file mode 100644
index 0000000..eed5162
--- /dev/null
+++ b/sfntly/port/refcount.h
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+// Object reference count and smart pointer implementation.
+
+// Smart pointer usage in sfntly:
+//
+// sfntly carries a smart pointer implementation like COM.  Ref-countable object
+// type inherits from RefCounted<>, which have AddRef and Release just like
+// IUnknown (but no QueryInterface).  Use a Ptr<> based smart pointer to hold
+// the object so that the object ref count is handled correctly.
+//
+// class Foo : public RefCounted<Foo> {
+//  public:
+//   static Foo* CreateInstance() {
+//     Ptr<Foo> obj = new Foo();  // ref count = 1
+//     return obj.Detach();
+//   }
+// };
+// typedef Ptr<Foo> FooPtr;  // common short-hand notation
+// FooPtr obj;
+// obj.Attach(Foo::CreatedInstance());  // ref count = 1
+// {
+//   FooPtr obj2 = obj;  // ref count = 2
+// }  // ref count = 1, obj2 out of scope
+// obj.Release();  // ref count = 0, object destroyed
+
+// Notes on usage:
+// 1. Virtual inherit from RefCount interface in base class if smart pointers
+//    are going to be defined.
+// 2. All RefCounted objects must be instantiated on the heap.  Allocating the
+//    object on stack will cause crash.
+// 3. Be careful when you have complex inheritance.  For example,
+//    class A : public RefCounted<A>;
+//    class B : public A, public RefCounted<B>;
+//    In this case the smart pointer is pretty dumb and don't count on it to
+//    nicely destroy your objects as designed. Try refactor your code like
+//    class I;  // the common interface and implementations
+//    class A : public I, public RefCounted<A>;  // A specific implementation
+//    class B : public I, public RefCounted<B>;  // B specific implementation
+// 4. Smart pointers here are very bad candidates for function parameters.  Use
+//    dumb pointers in function parameter list.
+// 5. When down_cast is performed on a dangling pointer due to bugs in code,
+//    VC++ will generate SEH which is not handled well in VC++ debugger.  One
+//    can use WinDBG to run it and get the faulting stack.
+// 6. Idioms for heap object as return value
+//    Foo* createFoo() { FooPtr obj = new Foo(); return obj.Detach(); }
+//    Foo* passthru() { FooPtr obj = createFoo(), return obj; }
+//    FooPtr end_scope_pointer;
+//    end_scope_pointer.Attach(passThrough);
+//    If you are not passing that object back, you are the end of scope.
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_
+
+#if !defined (NDEBUG)
+  #define ENABLE_OBJECT_COUNTER
+//  #define REF_COUNT_DEBUGGING
+#endif
+
+#if defined (REF_COUNT_DEBUGGING)
+  #include <stdio.h>
+  #include <typeinfo>
+#endif
+
+#include "sfntly/port/atomic.h"
+#include "sfntly/port/type.h"
+
+// Special tag for functions that requires caller to attach instead of using
+// assignment operators.
+#define CALLER_ATTACH
+
+#if defined (REF_COUNT_DEBUGGING)
+  #define DEBUG_OUTPUT(a) \
+      fprintf(stderr, "%s%s:oc=%d,oid=%d,rc=%d\n", a, \
+              typeid(this).name(), object_counter_, object_id_, ref_count_)
+#else
+  #define DEBUG_OUTPUT(a)
+#endif
+
+#if defined (_MSC_VER)
+  // VC 2008/2010 incorrectly gives this warning for pure virtual functions
+  // in virtual inheritance.  The only way to get around it is to disable it.
+  #pragma warning(disable:4250)
+#endif
+
+namespace sfntly {
+
+class RefCount {
+ public:
+  // Make gcc -Wnon-virtual-dtor happy.
+  virtual ~RefCount() {}
+
+  virtual size_t AddRef() const = 0;
+  virtual size_t Release() const = 0;
+};
+
+template <typename T>
+class NoAddRefRelease : public T {
+ public:
+  NoAddRefRelease();
+  ~NoAddRefRelease();
+
+ private:
+  virtual size_t AddRef() const = 0;
+  virtual size_t Release() const = 0;
+};
+
+template <typename TDerived>
+class RefCounted : virtual public RefCount {
+ public:
+  RefCounted() : ref_count_(0) {
+#if defined (ENABLE_OBJECT_COUNTER)
+    object_id_ = AtomicIncrement(&next_id_);
+    AtomicIncrement(&object_counter_);
+    DEBUG_OUTPUT("C ");
+#endif
+  }
+  RefCounted(const RefCounted<TDerived>&) : ref_count_(0) {}
+  virtual ~RefCounted() {
+#if defined (ENABLE_OBJECT_COUNTER)
+    AtomicDecrement(&object_counter_);
+    DEBUG_OUTPUT("D ");
+#endif
+  }
+
+  RefCounted<TDerived>& operator=(const RefCounted<TDerived>&) {
+    // Each object maintains own ref count, don't propagate.
+    return *this;
+  }
+
+  virtual size_t AddRef() const {
+    size_t new_count = AtomicIncrement(&ref_count_);
+    DEBUG_OUTPUT("A ");
+    return new_count;
+  }
+
+  virtual size_t Release() const {
+    size_t new_ref_count = AtomicDecrement(&ref_count_);
+    DEBUG_OUTPUT("R ");
+    if (new_ref_count == 0) {
+      // A C-style is used to cast away const-ness and to derived.
+      // lint does not like this but this is how it works.
+      delete (TDerived*)(this);
+    }
+    return new_ref_count;
+  }
+
+  mutable size_t ref_count_;  // reference count of current object
+#if defined (ENABLE_OBJECT_COUNTER)
+  static size_t object_counter_;
+  static size_t next_id_;
+  mutable size_t object_id_;
+#endif
+};
+
+#if defined (ENABLE_OBJECT_COUNTER)
+template <typename TDerived> size_t RefCounted<TDerived>::object_counter_ = 0;
+template <typename TDerived> size_t RefCounted<TDerived>::next_id_ = 0;
+#endif
+
+// semi-smart pointer for RefCount derived objects, similar to CComPtr
+template <typename T>
+class Ptr {
+ public:
+  Ptr() : p_(NULL) {
+  }
+
+  // This constructor shall not be explicit.
+  // lint does not like this but this is how it works.
+  Ptr(T* pT) : p_(NULL) {
+    *this = pT;
+  }
+
+  Ptr(const Ptr<T>& p) : p_(NULL) {
+    *this = p;
+  }
+
+  ~Ptr() {
+    Release();
+  }
+
+  T* operator=(T* pT) {
+    if (p_ == pT) {
+      return p_;
+    }
+    if (pT) {
+      RefCount* p = static_cast<RefCount*>(pT);
+      if (p == NULL) {
+        return NULL;
+      }
+      p->AddRef();  // always AddRef() before Release()
+    }
+    Release();
+    p_ = pT;
+    return p_;
+  }
+
+  T* operator=(const Ptr<T>& p) {
+    if (p_ == p.p_) {
+      return p_;
+    }
+    return operator=(p.p_);
+  }
+
+  operator T*&() {
+    return p_;
+  }
+
+  T& operator*() const {
+    return *p_;  // It can throw!
+  }
+
+  NoAddRefRelease<T>* operator->() const {
+    return (NoAddRefRelease<T>*)p_;  // It can throw!
+  }
+
+  bool operator!() const {
+    return (p_ == NULL);
+  }
+
+  bool operator<(const Ptr<T>& p) const {
+    return (p_ < p.p_);
+  }
+
+  bool operator!=(T* pT) const {
+    return !operator==(pT);
+  }
+
+  bool operator==(T* pT) const {
+    return (p_ == pT);
+  }
+
+  size_t Release() const {
+    size_t ref_count = 0;
+    if (p_) {
+      RefCount* p = static_cast<RefCount*>(p_);
+      if (p) {
+        ref_count = p->Release();
+      }
+      p_ = NULL;
+    }
+    return ref_count;
+  }
+
+  void Attach(T* pT) {
+    if (p_ != pT) {
+      Release();
+      p_ = pT;
+    }
+  }
+
+  T* Detach() {
+    T* pT = p_;
+    p_ = NULL;
+    return pT;
+  }
+
+  mutable T* p_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_
diff --git a/sfntly/port/type.h b/sfntly/port/type.h
new file mode 100644
index 0000000..20a5ba8
--- /dev/null
+++ b/sfntly/port/type.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_
+
+#include <assert.h>
+
+#if defined (_MSC_VER) && (_MSC_VER < 1600)
+  typedef unsigned char     uint8_t;
+  typedef signed char       int8_t;
+  typedef unsigned __int16  uint16_t;
+  typedef signed __int16    int16_t;
+  typedef unsigned __int32  uint32_t;
+  typedef signed __int32    int32_t;
+  typedef unsigned __int64  uint64_t;
+  typedef signed __int64    int64_t;
+  // Definitions to avoid ICU redefinition issue
+  #define U_HAVE_INT8_T 1
+  #define U_HAVE_UINT8_T 1
+  #define U_HAVE_INT16_T 1
+  #define U_HAVE_UINT16_T 1
+  #define U_HAVE_INT32_T 1
+  #define U_HAVE_UINT32_T 1
+  #define U_HAVE_INT64_T 1
+  #define U_HAVE_UINT64_T 1
+#else
+  #include <stdint.h>
+#endif
+
+#include <cstddef>
+#include <vector>
+#include <set>
+
+namespace sfntly {
+
+typedef uint8_t   byte_t;
+typedef uint16_t  word_t;
+typedef uint32_t  dword_t;
+typedef uint64_t  qword_t;
+
+typedef std::vector<byte_t> ByteVector;
+typedef std::vector<int32_t> IntegerList;
+typedef std::set<int32_t> IntegerSet;
+
+// A macro to disallow the copy constructor and operator= functions.
+// This should be used in the private: declarations for a class.
+#define NO_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&);               \
+  void operator=(const TypeName&)
+
+}  // namespace sfntly
+
+// Make google3 happy since it prohibits RTTI.
+template<typename To, typename From>
+inline To implicit_cast(From const &f) {
+  return f;
+}
+
+template<typename To, typename From>     // use like this: down_cast<T*>(foo);
+inline To down_cast(From* f) {                   // so we only accept pointers
+  // Ensures that To is a sub-type of From *.  This test is here only
+  // for compile-time type checking, and has no overhead in an
+  // optimized build at run-time, as it will be optimized away
+  // completely.
+#if defined (_MSC_VER)
+  #pragma warning(push)
+  #pragma warning(disable:4127)  // disable "conditional expression is constant"
+#endif
+  if (false) {
+    implicit_cast<From*, To>(0);
+  }
+#if defined (_MSC_VER)
+  #pragma warning(pop)
+#endif
+
+// The following code is the only place for RTTI.  It is done so to allow
+// additional type checking when SFNTLY_TYPE_VERIFICATION is defined.
+#if defined (SFNTLY_TYPE_VERIFICATION)
+  assert(f == NULL || dynamic_cast<To>(f) != NULL);
+#endif
+  return static_cast<To>(f);
+}
+
+#if !defined(WIN32)
+  #define UNREFERENCED_PARAMETER(p) do { (void)p; } while (0)
+#endif
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_
diff --git a/sfntly/table/bitmap/big_glyph_metrics.cc b/sfntly/table/bitmap/big_glyph_metrics.cc
new file mode 100644
index 0000000..d853212
--- /dev/null
+++ b/sfntly/table/bitmap/big_glyph_metrics.cc
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/big_glyph_metrics.h"
+
+namespace sfntly {
+/******************************************************************************
+ * BigGlyphMetrics class
+ ******************************************************************************/
+BigGlyphMetrics::BigGlyphMetrics(ReadableFontData* data)
+    : GlyphMetrics(data) {
+}
+
+BigGlyphMetrics::~BigGlyphMetrics() {
+}
+
+int32_t BigGlyphMetrics::Height() {
+  return data_->ReadByte(Offset::kHeight);
+}
+
+int32_t BigGlyphMetrics::Width() {
+  return data_->ReadByte(Offset::kWidth);
+}
+
+int32_t BigGlyphMetrics::HoriBearingX() {
+  return data_->ReadByte(Offset::kHoriBearingX);
+}
+
+int32_t BigGlyphMetrics::HoriBearingY() {
+  return data_->ReadByte(Offset::kHoriBearingY);
+}
+
+int32_t BigGlyphMetrics::HoriAdvance() {
+  return data_->ReadByte(Offset::kHoriAdvance);
+}
+
+int32_t BigGlyphMetrics::VertBearingX() {
+  return data_->ReadByte(Offset::kVertBearingX);
+}
+
+int32_t BigGlyphMetrics::VertBearingY() {
+  return data_->ReadByte(Offset::kVertBearingY);
+}
+
+int32_t BigGlyphMetrics::VertAdvance() {
+  return data_->ReadByte(Offset::kVertAdvance);
+}
+
+/******************************************************************************
+ * BigGlyphMetrics::Builder class
+ ******************************************************************************/
+BigGlyphMetrics::Builder::Builder(WritableFontData* data)
+    : GlyphMetrics::Builder(data) {
+}
+
+BigGlyphMetrics::Builder::Builder(ReadableFontData* data)
+    : GlyphMetrics::Builder(data) {
+}
+
+BigGlyphMetrics::Builder::~Builder() {
+}
+
+int32_t BigGlyphMetrics::Builder::Height() {
+  return InternalReadData()->ReadByte(Offset::kHeight);
+}
+
+void BigGlyphMetrics::Builder::SetHeight(byte_t height) {
+  InternalWriteData()->WriteByte(Offset::kHeight, height);
+}
+
+int32_t BigGlyphMetrics::Builder::Width() {
+  return InternalReadData()->ReadByte(Offset::kWidth);
+}
+
+void BigGlyphMetrics::Builder::SetWidth(byte_t width) {
+  InternalWriteData()->WriteByte(Offset::kWidth, width);
+}
+
+int32_t BigGlyphMetrics::Builder::HoriBearingX() {
+  return InternalReadData()->ReadByte(Offset::kHoriBearingX);
+}
+
+void BigGlyphMetrics::Builder::SetHoriBearingX(byte_t bearing) {
+  InternalWriteData()->WriteByte(Offset::kHoriBearingX, bearing);
+}
+
+int32_t BigGlyphMetrics::Builder::HoriBearingY() {
+  return InternalReadData()->ReadByte(Offset::kHoriBearingY);
+}
+
+void BigGlyphMetrics::Builder::SetHoriBearingY(byte_t bearing) {
+  InternalWriteData()->WriteByte(Offset::kHoriBearingY, bearing);
+}
+
+int32_t BigGlyphMetrics::Builder::HoriAdvance() {
+  return InternalReadData()->ReadByte(Offset::kHoriAdvance);
+}
+
+void BigGlyphMetrics::Builder::SetHoriAdvance(byte_t advance) {
+  InternalWriteData()->WriteByte(Offset::kHoriAdvance, advance);
+}
+
+int32_t BigGlyphMetrics::Builder::VertBearingX() {
+  return InternalReadData()->ReadByte(Offset::kVertBearingX);
+}
+
+void BigGlyphMetrics::Builder::SetVertBearingX(byte_t bearing) {
+  InternalWriteData()->WriteByte(Offset::kVertBearingX, bearing);
+}
+
+int32_t BigGlyphMetrics::Builder::VertBearingY() {
+  return InternalReadData()->ReadByte(Offset::kVertBearingY);
+}
+
+void BigGlyphMetrics::Builder::SetVertBearingY(byte_t bearing) {
+  InternalWriteData()->WriteByte(Offset::kVertBearingY, bearing);
+}
+
+int32_t BigGlyphMetrics::Builder::VertAdvance() {
+  return InternalReadData()->ReadByte(Offset::kVertAdvance);
+}
+
+void BigGlyphMetrics::Builder::SetVertAdvance(byte_t advance) {
+  InternalWriteData()->WriteByte(Offset::kVertAdvance, advance);
+}
+
+CALLER_ATTACH FontDataTable*
+    BigGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) {
+  BigGlyphMetricsPtr output = new BigGlyphMetrics(data);
+  return output.Detach();
+}
+
+void BigGlyphMetrics::Builder::SubDataSet() {
+  // NOP.
+}
+
+int32_t BigGlyphMetrics::Builder::SubDataSizeToSerialize() {
+  return 0;
+}
+
+bool BigGlyphMetrics::Builder::SubReadyToSerialize() {
+  return false;
+}
+
+int32_t BigGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) {
+  return Data()->CopyTo(new_data);
+}
+
+// static
+CALLER_ATTACH
+BigGlyphMetrics::Builder* BigGlyphMetrics::Builder::CreateBuilder() {
+  WritableFontDataPtr data;
+  data.Attach(WritableFontData::CreateWritableFontData(Offset::kMetricsLength));
+  BigGlyphMetricsBuilderPtr output = new BigGlyphMetrics::Builder(data);
+  return output.Detach();
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/big_glyph_metrics.h b/sfntly/table/bitmap/big_glyph_metrics.h
new file mode 100644
index 0000000..a91601c
--- /dev/null
+++ b/sfntly/table/bitmap/big_glyph_metrics.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_
+
+#include "sfntly/table/bitmap/glyph_metrics.h"
+
+namespace sfntly {
+
+class BigGlyphMetrics : public GlyphMetrics,
+                        public RefCounted<BigGlyphMetrics> {
+ public:
+  struct Offset {
+    enum {
+      kMetricsLength = 8,
+
+      kHeight = 0,
+      kWidth = 1,
+      kHoriBearingX = 2,
+      kHoriBearingY = 3,
+      kHoriAdvance = 4,
+      kVertBearingX = 5,
+      kVertBearingY = 6,
+      kVertAdvance = 7,
+    };
+  };
+
+  class Builder : public GlyphMetrics::Builder,
+                  public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    explicit Builder(WritableFontData* data);
+    explicit Builder(ReadableFontData* data);
+
+    virtual ~Builder();
+
+    int32_t Height();
+    void SetHeight(byte_t height);
+    int32_t Width();
+    void SetWidth(byte_t width);
+    int32_t HoriBearingX();
+    void SetHoriBearingX(byte_t bearing);
+    int32_t HoriBearingY();
+    void SetHoriBearingY(byte_t bearing);
+    int32_t HoriAdvance();
+    void SetHoriAdvance(byte_t advance);
+    int32_t VertBearingX();
+    void SetVertBearingX(byte_t bearing);
+    int32_t VertBearingY();
+    void SetVertBearingY(byte_t bearing);
+    int32_t VertAdvance();
+    void SetVertAdvance(byte_t advance);
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    // Static instantiation function.
+    static CALLER_ATTACH Builder* CreateBuilder();
+  };
+
+  explicit BigGlyphMetrics(ReadableFontData* data);
+  virtual ~BigGlyphMetrics();
+
+  int32_t Height();
+  int32_t Width();
+  int32_t HoriBearingX();
+  int32_t HoriBearingY();
+  int32_t HoriAdvance();
+  int32_t VertBearingX();
+  int32_t VertBearingY();
+  int32_t VertAdvance();
+};
+typedef Ptr<BigGlyphMetrics> BigGlyphMetricsPtr;
+typedef Ptr<BigGlyphMetrics::Builder> BigGlyphMetricsBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_
diff --git a/sfntly/table/bitmap/bitmap_glyph.cc b/sfntly/table/bitmap/bitmap_glyph.cc
new file mode 100644
index 0000000..334a0c0
--- /dev/null
+++ b/sfntly/table/bitmap/bitmap_glyph.cc
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/bitmap_glyph.h"
+#include "sfntly/table/bitmap/simple_bitmap_glyph.h"
+#include "sfntly/table/bitmap/composite_bitmap_glyph.h"
+
+namespace sfntly {
+/******************************************************************************
+ * BitmapGlyph class
+ ******************************************************************************/
+BitmapGlyph::~BitmapGlyph() {
+}
+
+CALLER_ATTACH BitmapGlyph* BitmapGlyph::CreateGlyph(ReadableFontData* data,
+                                                    int32_t format) {
+  BitmapGlyphPtr glyph;
+  BitmapGlyphBuilderPtr builder;
+  builder.Attach(Builder::CreateGlyphBuilder(data, format));
+  if (builder) {
+    glyph.Attach(down_cast<BitmapGlyph*>(builder->Build()));
+  }
+  return glyph;
+}
+
+BitmapGlyph::BitmapGlyph(ReadableFontData* data, int32_t format)
+    : SubTable(data), format_(format) {
+}
+
+/******************************************************************************
+ * BitmapGlyph::Builder class
+ ******************************************************************************/
+BitmapGlyph::Builder::~Builder() {
+}
+
+CALLER_ATTACH BitmapGlyph::Builder*
+BitmapGlyph::Builder::CreateGlyphBuilder(ReadableFontData* data,
+                                         int32_t format) {
+  BitmapGlyphBuilderPtr builder;
+  switch (format) {
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+      builder = new SimpleBitmapGlyph::Builder(data, format);
+      break;
+    case 8:
+    case 9:
+      builder = new CompositeBitmapGlyph::Builder(data, format);
+      break;
+  }
+  return builder.Detach();
+}
+
+BitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format)
+    : SubTable::Builder(data), format_(format) {
+}
+
+BitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format)
+    : SubTable::Builder(data), format_(format) {
+}
+
+CALLER_ATTACH
+FontDataTable* BitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) {
+  UNREFERENCED_PARAMETER(data);
+  return NULL;
+}
+
+void BitmapGlyph::Builder::SubDataSet() {
+  // NOP
+}
+
+int32_t BitmapGlyph::Builder::SubDataSizeToSerialize() {
+  return InternalReadData()->Length();
+}
+
+bool BitmapGlyph::Builder::SubReadyToSerialize() {
+  return true;
+}
+
+int32_t BitmapGlyph::Builder::SubSerialize(WritableFontData* new_data) {
+  return InternalReadData()->CopyTo(new_data);
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/bitmap_glyph.h b/sfntly/table/bitmap/bitmap_glyph.h
new file mode 100644
index 0000000..2dd4c3a
--- /dev/null
+++ b/sfntly/table/bitmap/bitmap_glyph.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_
+
+#include <vector>
+#include <map>
+
+#include "sfntly/table/subtable.h"
+
+namespace sfntly {
+
+class BitmapGlyph : public SubTable {
+ public:
+  struct Offset {
+    enum {
+      // header
+      kVersion = 0,
+
+      kSmallGlyphMetricsLength = 5,
+      kBigGlyphMetricsLength = 8,
+      // format 1
+      kGlyphFormat1_imageData = kSmallGlyphMetricsLength,
+
+      // format 2
+      kGlyphFormat2_imageData = kSmallGlyphMetricsLength,
+
+      // format 3
+
+      // format 4
+
+      // format 5
+      kGlyphFormat5_imageData = 0,
+
+      // format 6
+      kGlyphFormat6_imageData = kBigGlyphMetricsLength,
+
+      // format 7
+      kGlyphFormat7_imageData = kBigGlyphMetricsLength,
+
+      // format 8
+      kGlyphFormat8_numComponents = kSmallGlyphMetricsLength + 1,
+      kGlyphFormat8_componentArray = kGlyphFormat8_numComponents +
+                                     DataSize::kUSHORT,
+
+      // format 9
+      kGlyphFormat9_numComponents = kBigGlyphMetricsLength,
+      kGlyphFormat9_componentArray = kGlyphFormat9_numComponents +
+                                     DataSize::kUSHORT,
+
+      // ebdtComponent
+      kEbdtComponentLength = DataSize::kUSHORT + 2 * DataSize::kCHAR,
+      kEbdtComponent_glyphCode = 0,
+      kEbdtComponent_xOffset = 2,
+      kEbdtComponent_yOffset = 3,
+    };
+  };
+
+  // TODO(stuartg): builder is not functional at all
+  // - need to add subclasses for each type of bitmap glyph
+  class Builder : public SubTable::Builder {
+   public:
+    virtual ~Builder();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    int32_t format() { return format_; }
+
+    static CALLER_ATTACH Builder* CreateGlyphBuilder(ReadableFontData* data,
+                                                     int32_t format);
+
+   protected:
+    Builder(WritableFontData* data, int32_t format);
+    Builder(ReadableFontData* data, int32_t format);
+
+   private:
+    int32_t format_;
+  };
+
+  virtual ~BitmapGlyph();
+
+  static CALLER_ATTACH BitmapGlyph* CreateGlyph(ReadableFontData* data,
+                                                int32_t format);
+  int32_t format() { return format_; }
+
+  // UNIMPLEMENTED: toString()
+
+ protected:
+  BitmapGlyph(ReadableFontData* data, int32_t format);
+
+ private:
+  int32_t format_;
+};
+typedef Ptr<BitmapGlyph> BitmapGlyphPtr;
+typedef Ptr<BitmapGlyph::Builder> BitmapGlyphBuilderPtr;
+typedef std::map<int32_t, BitmapGlyphBuilderPtr> BitmapGlyphBuilderMap;
+typedef std::vector<BitmapGlyphBuilderMap> BitmapGlyphBuilderList;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_
diff --git a/sfntly/table/bitmap/bitmap_glyph_info.cc b/sfntly/table/bitmap/bitmap_glyph_info.cc
new file mode 100644
index 0000000..ab9953b
--- /dev/null
+++ b/sfntly/table/bitmap/bitmap_glyph_info.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/bitmap_glyph_info.h"
+
+namespace sfntly {
+
+BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id,
+                                 int32_t block_offset,
+                                 int32_t start_offset,
+                                 int32_t length,
+                                 int32_t format)
+    : glyph_id_(glyph_id),
+      relative_(true),
+      block_offset_(block_offset),
+      start_offset_(start_offset),
+      length_(length),
+      format_(format) {
+}
+
+BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id,
+                                 int32_t start_offset,
+                                 int32_t length,
+                                 int32_t format)
+    : glyph_id_(glyph_id),
+      relative_(false),
+      block_offset_(0),
+      start_offset_(start_offset),
+      length_(length),
+      format_(format) {
+}
+
+bool BitmapGlyphInfo::operator==(const BitmapGlyphInfo& rhs) const {
+  return (format_ == rhs.format_ &&
+          glyph_id_ == rhs.glyph_id_ &&
+          length_ == rhs.length_ &&
+          offset() == rhs.offset());
+}
+
+bool BitmapGlyphInfo::operator==(BitmapGlyphInfo* rhs) {
+  if (rhs == NULL) {
+    return this == NULL;
+  }
+  return (format_ == rhs->format() &&
+          glyph_id_ == rhs->glyph_id() &&
+          length_ == rhs->length() &&
+          offset() == rhs->offset());
+}
+
+bool StartOffsetComparator::operator()(BitmapGlyphInfo* lhs,
+                                       BitmapGlyphInfo* rhs) {
+  return lhs->start_offset() > rhs->start_offset();
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/bitmap_glyph_info.h b/sfntly/table/bitmap/bitmap_glyph_info.h
new file mode 100644
index 0000000..9921d0d
--- /dev/null
+++ b/sfntly/table/bitmap/bitmap_glyph_info.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_
+
+#include <vector>
+#include <map>
+
+#include "sfntly/table/subtable.h"
+
+namespace sfntly {
+
+// An immutable class holding bitmap glyph information.
+class BitmapGlyphInfo : public RefCounted<BitmapGlyphInfo> {
+ public:
+  // Constructor for a relative located glyph. The glyph's position in the EBDT
+  // table is a combination of it's block offset and it's own start offset.
+  // @param glyphId the glyph id
+  // @param blockOffset the offset of the block to which the glyph belongs
+  // @param startOffset the offset of the glyph within the block
+  // @param length the byte length
+  // @param format the glyph image format
+  BitmapGlyphInfo(int32_t glyph_id,
+                  int32_t block_offset,
+                  int32_t start_offset,
+                  int32_t length,
+                  int32_t format);
+
+  // Constructor for an absolute located glyph. The glyph's position in the EBDT
+  // table is only given by it's own start offset.
+  // @param glyphId the glyph id
+  // @param startOffset the offset of the glyph within the block
+  // @param length the byte length
+  // @param format the glyph image format
+  BitmapGlyphInfo(int32_t glyph_id,
+                  int32_t start_offset,
+                  int32_t length,
+                  int32_t format);
+
+  int32_t glyph_id() const { return glyph_id_; }
+  bool relative() const { return relative_; }
+  int32_t block_offset() const { return block_offset_; }
+  int32_t offset() const { return block_offset() + start_offset(); }
+  int32_t start_offset() const { return start_offset_; }
+  int32_t length() const { return length_; }
+  int32_t format() const { return format_; }
+
+  // UNIMPLEMENTED: hashCode()
+  bool operator==(const BitmapGlyphInfo& rhs) const;
+  bool operator==(BitmapGlyphInfo* rhs);
+
+ private:
+  int32_t glyph_id_;
+  bool relative_;
+  int32_t block_offset_;
+  int32_t start_offset_;
+  int32_t length_;
+  int32_t format_;
+};
+typedef Ptr<BitmapGlyphInfo> BitmapGlyphInfoPtr;
+typedef std::map<int32_t, BitmapGlyphInfoPtr> BitmapGlyphInfoMap;
+typedef std::vector<BitmapGlyphInfoMap> BitmapLocaList;
+
+class StartOffsetComparator {
+ public:
+  bool operator()(BitmapGlyphInfo* lhs, BitmapGlyphInfo* rhs);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_
diff --git a/sfntly/table/bitmap/bitmap_size_table.cc b/sfntly/table/bitmap/bitmap_size_table.cc
new file mode 100644
index 0000000..6c7d731
--- /dev/null
+++ b/sfntly/table/bitmap/bitmap_size_table.cc
@@ -0,0 +1,604 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/bitmap_size_table.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sfntly/math/font_math.h"
+#include "sfntly/table/bitmap/eblc_table.h"
+#include "sfntly/table/bitmap/index_sub_table_format1.h"
+#include "sfntly/table/bitmap/index_sub_table_format2.h"
+#include "sfntly/table/bitmap/index_sub_table_format3.h"
+#include "sfntly/table/bitmap/index_sub_table_format4.h"
+#include "sfntly/table/bitmap/index_sub_table_format5.h"
+
+namespace sfntly {
+/******************************************************************************
+ * BitmapSizeTable class
+ ******************************************************************************/
+BitmapSizeTable::~BitmapSizeTable() {
+}
+
+int32_t BitmapSizeTable::IndexSubTableArrayOffset() {
+  return data_->ReadULongAsInt(
+      EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset);
+}
+
+int32_t BitmapSizeTable::IndexTableSize() {
+  return data_->ReadULongAsInt(
+      EblcTable::Offset::kBitmapSizeTable_indexTableSize);
+}
+
+int32_t BitmapSizeTable::NumberOfIndexSubTables() {
+  return NumberOfIndexSubTables(data_, 0);
+}
+
+int32_t BitmapSizeTable::ColorRef() {
+  return data_->ReadULongAsInt(EblcTable::Offset::kBitmapSizeTable_colorRef);
+}
+
+int32_t BitmapSizeTable::StartGlyphIndex() {
+  return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_startGlyphIndex);
+}
+
+int32_t BitmapSizeTable::EndGlyphIndex() {
+  return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_endGlyphIndex);
+}
+
+int32_t BitmapSizeTable::PpemX() {
+  return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemX);
+}
+
+int32_t BitmapSizeTable::PpemY() {
+  return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemY);
+}
+
+int32_t BitmapSizeTable::BitDepth() {
+  return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_bitDepth);
+}
+
+int32_t BitmapSizeTable::FlagsAsInt() {
+  return data_->ReadChar(EblcTable::Offset::kBitmapSizeTable_flags);
+}
+
+IndexSubTable* BitmapSizeTable::GetIndexSubTable(int32_t index) {
+  IndexSubTableList* subtable_list = GetIndexSubTableList();
+  if (index >= 0 && (size_t)index < subtable_list->size()) {
+    return (*subtable_list)[index];
+  }
+  return NULL;
+}
+
+int32_t BitmapSizeTable::GlyphOffset(int32_t glyph_id) {
+  IndexSubTable* subtable = SearchIndexSubTables(glyph_id);
+  if (subtable == NULL) {
+    return -1;
+  }
+  return subtable->GlyphOffset(glyph_id);
+}
+
+int32_t BitmapSizeTable::GlyphLength(int32_t glyph_id) {
+  IndexSubTable* subtable = SearchIndexSubTables(glyph_id);
+  if (subtable == NULL) {
+    return -1;
+  }
+  return subtable->GlyphLength(glyph_id);
+}
+
+CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::GlyphInfo(int32_t glyph_id) {
+  IndexSubTable* sub_table = SearchIndexSubTables(glyph_id);
+  if (sub_table == NULL) {
+    return NULL;
+  }
+  return sub_table->GlyphInfo(glyph_id);
+}
+
+int32_t BitmapSizeTable::GlyphFormat(int32_t glyph_id) {
+  IndexSubTable* subtable = SearchIndexSubTables(glyph_id);
+  if (subtable == NULL) {
+    return -1;
+  }
+  return subtable->image_format();
+}
+
+BitmapSizeTable::BitmapSizeTable(ReadableFontData* data,
+                                 ReadableFontData* master_data)
+    : SubTable(data, master_data) {
+}
+
+// static
+int32_t BitmapSizeTable::NumberOfIndexSubTables(ReadableFontData* data,
+                                                int32_t table_offset) {
+  return data->ReadULongAsInt(table_offset +
+      EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables);
+}
+
+IndexSubTable* BitmapSizeTable::SearchIndexSubTables(int32_t glyph_id) {
+  // would be faster to binary search but too many size tables don't have
+  // sorted subtables
+#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH)
+  return BinarySearchIndexSubTables(glyph_id);
+#else
+  return LinearSearchIndexSubTables(glyph_id);
+#endif
+}
+
+IndexSubTable* BitmapSizeTable::LinearSearchIndexSubTables(int32_t glyph_id) {
+  IndexSubTableList* subtable_list = GetIndexSubTableList();
+  for (IndexSubTableList::iterator b = subtable_list->begin(),
+                                   e = subtable_list->end(); b != e; b++) {
+    if ((*b)->first_glyph_index() <= glyph_id &&
+        (*b)->last_glyph_index() >= glyph_id) {
+      return *b;
+    }
+  }
+  return NULL;
+}
+
+IndexSubTable* BitmapSizeTable::BinarySearchIndexSubTables(int32_t glyph_id) {
+  IndexSubTableList* subtable_list = GetIndexSubTableList();
+  int32_t index = 0;
+  int32_t bottom = 0;
+  int32_t top = subtable_list->size();
+  while (top != bottom) {
+    index = (top + bottom) / 2;
+    IndexSubTable* subtable = (*subtable_list)[index];
+    if (glyph_id < subtable->first_glyph_index()) {
+      // Location beow current location
+      top = index;
+    } else {
+      if (glyph_id <= subtable->last_glyph_index()) {
+        return subtable;
+      } else {
+        bottom = index + 1;
+      }
+    }
+  }
+  return NULL;
+}
+
+CALLER_ATTACH
+IndexSubTable* BitmapSizeTable::CreateIndexSubTable(int32_t index) {
+  return IndexSubTable::CreateIndexSubTable(master_read_data(),
+                                            IndexSubTableArrayOffset(),
+                                            index);
+}
+
+IndexSubTableList* BitmapSizeTable::GetIndexSubTableList() {
+  AutoLock lock(index_subtables_lock_);
+  if (index_subtables_.empty()) {
+    for (int32_t i = 0; i < NumberOfIndexSubTables(); ++i) {
+      IndexSubTablePtr table;
+      table.Attach(CreateIndexSubTable(i));
+      index_subtables_.push_back(table);
+    }
+  }
+  return &index_subtables_;
+}
+
+/******************************************************************************
+ * BitmapSizeTable::Builder class
+ ******************************************************************************/
+BitmapSizeTable::Builder::~Builder() {
+}
+
+CALLER_ATTACH
+FontDataTable* BitmapSizeTable::Builder::SubBuildTable(ReadableFontData* data) {
+  BitmapSizeTablePtr output = new BitmapSizeTable(data, master_read_data());
+  return output.Detach();
+}
+
+void BitmapSizeTable::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t BitmapSizeTable::Builder::SubDataSizeToSerialize() {
+  IndexSubTableBuilderList* builders = IndexSubTableBuilders();
+  if (builders->empty()) {
+    return 0;
+  }
+  int32_t size = EblcTable::Offset::kBitmapSizeTableLength;
+  bool variable = false;
+  for (IndexSubTableBuilderList::iterator b = builders->begin(),
+                                          e = builders->end(); b != e; b++) {
+    size += EblcTable::Offset::kIndexSubTableEntryLength;
+    int32_t sub_table_size = (*b)->SubDataSizeToSerialize();
+    int32_t padding = FontMath::PaddingRequired(abs(sub_table_size),
+                                                DataSize::kULONG);
+#if defined (SFNTLY_DEBUG_BITMAP)
+    fprintf(stderr, "subtable size=%d\n", sub_table_size);
+#endif
+    variable = (sub_table_size > 0) ? variable : true;
+    size += abs(sub_table_size) + padding;
+  }
+#if defined (SFNTLY_DEBUG_BITMAP)
+  fprintf(stderr, "bitmap table size=%d\n", variable ? -size : size);
+#endif
+  return variable ? -size : size;
+}
+
+bool BitmapSizeTable::Builder::SubReadyToSerialize() {
+  if (IndexSubTableBuilders()->empty()) {
+    return false;
+  }
+  return true;
+}
+
+int32_t BitmapSizeTable::Builder::SubSerialize(WritableFontData* new_data) {
+  SetNumberOfIndexSubTables(IndexSubTableBuilders()->size());
+  int32_t size = InternalReadData()->CopyTo(new_data);
+  return size;
+}
+
+CALLER_ATTACH BitmapSizeTable::Builder*
+BitmapSizeTable::Builder::CreateBuilder(WritableFontData* data,
+                                        ReadableFontData* master_data) {
+  BitmapSizeTableBuilderPtr output =
+      new BitmapSizeTable::Builder(data, master_data);
+  return output.Detach();
+}
+
+CALLER_ATTACH BitmapSizeTable::Builder*
+BitmapSizeTable::Builder::CreateBuilder(ReadableFontData* data,
+                                        ReadableFontData* master_data) {
+  BitmapSizeTableBuilderPtr output =
+      new BitmapSizeTable::Builder(data, master_data);
+  return output.Detach();
+}
+
+int32_t BitmapSizeTable::Builder::IndexSubTableArrayOffset() {
+  return InternalReadData()->ReadULongAsInt(
+      EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset);
+}
+
+void BitmapSizeTable::Builder::SetIndexSubTableArrayOffset(int32_t offset) {
+  InternalWriteData()->WriteULong(
+      EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset, offset);
+}
+
+int32_t BitmapSizeTable::Builder::IndexTableSize() {
+  return InternalReadData()->ReadULongAsInt(
+      EblcTable::Offset::kBitmapSizeTable_indexTableSize);
+}
+
+void BitmapSizeTable::Builder::SetIndexTableSize(int32_t size) {
+  InternalWriteData()->WriteULong(
+      EblcTable::Offset::kBitmapSizeTable_indexTableSize, size);
+}
+
+int32_t BitmapSizeTable::Builder::NumberOfIndexSubTables() {
+  return GetIndexSubTableBuilders()->size();
+}
+
+int32_t BitmapSizeTable::Builder::ColorRef() {
+  return InternalReadData()->ReadULongAsInt(
+      EblcTable::Offset::kBitmapSizeTable_colorRef);
+}
+
+int32_t BitmapSizeTable::Builder::StartGlyphIndex() {
+  return InternalReadData()->ReadUShort(
+      EblcTable::Offset::kBitmapSizeTable_startGlyphIndex);
+}
+
+int32_t BitmapSizeTable::Builder::EndGlyphIndex() {
+  return InternalReadData()->ReadUShort(
+      EblcTable::Offset::kBitmapSizeTable_endGlyphIndex);
+}
+
+int32_t BitmapSizeTable::Builder::PpemX() {
+  return InternalReadData()->ReadByte(
+      EblcTable::Offset::kBitmapSizeTable_ppemX);
+}
+
+int32_t BitmapSizeTable::Builder::PpemY() {
+  return InternalReadData()->ReadByte(
+      EblcTable::Offset::kBitmapSizeTable_ppemY);
+}
+
+int32_t BitmapSizeTable::Builder::BitDepth() {
+  return InternalReadData()->ReadByte(
+      EblcTable::Offset::kBitmapSizeTable_bitDepth);
+}
+
+int32_t BitmapSizeTable::Builder::FlagsAsInt() {
+  return InternalReadData()->ReadChar(
+      EblcTable::Offset::kBitmapSizeTable_flags);
+}
+
+IndexSubTable::Builder* BitmapSizeTable::Builder::IndexSubTableBuilder(
+    int32_t index) {
+  IndexSubTableBuilderList* sub_table_list = GetIndexSubTableBuilders();
+  return sub_table_list->at(index);
+}
+
+CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::Builder::GlyphInfo(
+    int32_t glyph_id) {
+  IndexSubTable::Builder* sub_table = SearchIndexSubTables(glyph_id);
+  if (sub_table == NULL) {
+    return NULL;
+  }
+  return sub_table->GlyphInfo(glyph_id);
+}
+
+int32_t BitmapSizeTable::Builder::GlyphOffset(int32_t glyph_id) {
+  IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id);
+  if (subtable == NULL) {
+    return -1;
+  }
+  return subtable->GlyphOffset(glyph_id);
+}
+
+int32_t BitmapSizeTable::Builder::GlyphLength(int32_t glyph_id) {
+  IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id);
+  if (subtable == NULL) {
+    return -1;
+  }
+  return subtable->GlyphLength(glyph_id);
+}
+
+int32_t BitmapSizeTable::Builder::GlyphFormat(int32_t glyph_id) {
+  IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id);
+  if (subtable == NULL) {
+    return -1;
+  }
+  return subtable->image_format();
+}
+
+IndexSubTableBuilderList* BitmapSizeTable::Builder::IndexSubTableBuilders() {
+  return GetIndexSubTableBuilders();
+}
+
+CALLER_ATTACH BitmapSizeTable::Builder::BitmapGlyphInfoIterator*
+BitmapSizeTable::Builder::GetIterator() {
+  Ptr<BitmapSizeTable::Builder::BitmapGlyphInfoIterator> output =
+      new BitmapSizeTable::Builder::BitmapGlyphInfoIterator(this);
+  return output.Detach();
+}
+
+void BitmapSizeTable::Builder::GenerateLocaMap(BitmapGlyphInfoMap* output) {
+  assert(output);
+  Ptr<BitmapSizeTable::Builder::BitmapGlyphInfoIterator> it;
+  it.Attach(GetIterator());
+  while (it->HasNext()) {
+    BitmapGlyphInfoPtr info;
+    info.Attach(it->Next());
+    (*output)[info->glyph_id()] = info;
+  }
+}
+
+void BitmapSizeTable::Builder::Revert() {
+  index_sub_tables_.clear();
+  set_model_changed(false);
+}
+
+BitmapSizeTable::Builder::Builder(WritableFontData* data,
+                                  ReadableFontData* master_data)
+    : SubTable::Builder(data, master_data) {
+}
+
+BitmapSizeTable::Builder::Builder(ReadableFontData* data,
+                                  ReadableFontData* master_data)
+    : SubTable::Builder(data, master_data) {
+}
+
+void BitmapSizeTable::Builder::SetNumberOfIndexSubTables(int32_t count) {
+  InternalWriteData()->WriteULong(
+      EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables, count);
+}
+
+IndexSubTable::Builder* BitmapSizeTable::Builder::SearchIndexSubTables(
+    int32_t glyph_id) {
+  // would be faster to binary search but too many size tables don't have
+  // sorted subtables
+#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH)
+  return BinarySearchIndexSubTables(glyph_id);
+#else
+  return LinearSearchIndexSubTables(glyph_id);
+#endif
+}
+
+IndexSubTable::Builder* BitmapSizeTable::Builder::LinearSearchIndexSubTables(
+    int32_t glyph_id) {
+  IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders();
+  for (IndexSubTableBuilderList::iterator b = subtable_list->begin(),
+                                          e = subtable_list->end();
+                                          b != e; b++) {
+    if ((*b)->first_glyph_index() <= glyph_id &&
+        (*b)->last_glyph_index() >= glyph_id) {
+      return *b;
+    }
+  }
+  return NULL;
+}
+
+IndexSubTable::Builder* BitmapSizeTable::Builder::BinarySearchIndexSubTables(
+    int32_t glyph_id) {
+  IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders();
+  int32_t index = 0;
+  int32_t bottom = 0;
+  int32_t top = subtable_list->size();
+  while (top != bottom) {
+    index = (top + bottom) / 2;
+    IndexSubTable::Builder* subtable = subtable_list->at(index);
+    if (glyph_id < subtable->first_glyph_index()) {
+      // Location beow current location
+      top = index;
+    } else {
+      if (glyph_id <= subtable->last_glyph_index()) {
+        return subtable;
+      } else {
+        bottom = index + 1;
+      }
+    }
+  }
+  return NULL;
+}
+
+IndexSubTableBuilderList* BitmapSizeTable::Builder::GetIndexSubTableBuilders() {
+  if (index_sub_tables_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &index_sub_tables_;
+}
+
+void BitmapSizeTable::Builder::Initialize(ReadableFontData* data) {
+  index_sub_tables_.clear();
+  if (data) {
+    int32_t number_of_index_subtables =
+        BitmapSizeTable::NumberOfIndexSubTables(data, 0);
+    index_sub_tables_.resize(number_of_index_subtables);
+    for (int32_t i = 0; i < number_of_index_subtables; ++i) {
+      index_sub_tables_[i].Attach(CreateIndexSubTableBuilder(i));
+    }
+  }
+}
+
+CALLER_ATTACH IndexSubTable::Builder*
+BitmapSizeTable::Builder::CreateIndexSubTableBuilder(int32_t index) {
+  return IndexSubTable::Builder::CreateBuilder(master_read_data(),
+                                               IndexSubTableArrayOffset(),
+                                               index);
+}
+
+/******************************************************************************
+ * BitmapSizeTable::Builder::BitmapGlyphInfoIterator class
+ ******************************************************************************/
+BitmapSizeTable::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
+    BitmapSizeTable::Builder* container)
+    : RefIterator<BitmapGlyphInfo, BitmapSizeTable::Builder>(container) {
+  sub_table_iter_ = container->IndexSubTableBuilders()->begin();
+  sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator());
+}
+
+bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext() {
+  if (sub_table_glyph_info_iter_ && HasNext(sub_table_glyph_info_iter_)) {
+    return true;
+  }
+  while (++sub_table_iter_ != container()->IndexSubTableBuilders()->end()) {
+    sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator());
+    if (HasNext(sub_table_glyph_info_iter_)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+CALLER_ATTACH
+BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next() {
+  if (!HasNext()) {
+    // Note: In C++, we do not throw exception when there's no element.
+    return NULL;
+  }
+  return Next(sub_table_glyph_info_iter_);
+}
+
+bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext(
+    BitmapGlyphInfoIter* iterator_base) {
+  if (iterator_base) {
+    switch (iterator_base->container_base()->index_format()) {
+      case 1: {
+        IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->HasNext();
+      }
+
+      case 2: {
+        IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->HasNext();
+      }
+
+      case 3: {
+        IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->HasNext();
+      }
+
+      case 4: {
+        IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->HasNext();
+      }
+
+      case 5: {
+        IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->HasNext();
+      }
+
+      default:
+        break;
+    }
+  }
+  return false;
+}
+
+CALLER_ATTACH
+BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next(
+    BitmapGlyphInfoIter* iterator_base) {
+  if (iterator_base) {
+    switch (iterator_base->container_base()->index_format()) {
+      case 1: {
+        IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->Next();
+      }
+
+      case 2: {
+        IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->Next();
+      }
+
+      case 3: {
+        IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->Next();
+      }
+
+      case 4: {
+        IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->Next();
+      }
+
+      case 5: {
+        IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->Next();
+      }
+
+      default:
+        break;
+    }
+  }
+  return NULL;
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/bitmap_size_table.h b/sfntly/table/bitmap/bitmap_size_table.h
new file mode 100644
index 0000000..6733e20
--- /dev/null
+++ b/sfntly/table/bitmap/bitmap_size_table.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_
+
+#include "sfntly/port/lock.h"
+#include "sfntly/table/bitmap/bitmap_glyph_info.h"
+#include "sfntly/table/bitmap/index_sub_table.h"
+
+namespace sfntly {
+// Binary search would be faster but many fonts have index subtables that
+// aren't sorted.
+// Note: preprocessor define is used to avoid const expression warnings in C++
+//       code.
+#define SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH 0
+
+class BitmapSizeTable : public SubTable,
+                        public RefCounted<BitmapSizeTable> {
+ public:
+  class Builder : public SubTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    class BitmapGlyphInfoIterator :
+        public RefIterator<BitmapGlyphInfo, Builder> {
+     public:
+      explicit BitmapGlyphInfoIterator(Builder* container);
+      virtual ~BitmapGlyphInfoIterator() {}
+
+      virtual bool HasNext();
+      CALLER_ATTACH virtual BitmapGlyphInfo* Next();
+
+     private:
+      bool HasNext(BitmapGlyphInfoIter* iterator_base);
+      CALLER_ATTACH BitmapGlyphInfo* Next(BitmapGlyphInfoIter* iterator_base);
+
+      IndexSubTableBuilderList::iterator sub_table_iter_;
+      BitmapGlyphInfoIterPtr sub_table_glyph_info_iter_;
+    };
+
+    virtual ~Builder();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
+                                                ReadableFontData* master_data);
+    static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
+                                                ReadableFontData* master_data);
+    // Gets the subtable array offset as set in the original table as read from
+    // the font file. This value cannot be explicitly set and will be generated
+    // during table building.
+    // @return the subtable array offset
+    int32_t IndexSubTableArrayOffset();
+
+    // Sets the subtable array offset. This is used only during the building
+    // process when the objects are being serialized.
+    // @param offset the offset to the index subtable array
+    void SetIndexSubTableArrayOffset(int32_t offset);
+
+    // Gets the subtable array size as set in the original table as read from
+    // the font file. This value cannot be explicitly set and will be generated
+    // during table building.
+    // @return the subtable array size
+    int32_t IndexTableSize();
+
+    // Sets the subtable size. This is used only during the building process
+    // when the objects are being serialized.
+    // @param size the offset to the index subtable array
+    void SetIndexTableSize(int32_t size);
+
+    int32_t NumberOfIndexSubTables();
+    int32_t ColorRef();
+    // TODO(stuartg): SBitLineMetrics hori();
+    // TODO(stuartg): SBitLineMetrics vert();
+    int32_t StartGlyphIndex();
+    int32_t EndGlyphIndex();
+    int32_t PpemX();
+    int32_t PpemY();
+    int32_t BitDepth();
+    int32_t FlagsAsInt();
+
+    IndexSubTable::Builder* IndexSubTableBuilder(int32_t index);
+    CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id);
+    int32_t GlyphOffset(int32_t glyph_id);
+    int32_t GlyphLength(int32_t glyph_id);
+    int32_t GlyphFormat(int32_t glyph_id);
+    IndexSubTableBuilderList* IndexSubTableBuilders();
+    // Note: renamed from iterator(), type is the derived type.
+    CALLER_ATTACH BitmapGlyphInfoIterator* GetIterator();
+    void GenerateLocaMap(BitmapGlyphInfoMap* output);
+
+   protected:
+    void Revert();
+
+   private:
+    Builder(WritableFontData* data, ReadableFontData* master_data);
+    Builder(ReadableFontData* data, ReadableFontData* master_data);
+
+    void SetNumberOfIndexSubTables(int32_t count);
+    IndexSubTable::Builder* SearchIndexSubTables(int32_t glyph_id);
+    IndexSubTable::Builder* LinearSearchIndexSubTables(int32_t glyph_id);
+    IndexSubTable::Builder* BinarySearchIndexSubTables(int32_t glyph_id);
+    IndexSubTableBuilderList* GetIndexSubTableBuilders();
+    void Initialize(ReadableFontData* data);
+    CALLER_ATTACH IndexSubTable::Builder* CreateIndexSubTableBuilder(
+        int32_t index);
+
+    IndexSubTableBuilderList index_sub_tables_;
+  };
+
+  virtual ~BitmapSizeTable();
+
+  int32_t IndexSubTableArrayOffset();
+  int32_t IndexTableSize();
+  int32_t NumberOfIndexSubTables();
+  int32_t ColorRef();
+  // TODO(stuartg): SBitLineMetrics hori();
+  // TODO(stuartg): SBitLineMetrics vert();
+  int32_t StartGlyphIndex();
+  int32_t EndGlyphIndex();
+  int32_t PpemX();
+  int32_t PpemY();
+  int32_t BitDepth();
+  int32_t FlagsAsInt();
+
+  // Note: renamed from indexSubTable()
+  IndexSubTable* GetIndexSubTable(int32_t index);
+  int32_t GlyphOffset(int32_t glyph_id);
+  int32_t GlyphLength(int32_t glyph_id);
+  CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id);
+  int32_t GlyphFormat(int32_t glyph_id);
+
+ protected:
+  BitmapSizeTable(ReadableFontData* data,
+                  ReadableFontData* master_data);
+
+ private:
+  static int32_t NumberOfIndexSubTables(ReadableFontData* data,
+                                        int32_t table_offset);
+  IndexSubTable* SearchIndexSubTables(int32_t glyph_id);
+  IndexSubTable* LinearSearchIndexSubTables(int32_t glyph_id);
+  IndexSubTable* BinarySearchIndexSubTables(int32_t glyph_id);
+  CALLER_ATTACH IndexSubTable* CreateIndexSubTable(int32_t index);
+  IndexSubTableList* GetIndexSubTableList();
+
+  Lock index_subtables_lock_;
+  IndexSubTableList index_subtables_;
+};
+typedef Ptr<BitmapSizeTable> BitmapSizeTablePtr;
+typedef std::vector<BitmapSizeTablePtr> BitmapSizeTableList;
+typedef Ptr<BitmapSizeTable::Builder> BitmapSizeTableBuilderPtr;
+typedef std::vector<BitmapSizeTableBuilderPtr> BitmapSizeTableBuilderList;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_
diff --git a/sfntly/table/bitmap/composite_bitmap_glyph.cc b/sfntly/table/bitmap/composite_bitmap_glyph.cc
new file mode 100644
index 0000000..ae7dc5a
--- /dev/null
+++ b/sfntly/table/bitmap/composite_bitmap_glyph.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/composite_bitmap_glyph.h"
+
+namespace sfntly {
+/******************************************************************************
+ * CompositeBitmapGlyph class
+ ******************************************************************************/
+CompositeBitmapGlyph::CompositeBitmapGlyph(ReadableFontData* data,
+                                           int32_t format)
+    : BitmapGlyph(data, format) {
+  Initialize(format);
+}
+
+CompositeBitmapGlyph::~CompositeBitmapGlyph() {
+}
+
+int32_t CompositeBitmapGlyph::NumComponents() {
+  return data_->ReadUShort(num_components_offset_);
+}
+
+CompositeBitmapGlyph::Component CompositeBitmapGlyph::GetComponent(
+    int32_t component_num) const {
+  int32_t component_offset = component_array_offset_ +
+                             component_num * Offset::kEbdtComponentLength;
+  return CompositeBitmapGlyph::Component(
+      data_->ReadUShort(component_offset + Offset::kEbdtComponent_glyphCode),
+      data_->ReadChar(component_offset + Offset::kEbdtComponent_xOffset),
+      data_->ReadChar(component_offset + Offset::kEbdtComponent_yOffset));
+}
+
+void CompositeBitmapGlyph::Initialize(int32_t format) {
+  if (format == 8) {
+    num_components_offset_ = Offset::kGlyphFormat8_numComponents;
+    component_array_offset_ = Offset::kGlyphFormat8_componentArray;
+  } else if (format == 9) {
+    num_components_offset_ = Offset::kGlyphFormat9_numComponents;
+    component_array_offset_ = Offset::kGlyphFormat9_componentArray;
+  } else {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IllegalStateException("Attempt to create a Composite Bitmap Glyph "
+                                "with a non-composite format.");
+#endif
+  }
+}
+
+/******************************************************************************
+ * CompositeBitmapGlyph::Component class
+ ******************************************************************************/
+CompositeBitmapGlyph::Component::Component(const Component& rhs)
+    : glyph_code_(rhs.glyph_code_),
+      x_offset_(rhs.x_offset_),
+      y_offset_(rhs.y_offset_) {
+}
+
+bool CompositeBitmapGlyph::Component::operator==(
+    const CompositeBitmapGlyph::Component& rhs) {
+  return glyph_code_ == rhs.glyph_code_;
+}
+
+CompositeBitmapGlyph::Component& CompositeBitmapGlyph::Component::operator=(
+    const CompositeBitmapGlyph::Component& rhs) {
+  glyph_code_ = rhs.glyph_code_;
+  x_offset_ = rhs.x_offset_;
+  y_offset_ = rhs.y_offset_;
+  return *this;
+}
+
+CompositeBitmapGlyph::Component::Component(int32_t glyph_code,
+                                           int32_t x_offset,
+                                           int32_t y_offset)
+    : glyph_code_(glyph_code), x_offset_(x_offset), y_offset_(y_offset) {
+}
+
+/******************************************************************************
+ * CompositeBitmapGlyph::Builder class
+ ******************************************************************************/
+CompositeBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format)
+    : BitmapGlyph::Builder(data, format) {
+}
+
+CompositeBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format)
+    : BitmapGlyph::Builder(data, format) {
+}
+
+CompositeBitmapGlyph::Builder::~Builder() {
+}
+
+CALLER_ATTACH FontDataTable*
+CompositeBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) {
+  Ptr<CompositeBitmapGlyph> glyph = new CompositeBitmapGlyph(data, format());
+  return glyph.Detach();
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/composite_bitmap_glyph.h b/sfntly/table/bitmap/composite_bitmap_glyph.h
new file mode 100644
index 0000000..897db7e
--- /dev/null
+++ b/sfntly/table/bitmap/composite_bitmap_glyph.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_
+
+#include "sfntly/table/bitmap/bitmap_glyph.h"
+
+namespace sfntly {
+
+class CompositeBitmapGlyph : public BitmapGlyph,
+                             public RefCounted<CompositeBitmapGlyph> {
+ public:
+  class Component {
+   public:
+    Component(const Component& rhs);
+
+    int32_t glyph_code() { return glyph_code_; }
+    int32_t x_offset() { return x_offset_; }
+    int32_t y_offset() { return y_offset_; }
+
+    // UNIMPLEMENTED: int hashCode()
+    bool operator==(const Component& rhs);
+    Component& operator=(const Component& rhs);
+
+   protected:
+    Component(int32_t glyph_code, int32_t x_offset, int32_t y_offset);
+
+   private:
+    int32_t glyph_code_;
+    int32_t x_offset_;
+    int32_t y_offset_;
+
+    friend class CompositeBitmapGlyph;
+  };
+
+  class Builder : public BitmapGlyph::Builder,
+                  public RefCounted<Builder> {
+   public:
+    Builder(WritableFontData* data, int32_t format);
+    Builder(ReadableFontData* data, int32_t format);
+    virtual ~Builder();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+  };
+
+  CompositeBitmapGlyph(ReadableFontData* data, int32_t format);
+  virtual ~CompositeBitmapGlyph();
+  int32_t NumComponents();
+  // Note: returned immutable object over stack.
+  Component GetComponent(int32_t component_num) const;
+
+ private:
+  void Initialize(int32_t format);
+
+  int32_t num_components_offset_;
+  int32_t component_array_offset_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_
diff --git a/sfntly/table/bitmap/ebdt_table.cc b/sfntly/table/bitmap/ebdt_table.cc
new file mode 100644
index 0000000..eeb1fa0
--- /dev/null
+++ b/sfntly/table/bitmap/ebdt_table.cc
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/ebdt_table.h"
+
+#include <stdlib.h>
+
+#include "sfntly/table/bitmap/composite_bitmap_glyph.h"
+#include "sfntly/table/bitmap/simple_bitmap_glyph.h"
+
+namespace sfntly {
+/******************************************************************************
+ * EbdtTable class
+ ******************************************************************************/
+EbdtTable::~EbdtTable() {
+}
+
+int32_t EbdtTable::Version() {
+  return data_->ReadFixed(Offset::kVersion);
+}
+
+CALLER_ATTACH
+BitmapGlyph* EbdtTable::Glyph(int32_t offset, int32_t length, int32_t format) {
+  ReadableFontDataPtr glyph_data;
+  glyph_data.Attach(down_cast<ReadableFontData*>(data_->Slice(offset, length)));
+  return BitmapGlyph::CreateGlyph(glyph_data, format);
+}
+
+EbdtTable::EbdtTable(Header* header, ReadableFontData* data)
+    : SubTableContainerTable(header, data) {
+}
+
+/******************************************************************************
+ * EbdtTable::Builder class
+ ******************************************************************************/
+EbdtTable::Builder::Builder(Header* header, WritableFontData* data)
+  : SubTableContainerTable::Builder(header, data) {
+}
+
+EbdtTable::Builder::Builder(Header* header, ReadableFontData* data)
+  : SubTableContainerTable::Builder(header, data) {
+}
+
+EbdtTable::Builder::~Builder() {
+}
+
+CALLER_ATTACH FontDataTable*
+    EbdtTable::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new EbdtTable(header(), data);
+  return table.Detach();
+}
+
+void EbdtTable::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t EbdtTable::Builder::SubDataSizeToSerialize() {
+  if (glyph_builders_.empty()) {
+    return 0;
+  }
+  bool fixed = true;
+  int32_t size = Offset::kHeaderLength;
+  for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(),
+                                        builder_end = glyph_builders_.end();
+                                        builder_map != builder_end;
+                                        builder_map++) {
+    for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(),
+                                         glyph_entry_end = builder_map->end();
+                                         glyph_entry != glyph_entry_end;
+                                         glyph_entry++) {
+      int32_t glyph_size = glyph_entry->second->SubDataSizeToSerialize();
+      size += abs(glyph_size);
+      fixed = (glyph_size <= 0) ? false : fixed;
+    }
+  }
+  return (fixed ? 1 : -1) * size;
+}
+
+bool EbdtTable::Builder::SubReadyToSerialize() {
+  if (glyph_builders_.empty()) {
+    return false;
+  }
+  return true;
+}
+
+int32_t EbdtTable::Builder::SubSerialize(WritableFontData* new_data) {
+  int32_t size = 0;
+  size += new_data->WriteFixed(Offset::kVersion, kVersion);
+  for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(),
+                                        builder_end = glyph_builders_.end();
+                                        builder_map != builder_end;
+                                        builder_map++) {
+    for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(),
+                                         glyph_entry_end = builder_map->end();
+                                         glyph_entry != glyph_entry_end;
+                                         glyph_entry++) {
+      WritableFontDataPtr slice;
+      slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size)));
+      size += glyph_entry->second->SubSerialize(slice);
+    }
+  }
+  return size;
+}
+
+void EbdtTable::Builder::SetLoca(BitmapLocaList* loca_list) {
+  assert(loca_list);
+  Revert();
+  glyph_loca_.resize(loca_list->size());
+  std::copy(loca_list->begin(), loca_list->end(), glyph_loca_.begin());
+}
+
+void EbdtTable::Builder::GenerateLocaList(BitmapLocaList* output) {
+  assert(output);
+  output->clear();
+
+  if (glyph_builders_.empty()) {
+    if (glyph_loca_.empty()) {
+      return;
+    }
+  }
+
+  int start_offset = Offset::kHeaderLength;
+  for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(),
+                                        builder_end = glyph_builders_.end();
+                                        builder_map != builder_end;
+                                        builder_map++) {
+    BitmapGlyphInfoMap new_loca_map;
+    int32_t glyph_offset = 0;
+    for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(),
+                                         glyph_end = builder_map->end();
+                                         glyph_entry != glyph_end;
+                                         glyph_entry++) {
+      BitmapGlyphBuilderPtr builder = glyph_entry->second;
+      int32_t size = builder->SubDataSizeToSerialize();
+      BitmapGlyphInfoPtr info = new BitmapGlyphInfo(glyph_entry->first,
+          start_offset + glyph_offset, size, builder->format());
+      new_loca_map[glyph_entry->first] = info;
+      glyph_offset += size;
+    }
+    start_offset += glyph_offset;
+    output->push_back(new_loca_map);
+  }
+}
+
+BitmapGlyphBuilderList* EbdtTable::Builder::GlyphBuilders() {
+  return GetGlyphBuilders();
+}
+
+void EbdtTable::Builder::SetGlyphBuilders(
+    BitmapGlyphBuilderList* glyph_builders) {
+  glyph_builders_.clear();
+  std::copy(glyph_builders->begin(), glyph_builders->end(),
+            glyph_builders_.begin());
+  set_model_changed();
+}
+
+void EbdtTable::Builder::Revert() {
+  glyph_loca_.clear();
+  glyph_builders_.clear();
+  set_model_changed(false);
+}
+
+CALLER_ATTACH
+EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header,
+                                                      WritableFontData* data) {
+  Ptr<EbdtTable::Builder> builder;
+  builder = new Builder(header, data);
+  return builder.Detach();
+}
+
+CALLER_ATTACH
+EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header,
+                                                      ReadableFontData* data) {
+  Ptr<EbdtTable::Builder> builder;
+  builder = new Builder(header, data);
+  return builder.Detach();
+}
+
+BitmapGlyphBuilderList* EbdtTable::Builder::GetGlyphBuilders() {
+  if (glyph_builders_.empty()) {
+    if (glyph_loca_.empty()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+      throw IllegalStateException(
+          "Loca values not set - unable to parse glyph data.");
+#endif
+      return NULL;
+    }
+    Initialize(InternalReadData(), &glyph_loca_, &glyph_builders_);
+    set_model_changed();
+  }
+  return &glyph_builders_;
+}
+
+void EbdtTable::Builder::Initialize(ReadableFontData* data,
+                                    BitmapLocaList* loca_list,
+                                    BitmapGlyphBuilderList* output) {
+  assert(loca_list);
+  assert(output);
+
+  output->clear();
+  if (data) {
+    for (BitmapLocaList::iterator loca_map = loca_list->begin(),
+                                  loca_end = loca_list->end();
+                                  loca_map != loca_end; loca_map++) {
+      BitmapGlyphBuilderMap glyph_builder_map;
+      for (BitmapGlyphInfoMap::iterator entry = loca_map->begin(),
+                                        entry_end = loca_map->end();
+                                        entry != entry_end; entry++) {
+        BitmapGlyphInfoPtr info = entry->second;
+        ReadableFontDataPtr slice;
+        slice.Attach(down_cast<ReadableFontData*>(data->Slice(
+            info->offset(), info->length())));
+        BitmapGlyphBuilderPtr glyph_builder;
+        glyph_builder.Attach(BitmapGlyph::Builder::CreateGlyphBuilder(
+            slice, info->format()));
+        glyph_builder_map[entry->first] = glyph_builder;
+      }
+      output->push_back(glyph_builder_map);
+    }
+  }
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/ebdt_table.h b/sfntly/table/bitmap/ebdt_table.h
new file mode 100644
index 0000000..d138c14
--- /dev/null
+++ b/sfntly/table/bitmap/ebdt_table.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_
+
+#include "sfntly/table/bitmap/bitmap_glyph.h"
+#include "sfntly/table/bitmap/bitmap_glyph_info.h"
+#include "sfntly/table/subtable_container_table.h"
+
+namespace sfntly {
+
+class EbdtTable : public SubTableContainerTable,
+                  public RefCounted<EbdtTable> {
+ public:
+  struct Offset {
+    enum {
+      kVersion = 0,
+      kHeaderLength = DataSize::kFixed,
+    };
+  };
+
+  class Builder : public SubTableContainerTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual void SubDataSet();
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+
+    void SetLoca(BitmapLocaList* loca_list);
+    void GenerateLocaList(BitmapLocaList* output);
+
+    // Gets the List of glyph builders for the glyph table builder. These may be
+    // manipulated in any way by the caller and the changes will be reflected in
+    // the final glyph table produced.
+    // If there is no current data for the glyph builder or the glyph builders
+    // have not been previously set then this will return an empty glyph builder
+    // List. If there is current data (i.e. data read from an existing font) and
+    // the loca list has not been set or is null, empty, or invalid, then an
+    // empty glyph builder List will be returned.
+    // @return the list of glyph builders
+    BitmapGlyphBuilderList* GlyphBuilders();
+
+    // Replace the internal glyph builders with the one provided. The provided
+    // list and all contained objects belong to this builder.
+    // This call is only required if the entire set of glyphs in the glyph
+    // table builder are being replaced. If the glyph builder list provided from
+    // the {@link EbdtTable.Builder#glyphBuilders()} is being used and modified
+    // then those changes will already be reflected in the glyph table builder.
+    // @param glyphBuilders the new glyph builders
+    void SetGlyphBuilders(BitmapGlyphBuilderList* glyph_builders);
+
+    void Revert();
+
+    // Create a new builder using the header information and data provided.
+    // @param header the header information
+    // @param data the data holding the table
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                ReadableFontData* data);
+
+   private:
+    BitmapGlyphBuilderList* GetGlyphBuilders();
+    static void Initialize(ReadableFontData* data,
+                           BitmapLocaList* loca_list,
+                           BitmapGlyphBuilderList* output);
+
+    static const int32_t kVersion = 0x00020000;  // TODO(stuartg): const/enum
+    BitmapLocaList glyph_loca_;
+    BitmapGlyphBuilderList glyph_builders_;
+  };
+
+  virtual ~EbdtTable();
+  int32_t Version();
+  CALLER_ATTACH BitmapGlyph* Glyph(int32_t offset,
+                                   int32_t length,
+                                   int32_t format);
+ protected:
+  EbdtTable(Header* header, ReadableFontData* data);
+};
+typedef Ptr<EbdtTable> EbdtTablePtr;
+typedef Ptr<EbdtTable::Builder> EbdtTableBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_
diff --git a/sfntly/table/bitmap/eblc_table.cc b/sfntly/table/bitmap/eblc_table.cc
new file mode 100644
index 0000000..0ad2764
--- /dev/null
+++ b/sfntly/table/bitmap/eblc_table.cc
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/eblc_table.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sfntly/math/font_math.h"
+
+namespace sfntly {
+/******************************************************************************
+ * EblcTable class
+ ******************************************************************************/
+int32_t EblcTable::Version() {
+  return data_->ReadFixed(Offset::kVersion);
+}
+
+int32_t EblcTable::NumSizes() {
+  return data_->ReadULongAsInt(Offset::kNumSizes);
+}
+
+BitmapSizeTable* EblcTable::GetBitmapSizeTable(int32_t index) {
+  if (index < 0 || index > NumSizes()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException(
+        "Size table index is outside the range of tables.");
+#endif
+    return NULL;
+  }
+  BitmapSizeTableList* bitmap_size_table_list = GetBitmapSizeTableList();
+  if (bitmap_size_table_list) {
+    return (*bitmap_size_table_list)[index];
+  }
+  return NULL;
+}
+
+EblcTable::EblcTable(Header* header, ReadableFontData* data)
+    : SubTableContainerTable(header, data) {
+}
+
+BitmapSizeTableList* EblcTable::GetBitmapSizeTableList() {
+  AutoLock lock(bitmap_size_table_lock_);
+  if (bitmap_size_table_.empty()) {
+    CreateBitmapSizeTable(data_, NumSizes(), &bitmap_size_table_);
+  }
+  return &bitmap_size_table_;
+}
+
+// static
+void EblcTable::CreateBitmapSizeTable(ReadableFontData* data,
+                                      int32_t num_sizes,
+                                      BitmapSizeTableList* output) {
+  assert(data);
+  assert(output);
+  for (int32_t i = 0; i < num_sizes; ++i) {
+    ReadableFontDataPtr new_data;
+    new_data.Attach(down_cast<ReadableFontData*>(
+        data->Slice(Offset::kBitmapSizeTableArrayStart +
+                    i * Offset::kBitmapSizeTableLength,
+                    Offset::kBitmapSizeTableLength)));
+    BitmapSizeTableBuilderPtr size_builder;
+    size_builder.Attach(
+        BitmapSizeTable::Builder::CreateBuilder(new_data, data));
+    BitmapSizeTablePtr size;
+    size.Attach(down_cast<BitmapSizeTable*>(size_builder->Build()));
+    output->push_back(size);
+  }
+}
+
+/******************************************************************************
+ * EblcTable::Builder class
+ ******************************************************************************/
+EblcTable::Builder::Builder(Header* header, WritableFontData* data)
+    : SubTableContainerTable::Builder(header, data) {
+}
+
+EblcTable::Builder::Builder(Header* header, ReadableFontData* data)
+    : SubTableContainerTable::Builder(header, data) {
+}
+
+EblcTable::Builder::~Builder() {
+}
+
+int32_t EblcTable::Builder::SubSerialize(WritableFontData* new_data) {
+  // header
+  int32_t size = new_data->WriteFixed(0, kVersion);
+  size += new_data->WriteULong(size, size_table_builders_.size());
+
+  // calculate the offsets
+  // offset to the start of the size table array
+  int32_t size_table_start_offset = size;
+  // walking offset in the size table array
+  int32_t size_table_offset = size_table_start_offset;
+  // offset to the start of the whole index subtable block
+  int32_t sub_table_block_start_offset = size_table_offset +
+      size_table_builders_.size() * Offset::kBitmapSizeTableLength;
+  // walking offset in the index subtable
+  // points to the start of the current subtable block
+  int32_t current_sub_table_block_start_offset = sub_table_block_start_offset;
+
+#if defined (SFNTLY_DEBUG_BITMAP)
+  int32_t size_index = 0;
+#endif
+  for (BitmapSizeTableBuilderList::iterator
+           size_builder = size_table_builders_.begin(),
+           size_builder_end = size_table_builders_.end();
+       size_builder != size_builder_end; size_builder++) {
+    (*size_builder)->SetIndexSubTableArrayOffset(
+        current_sub_table_block_start_offset);
+    IndexSubTableBuilderList* index_sub_table_builder_list =
+        (*size_builder)->IndexSubTableBuilders();
+
+    // walking offset within the current subTable array
+    int32_t index_sub_table_array_offset = current_sub_table_block_start_offset;
+    // walking offset within the subTable entries
+    int32_t index_sub_table_offset = index_sub_table_array_offset +
+        index_sub_table_builder_list->size() * Offset::kIndexSubHeaderLength;
+
+#if defined (SFNTLY_DEBUG_BITMAP)
+    fprintf(stderr, "size %d: sizeTable=%x, current subTable Block=%x, ",
+            size_index, size_table_offset,
+            current_sub_table_block_start_offset);
+    fprintf(stderr, "index subTableStart=%x\n", index_sub_table_offset);
+    size_index++;
+    int32_t sub_table_index = 0;
+#endif
+    for (IndexSubTableBuilderList::iterator
+             index_sub_table_builder = index_sub_table_builder_list->begin(),
+             index_sub_table_builder_end = index_sub_table_builder_list->end();
+         index_sub_table_builder != index_sub_table_builder_end;
+         index_sub_table_builder++) {
+#if defined (SFNTLY_DEBUG_BITMAP)
+      fprintf(stderr, "\tsubTableIndex %d: format=%x, ", sub_table_index,
+              (*index_sub_table_builder)->index_format());
+      fprintf(stderr, "indexSubTableArrayOffset=%x, indexSubTableOffset=%x\n",
+              index_sub_table_array_offset, index_sub_table_offset);
+      sub_table_index++;
+#endif
+      // array entry
+      index_sub_table_array_offset += new_data->WriteUShort(
+          index_sub_table_array_offset,
+          (*index_sub_table_builder)->first_glyph_index());
+      index_sub_table_array_offset += new_data->WriteUShort(
+          index_sub_table_array_offset,
+          (*index_sub_table_builder)->last_glyph_index());
+      index_sub_table_array_offset += new_data->WriteULong(
+          index_sub_table_array_offset,
+          index_sub_table_offset - current_sub_table_block_start_offset);
+
+      // index sub table
+      WritableFontDataPtr slice_index_sub_table;
+      slice_index_sub_table.Attach(down_cast<WritableFontData*>(
+          new_data->Slice(index_sub_table_offset)));
+      int32_t current_sub_table_size =
+          (*index_sub_table_builder)->SubSerialize(slice_index_sub_table);
+      int32_t padding = FontMath::PaddingRequired(current_sub_table_size,
+                                                  DataSize::kULONG);
+#if defined (SFNTLY_DEBUG_BITMAP)
+      fprintf(stderr, "\t\tsubTableSize = %x, padding = %x\n",
+              current_sub_table_size, padding);
+#endif
+      index_sub_table_offset += current_sub_table_size;
+      index_sub_table_offset +=
+          new_data->WritePadding(index_sub_table_offset, padding);
+    }
+
+    // serialize size table
+    (*size_builder)->SetIndexTableSize(
+        index_sub_table_offset - current_sub_table_block_start_offset);
+    WritableFontDataPtr slice_size_table;
+    slice_size_table.Attach(down_cast<WritableFontData*>(
+        new_data->Slice(size_table_offset)));
+    size_table_offset += (*size_builder)->SubSerialize(slice_size_table);
+
+    current_sub_table_block_start_offset = index_sub_table_offset;
+  }
+  return size + current_sub_table_block_start_offset;
+}
+
+bool EblcTable::Builder::SubReadyToSerialize() {
+  if (size_table_builders_.empty()) {
+    return false;
+  }
+  for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(),
+                                            e = size_table_builders_.end();
+                                            b != e; b++) {
+    if (!(*b)->SubReadyToSerialize()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+int32_t EblcTable::Builder::SubDataSizeToSerialize() {
+  if (size_table_builders_.empty()) {
+    return 0;
+  }
+  int32_t size = Offset::kHeaderLength;
+  bool variable = false;
+#if defined (SFNTLY_DEBUG_BITMAP)
+  size_t size_index = 0;
+#endif
+  for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(),
+                                            e = size_table_builders_.end();
+                                            b != e; b++) {
+    int32_t size_builder_size = (*b)->SubDataSizeToSerialize();
+#if defined (SFNTLY_DEBUG_BITMAP)
+    fprintf(stderr, "sizeIndex = %d, sizeBuilderSize=0x%x (%d)\n",
+            size_index++, size_builder_size, size_builder_size);
+#endif
+    variable = size_builder_size > 0 ? variable : true;
+    size += abs(size_builder_size);
+  }
+#if defined (SFNTLY_DEBUG_BITMAP)
+  fprintf(stderr, "eblc size=%d\n", size);
+#endif
+  return variable ? -size : size;
+}
+
+void EblcTable::Builder::SubDataSet() {
+  Revert();
+}
+
+BitmapSizeTableBuilderList* EblcTable::Builder::BitmapSizeBuilders() {
+  return GetSizeList();
+}
+
+void EblcTable::Builder::Revert() {
+  size_table_builders_.clear();
+  set_model_changed(false);
+}
+
+void EblcTable::Builder::GenerateLocaList(BitmapLocaList* output) {
+  assert(output);
+  BitmapSizeTableBuilderList* size_builder_list = GetSizeList();
+  output->clear();
+#if defined (SFNTLY_DEBUG_BITMAP)
+  int32_t size_index = 0;
+#endif
+  for (BitmapSizeTableBuilderList::iterator b = size_builder_list->begin(),
+                                            e = size_builder_list->end();
+                                            b != e; b++) {
+#if defined (SFNTLY_DEBUG_BITMAP)
+    fprintf(stderr, "size table = %d\n", size_index++);
+#endif
+    BitmapGlyphInfoMap loca_map;
+    (*b)->GenerateLocaMap(&loca_map);
+    output->push_back(loca_map);
+  }
+}
+
+CALLER_ATTACH
+FontDataTable* EblcTable::Builder::SubBuildTable(ReadableFontData* data) {
+  Ptr<EblcTable> new_table = new EblcTable(header(), data);
+  return new_table.Detach();
+}
+
+// static
+CALLER_ATTACH EblcTable::Builder*
+    EblcTable::Builder::CreateBuilder(Header* header, WritableFontData* data) {
+  Ptr<EblcTable::Builder> new_builder = new EblcTable::Builder(header, data);
+  return new_builder.Detach();
+}
+
+// static
+CALLER_ATTACH EblcTable::Builder*
+    EblcTable::Builder::CreateBuilder(Header* header, ReadableFontData* data) {
+  Ptr<EblcTable::Builder> new_builder = new EblcTable::Builder(header, data);
+  return new_builder.Detach();
+}
+
+BitmapSizeTableBuilderList* EblcTable::Builder::GetSizeList() {
+  if (size_table_builders_.empty()) {
+    Initialize(InternalReadData(), &size_table_builders_);
+    set_model_changed();
+  }
+  return &size_table_builders_;
+}
+
+void EblcTable::Builder::Initialize(ReadableFontData* data,
+                                    BitmapSizeTableBuilderList* output) {
+  assert(output);
+  if (data) {
+    int32_t num_sizes = data->ReadULongAsInt(Offset::kNumSizes);
+    for (int32_t i = 0; i < num_sizes; ++i) {
+      ReadableFontDataPtr new_data;
+      new_data.Attach(down_cast<ReadableFontData*>(
+          data->Slice(Offset::kBitmapSizeTableArrayStart +
+                      i * Offset::kBitmapSizeTableLength,
+                      Offset::kBitmapSizeTableLength)));
+      BitmapSizeTableBuilderPtr size_builder;
+      size_builder.Attach(BitmapSizeTable::Builder::CreateBuilder(
+          new_data, data));
+      output->push_back(size_builder);
+    }
+  }
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/eblc_table.h b/sfntly/table/bitmap/eblc_table.h
new file mode 100644
index 0000000..b04338a
--- /dev/null
+++ b/sfntly/table/bitmap/eblc_table.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_
+
+#include "sfntly/port/lock.h"
+#include "sfntly/table/bitmap/big_glyph_metrics.h"
+#include "sfntly/table/bitmap/bitmap_glyph.h"
+#include "sfntly/table/bitmap/bitmap_size_table.h"
+#include "sfntly/table/subtable_container_table.h"
+
+namespace sfntly {
+
+class EblcTable : public SubTableContainerTable,
+                  public RefCounted<EblcTable> {
+ public:
+  struct Offset {
+    enum {
+      // header
+      kVersion = 0,
+      kNumSizes = 4,
+      kHeaderLength = kNumSizes + DataSize::kULONG,
+
+      // bitmapSizeTable
+      kBitmapSizeTableArrayStart = kHeaderLength,
+      kBitmapSizeTableLength = 48,
+      kBitmapSizeTable_indexSubTableArrayOffset = 0,
+      kBitmapSizeTable_indexTableSize = 4,
+      kBitmapSizeTable_numberOfIndexSubTables = 8,
+      kBitmapSizeTable_colorRef = 12,
+      kBitmapSizeTable_hori = 16,
+      kBitmapSizeTable_vert = 28,
+      kBitmapSizeTable_startGlyphIndex = 40,
+      kBitmapSizeTable_endGlyphIndex = 42,
+      kBitmapSizeTable_ppemX = 44,
+      kBitmapSizeTable_ppemY = 45,
+      kBitmapSizeTable_bitDepth = 46,
+      kBitmapSizeTable_flags = 47,
+
+      // sbitLineMetrics
+      kSbitLineMetricsLength = 12,
+      kSbitLineMetrics_ascender = 0,
+      kSbitLineMetrics_descender = 1,
+      kSbitLineMetrics_widthMax = 2,
+      kSbitLineMetrics_caretSlopeNumerator = 3,
+      kSbitLineMetrics_caretSlopeDenominator = 4,
+      kSbitLineMetrics_caretOffset = 5,
+      kSbitLineMetrics_minOriginSB = 6,
+      kSbitLineMetrics_minAdvanceSB = 7,
+      kSbitLineMetrics_maxBeforeBL = 8,
+      kSbitLineMetrics_minAfterBL = 9,
+      kSbitLineMetrics_pad1 = 10,
+      kSbitLineMetrics_pad2 = 11,
+
+      // indexSubTable
+      kIndexSubTableEntryLength = 8,
+      kIndexSubTableEntry_firstGlyphIndex = 0,
+      kIndexSubTableEntry_lastGlyphIndex = 2,
+      kIndexSubTableEntry_additionalOffsetToIndexSubTable = 4,
+
+      // indexSubHeader
+      kIndexSubHeaderLength = 8,
+      kIndexSubHeader_indexFormat = 0,
+      kIndexSubHeader_imageFormat = 2,
+      kIndexSubHeader_imageDataOffset = 4,
+
+      // indexSubTable - all offset relative to the subtable start
+
+      // indexSubTable1
+      kIndexSubTable1_offsetArray = kIndexSubHeaderLength,
+      kIndexSubTable1_builderDataSize = kIndexSubHeaderLength,
+
+      // kIndexSubTable2
+      kIndexSubTable2Length = kIndexSubHeaderLength +
+                              DataSize::kULONG +
+                              BitmapGlyph::Offset::kBigGlyphMetricsLength,
+      kIndexSubTable2_imageSize = kIndexSubHeaderLength,
+      kIndexSubTable2_bigGlyphMetrics = kIndexSubTable2_imageSize +
+                                        DataSize::kULONG,
+      kIndexSubTable2_builderDataSize = kIndexSubTable2_bigGlyphMetrics +
+                                        BigGlyphMetrics::Offset::kMetricsLength,
+
+      // kIndexSubTable3
+      kIndexSubTable3_offsetArray = kIndexSubHeaderLength,
+      kIndexSubTable3_builderDataSize = kIndexSubTable3_offsetArray,
+
+      // kIndexSubTable4
+      kIndexSubTable4_numGlyphs = kIndexSubHeaderLength,
+      kIndexSubTable4_glyphArray = kIndexSubTable4_numGlyphs +
+                                   DataSize::kULONG,
+      kIndexSubTable4_codeOffsetPairLength = 2 * DataSize::kUSHORT,
+      kIndexSubTable4_codeOffsetPair_glyphCode = 0,
+      kIndexSubTable4_codeOffsetPair_offset = DataSize::kUSHORT,
+      kIndexSubTable4_builderDataSize = kIndexSubTable4_glyphArray,
+
+      // kIndexSubTable5
+      kIndexSubTable5_imageSize = kIndexSubHeaderLength,
+      kIndexSubTable5_bigGlyphMetrics = kIndexSubTable5_imageSize +
+                                        DataSize::kULONG,
+      kIndexSubTable5_numGlyphs = kIndexSubTable5_bigGlyphMetrics +
+                                  BitmapGlyph::Offset::kBigGlyphMetricsLength,
+      kIndexSubTable5_glyphArray = kIndexSubTable5_numGlyphs +
+                                   DataSize::kULONG,
+      kIndexSubTable5_builderDataSize = kIndexSubTable5_glyphArray,
+
+      // codeOffsetPair
+      kCodeOffsetPairLength = 2 * DataSize::kUSHORT,
+      kCodeOffsetPair_glyphCode = 0,
+      kCodeOffsetPair_offset = DataSize::kUSHORT,
+    };
+  };
+
+  class Builder : public SubTableContainerTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual void SubDataSet();
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+
+    BitmapSizeTableBuilderList* BitmapSizeBuilders();
+    void Revert();
+
+    // Generates the loca list for the EBDT table. The list is intended to be
+    // used by the EBDT to allow it to parse the glyph data and generate glyph
+    // objects. After returning from this method the list belongs to the caller.
+    // The list entries are in the same order as the size table builders are at
+    // the time of this call.
+    // @return the list of loca maps with one for each size table builder
+    void GenerateLocaList(BitmapLocaList* output);
+
+    // Create a new builder using the header information and data provided.
+    // @param header the header information
+    // @param data the data holding the table
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                ReadableFontData* data);
+
+   private:
+    BitmapSizeTableBuilderList* GetSizeList();
+    void Initialize(ReadableFontData* data, BitmapSizeTableBuilderList* output);
+
+    static const int32_t kVersion = 0x00020000;
+    BitmapSizeTableBuilderList size_table_builders_;
+  };
+
+  int32_t Version();
+  int32_t NumSizes();
+  // UNIMPLEMENTED: toString()
+
+  BitmapSizeTable* GetBitmapSizeTable(int32_t index);
+
+  static const int32_t NOTDEF = -1;
+
+ protected:
+  EblcTable(Header* header, ReadableFontData* data);
+
+ private:
+  BitmapSizeTableList* GetBitmapSizeTableList();
+
+  static void CreateBitmapSizeTable(ReadableFontData* data,
+                                    int32_t num_sizes,
+                                    BitmapSizeTableList* output);
+
+  Lock bitmap_size_table_lock_;
+  BitmapSizeTableList bitmap_size_table_;
+};
+typedef Ptr<EblcTable> EblcTablePtr;
+typedef Ptr<EblcTable::Builder> EblcTableBuilderPtr;
+}
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_
diff --git a/sfntly/table/bitmap/ebsc_table.cc b/sfntly/table/bitmap/ebsc_table.cc
new file mode 100644
index 0000000..458c2d4
--- /dev/null
+++ b/sfntly/table/bitmap/ebsc_table.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/ebsc_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * EbscTable class
+ ******************************************************************************/
+EbscTable::~EbscTable() {
+}
+
+int32_t EbscTable::Version() {
+  return data_->ReadFixed(Offset::kVersion);
+}
+
+int32_t EbscTable::NumSizes() {
+  return data_->ReadULongAsInt(Offset::kNumSizes);
+}
+
+EbscTable::EbscTable(Header* header, ReadableFontData* data)
+    : Table(header, data) {
+}
+
+/******************************************************************************
+ * EbscTable::BitmapScaleTable class
+ ******************************************************************************/
+EbscTable::BitmapScaleTable::~BitmapScaleTable() {
+}
+
+EbscTable::BitmapScaleTable::BitmapScaleTable(ReadableFontData* data)
+    : SubTable(data) {
+}
+
+int32_t EbscTable::BitmapScaleTable::PpemX() {
+  return data_->ReadByte(Offset::kBitmapScaleTable_ppemX);
+}
+
+int32_t EbscTable::BitmapScaleTable::PpemY() {
+  return data_->ReadByte(Offset::kBitmapScaleTable_ppemY);
+}
+
+int32_t EbscTable::BitmapScaleTable::SubstitutePpemX() {
+  return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemX);
+}
+
+int32_t EbscTable::BitmapScaleTable::SubstitutePpemY() {
+  return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemY);
+}
+
+/******************************************************************************
+ * EbscTable::Builder class
+ ******************************************************************************/
+EbscTable::Builder::~Builder() {
+}
+
+CALLER_ATTACH EbscTable::Builder* EbscTable::Builder::CreateBuilder(
+    Header* header, WritableFontData* data) {
+  EbscTableBuilderPtr builder = new EbscTable::Builder(header, data);
+  return builder.Detach();
+}
+
+EbscTable::Builder::Builder(Header* header, WritableFontData* data)
+    : Table::Builder(header, data) {
+}
+
+EbscTable::Builder::Builder(Header* header, ReadableFontData* data)
+    : Table::Builder(header, data) {
+}
+
+CALLER_ATTACH
+FontDataTable* EbscTable::Builder::SubBuildTable(ReadableFontData* data) {
+  EbscTablePtr output = new EbscTable(header(), data);
+  return output.Detach();
+}
+
+void EbscTable::Builder::SubDataSet() {
+  // NOP
+}
+
+int32_t EbscTable::Builder::SubDataSizeToSerialize() {
+  return 0;
+}
+
+bool EbscTable::Builder::SubReadyToSerialize() {
+  return false;
+}
+
+int32_t EbscTable::Builder::SubSerialize(WritableFontData* new_data) {
+  UNREFERENCED_PARAMETER(new_data);
+  return 0;
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/ebsc_table.h b/sfntly/table/bitmap/ebsc_table.h
new file mode 100644
index 0000000..b79df38
--- /dev/null
+++ b/sfntly/table/bitmap/ebsc_table.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+namespace sfntly {
+
+class EbscTable : public Table,
+                  public RefCounted<EbscTable> {
+ public:
+  struct Offset {
+    enum {
+      // header
+      kVersion = 0,
+      kNumSizes = DataSize::kFixed,
+      kHeaderLength = kNumSizes + DataSize::kULONG,
+      kBitmapScaleTableStart = kHeaderLength,
+
+      // bitmapScaleTable
+      kBitmapScaleTable_hori = 0,
+      kBitmapScaleTable_vert = EblcTable::Offset::kSbitLineMetricsLength,
+      kBitmapScaleTable_ppemX = kBitmapScaleTable_vert +
+                                EblcTable::Offset::kSbitLineMetricsLength,
+      kBitmapScaleTable_ppemY = kBitmapScaleTable_ppemX + DataSize::kBYTE,
+      kBitmapScaleTable_substitutePpemX = kBitmapScaleTable_ppemY +
+                                          DataSize::kBYTE,
+      kBitmapScaleTable_substitutePpemY = kBitmapScaleTable_substitutePpemX +
+                                          DataSize::kBYTE,
+      kBitmapScaleTableLength = kBitmapScaleTable_substitutePpemY +
+                                DataSize::kBYTE,
+    };
+  };
+
+  class BitmapScaleTable : public SubTable,
+                           public RefCounted<BitmapScaleTable> {
+   public:
+    virtual ~BitmapScaleTable();
+    int32_t PpemX();
+    int32_t PpemY();
+    int32_t SubstitutePpemX();
+    int32_t SubstitutePpemY();
+
+   protected:
+    // Note: caller to do data->Slice(offset, Offset::kBitmapScaleTableLength)
+    explicit BitmapScaleTable(ReadableFontData* data);
+  };
+
+  // TODO(stuartg): currently the builder just builds from initial data
+  // - need to make fully working but few if any examples to test with
+  class Builder : public Table::Builder,
+                  public RefCounted<Builder> {
+   public:
+    virtual ~Builder();
+
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+
+   protected:
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+  };
+
+  virtual ~EbscTable();
+
+  int32_t Version();
+  int32_t NumSizes();
+  // Note: renamed from bitmapScaleTable
+  CALLER_ATTACH BitmapScaleTable* GetBitmapScaleTable(int32_t index);
+
+ private:
+  EbscTable(Header* header, ReadableFontData* data);
+  friend class Builder;
+};
+typedef Ptr<EbscTable> EbscTablePtr;
+typedef Ptr<EbscTable::Builder> EbscTableBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_
diff --git a/sfntly/table/bitmap/glyph_metrics.cc b/sfntly/table/bitmap/glyph_metrics.cc
new file mode 100644
index 0000000..e91eb99
--- /dev/null
+++ b/sfntly/table/bitmap/glyph_metrics.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/glyph_metrics.h"
+
+namespace sfntly {
+
+GlyphMetrics::~GlyphMetrics() {
+}
+
+GlyphMetrics::GlyphMetrics(ReadableFontData* data)
+    : SubTable(data) {
+}
+
+GlyphMetrics::Builder::~Builder() {
+}
+
+GlyphMetrics::Builder::Builder(WritableFontData* data)
+    : SubTable::Builder(data) {
+}
+
+GlyphMetrics::Builder::Builder(ReadableFontData* data)
+    : SubTable::Builder(data) {
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/glyph_metrics.h b/sfntly/table/bitmap/glyph_metrics.h
new file mode 100644
index 0000000..5f16aaa
--- /dev/null
+++ b/sfntly/table/bitmap/glyph_metrics.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_
+
+#include "sfntly/table/subtable.h"
+
+namespace sfntly {
+
+class GlyphMetrics : public SubTable {
+ public:
+  virtual ~GlyphMetrics();
+
+ protected:
+  class Builder : public SubTable::Builder {
+   public:
+    virtual ~Builder();
+
+   protected:
+    explicit Builder(WritableFontData* data);
+    explicit Builder(ReadableFontData* data);
+  };
+
+  explicit GlyphMetrics(ReadableFontData* data);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_
diff --git a/sfntly/table/bitmap/index_sub_table.cc b/sfntly/table/bitmap/index_sub_table.cc
new file mode 100644
index 0000000..5e29784
--- /dev/null
+++ b/sfntly/table/bitmap/index_sub_table.cc
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/index_sub_table.h"
+
+#include "sfntly/table/bitmap/eblc_table.h"
+#include "sfntly/table/bitmap/index_sub_table_format1.h"
+#include "sfntly/table/bitmap/index_sub_table_format2.h"
+#include "sfntly/table/bitmap/index_sub_table_format3.h"
+#include "sfntly/table/bitmap/index_sub_table_format4.h"
+#include "sfntly/table/bitmap/index_sub_table_format5.h"
+
+namespace sfntly {
+/******************************************************************************
+ * IndexSubTable class
+ ******************************************************************************/
+CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::GlyphInfo(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return NULL;
+  }
+  if (GlyphStartOffset(glyph_id) == -1) {
+    return NULL;
+  }
+  BitmapGlyphInfoPtr output = new BitmapGlyphInfo(glyph_id,
+                                                  image_data_offset(),
+                                                  GlyphStartOffset(glyph_id),
+                                                  GlyphLength(glyph_id),
+                                                  image_format());
+  return output.Detach();
+}
+
+int32_t IndexSubTable::GlyphOffset(int32_t glyph_id) {
+  int32_t glyph_start_offset = GlyphStartOffset(glyph_id);
+  if (glyph_start_offset == -1) {
+    return -1;
+  }
+  return image_data_offset() + glyph_start_offset;
+}
+
+// static
+CALLER_ATTACH IndexSubTable*
+    IndexSubTable::CreateIndexSubTable(ReadableFontData* data,
+                                       int32_t offset_to_index_sub_table_array,
+                                       int32_t array_index) {
+  IndexSubTableBuilderPtr builder;
+  builder.Attach(IndexSubTable::Builder::CreateBuilder(
+      data, offset_to_index_sub_table_array, array_index));
+  return down_cast<IndexSubTable*>(builder->Build());
+}
+
+IndexSubTable::IndexSubTable(ReadableFontData* data,
+                             int32_t first_glyph_index,
+                             int32_t last_glyph_index)
+    : SubTable(data),
+      first_glyph_index_(first_glyph_index),
+      last_glyph_index_(last_glyph_index) {
+  index_format_ =
+      data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat);
+  image_format_ =
+      data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat);
+  image_data_offset_ =
+      data_->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset);
+}
+
+int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id) {
+  return CheckGlyphRange(glyph_id, first_glyph_index(), last_glyph_index());
+}
+
+// static
+int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id,
+                                       int32_t first_glyph_id,
+                                       int32_t last_glyph_id) {
+  if (glyph_id < first_glyph_id || glyph_id > last_glyph_id) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException("Glyph ID is outside of the allowed range.");
+#endif
+    return -1;
+  }
+  return glyph_id - first_glyph_id;
+}
+
+/******************************************************************************
+ * IndexSubTable::Builder class
+ ******************************************************************************/
+IndexSubTable::Builder::~Builder() {
+}
+
+void IndexSubTable::Builder::Revert() {
+  set_model_changed(false);
+  Initialize(InternalReadData());
+}
+
+CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::Builder::GlyphInfo(
+    int32_t glyph_id) {
+  BitmapGlyphInfoPtr glyph_info =
+      new BitmapGlyphInfo(glyph_id,
+                          image_data_offset(),
+                          GlyphStartOffset(glyph_id),
+                          GlyphLength(glyph_id),
+                          image_format());
+  return glyph_info.Detach();
+}
+
+int32_t IndexSubTable::Builder::GlyphOffset(int32_t glyph_id) {
+  return image_data_offset() + GlyphStartOffset(glyph_id);
+}
+
+// static
+CALLER_ATTACH IndexSubTable::Builder*
+IndexSubTable::Builder::CreateBuilder(int32_t index_format) {
+  switch (index_format) {
+    case Format::FORMAT_1:
+      return IndexSubTableFormat1::Builder::CreateBuilder();
+    case Format::FORMAT_2:
+      return IndexSubTableFormat2::Builder::CreateBuilder();
+    case Format::FORMAT_3:
+      return IndexSubTableFormat3::Builder::CreateBuilder();
+    case Format::FORMAT_4:
+      return IndexSubTableFormat4::Builder::CreateBuilder();
+    case Format::FORMAT_5:
+      return IndexSubTableFormat5::Builder::CreateBuilder();
+    default:
+#if !defined (SFNTLY_NO_EXCEPTION)
+      throw IllegalArgumentException("Invalid index subtable format");
+#endif
+      return NULL;
+  }
+}
+
+// static
+CALLER_ATTACH IndexSubTable::Builder*
+IndexSubTable::Builder::CreateBuilder(ReadableFontData* data,
+    int32_t offset_to_index_sub_table_array, int32_t array_index) {
+  int32_t index_sub_table_entry_offset =
+      offset_to_index_sub_table_array +
+      array_index * EblcTable::Offset::kIndexSubTableEntryLength;
+  int32_t first_glyph_index =
+      data->ReadUShort(index_sub_table_entry_offset +
+                       EblcTable::Offset::kIndexSubTableEntry_firstGlyphIndex);
+  int32_t last_glyph_index =
+      data->ReadUShort(index_sub_table_entry_offset +
+                       EblcTable::Offset::kIndexSubTableEntry_lastGlyphIndex);
+  int32_t additional_offset_to_index_subtable = data->ReadULongAsInt(
+      index_sub_table_entry_offset +
+      EblcTable::Offset::kIndexSubTableEntry_additionalOffsetToIndexSubTable);
+  int32_t index_sub_table_offset = offset_to_index_sub_table_array +
+                                   additional_offset_to_index_subtable;
+  int32_t index_format = data->ReadUShort(index_sub_table_offset);
+  switch (index_format) {
+    case 1:
+      return IndexSubTableFormat1::Builder::CreateBuilder(
+          data, index_sub_table_offset, first_glyph_index, last_glyph_index);
+    case 2:
+      return IndexSubTableFormat2::Builder::CreateBuilder(
+          data, index_sub_table_offset, first_glyph_index, last_glyph_index);
+    case 3:
+      return IndexSubTableFormat3::Builder::CreateBuilder(
+          data, index_sub_table_offset, first_glyph_index, last_glyph_index);
+    case 4:
+      return IndexSubTableFormat4::Builder::CreateBuilder(
+          data, index_sub_table_offset, first_glyph_index, last_glyph_index);
+    case 5:
+      return IndexSubTableFormat5::Builder::CreateBuilder(
+          data, index_sub_table_offset, first_glyph_index, last_glyph_index);
+    default:
+      // Unknown format and unable to process.
+#if !defined (SFNTLY_NO_EXCEPTION)
+      throw IllegalArgumentException("Invalid Index Subtable Format");
+#endif
+      break;
+  }
+  return NULL;
+}
+
+CALLER_ATTACH
+FontDataTable* IndexSubTable::Builder::SubBuildTable(ReadableFontData* data) {
+  UNREFERENCED_PARAMETER(data);
+  return NULL;
+}
+
+void IndexSubTable::Builder::SubDataSet() {
+  // NOP
+}
+
+int32_t IndexSubTable::Builder::SubDataSizeToSerialize() {
+  return 0;
+}
+
+bool IndexSubTable::Builder::SubReadyToSerialize() {
+  return false;
+}
+
+int32_t IndexSubTable::Builder::SubSerialize(WritableFontData* new_data) {
+  UNREFERENCED_PARAMETER(new_data);
+  return 0;
+}
+
+IndexSubTable::Builder::Builder(int32_t data_size, int32_t index_format)
+    : SubTable::Builder(data_size),
+      first_glyph_index_(0),
+      last_glyph_index_(0),
+      index_format_(index_format),
+      image_format_(0),
+      image_data_offset_(0) {
+}
+
+IndexSubTable::Builder::Builder(int32_t index_format,
+                                int32_t image_format,
+                                int32_t image_data_offset,
+                                int32_t data_size)
+    : SubTable::Builder(data_size),
+      first_glyph_index_(0),
+      last_glyph_index_(0),
+      index_format_(index_format),
+      image_format_(image_format),
+      image_data_offset_(image_data_offset) {
+}
+
+IndexSubTable::Builder::Builder(WritableFontData* data,
+                                int32_t first_glyph_index,
+                                int32_t last_glyph_index)
+    : SubTable::Builder(data),
+      first_glyph_index_(first_glyph_index),
+      last_glyph_index_(last_glyph_index) {
+  Initialize(data);
+}
+
+IndexSubTable::Builder::Builder(ReadableFontData* data,
+                                int32_t first_glyph_index,
+                                int32_t last_glyph_index)
+    : SubTable::Builder(data),
+      first_glyph_index_(first_glyph_index),
+      last_glyph_index_(last_glyph_index) {
+  Initialize(data);
+}
+
+int32_t IndexSubTable::Builder::CheckGlyphRange(int32_t glyph_id) {
+  return IndexSubTable::CheckGlyphRange(glyph_id,
+                                        first_glyph_index(),
+                                        last_glyph_index());
+}
+
+int32_t IndexSubTable::Builder::SerializeIndexSubHeader(
+    WritableFontData* data) {
+  int32_t size =
+      data->WriteUShort(EblcTable::Offset::kIndexSubHeader_indexFormat,
+                        index_format());
+  size += data->WriteUShort(EblcTable::Offset::kIndexSubHeader_imageFormat,
+                            image_format());
+  size += data->WriteULong(EblcTable::Offset::kIndexSubHeader_imageDataOffset,
+                           image_data_offset());
+  return size;
+}
+
+void IndexSubTable::Builder::Initialize(ReadableFontData* data) {
+  index_format_ =
+      data->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat);
+  image_format_ =
+      data->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat);
+  image_data_offset_ =
+      data->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset);
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/index_sub_table.h b/sfntly/table/bitmap/index_sub_table.h
new file mode 100644
index 0000000..6d27129
--- /dev/null
+++ b/sfntly/table/bitmap/index_sub_table.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_
+
+#include <vector>
+
+#include "sfntly/port/java_iterator.h"
+#include "sfntly/table/subtable.h"
+#include "sfntly/table/bitmap/bitmap_glyph_info.h"
+
+namespace sfntly {
+
+class IndexSubTable : public SubTable {
+ public:
+  struct Format {
+    enum {
+      FORMAT_1 = 1,
+      FORMAT_2 = 2,
+      FORMAT_3 = 3,
+      FORMAT_4 = 4,
+      FORMAT_5 = 5,
+    };
+  };
+
+  class Builder : public SubTable::Builder {
+   public:
+    virtual ~Builder();
+
+    void Revert();
+
+    int32_t index_format() { return index_format_; }
+    int32_t first_glyph_index() { return first_glyph_index_; }
+    void set_first_glyph_index(int32_t v) { first_glyph_index_ = v; }
+    int32_t last_glyph_index() { return last_glyph_index_; }
+    void set_last_glyph_index(int32_t v) { last_glyph_index_ = v; }
+    int32_t image_format() { return image_format_; }
+    void set_image_format(int32_t v) { image_format_ = v; }
+    int32_t image_data_offset() { return image_data_offset_; }
+    void set_image_data_offset(int32_t v) { image_data_offset_ = v; }
+
+    virtual int32_t NumGlyphs() = 0;
+
+    // Gets the glyph info for the specified glyph id.
+    // @param glyphId the glyph id to look up
+    // @return the glyph info
+    CALLER_ATTACH virtual BitmapGlyphInfo* GlyphInfo(int32_t glyph_id);
+
+    // Gets the full offset of the glyph within the EBDT table.
+    // @param glyphId the glyph id
+    // @return the glyph offset
+    virtual int32_t GlyphOffset(int32_t glyph_id);
+
+    // Gets the offset of the glyph relative to the block for this index
+    // subtable.
+    // @param glyphId the glyph id
+    // @return the glyph offset
+    virtual int32_t GlyphStartOffset(int32_t glyph_id) = 0;
+
+    // Gets the length of the glyph within the EBDT table.
+    // @param glyphId the glyph id
+    // @return the glyph offset
+    virtual int32_t GlyphLength(int32_t glyph_id) = 0;
+
+    // Note: renamed from java iterator()
+    CALLER_ATTACH virtual Iterator<BitmapGlyphInfo, IndexSubTable::Builder>*
+        GetIterator() = 0;
+
+    // Static instantiation function.
+    static CALLER_ATTACH Builder* CreateBuilder(int32_t index_format);
+    static CALLER_ATTACH Builder*
+        CreateBuilder(ReadableFontData* data,
+                      int32_t offset_to_index_sub_table_array,
+                      int32_t array_index);
+
+    // The following methods will never be called but they need to be here to
+    // allow the BitmapSizeTable to see these methods through an abstract
+    // reference.
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+   protected:
+    Builder(int32_t data_size, int32_t index_format);
+    Builder(int32_t index_format,
+            int32_t image_format,
+            int32_t image_data_offset,
+            int32_t data_size);
+    Builder(WritableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    Builder(ReadableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+
+    // Checks that the glyph id is within the correct range. If it returns the
+    // offset of the glyph id from the start of the range.
+    // @param glyphId
+    // @return the offset of the glyphId from the start of the glyph range
+    // @throws IndexOutOfBoundsException if the glyph id is not within the
+    //         correct range
+    int32_t CheckGlyphRange(int32_t glyph_id);
+    int32_t SerializeIndexSubHeader(WritableFontData* data);
+
+   private:
+    void Initialize(ReadableFontData* data);
+
+    int32_t first_glyph_index_;
+    int32_t last_glyph_index_;
+    int32_t index_format_;
+    int32_t image_format_;
+    int32_t image_data_offset_;
+  };
+
+  int32_t index_format() { return index_format_; }
+  int32_t first_glyph_index() { return first_glyph_index_; }
+  int32_t last_glyph_index() { return last_glyph_index_; }
+  int32_t image_format() { return image_format_; }
+  int32_t image_data_offset() { return image_data_offset_; }
+
+  CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id);
+  virtual int32_t GlyphOffset(int32_t glyph_id);
+  virtual int32_t GlyphStartOffset(int32_t glyph_id) = 0;
+  virtual int32_t GlyphLength(int32_t glyph_id) = 0;
+  virtual int32_t NumGlyphs() = 0;
+
+  static CALLER_ATTACH IndexSubTable*
+      CreateIndexSubTable(ReadableFontData* data,
+                          int32_t offset_to_index_sub_table_array,
+                          int32_t array_index);
+
+ protected:
+  // Note: the constructor does not implement offset/length form provided in
+  //       Java to avoid heavy lifting in constructors.  Callers to call
+  //       GetDataLength() static method of the derived class to get proper
+  //       length and slice ahead.
+  IndexSubTable(ReadableFontData* data,
+                int32_t first_glyph_index,
+                int32_t last_glyph_index);
+
+  int32_t CheckGlyphRange(int32_t glyph_id);
+  static int32_t CheckGlyphRange(int32_t glyph_id,
+                                 int32_t first_glyph_id,
+                                 int32_t last_glyph_id);
+
+ private:
+  int32_t first_glyph_index_;
+  int32_t last_glyph_index_;
+  int32_t index_format_;
+  int32_t image_format_;
+  int32_t image_data_offset_;
+};
+typedef Ptr<IndexSubTable> IndexSubTablePtr;
+typedef std::vector<IndexSubTablePtr> IndexSubTableList;
+typedef Ptr<IndexSubTable::Builder> IndexSubTableBuilderPtr;
+typedef std::vector<IndexSubTableBuilderPtr> IndexSubTableBuilderList;
+typedef Iterator<BitmapGlyphInfo, IndexSubTable::Builder> BitmapGlyphInfoIter;
+typedef Ptr<BitmapGlyphInfoIter> BitmapGlyphInfoIterPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_
diff --git a/sfntly/table/bitmap/index_sub_table_format1.cc b/sfntly/table/bitmap/index_sub_table_format1.cc
new file mode 100644
index 0000000..5199e18
--- /dev/null
+++ b/sfntly/table/bitmap/index_sub_table_format1.cc
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/index_sub_table_format1.h"
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * IndexSubTableFormat1 class
+ ******************************************************************************/
+// static
+int32_t IndexSubTableFormat1::GetDataLength(ReadableFontData* data,
+                                            int32_t offset,
+                                            int32_t first,
+                                            int32_t last) {
+  UNREFERENCED_PARAMETER(data);
+  UNREFERENCED_PARAMETER(offset);
+  return (last - first + 1 + 1) * DataSize::kULONG;
+}
+
+IndexSubTableFormat1::~IndexSubTableFormat1() {
+}
+
+int32_t IndexSubTableFormat1::NumGlyphs() {
+  return last_glyph_index() - first_glyph_index() + 1;
+}
+
+int32_t IndexSubTableFormat1::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  return Loca(loca);
+}
+
+int32_t IndexSubTableFormat1::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  return Loca(loca + 1) - Loca(loca);
+}
+
+IndexSubTableFormat1::IndexSubTableFormat1(ReadableFontData* data,
+                                           int32_t first_glyph_index,
+                                           int32_t last_glyph_index)
+    : IndexSubTable(data, first_glyph_index, last_glyph_index) {
+}
+
+int32_t IndexSubTableFormat1::Loca(int32_t loca) {
+  return image_data_offset() +
+         data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable1_offsetArray +
+                               loca * DataSize::kULONG);
+}
+
+/******************************************************************************
+ * IndexSubTableFormat1::Builder class
+ ******************************************************************************/
+IndexSubTableFormat1::Builder::~Builder() {
+}
+
+int32_t IndexSubTableFormat1::Builder::NumGlyphs() {
+  return GetOffsetArray()->size() - 1;
+}
+
+int32_t IndexSubTableFormat1::Builder::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return 0;
+  }
+  IntegerList* offset_array = GetOffsetArray();
+  return offset_array->at(loca + 1) - offset_array->at(loca);
+}
+
+int32_t IndexSubTableFormat1::Builder::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  return GetOffsetArray()->at(loca);
+}
+
+CALLER_ATTACH IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*
+    IndexSubTableFormat1::Builder::GetIterator() {
+  Ptr<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator> it =
+      new IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator(this);
+  return it.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat1::Builder*
+IndexSubTableFormat1::Builder::CreateBuilder() {
+  IndexSubTableFormat1BuilderPtr output = new IndexSubTableFormat1::Builder();
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat1::Builder*
+IndexSubTableFormat1::Builder::CreateBuilder(ReadableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  ReadableFontDataPtr new_data;
+  new_data.Attach(down_cast<ReadableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  if (new_data == NULL) {
+    return NULL;
+  }
+  IndexSubTableFormat1BuilderPtr output =
+      new IndexSubTableFormat1::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+
+// static
+CALLER_ATTACH IndexSubTableFormat1::Builder*
+IndexSubTableFormat1::Builder::CreateBuilder(WritableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  WritableFontDataPtr new_data;
+  new_data.Attach(down_cast<WritableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  IndexSubTableFormat1BuilderPtr output =
+      new IndexSubTableFormat1::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+CALLER_ATTACH FontDataTable* IndexSubTableFormat1::Builder::SubBuildTable(
+    ReadableFontData* data) {
+  IndexSubTableFormat1Ptr output = new IndexSubTableFormat1(
+      data, first_glyph_index(), last_glyph_index());
+  return output.Detach();
+}
+
+void IndexSubTableFormat1::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t IndexSubTableFormat1::Builder::SubDataSizeToSerialize() {
+  if (offset_array_.empty()) {
+    return InternalReadData()->Length();
+  }
+  return EblcTable::Offset::kIndexSubHeaderLength +
+         offset_array_.size() * DataSize::kULONG;
+}
+
+bool IndexSubTableFormat1::Builder::SubReadyToSerialize() {
+  if (!offset_array_.empty()) {
+    return true;
+  }
+  return false;
+}
+
+int32_t IndexSubTableFormat1::Builder::SubSerialize(
+    WritableFontData* new_data) {
+  int32_t size = SerializeIndexSubHeader(new_data);
+  if (!model_changed()) {
+    if (InternalReadData() == NULL) {
+      return size;
+    }
+    ReadableFontDataPtr source;
+    WritableFontDataPtr target;
+    source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
+        EblcTable::Offset::kIndexSubTable1_offsetArray)));
+    target.Attach(down_cast<WritableFontData*>(new_data->Slice(
+        EblcTable::Offset::kIndexSubTable1_offsetArray)));
+    size += source->CopyTo(target);
+  } else {
+    for (IntegerList::iterator b = GetOffsetArray()->begin(),
+                               e = GetOffsetArray()->end(); b != e; b++) {
+      size += new_data->WriteLong(size, *b);
+    }
+  }
+  return size;
+}
+
+IntegerList* IndexSubTableFormat1::Builder::OffsetArray() {
+  return GetOffsetArray();
+}
+
+void IndexSubTableFormat1::Builder::SetOffsetArray(
+    const IntegerList& offset_array) {
+  offset_array_.clear();
+  offset_array_ = offset_array;
+  set_model_changed();
+}
+
+void IndexSubTableFormat1::Builder::Revert() {
+  offset_array_.clear();
+  IndexSubTable::Builder::Revert();
+}
+
+IndexSubTableFormat1::Builder::Builder()
+    : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable1_builderDataSize,
+                             IndexSubTable::Format::FORMAT_1) {
+}
+
+IndexSubTableFormat1::Builder::Builder(WritableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IndexSubTableFormat1::Builder::Builder(ReadableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IntegerList* IndexSubTableFormat1::Builder::GetOffsetArray() {
+  if (offset_array_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &offset_array_;
+}
+
+void IndexSubTableFormat1::Builder::Initialize(ReadableFontData* data) {
+  offset_array_.clear();
+  if (data) {
+    int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1;
+    for (int32_t i = 0; i < num_offsets; ++i) {
+      offset_array_.push_back(data->ReadULongAsInt(
+          EblcTable::Offset::kIndexSubTable1_offsetArray +
+          i * DataSize::kULONG));
+    }
+  }
+}
+
+// static
+int32_t IndexSubTableFormat1::Builder::DataLength(
+    ReadableFontData* data,
+    int32_t index_sub_table_offset,
+    int32_t first_glyph_index,
+    int32_t last_glyph_index) {
+  UNREFERENCED_PARAMETER(data);
+  UNREFERENCED_PARAMETER(index_sub_table_offset);
+  return EblcTable::Offset::kIndexSubHeaderLength +
+         (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kULONG;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator class
+ ******************************************************************************/
+IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
+    IndexSubTableFormat1::Builder* container)
+    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat1::Builder,
+                  IndexSubTable::Builder>(container) {
+  glyph_id_ = container->first_glyph_index();
+}
+
+bool IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::HasNext() {
+  if (glyph_id_ <= container()->last_glyph_index()) {
+    return true;
+  }
+  return false;
+}
+
+CALLER_ATTACH BitmapGlyphInfo*
+IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::Next() {
+  BitmapGlyphInfoPtr output;
+  if (!HasNext()) {
+    // Note: In C++, we do not throw exception when there's no element.
+    return NULL;
+  }
+  output = new BitmapGlyphInfo(glyph_id_,
+                               container()->image_data_offset(),
+                               container()->GlyphStartOffset(glyph_id_),
+                               container()->GlyphLength(glyph_id_),
+                               container()->image_format());
+  glyph_id_++;
+  return output.Detach();
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/index_sub_table_format1.h b/sfntly/table/bitmap/index_sub_table_format1.h
new file mode 100644
index 0000000..33171c1
--- /dev/null
+++ b/sfntly/table/bitmap/index_sub_table_format1.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_
+
+#include "sfntly/port/java_iterator.h"
+#include "sfntly/table/bitmap/index_sub_table.h"
+
+namespace sfntly {
+// Format 1 Index Subtable Entry.
+class IndexSubTableFormat1 : public IndexSubTable,
+                             public RefCounted<IndexSubTableFormat1> {
+ public:
+  class Builder : public IndexSubTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    class BitmapGlyphInfoIterator
+        : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> {
+     public:
+      explicit BitmapGlyphInfoIterator(Builder* container);
+      virtual ~BitmapGlyphInfoIterator() {}
+
+      virtual bool HasNext();
+      CALLER_ATTACH virtual BitmapGlyphInfo* Next();
+
+     private:
+      int32_t glyph_id_;
+    };
+
+    virtual ~Builder();
+    virtual int32_t NumGlyphs();
+    virtual int32_t GlyphLength(int32_t glyph_id);
+    virtual int32_t GlyphStartOffset(int32_t glyph_id);
+    CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    IntegerList* OffsetArray();
+    void SetOffsetArray(const IntegerList& offset_array);
+    CALLER_ATTACH BitmapGlyphInfoIter* Iterator();
+
+    static CALLER_ATTACH Builder* CreateBuilder();
+    static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+    static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+
+   protected:
+    void Revert();
+
+   private:
+    Builder();
+    Builder(WritableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    Builder(ReadableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    IntegerList* GetOffsetArray();
+    void Initialize(ReadableFontData* data);
+
+    static int32_t DataLength(ReadableFontData* data,
+                              int32_t index_sub_table_offset,
+                              int32_t first_glyph_index,
+                              int32_t last_glyph_index);
+
+    IntegerList offset_array_;
+  };
+
+  virtual ~IndexSubTableFormat1();
+
+  virtual int32_t NumGlyphs();
+  virtual int32_t GlyphStartOffset(int32_t glyph_id);
+  virtual int32_t GlyphLength(int32_t glyph_id);
+
+  static int32_t GetDataLength(ReadableFontData* data,
+                               int32_t offset,
+                               int32_t first,
+                               int32_t last);
+
+ private:
+  IndexSubTableFormat1(ReadableFontData* data,
+                       int32_t first_glyph_index,
+                       int32_t last_glyph_index);
+  int32_t Loca(int32_t loca_index);
+
+  friend class Builder;
+};
+typedef Ptr<IndexSubTableFormat1> IndexSubTableFormat1Ptr;
+typedef Ptr<IndexSubTableFormat1::Builder> IndexSubTableFormat1BuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_
diff --git a/sfntly/table/bitmap/index_sub_table_format2.cc b/sfntly/table/bitmap/index_sub_table_format2.cc
new file mode 100644
index 0000000..ce73e9b
--- /dev/null
+++ b/sfntly/table/bitmap/index_sub_table_format2.cc
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/index_sub_table_format2.h"
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * IndexSubTableFormat2 class
+ ******************************************************************************/
+IndexSubTableFormat2::~IndexSubTableFormat2() {
+}
+
+int32_t IndexSubTableFormat2::ImageSize() {
+  return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable2_imageSize);
+}
+
+CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat2::BigMetrics() {
+  ReadableFontDataPtr slice;
+  slice.Attach(down_cast<ReadableFontData*>(
+      data_->Slice(EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics,
+                   BigGlyphMetrics::Offset::kMetricsLength)));
+  BigGlyphMetricsPtr output = new BigGlyphMetrics(slice);
+  return output.Detach();
+}
+
+int32_t IndexSubTableFormat2::NumGlyphs() {
+  return last_glyph_index() - first_glyph_index() + 1;
+}
+
+int32_t IndexSubTableFormat2::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  return loca * image_size_;
+}
+
+int32_t IndexSubTableFormat2::GlyphLength(int32_t glyph_id) {
+  if (CheckGlyphRange(glyph_id) == -1) {
+    return 0;
+  }
+  return image_size_;
+}
+
+IndexSubTableFormat2::IndexSubTableFormat2(ReadableFontData* data,
+                                           int32_t first,
+                                           int32_t last)
+    : IndexSubTable(data, first, last) {
+  image_size_ =
+      data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable2_imageSize);
+}
+
+/******************************************************************************
+ * IndexSubTableFormat2::Builder class
+ ******************************************************************************/
+IndexSubTableFormat2::Builder::~Builder() {
+}
+
+int32_t IndexSubTableFormat2::Builder::NumGlyphs() {
+  return last_glyph_index() - first_glyph_index() + 1;
+}
+
+int32_t IndexSubTableFormat2::Builder::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  return loca * ImageSize();
+}
+
+int32_t IndexSubTableFormat2::Builder::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return 0;
+  }
+  return ImageSize();
+}
+
+CALLER_ATTACH IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*
+    IndexSubTableFormat2::Builder::GetIterator() {
+  Ptr<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator> it =
+      new IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator(this);
+  return it.Detach();
+}
+
+int32_t IndexSubTableFormat2::Builder::ImageSize() {
+  return InternalReadData()->ReadULongAsInt(
+      EblcTable::Offset::kIndexSubTable2_imageSize);
+}
+
+void IndexSubTableFormat2::Builder::SetImageSize(int32_t image_size) {
+  InternalWriteData()->WriteULong(EblcTable::Offset::kIndexSubTable2_imageSize,
+                                  image_size);
+}
+
+BigGlyphMetrics::Builder* IndexSubTableFormat2::Builder::BigMetrics() {
+  if (metrics_ == NULL) {
+    WritableFontDataPtr data;
+    data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice(
+        EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics,
+        BigGlyphMetrics::Offset::kMetricsLength)));
+    metrics_ = new BigGlyphMetrics::Builder(data);
+  }
+  return metrics_;
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat2::Builder*
+IndexSubTableFormat2::Builder::CreateBuilder() {
+  IndexSubTableFormat2BuilderPtr output = new IndexSubTableFormat2::Builder();
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat2::Builder*
+IndexSubTableFormat2::Builder::CreateBuilder(ReadableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  ReadableFontDataPtr new_data;
+  new_data.Attach(down_cast<ReadableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  if (new_data == NULL) {
+    return NULL;
+  }
+  IndexSubTableFormat2BuilderPtr output =
+      new IndexSubTableFormat2::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat2::Builder*
+IndexSubTableFormat2::Builder::CreateBuilder(WritableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  WritableFontDataPtr new_data;
+  new_data.Attach(down_cast<WritableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  IndexSubTableFormat2BuilderPtr output =
+      new IndexSubTableFormat2::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+CALLER_ATTACH FontDataTable* IndexSubTableFormat2::Builder::SubBuildTable(
+    ReadableFontData* data) {
+  IndexSubTableFormat2Ptr output = new IndexSubTableFormat2(
+      data, first_glyph_index(), last_glyph_index());
+  return output.Detach();
+}
+
+void IndexSubTableFormat2::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t IndexSubTableFormat2::Builder::SubDataSizeToSerialize() {
+  return EblcTable::Offset::kIndexSubTable2Length;
+}
+
+bool IndexSubTableFormat2::Builder::SubReadyToSerialize() {
+  return true;
+}
+
+int32_t IndexSubTableFormat2::Builder::SubSerialize(
+    WritableFontData* new_data) {
+  int32_t size = SerializeIndexSubHeader(new_data);
+  if (metrics_ == NULL) {
+    ReadableFontDataPtr source;
+    WritableFontDataPtr target;
+    source.Attach(down_cast<ReadableFontData*>(
+        InternalReadData()->Slice(size)));
+    target.Attach(down_cast<WritableFontData*>(new_data->Slice(size)));
+    size += source->CopyTo(target);
+  } else {
+    WritableFontDataPtr slice;
+    size += new_data->WriteLong(EblcTable::Offset::kIndexSubTable2_imageSize,
+                                ImageSize());
+    slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size)));
+    size += metrics_->SubSerialize(slice);
+  }
+  return size;
+}
+
+IndexSubTableFormat2::Builder::Builder()
+    : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize,
+                             IndexSubTable::Format::FORMAT_2) {
+  metrics_.Attach(BigGlyphMetrics::Builder::CreateBuilder());
+}
+
+IndexSubTableFormat2::Builder::Builder(WritableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IndexSubTableFormat2::Builder::Builder(ReadableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+// static
+int32_t IndexSubTableFormat2::Builder::DataLength(
+    ReadableFontData* data,
+    int32_t index_sub_table_offset,
+    int32_t first_glyph_index,
+    int32_t last_glyph_index) {
+  UNREFERENCED_PARAMETER(data);
+  UNREFERENCED_PARAMETER(index_sub_table_offset);
+  UNREFERENCED_PARAMETER(first_glyph_index);
+  UNREFERENCED_PARAMETER(last_glyph_index);
+  return EblcTable::Offset::kIndexSubTable2Length;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator class
+ ******************************************************************************/
+IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
+    IndexSubTableFormat2::Builder* container)
+    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat2::Builder,
+                  IndexSubTable::Builder>(container) {
+  glyph_id_ = container->first_glyph_index();
+}
+
+bool IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::HasNext() {
+  if (glyph_id_ <= container()->last_glyph_index()) {
+    return true;
+  }
+  return false;
+}
+
+CALLER_ATTACH BitmapGlyphInfo*
+IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::Next() {
+  BitmapGlyphInfoPtr output;
+  if (!HasNext()) {
+    // Note: In C++, we do not throw exception when there's no element.
+    return NULL;
+  }
+  output = new BitmapGlyphInfo(glyph_id_,
+                               container()->image_data_offset(),
+                               container()->GlyphStartOffset(glyph_id_),
+                               container()->GlyphLength(glyph_id_),
+                               container()->image_format());
+  glyph_id_++;
+  return output.Detach();
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/index_sub_table_format2.h b/sfntly/table/bitmap/index_sub_table_format2.h
new file mode 100644
index 0000000..784e8a3
--- /dev/null
+++ b/sfntly/table/bitmap/index_sub_table_format2.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT2_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT2_H_
+
+#include "sfntly/table/bitmap/index_sub_table.h"
+#include "sfntly/table/bitmap/big_glyph_metrics.h"
+
+namespace sfntly {
+// Format 2 Index Subtable Entry.
+class IndexSubTableFormat2 : public IndexSubTable,
+                             public RefCounted<IndexSubTableFormat2> {
+ public:
+  class Builder : public IndexSubTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    class BitmapGlyphInfoIterator
+        : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> {
+     public:
+      explicit BitmapGlyphInfoIterator(Builder* container);
+      virtual ~BitmapGlyphInfoIterator() {}
+
+      virtual bool HasNext();
+      CALLER_ATTACH virtual BitmapGlyphInfo* Next();
+
+     private:
+      int32_t glyph_id_;
+    };
+
+    virtual ~Builder();
+    virtual int32_t NumGlyphs();
+    virtual int32_t GlyphStartOffset(int32_t glyph_id);
+    virtual int32_t GlyphLength(int32_t glyph_id);
+    CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    int32_t ImageSize();
+    void SetImageSize(int32_t image_size);
+    BigGlyphMetrics::Builder* BigMetrics();
+
+    static CALLER_ATTACH Builder* CreateBuilder();
+    static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+    static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+   private:
+    Builder();
+    Builder(WritableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    Builder(ReadableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+
+    static int32_t DataLength(ReadableFontData* data,
+                              int32_t index_sub_table_offset,
+                              int32_t first_glyph_index,
+                              int32_t last_glyph_index);
+
+    BigGlyphMetricsBuilderPtr metrics_;
+  };
+
+  virtual ~IndexSubTableFormat2();
+
+  int32_t ImageSize();
+  CALLER_ATTACH BigGlyphMetrics* BigMetrics();
+
+  virtual int32_t NumGlyphs();
+  virtual int32_t GlyphStartOffset(int32_t glyph_id);
+  virtual int32_t GlyphLength(int32_t glyph_id);
+
+ private:
+  IndexSubTableFormat2(ReadableFontData* data, int32_t first, int32_t last);
+
+  int32_t image_size_;
+  friend class Builder;
+};
+typedef Ptr<IndexSubTableFormat2> IndexSubTableFormat2Ptr;
+typedef Ptr<IndexSubTableFormat2::Builder> IndexSubTableFormat2BuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_
diff --git a/sfntly/table/bitmap/index_sub_table_format3.cc b/sfntly/table/bitmap/index_sub_table_format3.cc
new file mode 100644
index 0000000..e2679b7
--- /dev/null
+++ b/sfntly/table/bitmap/index_sub_table_format3.cc
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/index_sub_table_format3.h"
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * IndexSubTableFormat3 class
+ ******************************************************************************/
+IndexSubTableFormat3::~IndexSubTableFormat3() {
+}
+
+int32_t IndexSubTableFormat3::NumGlyphs() {
+  return last_glyph_index() - first_glyph_index() + 1;
+}
+
+int32_t IndexSubTableFormat3::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca != -1) {
+    return Loca(loca);
+  }
+  return -1;
+}
+
+int32_t IndexSubTableFormat3::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca != -1) {
+    return Loca(glyph_id + 1) - Loca(glyph_id);
+  }
+  return 0;
+}
+
+// static
+int32_t IndexSubTableFormat3::GetDataLength(ReadableFontData* data,
+                                            int32_t offset,
+                                            int32_t first,
+                                            int32_t last) {
+  UNREFERENCED_PARAMETER(data);
+  UNREFERENCED_PARAMETER(offset);
+  return (last - first + 1 + 1) * DataSize::kUSHORT;
+}
+
+IndexSubTableFormat3::IndexSubTableFormat3(ReadableFontData* data,
+                                           int32_t first_glyph_index,
+                                           int32_t last_glyph_index)
+    : IndexSubTable(data, first_glyph_index, last_glyph_index) {
+}
+
+int32_t IndexSubTableFormat3::Loca(int32_t loca) {
+  int32_t read_offset =
+      data_->ReadUShort(EblcTable::Offset::kIndexSubTable3_offsetArray +
+                        loca * DataSize::kUSHORT);
+  return read_offset;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat3::Builder class
+ ******************************************************************************/
+IndexSubTableFormat3::Builder::~Builder() {
+}
+
+int32_t IndexSubTableFormat3::Builder::NumGlyphs() {
+  return GetOffsetArray()->size() - 1;
+}
+
+int32_t IndexSubTableFormat3::Builder::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  return GetOffsetArray()->at(loca);
+}
+
+int32_t IndexSubTableFormat3::Builder::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return 0;
+  }
+  IntegerList* offset_array = GetOffsetArray();
+  return offset_array->at(loca + 1) - offset_array->at(loca);
+}
+
+CALLER_ATTACH IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*
+    IndexSubTableFormat3::Builder::GetIterator() {
+  Ptr<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator> it =
+      new IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator(this);
+  return it.Detach();
+}
+
+void IndexSubTableFormat3::Builder::Revert() {
+  offset_array_.clear();
+  IndexSubTable::Builder::Revert();
+}
+
+void IndexSubTableFormat3::Builder::SetOffsetArray(
+    const IntegerList& offset_array) {
+  offset_array_.clear();
+  offset_array_ = offset_array;
+  set_model_changed();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat3::Builder*
+IndexSubTableFormat3::Builder::CreateBuilder() {
+  IndexSubTableFormat3BuilderPtr output = new IndexSubTableFormat3::Builder();
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat3::Builder*
+IndexSubTableFormat3::Builder::CreateBuilder(ReadableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  ReadableFontDataPtr new_data;
+  new_data.Attach(down_cast<ReadableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  if (new_data == NULL) {
+    return NULL;
+  }
+  IndexSubTableFormat3BuilderPtr output =
+      new IndexSubTableFormat3::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat3::Builder*
+IndexSubTableFormat3::Builder::CreateBuilder(WritableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  WritableFontDataPtr new_data;
+  new_data.Attach(down_cast<WritableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  IndexSubTableFormat3BuilderPtr output =
+      new IndexSubTableFormat3::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+CALLER_ATTACH FontDataTable* IndexSubTableFormat3::Builder::SubBuildTable(
+    ReadableFontData* data) {
+  IndexSubTableFormat3Ptr output = new IndexSubTableFormat3(
+      data, first_glyph_index(), last_glyph_index());
+  return output.Detach();
+}
+
+void IndexSubTableFormat3::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t IndexSubTableFormat3::Builder::SubDataSizeToSerialize() {
+  if (offset_array_.empty()) {
+    return InternalReadData()->Length();
+  }
+  return EblcTable::Offset::kIndexSubHeaderLength +
+         offset_array_.size() * DataSize::kULONG;
+}
+
+bool IndexSubTableFormat3::Builder::SubReadyToSerialize() {
+  if (!offset_array_.empty()) {
+    return true;
+  }
+  return false;
+}
+
+int32_t IndexSubTableFormat3::Builder::SubSerialize(
+    WritableFontData* new_data) {
+  int32_t size = SerializeIndexSubHeader(new_data);
+  if (!model_changed()) {
+    if (InternalReadData() == NULL) {
+      return size;
+    }
+    ReadableFontDataPtr source;
+    WritableFontDataPtr target;
+    source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
+        EblcTable::Offset::kIndexSubTable3_offsetArray)));
+    target.Attach(down_cast<WritableFontData*>(new_data->Slice(
+        EblcTable::Offset::kIndexSubTable3_offsetArray)));
+    size += source->CopyTo(target);
+  } else {
+    for (IntegerList::iterator b = GetOffsetArray()->begin(),
+                               e = GetOffsetArray()->end(); b != e; b++) {
+      size += new_data->WriteUShort(size, *b);
+    }
+  }
+  return size;
+}
+
+IndexSubTableFormat3::Builder::Builder()
+    : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize,
+                             IndexSubTable::Format::FORMAT_3) {
+}
+
+IndexSubTableFormat3::Builder::Builder(WritableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IndexSubTableFormat3::Builder::Builder(ReadableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IntegerList* IndexSubTableFormat3::Builder::GetOffsetArray() {
+  if (offset_array_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &offset_array_;
+}
+
+void IndexSubTableFormat3::Builder::Initialize(ReadableFontData* data) {
+  offset_array_.clear();
+  if (data) {
+    int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1;
+    for (int32_t i = 0; i < num_offsets; ++i) {
+      offset_array_.push_back(data->ReadUShort(
+         EblcTable::Offset::kIndexSubTable3_offsetArray +
+         i * DataSize::kUSHORT));
+    }
+  }
+}
+
+// static
+int32_t IndexSubTableFormat3::Builder::DataLength(
+    ReadableFontData* data,
+    int32_t index_sub_table_offset,
+    int32_t first_glyph_index,
+    int32_t last_glyph_index) {
+  UNREFERENCED_PARAMETER(data);
+  UNREFERENCED_PARAMETER(index_sub_table_offset);
+  return EblcTable::Offset::kIndexSubHeaderLength +
+         (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kUSHORT;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator class
+ ******************************************************************************/
+IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
+    IndexSubTableFormat3::Builder* container)
+    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat3::Builder,
+                  IndexSubTable::Builder>(container) {
+  glyph_id_ = container->first_glyph_index();
+}
+
+bool IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::HasNext() {
+  if (glyph_id_ <= container()->last_glyph_index()) {
+    return true;
+  }
+  return false;
+}
+
+CALLER_ATTACH BitmapGlyphInfo*
+IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::Next() {
+  BitmapGlyphInfoPtr output;
+  if (!HasNext()) {
+    // Note: In C++, we do not throw exception when there's no element.
+    return NULL;
+  }
+  output = new BitmapGlyphInfo(glyph_id_,
+                               container()->image_data_offset(),
+                               container()->GlyphStartOffset(glyph_id_),
+                               container()->GlyphLength(glyph_id_),
+                               container()->image_format());
+  glyph_id_++;
+  return output.Detach();
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/index_sub_table_format3.h b/sfntly/table/bitmap/index_sub_table_format3.h
new file mode 100644
index 0000000..d71f857
--- /dev/null
+++ b/sfntly/table/bitmap/index_sub_table_format3.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_
+
+#include "sfntly/table/bitmap/index_sub_table.h"
+
+namespace sfntly {
+// Format 3 Index Subtable Entry.
+class IndexSubTableFormat3 : public IndexSubTable,
+                             public RefCounted<IndexSubTableFormat3> {
+ public:
+  class Builder : public IndexSubTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    class BitmapGlyphInfoIterator
+        : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> {
+     public:
+      explicit BitmapGlyphInfoIterator(Builder* container);
+      virtual ~BitmapGlyphInfoIterator() {}
+
+      virtual bool HasNext();
+      CALLER_ATTACH virtual BitmapGlyphInfo* Next();
+
+     private:
+      int32_t glyph_id_;
+    };
+
+    virtual ~Builder();
+    virtual int32_t NumGlyphs();
+    virtual int32_t GlyphStartOffset(int32_t glyph_id);
+    virtual int32_t GlyphLength(int32_t glyph_id);
+    CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    void SetOffsetArray(const IntegerList& offset_array);
+
+    static CALLER_ATTACH Builder* CreateBuilder();
+    static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+    static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+
+   protected:
+    void Revert();
+
+   private:
+    Builder();
+    Builder(WritableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    Builder(ReadableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    IntegerList* GetOffsetArray();
+    void Initialize(ReadableFontData* data);
+
+    static int32_t DataLength(ReadableFontData* data,
+                              int32_t index_sub_table_offset,
+                              int32_t first_glyph_index,
+                              int32_t last_glyph_index);
+
+    IntegerList offset_array_;
+  };
+
+  virtual ~IndexSubTableFormat3();
+
+  virtual int32_t NumGlyphs();
+  virtual int32_t GlyphStartOffset(int32_t glyph_id);
+  virtual int32_t GlyphLength(int32_t glyph_id);
+
+  static int32_t GetDataLength(ReadableFontData* data,
+                               int32_t offset,
+                               int32_t first,
+                               int32_t last);
+
+ private:
+  IndexSubTableFormat3(ReadableFontData* data,
+                       int32_t first_glyph_index,
+                       int32_t last_glyph_index);
+  int32_t Loca(int32_t loca_index);
+
+  friend class Builder;
+};
+typedef Ptr<IndexSubTableFormat3> IndexSubTableFormat3Ptr;
+typedef Ptr<IndexSubTableFormat3::Builder> IndexSubTableFormat3BuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_
diff --git a/sfntly/table/bitmap/index_sub_table_format4.cc b/sfntly/table/bitmap/index_sub_table_format4.cc
new file mode 100644
index 0000000..5baa2a5
--- /dev/null
+++ b/sfntly/table/bitmap/index_sub_table_format4.cc
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/index_sub_table_format4.h"
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * IndexSubTableFormat4 class
+ ******************************************************************************/
+IndexSubTableFormat4::~IndexSubTableFormat4() {
+}
+
+int32_t IndexSubTableFormat4::NumGlyphs() {
+  return IndexSubTableFormat4::NumGlyphs(data_, 0);
+}
+
+int32_t IndexSubTableFormat4::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  int32_t pair_index = FindCodeOffsetPair(glyph_id);
+  if (pair_index < 0) {
+    return -1;
+  }
+  return data_->ReadUShort(EblcTable::Offset::kIndexSubTable4_glyphArray +
+                           pair_index *
+                           EblcTable::Offset::kCodeOffsetPairLength +
+                           EblcTable::Offset::kCodeOffsetPair_offset);
+}
+
+int32_t IndexSubTableFormat4::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+
+  int32_t pair_index = FindCodeOffsetPair(glyph_id);
+  if (pair_index < 0) {
+    return -1;
+  }
+  return data_->ReadUShort(
+             EblcTable::Offset::kIndexSubTable4_glyphArray +
+             (pair_index + 1) * EblcTable::Offset::kCodeOffsetPairLength +
+             EblcTable::Offset::kCodeOffsetPair_offset) -
+         data_->ReadUShort(
+             EblcTable::Offset::kIndexSubTable4_glyphArray +
+             (pair_index) * EblcTable::Offset::kCodeOffsetPairLength +
+             EblcTable::Offset::kCodeOffsetPair_offset);
+}
+
+IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data,
+                                           int32_t first,
+                                           int32_t last)
+    : IndexSubTable(data, first, last) {
+}
+
+int32_t IndexSubTableFormat4::FindCodeOffsetPair(int32_t glyph_id) {
+  return data_->SearchUShort(EblcTable::Offset::kIndexSubTable4_glyphArray,
+                             EblcTable::Offset::kCodeOffsetPairLength,
+                             NumGlyphs(),
+                             glyph_id);
+}
+
+int32_t IndexSubTableFormat4::NumGlyphs(ReadableFontData* data,
+                                        int32_t table_offset) {
+  int32_t num_glyphs = data->ReadULongAsInt(table_offset +
+      EblcTable::Offset::kIndexSubTable4_numGlyphs);
+  return num_glyphs;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat4::CodeOffsetPair related class
+ ******************************************************************************/
+IndexSubTableFormat4::CodeOffsetPair::CodeOffsetPair(int32_t glyph_code,
+                                                     int32_t offset)
+    : glyph_code_(glyph_code), offset_(offset) {
+}
+
+IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder()
+    : CodeOffsetPair(0, 0) {
+}
+
+IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder(
+    int32_t glyph_code, int32_t offset)
+    : CodeOffsetPair(glyph_code, offset) {
+}
+
+bool IndexSubTableFormat4::CodeOffsetPairGlyphCodeComparator::operator()(
+    const CodeOffsetPair& lhs, const CodeOffsetPair& rhs) {
+  return lhs.glyph_code() < rhs.glyph_code();
+}
+
+/******************************************************************************
+ * IndexSubTableFormat4::Builder class
+ ******************************************************************************/
+IndexSubTableFormat4::Builder::~Builder() {
+}
+
+int32_t IndexSubTableFormat4::Builder::NumGlyphs() {
+  return GetOffsetArray()->size() - 1;
+}
+
+int32_t IndexSubTableFormat4::Builder::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return 0;
+  }
+  int32_t pair_index = FindCodeOffsetPair(glyph_id);
+  if (pair_index == -1) {
+    return 0;
+  }
+  return GetOffsetArray()->at(pair_index + 1).offset() -
+         GetOffsetArray()->at(pair_index).offset();
+}
+
+int32_t IndexSubTableFormat4::Builder::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  int32_t pair_index = FindCodeOffsetPair(glyph_id);
+  if (pair_index == -1) {
+    return -1;
+  }
+  return GetOffsetArray()->at(pair_index).offset();
+}
+
+CALLER_ATTACH IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*
+    IndexSubTableFormat4::Builder::GetIterator() {
+  Ptr<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator> it =
+      new IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator(this);
+  return it.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat4::Builder*
+IndexSubTableFormat4::Builder::CreateBuilder() {
+  IndexSubTableFormat4BuilderPtr output = new IndexSubTableFormat4::Builder();
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat4::Builder*
+IndexSubTableFormat4::Builder::CreateBuilder(ReadableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  ReadableFontDataPtr new_data;
+  new_data.Attach(down_cast<ReadableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  if (new_data == NULL) {
+    return NULL;
+  }
+  IndexSubTableFormat4BuilderPtr output =
+      new IndexSubTableFormat4::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat4::Builder*
+IndexSubTableFormat4::Builder::CreateBuilder(WritableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  WritableFontDataPtr new_data;
+  new_data.Attach(down_cast<WritableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  IndexSubTableFormat4BuilderPtr output =
+      new IndexSubTableFormat4::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+CALLER_ATTACH FontDataTable* IndexSubTableFormat4::Builder::SubBuildTable(
+    ReadableFontData* data) {
+  IndexSubTableFormat4Ptr output = new IndexSubTableFormat4(
+      data, first_glyph_index(), last_glyph_index());
+  return output.Detach();
+}
+
+void IndexSubTableFormat4::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t IndexSubTableFormat4::Builder::SubDataSizeToSerialize() {
+  if (offset_pair_array_.empty()) {
+    return InternalReadData()->Length();
+  }
+  return EblcTable::Offset::kIndexSubHeaderLength + DataSize::kULONG +
+         GetOffsetArray()->size() *
+         EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength;
+}
+
+bool IndexSubTableFormat4::Builder::SubReadyToSerialize() {
+  if (!offset_pair_array_.empty()) {
+    return true;
+  }
+  return false;
+}
+
+int32_t IndexSubTableFormat4::Builder::SubSerialize(
+    WritableFontData* new_data) {
+  int32_t size = SerializeIndexSubHeader(new_data);
+  if (!model_changed()) {
+    if (InternalReadData() == NULL) {
+      return size;
+    }
+    ReadableFontDataPtr source;
+    WritableFontDataPtr target;
+    source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
+        EblcTable::Offset::kIndexSubTable4_glyphArray)));
+    target.Attach(down_cast<WritableFontData*>(new_data->Slice(
+        EblcTable::Offset::kIndexSubTable4_glyphArray)));
+    size += source->CopyTo(target);
+  } else {
+    size += new_data->WriteLong(size, offset_pair_array_.size() - 1);
+    for (std::vector<CodeOffsetPairBuilder>::iterator
+             b = GetOffsetArray()->begin(), e = GetOffsetArray()->end();
+             b != e; b++) {
+      size += new_data->WriteUShort(size, b->glyph_code());
+      size += new_data->WriteUShort(size, b->offset());
+    }
+  }
+  return size;
+}
+
+void IndexSubTableFormat4::Builder::Revert() {
+  offset_pair_array_.clear();
+  IndexSubTable::Builder::Revert();
+}
+
+void IndexSubTableFormat4::Builder::SetOffsetArray(
+    const std::vector<CodeOffsetPairBuilder>& pair_array) {
+  offset_pair_array_.clear();
+  offset_pair_array_ = pair_array;
+  set_model_changed();
+}
+
+IndexSubTableFormat4::Builder::Builder()
+  : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable4_builderDataSize,
+                           Format::FORMAT_4) {
+}
+
+IndexSubTableFormat4::Builder::Builder(WritableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IndexSubTableFormat4::Builder::Builder(ReadableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder>*
+IndexSubTableFormat4::Builder::GetOffsetArray() {
+  if (offset_pair_array_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &offset_pair_array_;
+}
+
+void IndexSubTableFormat4::Builder::Initialize(ReadableFontData* data) {
+  offset_pair_array_.clear();
+  if (data) {
+    int32_t num_pairs = IndexSubTableFormat4::NumGlyphs(data, 0) + 1;
+    int32_t offset = EblcTable::Offset::kIndexSubTable4_glyphArray;
+    for (int32_t i = 0; i < num_pairs; ++i) {
+      int32_t glyph_code = data->ReadUShort(offset +
+          EblcTable::Offset::kIndexSubTable4_codeOffsetPair_glyphCode);
+      int32_t glyph_offset = data->ReadUShort(offset +
+          EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset);
+      offset += EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength;
+      CodeOffsetPairBuilder pair_builder(glyph_code, glyph_offset);
+      offset_pair_array_.push_back(pair_builder);
+    }
+  }
+}
+
+int32_t IndexSubTableFormat4::Builder::FindCodeOffsetPair(int32_t glyph_id) {
+  std::vector<CodeOffsetPairBuilder>* pair_list = GetOffsetArray();
+  int32_t location = 0;
+  int32_t bottom = 0;
+  int32_t top = pair_list->size();
+  while (top != bottom) {
+    location = (top + bottom) / 2;
+    CodeOffsetPairBuilder* pair = &(pair_list->at(location));
+    if (glyph_id < pair->glyph_code()) {
+      // location is below current location
+      top = location;
+    } else if (glyph_id > pair->glyph_code()) {
+      // location is above current location
+      bottom = location + 1;
+    } else {
+      return location;
+    }
+  }
+  return -1;
+}
+
+// static
+int32_t IndexSubTableFormat4::Builder::DataLength(
+    ReadableFontData* data,
+    int32_t index_sub_table_offset,
+    int32_t first_glyph_index,
+    int32_t last_glyph_index) {
+  int32_t num_glyphs = IndexSubTableFormat4::NumGlyphs(data,
+                                                       index_sub_table_offset);
+  UNREFERENCED_PARAMETER(first_glyph_index);
+  UNREFERENCED_PARAMETER(last_glyph_index);
+  return EblcTable::Offset::kIndexSubTable4_glyphArray +
+         num_glyphs * EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset;
+}
+
+
+/******************************************************************************
+ * IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator class
+ ******************************************************************************/
+IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
+    IndexSubTableFormat4::Builder* container)
+    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat4::Builder,
+                  IndexSubTable::Builder>(container),
+      code_offset_pair_index_(0) {
+}
+
+bool IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::HasNext() {
+  if (code_offset_pair_index_ <
+      (int32_t)(container()->GetOffsetArray()->size() - 1)) {
+    return true;
+  }
+  return false;
+}
+
+CALLER_ATTACH BitmapGlyphInfo*
+IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::Next() {
+  BitmapGlyphInfoPtr output;
+  if (!HasNext()) {
+    // Note: In C++, we do not throw exception when there's no element.
+    return NULL;
+  }
+  std::vector<CodeOffsetPairBuilder>* offset_array =
+      container()->GetOffsetArray();
+  int32_t offset = offset_array->at(code_offset_pair_index_).offset();
+  int32_t next_offset = offset_array->at(code_offset_pair_index_ + 1).offset();
+  int32_t glyph_code = offset_array->at(code_offset_pair_index_).glyph_code();
+  output = new BitmapGlyphInfo(glyph_code,
+                               container()->image_data_offset(),
+                               offset,
+                               next_offset - offset,
+                               container()->image_format());
+  code_offset_pair_index_++;
+  return output.Detach();
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/index_sub_table_format4.h b/sfntly/table/bitmap/index_sub_table_format4.h
new file mode 100644
index 0000000..efd540f
--- /dev/null
+++ b/sfntly/table/bitmap/index_sub_table_format4.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_
+
+#include "sfntly/table/bitmap/index_sub_table.h"
+
+namespace sfntly {
+
+class IndexSubTableFormat4 : public IndexSubTable,
+                             public RefCounted<IndexSubTableFormat4> {
+ public:
+  class CodeOffsetPair {
+   public:
+    int32_t glyph_code() const { return glyph_code_; }
+    int32_t offset() const { return offset_; }
+
+   protected:
+    CodeOffsetPair(int32_t glyph_code, int32_t offset);
+
+    // TODO(arthurhsu): C++ style guide prohibits protected members.
+    int32_t glyph_code_;
+    int32_t offset_;
+  };
+
+  class CodeOffsetPairBuilder : public CodeOffsetPair {
+   public:
+    CodeOffsetPairBuilder();
+    CodeOffsetPairBuilder(int32_t glyph_code, int32_t offset);
+    void set_glyph_code(int32_t v) { glyph_code_ = v; }
+    void set_offset(int32_t v) { offset_ = v; }
+  };
+
+  class CodeOffsetPairGlyphCodeComparator {
+   public:
+    bool operator()(const CodeOffsetPair& lhs, const CodeOffsetPair& rhs);
+  };
+
+  class Builder : public IndexSubTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    class BitmapGlyphInfoIterator
+        : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> {
+     public:
+      explicit BitmapGlyphInfoIterator(Builder* container);
+      virtual ~BitmapGlyphInfoIterator() {}
+
+      virtual bool HasNext();
+      CALLER_ATTACH virtual BitmapGlyphInfo* Next();
+
+     private:
+      int32_t code_offset_pair_index_;
+    };
+
+    virtual ~Builder();
+    virtual int32_t NumGlyphs();
+    virtual int32_t GlyphLength(int32_t glyph_id);
+    virtual int32_t GlyphStartOffset(int32_t glyph_id);
+    CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    void Revert();
+    void SetOffsetArray(const std::vector<CodeOffsetPairBuilder>& pair_array);
+
+    static CALLER_ATTACH Builder* CreateBuilder();
+    static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+    static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+   private:
+    Builder();
+    Builder(WritableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    Builder(ReadableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    std::vector<CodeOffsetPairBuilder>* GetOffsetArray();
+    void Initialize(ReadableFontData* data);
+    int32_t FindCodeOffsetPair(int32_t glyph_id);
+
+    static int32_t DataLength(ReadableFontData* data,
+                              int32_t index_sub_table_offset,
+                              int32_t first_glyph_index,
+                              int32_t last_glyph_index);
+
+    std::vector<CodeOffsetPairBuilder> offset_pair_array_;
+  };
+
+  virtual ~IndexSubTableFormat4();
+
+  virtual int32_t NumGlyphs();
+  virtual int32_t GlyphStartOffset(int32_t glyph_id);
+  virtual int32_t GlyphLength(int32_t glyph_id);
+
+ private:
+  IndexSubTableFormat4(ReadableFontData* data,
+                       int32_t first_glyph_index,
+                       int32_t last_glyph_index);
+
+  int32_t FindCodeOffsetPair(int32_t glyph_id);
+  static int32_t NumGlyphs(ReadableFontData* data, int32_t table_offset);
+
+  friend class Builder;
+};
+typedef Ptr<IndexSubTableFormat4> IndexSubTableFormat4Ptr;
+typedef Ptr<IndexSubTableFormat4::Builder> IndexSubTableFormat4BuilderPtr;
+typedef std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder>
+            CodeOffsetPairBuilderList;
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_
diff --git a/sfntly/table/bitmap/index_sub_table_format5.cc b/sfntly/table/bitmap/index_sub_table_format5.cc
new file mode 100644
index 0000000..0ca21fe
--- /dev/null
+++ b/sfntly/table/bitmap/index_sub_table_format5.cc
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/index_sub_table_format5.h"
+
+#include <algorithm>
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * IndexSubTableFormat5 class
+ ******************************************************************************/
+IndexSubTableFormat5::~IndexSubTableFormat5() {
+}
+
+int32_t IndexSubTableFormat5::NumGlyphs() {
+  return NumGlyphs(data_, 0);
+}
+
+int32_t IndexSubTableFormat5::GlyphStartOffset(int32_t glyph_id) {
+  int32_t check = CheckGlyphRange(glyph_id);
+  if (check == -1) {
+    return -1;
+  }
+  int32_t loca = ReadFontData()->SearchUShort(
+      EblcTable::Offset::kIndexSubTable5_glyphArray,
+      DataSize::kUSHORT,
+      NumGlyphs(),
+      glyph_id);
+  if (loca == -1) {
+    return loca;
+  }
+  return loca * ImageSize();
+}
+
+int32_t IndexSubTableFormat5::GlyphLength(int32_t glyph_id) {
+  int32_t check = CheckGlyphRange(glyph_id);
+  if (check == -1) {
+    return 0;
+  }
+  return image_size_;
+}
+
+int32_t IndexSubTableFormat5::ImageSize() {
+  return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable5_imageSize);
+}
+
+CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat5::BigMetrics() {
+  ReadableFontDataPtr data;
+  data.Attach(down_cast<ReadableFontData*>(data_->Slice(
+      EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics,
+      BigGlyphMetrics::Offset::kMetricsLength)));
+  BigGlyphMetricsPtr output = new BigGlyphMetrics(data);
+  return output.Detach();
+}
+
+IndexSubTableFormat5::IndexSubTableFormat5(ReadableFontData* data,
+                                           int32_t first_glyph_index,
+                                           int32_t last_glyph_index)
+    : IndexSubTable(data, first_glyph_index, last_glyph_index) {
+  image_size_ = data_->ReadULongAsInt(
+      EblcTable::Offset::kIndexSubTable5_imageSize);
+}
+
+// static
+int32_t IndexSubTableFormat5::NumGlyphs(ReadableFontData* data,
+                                        int32_t table_offset) {
+  int32_t num_glyphs = data->ReadULongAsInt(table_offset +
+      EblcTable::Offset::kIndexSubTable5_numGlyphs);
+  return num_glyphs;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat5::Builder class
+ ******************************************************************************/
+IndexSubTableFormat5::Builder::~Builder() {
+}
+
+int32_t IndexSubTableFormat5::Builder::NumGlyphs() {
+  return GetGlyphArray()->size();
+}
+
+int32_t IndexSubTableFormat5::Builder::GlyphLength(int32_t glyph_id) {
+  UNREFERENCED_PARAMETER(glyph_id);
+  return ImageSize();
+}
+
+int32_t IndexSubTableFormat5::Builder::GlyphStartOffset(int32_t glyph_id) {
+  int32_t check = CheckGlyphRange(glyph_id);
+  if (check == -1) {
+    return -1;
+  }
+  IntegerList* glyph_array = GetGlyphArray();
+  IntegerList::iterator it = std::find(glyph_array->begin(),
+                                       glyph_array->end(),
+                                       glyph_id);
+  if (it == glyph_array->end()) {
+    return -1;
+  }
+  return (it - glyph_array->begin()) * ImageSize();
+}
+
+CALLER_ATTACH IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*
+    IndexSubTableFormat5::Builder::GetIterator() {
+  Ptr<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator> it =
+      new IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator(this);
+  return it.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat5::Builder*
+IndexSubTableFormat5::Builder::CreateBuilder() {
+  IndexSubTableFormat5BuilderPtr output = new IndexSubTableFormat5::Builder();
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat5::Builder*
+IndexSubTableFormat5::Builder::CreateBuilder(ReadableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  ReadableFontDataPtr new_data;
+  new_data.Attach(down_cast<ReadableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  if (new_data == NULL) {
+    return NULL;
+  }
+  IndexSubTableFormat5BuilderPtr output =
+      new IndexSubTableFormat5::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat5::Builder*
+IndexSubTableFormat5::Builder::CreateBuilder(WritableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  WritableFontDataPtr new_data;
+  new_data.Attach(down_cast<WritableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  IndexSubTableFormat5BuilderPtr output =
+      new IndexSubTableFormat5::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+CALLER_ATTACH FontDataTable* IndexSubTableFormat5::Builder::SubBuildTable(
+    ReadableFontData* data) {
+  IndexSubTableFormat5Ptr output = new IndexSubTableFormat5(
+      data, first_glyph_index(), last_glyph_index());
+  return output.Detach();
+}
+
+void IndexSubTableFormat5::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t IndexSubTableFormat5::Builder::SubDataSizeToSerialize() {
+  if (glyph_array_.empty()) {
+    return InternalReadData()->Length();
+  }
+  return EblcTable::Offset::kIndexSubTable5_builderDataSize +
+         glyph_array_.size() * DataSize::kUSHORT;
+}
+
+bool IndexSubTableFormat5::Builder::SubReadyToSerialize() {
+  if (!glyph_array_.empty()) {
+    return true;
+  }
+  return false;
+}
+
+int32_t IndexSubTableFormat5::Builder::SubSerialize(
+    WritableFontData* new_data) {
+  int32_t size = SerializeIndexSubHeader(new_data);
+  if (!model_changed()) {
+    ReadableFontDataPtr source;
+    WritableFontDataPtr target;
+    source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
+        EblcTable::Offset::kIndexSubTable5_imageSize)));
+    target.Attach(down_cast<WritableFontData*>(new_data->Slice(
+        EblcTable::Offset::kIndexSubTable5_imageSize)));
+    size += source->CopyTo(target);
+  } else {
+    size += new_data->WriteULong(EblcTable::Offset::kIndexSubTable5_imageSize,
+                                 ImageSize());
+    WritableFontDataPtr slice;
+    slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size)));
+    size += BigMetrics()->SubSerialize(slice);
+    size += new_data->WriteULong(size, glyph_array_.size());
+    for (IntegerList::iterator b = glyph_array_.begin(), e = glyph_array_.end();
+                               b != e; b++) {
+      size += new_data->WriteUShort(size, *b);
+    }
+  }
+  return size;
+}
+
+int32_t IndexSubTableFormat5::Builder::ImageSize() {
+  return InternalReadData()->ReadULongAsInt(
+      EblcTable::Offset::kIndexSubTable5_imageSize);
+}
+
+void IndexSubTableFormat5::Builder::SetImageSize(int32_t image_size) {
+  InternalWriteData()->WriteULong(
+      EblcTable::Offset::kIndexSubTable5_imageSize, image_size);
+}
+
+BigGlyphMetrics::Builder* IndexSubTableFormat5::Builder::BigMetrics() {
+  if (metrics_ == NULL) {
+    WritableFontDataPtr data;
+    data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice(
+        EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics,
+        BigGlyphMetrics::Offset::kMetricsLength)));
+    metrics_ = new BigGlyphMetrics::Builder(data);
+    set_model_changed();
+  }
+  return metrics_;
+}
+
+IntegerList* IndexSubTableFormat5::Builder::GlyphArray() {
+  return GetGlyphArray();
+}
+
+void IndexSubTableFormat5::Builder::SetGlyphArray(const IntegerList& v) {
+  glyph_array_.clear();
+  glyph_array_ = v;
+  set_model_changed();
+}
+
+void IndexSubTableFormat5::Builder::Revert() {
+  glyph_array_.clear();
+  IndexSubTable::Builder::Revert();
+}
+
+IndexSubTableFormat5::Builder::Builder()
+    : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable5_builderDataSize,
+                             IndexSubTable::Format::FORMAT_5) {
+}
+
+IndexSubTableFormat5::Builder::Builder(WritableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IndexSubTableFormat5::Builder::Builder(ReadableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IntegerList* IndexSubTableFormat5::Builder::GetGlyphArray() {
+  if (glyph_array_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &glyph_array_;
+}
+
+void IndexSubTableFormat5::Builder::Initialize(ReadableFontData* data) {
+  glyph_array_.clear();
+  if (data) {
+    int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, 0);
+    for (int32_t i = 0; i < num_glyphs; ++i) {
+      glyph_array_.push_back(data->ReadUShort(
+          EblcTable::Offset::kIndexSubTable5_glyphArray +
+          i * DataSize::kUSHORT));
+    }
+  }
+}
+
+// static
+int32_t IndexSubTableFormat5::Builder::DataLength(
+    ReadableFontData* data,
+    int32_t index_sub_table_offset,
+    int32_t first_glyph_index,
+    int32_t last_glyph_index) {
+  int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data,
+                                                       index_sub_table_offset);
+  UNREFERENCED_PARAMETER(first_glyph_index);
+  UNREFERENCED_PARAMETER(last_glyph_index);
+  return EblcTable::Offset::kIndexSubTable5_glyphArray +
+         num_glyphs * DataSize::kUSHORT;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator class
+ ******************************************************************************/
+IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
+    IndexSubTableFormat5::Builder* container)
+    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat5::Builder,
+                  IndexSubTable::Builder>(container),
+      offset_index_(0) {
+}
+
+bool IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::HasNext() {
+  if (offset_index_ < (int32_t)(container()->GetGlyphArray()->size())) {
+    return true;
+  }
+  return false;
+}
+
+CALLER_ATTACH BitmapGlyphInfo*
+IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::Next() {
+  BitmapGlyphInfoPtr output;
+  if (!HasNext()) {
+    // Note: In C++, we do not throw exception when there's no element.
+    return NULL;
+  }
+  output = new BitmapGlyphInfo(container()->GetGlyphArray()->at(offset_index_),
+                               container()->image_data_offset(),
+                               offset_index_ * container()->ImageSize(),
+                               container()->ImageSize(),
+                               container()->image_format());
+  offset_index_++;
+  return output.Detach();
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/index_sub_table_format5.h b/sfntly/table/bitmap/index_sub_table_format5.h
new file mode 100644
index 0000000..a39e88c
--- /dev/null
+++ b/sfntly/table/bitmap/index_sub_table_format5.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_
+
+#include "sfntly/table/bitmap/big_glyph_metrics.h"
+#include "sfntly/table/bitmap/index_sub_table.h"
+
+namespace sfntly {
+
+class IndexSubTableFormat5 : public IndexSubTable,
+                             public RefCounted<IndexSubTableFormat5> {
+ public:
+  class Builder : public IndexSubTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    class BitmapGlyphInfoIterator
+        : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> {
+     public:
+      explicit BitmapGlyphInfoIterator(Builder* container);
+      virtual ~BitmapGlyphInfoIterator() {}
+
+      virtual bool HasNext();
+      CALLER_ATTACH virtual BitmapGlyphInfo* Next();
+
+     private:
+      int32_t offset_index_;
+    };
+    virtual ~Builder();
+    virtual int32_t NumGlyphs();
+    virtual int32_t GlyphLength(int32_t glyph_id);
+    virtual int32_t GlyphStartOffset(int32_t glyph_id);
+    CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    int32_t ImageSize();
+    void SetImageSize(int32_t image_size);
+    BigGlyphMetrics::Builder* BigMetrics();
+    IntegerList* GlyphArray();
+    void SetGlyphArray(const IntegerList& v);
+
+    static CALLER_ATTACH Builder* CreateBuilder();
+    static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+    static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+   protected:
+    void Revert();
+
+   private:
+    Builder();
+    Builder(WritableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    Builder(ReadableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+
+    IntegerList* GetGlyphArray();
+    void Initialize(ReadableFontData* data);
+
+    static int32_t DataLength(ReadableFontData* data,
+                              int32_t index_sub_table_offset,
+                              int32_t first_glyph_index,
+                              int32_t last_glyph_index);
+
+    IntegerList glyph_array_;
+    BigGlyphMetricsBuilderPtr metrics_;
+  };
+  virtual ~IndexSubTableFormat5();
+
+  virtual int32_t NumGlyphs();
+  virtual int32_t GlyphStartOffset(int32_t glyph_id);
+  virtual int32_t GlyphLength(int32_t glyph_id);
+
+  int32_t ImageSize();
+  CALLER_ATTACH BigGlyphMetrics* BigMetrics();
+
+ private:
+  IndexSubTableFormat5(ReadableFontData* data,
+                       int32_t first_glyph_index,
+                       int32_t last_glyph_index);
+
+  static int32_t NumGlyphs(ReadableFontData* dta, int32_t table_offset);
+
+  int32_t image_size_;
+
+  friend class Builder;
+};
+typedef Ptr<IndexSubTableFormat5> IndexSubTableFormat5Ptr;
+typedef Ptr<IndexSubTableFormat5::Builder> IndexSubTableFormat5BuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_
diff --git a/sfntly/table/bitmap/simple_bitmap_glyph.cc b/sfntly/table/bitmap/simple_bitmap_glyph.cc
new file mode 100644
index 0000000..87031a1
--- /dev/null
+++ b/sfntly/table/bitmap/simple_bitmap_glyph.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/simple_bitmap_glyph.h"
+
+namespace sfntly {
+
+SimpleBitmapGlyph::SimpleBitmapGlyph(ReadableFontData* data, int32_t format)
+    : BitmapGlyph(data, format) {
+}
+
+SimpleBitmapGlyph::~SimpleBitmapGlyph() {
+}
+
+SimpleBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format)
+    : BitmapGlyph::Builder(data, format) {
+}
+
+SimpleBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format)
+    : BitmapGlyph::Builder(data, format) {
+}
+
+SimpleBitmapGlyph::Builder::~Builder() {
+}
+
+CALLER_ATTACH FontDataTable*
+SimpleBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) {
+  Ptr<SimpleBitmapGlyph> glyph = new SimpleBitmapGlyph(data, format());
+  return glyph.Detach();
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/simple_bitmap_glyph.h b/sfntly/table/bitmap/simple_bitmap_glyph.h
new file mode 100644
index 0000000..56ede10
--- /dev/null
+++ b/sfntly/table/bitmap/simple_bitmap_glyph.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_
+
+#include "sfntly/table/bitmap/bitmap_glyph.h"
+
+namespace sfntly {
+
+class SimpleBitmapGlyph : public BitmapGlyph,
+                          public RefCounted<SimpleBitmapGlyph> {
+ public:
+  class Builder : public BitmapGlyph::Builder,
+                  public RefCounted<Builder> {
+   public:
+    Builder(WritableFontData* data, int32_t format);
+    Builder(ReadableFontData* data, int32_t format);
+    virtual ~Builder();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+  };
+
+  SimpleBitmapGlyph(ReadableFontData* data, int32_t format);
+  virtual ~SimpleBitmapGlyph();
+};
+typedef Ptr<SimpleBitmapGlyph> SimpleBitmapGlyphPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_
diff --git a/sfntly/table/bitmap/small_glyph_metrics.cc b/sfntly/table/bitmap/small_glyph_metrics.cc
new file mode 100644
index 0000000..0f3c1e9
--- /dev/null
+++ b/sfntly/table/bitmap/small_glyph_metrics.cc
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/bitmap/small_glyph_metrics.h"
+
+namespace sfntly {
+/******************************************************************************
+ * SmallGlyphMetrics class
+ ******************************************************************************/
+SmallGlyphMetrics::SmallGlyphMetrics(ReadableFontData* data)
+    : GlyphMetrics(data) {
+}
+
+SmallGlyphMetrics::~SmallGlyphMetrics() {
+}
+
+int32_t SmallGlyphMetrics::Height() {
+  return data_->ReadByte(Offset::kHeight);
+}
+
+int32_t SmallGlyphMetrics::Width() {
+  return data_->ReadByte(Offset::kWidth);
+}
+
+int32_t SmallGlyphMetrics::BearingX() {
+  return data_->ReadByte(Offset::kBearingX);
+}
+
+int32_t SmallGlyphMetrics::BearingY() {
+  return data_->ReadByte(Offset::kBearingY);
+}
+
+int32_t SmallGlyphMetrics::Advance() {
+  return data_->ReadByte(Offset::kAdvance);
+}
+
+/******************************************************************************
+ * SmallGlyphMetrics::Builder class
+ ******************************************************************************/
+SmallGlyphMetrics::Builder::Builder(WritableFontData* data)
+    : GlyphMetrics::Builder(data) {
+}
+
+SmallGlyphMetrics::Builder::Builder(ReadableFontData* data)
+    : GlyphMetrics::Builder(data) {
+}
+
+SmallGlyphMetrics::Builder::~Builder() {
+}
+
+int32_t SmallGlyphMetrics::Builder::Height() {
+  return InternalReadData()->ReadByte(Offset::kHeight);
+}
+
+void SmallGlyphMetrics::Builder::SetHeight(byte_t height) {
+  InternalWriteData()->WriteByte(Offset::kHeight, height);
+}
+
+int32_t SmallGlyphMetrics::Builder::Width() {
+  return InternalReadData()->ReadByte(Offset::kWidth);
+}
+
+void SmallGlyphMetrics::Builder::SetWidth(byte_t width) {
+  InternalWriteData()->WriteByte(Offset::kWidth, width);
+}
+
+int32_t SmallGlyphMetrics::Builder::BearingX() {
+  return InternalReadData()->ReadByte(Offset::kBearingX);
+}
+
+void SmallGlyphMetrics::Builder::SetBearingX(byte_t bearing) {
+  InternalWriteData()->WriteByte(Offset::kBearingX, bearing);
+}
+
+int32_t SmallGlyphMetrics::Builder::BearingY() {
+  return InternalReadData()->ReadByte(Offset::kBearingY);
+}
+
+void SmallGlyphMetrics::Builder::SetBearingY(byte_t bearing) {
+  InternalWriteData()->WriteByte(Offset::kBearingY, bearing);
+}
+
+int32_t SmallGlyphMetrics::Builder::Advance() {
+  return InternalReadData()->ReadByte(Offset::kAdvance);
+}
+
+void SmallGlyphMetrics::Builder::SetAdvance(byte_t advance) {
+  InternalWriteData()->WriteByte(Offset::kAdvance, advance);
+}
+
+CALLER_ATTACH FontDataTable*
+    SmallGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) {
+  SmallGlyphMetricsPtr output = new SmallGlyphMetrics(data);
+  return output.Detach();
+}
+
+void SmallGlyphMetrics::Builder::SubDataSet() {
+  // NOP.
+}
+
+int32_t SmallGlyphMetrics::Builder::SubDataSizeToSerialize() {
+  return 0;
+}
+
+bool SmallGlyphMetrics::Builder::SubReadyToSerialize() {
+  return false;
+}
+
+int32_t SmallGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) {
+  return Data()->CopyTo(new_data);
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/bitmap/small_glyph_metrics.h b/sfntly/table/bitmap/small_glyph_metrics.h
new file mode 100644
index 0000000..ea13720
--- /dev/null
+++ b/sfntly/table/bitmap/small_glyph_metrics.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/table/bitmap/glyph_metrics.h"
+
+namespace sfntly {
+
+class SmallGlyphMetrics : public GlyphMetrics,
+                          public RefCounted<SmallGlyphMetrics> {
+ public:
+  struct Offset {
+    enum {
+      kMetricsLength = 5,
+      kHeight = 0,
+      kWidth = 1,
+      kBearingX = 2,
+      kBearingY = 3,
+      kAdvance = 4,
+    };
+  };
+
+  class Builder : public GlyphMetrics::Builder,
+                  public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    explicit Builder(WritableFontData* data);
+    explicit Builder(ReadableFontData* data);
+    virtual ~Builder();
+
+    int32_t Height();
+    void SetHeight(byte_t height);
+    int32_t Width();
+    void SetWidth(byte_t width);
+    int32_t BearingX();
+    void SetBearingX(byte_t bearing);
+    int32_t BearingY();
+    void SetBearingY(byte_t bearing);
+    int32_t Advance();
+    void SetAdvance(byte_t advance);
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+  };
+
+  explicit SmallGlyphMetrics(ReadableFontData* data);
+  virtual ~SmallGlyphMetrics();
+
+  int32_t Height();
+  int32_t Width();
+  int32_t BearingX();
+  int32_t BearingY();
+  int32_t Advance();
+};
+typedef Ptr<SmallGlyphMetrics> SmallGlyphMetricsPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_
diff --git a/sfntly/table/byte_array_table_builder.cc b/sfntly/table/byte_array_table_builder.cc
new file mode 100644
index 0000000..631a05f
--- /dev/null
+++ b/sfntly/table/byte_array_table_builder.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 "sfntly/table/byte_array_table_builder.h"
+
+namespace sfntly {
+
+ByteArrayTableBuilder::~ByteArrayTableBuilder() {}
+
+int32_t ByteArrayTableBuilder::ByteValue(int32_t index) {
+  ReadableFontDataPtr data = InternalReadData();
+  if (data == NULL) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("No font data for the table");
+#endif
+    return -1;
+  }
+  return data->ReadByte(index);
+}
+
+void ByteArrayTableBuilder::SetByteValue(int32_t index, byte_t b) {
+  WritableFontDataPtr data = InternalWriteData();
+  if (data == NULL) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("No font data for the table");
+#endif
+    return;
+  }
+  data->WriteByte(index, b);
+}
+
+int32_t ByteArrayTableBuilder::ByteCount() {
+  ReadableFontDataPtr data = InternalReadData();
+  if (data == NULL) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("No font data for the table");
+#endif
+    return 0;
+  }
+  return data->Length();
+}
+
+ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header,
+                                               WritableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header,
+                                               ReadableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header)
+    : TableBasedTableBuilder(header) {
+}
+
+}  // namespace sfntly
diff --git a/sfntly/table/byte_array_table_builder.h b/sfntly/table/byte_array_table_builder.h
new file mode 100644
index 0000000..42d27a8
--- /dev/null
+++ b/sfntly/table/byte_array_table_builder.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_
+
+#include "sfntly/table/table_based_table_builder.h"
+
+namespace sfntly {
+
+// An abstract builder base for byte array based tables.
+class ByteArrayTableBuilder : public TableBasedTableBuilder {
+ public:
+  virtual ~ByteArrayTableBuilder();
+
+  // Get the byte value at the specified index. The index is relative to the
+  // start of the table.
+  // @param index index relative to the start of the table
+  // @return byte value at the given index
+  virtual int32_t ByteValue(int32_t index);
+
+  // Set the byte value at the specified index. The index is relative to the
+  // start of the table.
+  // @param index index relative to the start of the table
+  // @param b byte value to set
+  virtual void SetByteValue(int32_t index, byte_t b);
+
+  // Get the number of bytes set for this table. It may include padding bytes at
+  // the end.
+  virtual int32_t ByteCount();
+
+ protected:
+  ByteArrayTableBuilder(Header* header, WritableFontData* data);
+  ByteArrayTableBuilder(Header* header, ReadableFontData* data);
+  explicit ByteArrayTableBuilder(Header* header);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_
diff --git a/sfntly/table/core/cmap_table.cc b/sfntly/table/core/cmap_table.cc
new file mode 100644
index 0000000..1c83d2e
--- /dev/null
+++ b/sfntly/table/core/cmap_table.cc
@@ -0,0 +1,1287 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+// type.h needs to be included first because of building issues on Windows
+// Type aliases we delcare are defined in other headers and make the build
+// fail otherwise.
+#include "sfntly/port/type.h"
+#include "sfntly/table/core/cmap_table.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <utility>
+
+#include "sfntly/font.h"
+#include "sfntly/math/font_math.h"
+#include "sfntly/port/endian.h"
+#include "sfntly/port/exception_type.h"
+#include "sfntly/table/core/name_table.h"
+
+namespace sfntly {
+
+const int32_t CMapTable::NOTDEF = 0;
+
+CMapTable::CMapId CMapTable::WINDOWS_BMP = {
+  PlatformId::kWindows,
+  WindowsEncodingId::kUnicodeUCS2
+};
+CMapTable::CMapId CMapTable::WINDOWS_UCS4 = {
+  PlatformId::kWindows,
+  WindowsEncodingId::kUnicodeUCS4
+};
+CMapTable::CMapId CMapTable::MAC_ROMAN = {
+  PlatformId::kWindows,
+  MacintoshEncodingId::kRoman
+};
+
+/******************************************************************************
+ * CMapTable class
+ ******************************************************************************/
+CMapTable::CMapTable(Header* header, ReadableFontData* data)
+  : SubTableContainerTable(header, data) {
+}
+
+CMapTable::~CMapTable() {}
+
+CALLER_ATTACH CMapTable::CMap* CMapTable::GetCMap(const int32_t index) {
+  if (index < 0 || index > NumCMaps()) {
+#ifndef SFNTLY_NO_EXCEPTION
+    throw IndexOutOfBoundException("Requested CMap index is out of bounds.");
+#else
+    return NULL;
+#endif
+  }
+  int32_t platform_id = PlatformId(index);
+  int32_t encoding_id = EncodingId(index);
+  CMapId cmap_id = NewCMapId(platform_id, encoding_id);
+  int32_t offset_ = Offset(index);
+  Ptr<FontDataTable::Builder> cmap_builder =
+      (CMap::Builder::GetBuilder(data_, offset_, cmap_id));
+  if (!cmap_builder) {
+#ifndef SFNTLY_NO_EXCEPTION
+    throw NoSuchElementException("Cannot find builder for requested CMap.");
+#else
+    return NULL;
+#endif
+  }
+  return down_cast<CMapTable::CMap*>(cmap_builder->Build());
+}
+
+CALLER_ATTACH CMapTable::CMap* CMapTable::GetCMap(const int32_t platform_id,
+                                                  const int32_t encoding_id) {
+  return GetCMap(NewCMapId(platform_id, encoding_id));
+}
+
+CALLER_ATTACH CMapTable::CMap*
+CMapTable::GetCMap(const CMapTable::CMapId cmap_id) {
+  CMapIdFilter id_filter(cmap_id);
+  CMapIterator cmap_iterator(this, &id_filter);
+  // There can only be one cmap with a particular CMapId
+  if (cmap_iterator.HasNext()) {
+    Ptr<CMapTable::CMap> cmap;
+    cmap.Attach(cmap_iterator.Next());
+    return cmap.Detach();
+  }
+#ifndef SFNTLY_NO_EXCEPTION
+  throw NoSuchElementException();
+#else
+  return NULL;
+#endif
+}
+
+int32_t CMapTable::Version() {
+  return data_->ReadUShort(Offset::kVersion);
+}
+
+int32_t CMapTable::NumCMaps() {
+  return data_->ReadUShort(Offset::kNumTables);
+}
+
+CMapTable::CMapId CMapTable::GetCMapId(int32_t index) {
+  return NewCMapId(PlatformId(index), EncodingId(index));
+}
+
+int32_t CMapTable::PlatformId(int32_t index) {
+  return data_->ReadUShort(Offset::kEncodingRecordPlatformId +
+                           OffsetForEncodingRecord(index));
+}
+
+int32_t CMapTable::EncodingId(int32_t index) {
+  return data_->ReadUShort(Offset::kEncodingRecordEncodingId +
+                           OffsetForEncodingRecord(index));
+}
+
+int32_t CMapTable::Offset(int32_t index) {
+  return data_->ReadULongAsInt(Offset::kEncodingRecordOffset +
+                               OffsetForEncodingRecord(index));
+}
+
+int32_t CMapTable::OffsetForEncodingRecord(int32_t index) {
+  return Offset::kEncodingRecordStart + index * Offset::kEncodingRecordSize;
+}
+
+CMapTable::CMapId CMapTable::NewCMapId(int32_t platform_id,
+                                       int32_t encoding_id) {
+  CMapId result;
+  result.platform_id = platform_id;
+  result.encoding_id = encoding_id;
+  return result;
+}
+
+CMapTable::CMapId CMapTable::NewCMapId(const CMapId& obj) {
+  CMapId result;
+  result.platform_id = obj.platform_id;
+  result.encoding_id = obj.encoding_id;
+  return result;
+}
+
+/******************************************************************************
+ * CMapTable::CMapIterator class
+ ******************************************************************************/
+CMapTable::CMapIterator::CMapIterator(CMapTable* table,
+                                      const CMapFilter* filter)
+    : table_index_(0), filter_(filter), table_(table) {
+}
+
+bool CMapTable::CMapIterator::HasNext() {
+  if (!filter_) {
+    if (table_index_ < table_->NumCMaps()) {
+      return true;
+    }
+    return false;
+  }
+
+  for (; table_index_ < table_->NumCMaps(); ++table_index_) {
+    if (filter_->accept(table_->GetCMapId(table_index_))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+CALLER_ATTACH CMapTable::CMap* CMapTable::CMapIterator::Next() {
+  if (!HasNext()) {
+#ifndef SFNTLY_NO_EXCEPTION
+    throw NoSuchElementException();
+#else
+    return NULL;
+#endif
+  }
+  CMapPtr next_cmap;
+  next_cmap.Attach(table_->GetCMap(table_index_++));
+  if (next_cmap == NULL) {
+#ifndef SFNTLY_NO_EXCEPTION
+    throw NoSuchElementException("Error during the creation of the CMap");
+#else
+    return NULL;
+#endif
+  }
+  return next_cmap.Detach();
+}
+
+/******************************************************************************
+ * CMapTable::CMapId class
+ ******************************************************************************/
+
+/******************************************************************************
+ * CMapTable::CMapIdComparator class
+ ******************************************************************************/
+
+bool CMapTable::CMapIdComparator::operator()(const CMapId& lhs,
+                                             const CMapId& rhs) const {
+  return ((lhs.platform_id << 8 | lhs.encoding_id) >
+      (rhs.platform_id << 8 | rhs.encoding_id));
+}
+
+/******************************************************************************
+ * CMapTable::CMapIdFilter class
+ ******************************************************************************/
+CMapTable::CMapIdFilter::CMapIdFilter(const CMapId wanted_id)
+    : wanted_id_(wanted_id),
+      comparator_(NULL) {
+}
+
+CMapTable::CMapIdFilter::CMapIdFilter(const CMapId wanted_id,
+                                      const CMapIdComparator* comparator)
+    : wanted_id_(wanted_id),
+      comparator_(comparator) {
+}
+
+bool CMapTable::CMapIdFilter::accept(const CMapId& cmap_id) const {
+  if (!comparator_)
+    return wanted_id_ == cmap_id;
+  return (*comparator_)(wanted_id_, cmap_id);
+}
+
+/******************************************************************************
+ * CMapTable::CMap class
+ ******************************************************************************/
+CMapTable::CMap::CMap(ReadableFontData* data, int32_t format,
+                      const CMapId& cmap_id)
+    : SubTable(data), format_(format), cmap_id_(cmap_id) {
+}
+
+CMapTable::CMap::~CMap() {
+}
+
+/******************************************************************************
+ * CMapTable::CMap::Builder class
+ ******************************************************************************/
+CMapTable::CMap::Builder::~Builder() {
+}
+
+CALLER_ATTACH CMapTable::CMap::Builder*
+    CMapTable::CMap::Builder::GetBuilder(ReadableFontData* data, int32_t offset,
+                                         const CMapId& cmap_id) {
+  // NOT IMPLEMENTED: Java enum value validation
+  int32_t format = data->ReadUShort(offset);
+  CMapBuilderPtr builder;
+  switch (format) {
+    case CMapFormat::kFormat0:
+      builder.Attach(CMapFormat0::Builder::NewInstance(data, offset, cmap_id));
+      break;
+    case CMapFormat::kFormat2:
+#if defined (SFNTLY_DEBUG_CMAP)
+      fprintf(stderr, "Requesting Format2 builder, but it's unsupported; "
+              "returning NULL\n");
+#endif
+      break;
+    case CMapFormat::kFormat4:
+      builder.Attach(CMapFormat4::Builder::NewInstance(data, offset, cmap_id));
+      break;
+    default:
+#ifdef SFNTLY_DEBUG_CMAP
+      fprintf(stderr, "Unknown builder format requested\n");
+#endif
+      break;
+  }
+  return builder.Detach();
+}
+
+CALLER_ATTACH CMapTable::CMap::Builder*
+CMapTable::CMap::Builder::GetBuilder(int32_t format, const CMapId& cmap_id) {
+  Ptr<CMapTable::CMap::Builder> builder;
+  switch (format) {
+    case CMapFormat::kFormat0:
+      builder.Attach(CMapFormat0::Builder::NewInstance(cmap_id));
+      break;
+    case CMapFormat::kFormat2:
+#if defined (SFNTLY_DEBUG_CMAP)
+      fprintf(stderr, "Requesting Format2 builder, but it's unsupported; "
+              "returning NULL\n");
+#endif
+      break;
+    case CMapFormat::kFormat4:
+      builder.Attach(CMapFormat4::Builder::NewInstance(cmap_id));
+      break;
+    default:
+#ifdef SFNTLY_DEBUG_CMAP
+      fprintf(stderr, "Unknown builder format requested\n");
+#endif
+      break;
+  }
+  return builder.Detach();
+}
+
+CMapTable::CMap::Builder::Builder(ReadableFontData* data,
+                                  int32_t format,
+                                  const CMapId& cmap_id)
+    : SubTable::Builder(data),
+      format_(format),
+      cmap_id_(cmap_id),
+      language_(0) {
+}
+
+CMapTable::CMap::Builder::Builder(WritableFontData* data,
+                                  int32_t format,
+                                  const CMapId& cmap_id)
+    : SubTable::Builder(data),
+      format_(format),
+      cmap_id_(cmap_id),
+      language_(0) {
+}
+
+int32_t CMapTable::CMap::Builder::SubSerialize(WritableFontData* new_data) {
+  return InternalReadData()->CopyTo(new_data);
+}
+
+bool CMapTable::CMap::Builder::SubReadyToSerialize() {
+  return true;
+}
+
+int32_t CMapTable::CMap::Builder::SubDataSizeToSerialize() {
+  ReadableFontDataPtr read_data = InternalReadData();
+  if (!read_data)
+    return 0;
+  return read_data->Length();
+}
+
+void CMapTable::CMap::Builder::SubDataSet() {
+  // NOP
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat0
+ ******************************************************************************/
+CMapTable::CMapFormat0::~CMapFormat0() {
+}
+
+int32_t CMapTable::CMapFormat0::Language() {
+  return 0;
+}
+
+int32_t CMapTable::CMapFormat0::GlyphId(int32_t character) {
+  if (character < 0 || character > 255) {
+    return CMapTable::NOTDEF;
+  }
+  return data_->ReadUByte(character + Offset::kFormat0GlyphIdArray);
+}
+
+CMapTable::CMapFormat0::CMapFormat0(ReadableFontData* data,
+                                    const CMapId& cmap_id)
+    : CMap(data, CMapFormat::kFormat0, cmap_id) {
+}
+
+CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat0::Iterator() {
+  return new CMapTable::CMapFormat0::CharacterIterator(0, 0xff);
+}
+
+
+/******************************************************************************
+ * CMapTable::CMapFormat0::CharacterIterator
+ ******************************************************************************/
+CMapTable::CMapFormat0::CharacterIterator::CharacterIterator(int32_t start,
+                                                             int32_t end)
+    : character_(start),
+    max_character_(end) {
+}
+
+CMapTable::CMapFormat0::CharacterIterator::~CharacterIterator() {}
+
+bool CMapTable::CMapFormat0::CharacterIterator::HasNext() {
+  return character_ < max_character_;
+}
+
+int32_t CMapTable::CMapFormat0::CharacterIterator::Next() {
+  if (HasNext())
+    return character_++;
+#ifndef SFNTLY_NO_EXCEPTION
+  throw NoSuchElementException("No more characters to iterate.");
+#endif
+  return -1;
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat0::Builder
+ ******************************************************************************/
+// static
+CALLER_ATTACH CMapTable::CMapFormat0::Builder*
+CMapTable::CMapFormat0::Builder::NewInstance(WritableFontData* data,
+                                             int32_t offset,
+                                             const CMapId& cmap_id) {
+  WritableFontDataPtr wdata;
+  if (data) {
+    wdata.Attach(down_cast<WritableFontData*>(
+        data->Slice(offset,
+                    data->ReadUShort(offset + Offset::kFormat0Length))));
+  }
+  return new Builder(wdata, CMapFormat::kFormat0, cmap_id);
+}
+
+// static
+CALLER_ATTACH CMapTable::CMapFormat0::Builder*
+CMapTable::CMapFormat0::Builder::NewInstance(ReadableFontData* data,
+                                             int32_t offset,
+                                             const CMapId& cmap_id) {
+  ReadableFontDataPtr rdata;
+  if (data) {
+    rdata.Attach(down_cast<ReadableFontData*>(
+        data->Slice(offset,
+                    data->ReadUShort(offset + Offset::kFormat0Length))));
+  }
+  return new Builder(rdata, CMapFormat::kFormat0, cmap_id);
+}
+
+// static
+CALLER_ATTACH CMapTable::CMapFormat0::Builder*
+CMapTable::CMapFormat0::Builder::NewInstance(const CMapId& cmap_id) {
+  return new Builder(cmap_id);
+}
+
+// Always call NewInstance instead of the constructor for creating a new builder
+// object! This refactoring avoids memory leaks when slicing the font data.
+CMapTable::CMapFormat0::Builder::Builder(WritableFontData* data, int32_t offset,
+                                         const CMapId& cmap_id)
+    : CMapTable::CMap::Builder(data, CMapFormat::kFormat0, cmap_id) {
+  UNREFERENCED_PARAMETER(offset);
+}
+
+CMapTable::CMapFormat0::Builder::Builder(
+    ReadableFontData* data,
+    int32_t offset,
+    const CMapId& cmap_id)
+    : CMapTable::CMap::Builder(data, CMapFormat::kFormat0, cmap_id) {
+  UNREFERENCED_PARAMETER(offset);
+}
+
+CMapTable::CMapFormat0::Builder::Builder(const CMapId& cmap_id)
+    : CMap::Builder(reinterpret_cast<ReadableFontData*>(NULL),
+                    CMapFormat::kFormat0,
+                    cmap_id) {
+}
+
+CMapTable::CMapFormat0::Builder::~Builder() {
+}
+
+CALLER_ATTACH FontDataTable*
+    CMapTable::CMapFormat0::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new CMapFormat0(data, cmap_id());
+  return table.Detach();
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat2
+ ******************************************************************************/
+CMapTable::CMapFormat2::~CMapFormat2() {
+}
+
+int32_t CMapTable::CMapFormat2::Language() {
+  return 0;
+}
+
+int32_t CMapTable::CMapFormat2::GlyphId(int32_t character) {
+  if (character > 0xffff) {
+    return CMapTable::NOTDEF;
+  }
+
+  uint32_t c = ToBE32(character);
+  byte_t high_byte = (c >> 8) & 0xff;
+  byte_t low_byte = c & 0xff;
+  int32_t offset = SubHeaderOffset(high_byte);
+
+  if (offset == 0) {
+    low_byte = high_byte;
+    high_byte = 0;
+  }
+
+  int32_t first_code = FirstCode(high_byte);
+  int32_t entry_count = EntryCount(high_byte);
+
+  if (low_byte < first_code || low_byte >= first_code + entry_count) {
+    return CMapTable::NOTDEF;
+  }
+
+  int32_t id_range_offset = IdRangeOffset(high_byte);
+
+  // position of idRangeOffset + value of idRangeOffset + index for low byte
+  // = firstcode
+  int32_t p_location = (offset + Offset::kFormat2SubHeader_idRangeOffset) +
+      id_range_offset +
+      (low_byte - first_code) * DataSize::kUSHORT;
+  int p = data_->ReadUShort(p_location);
+  if (p == 0) {
+    return CMapTable::NOTDEF;
+  }
+
+  if (offset == 0) {
+    return p;
+  }
+  int id_delta = IdDelta(high_byte);
+  return (p + id_delta) % 65536;
+}
+
+int32_t CMapTable::CMapFormat2::BytesConsumed(int32_t character) {
+  uint32_t c = ToBE32(character);
+  int32_t high_byte = (c >> 8) & 0xff;
+  int32_t offset = SubHeaderOffset(high_byte);
+  return (offset == 0) ? 1 : 2;
+}
+
+CMapTable::CMapFormat2::CMapFormat2(ReadableFontData* data,
+                                    const CMapId& cmap_id)
+    : CMap(data, CMapFormat::kFormat2, cmap_id) {
+}
+
+int32_t CMapTable::CMapFormat2::SubHeaderOffset(int32_t sub_header_index) {
+  return data_->ReadUShort(Offset::kFormat2SubHeaderKeys +
+                           sub_header_index * DataSize::kUSHORT);
+}
+
+int32_t CMapTable::CMapFormat2::FirstCode(int32_t sub_header_index) {
+  int32_t sub_header_offset = SubHeaderOffset(sub_header_index);
+  return data_->ReadUShort(sub_header_offset +
+                           Offset::kFormat2SubHeaderKeys +
+                           Offset::kFormat2SubHeader_firstCode);
+}
+
+int32_t CMapTable::CMapFormat2::EntryCount(int32_t sub_header_index) {
+  int32_t sub_header_offset = SubHeaderOffset(sub_header_index);
+  return data_->ReadUShort(sub_header_offset +
+                           Offset::kFormat2SubHeaderKeys +
+                           Offset::kFormat2SubHeader_entryCount);
+}
+
+int32_t CMapTable::CMapFormat2::IdRangeOffset(int32_t sub_header_index) {
+  int32_t sub_header_offset = SubHeaderOffset(sub_header_index);
+  return data_->ReadUShort(sub_header_offset +
+                           Offset::kFormat2SubHeaderKeys +
+                           Offset::kFormat2SubHeader_idRangeOffset);
+}
+
+int32_t CMapTable::CMapFormat2::IdDelta(int32_t sub_header_index) {
+  int32_t sub_header_offset = SubHeaderOffset(sub_header_index);
+  return data_->ReadUShort(sub_header_offset +
+                           Offset::kFormat2SubHeaderKeys +
+                           Offset::kFormat2SubHeader_idDelta);
+}
+
+CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat2::Iterator() {
+  // UNIMPLEMENTED
+  return NULL;
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat2::Builder
+ ******************************************************************************/
+CMapTable::CMapFormat2::Builder::Builder(WritableFontData* data,
+                                         int32_t offset,
+                                         const CMapId& cmap_id)
+    : CMapTable::CMap::Builder(data ? down_cast<WritableFontData*>(
+                                   data->Slice(offset, data->ReadUShort(
+                                       offset + Offset::kFormat0Length)))
+                               : reinterpret_cast<WritableFontData*>(NULL),
+                               CMapFormat::kFormat2, cmap_id) {
+  // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix.
+}
+
+CMapTable::CMapFormat2::Builder::Builder(ReadableFontData* data,
+                                         int32_t offset,
+                                         const CMapId& cmap_id)
+    : CMapTable::CMap::Builder(data ? down_cast<ReadableFontData*>(
+                                   data->Slice(offset, data->ReadUShort(
+                                       offset + Offset::kFormat0Length)))
+                               : reinterpret_cast<ReadableFontData*>(NULL),
+                               CMapFormat::kFormat2, cmap_id) {
+  // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix.
+}
+
+CMapTable::CMapFormat2::Builder::~Builder() {
+}
+
+CALLER_ATTACH FontDataTable*
+    CMapTable::CMapFormat2::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new CMapFormat2(data, cmap_id());
+  return table.Detach();
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat4
+ ******************************************************************************/
+CMapTable::CMapFormat4::CMapFormat4(ReadableFontData* data,
+                                    const CMapId& cmap_id)
+    : CMap(data, CMapFormat::kFormat4, cmap_id),
+      seg_count_(SegCount(data)),
+      start_code_offset_(StartCodeOffset(seg_count_)),
+      id_delta_offset_(IdDeltaOffset(seg_count_)),
+      glyph_id_array_offset_(GlyphIdArrayOffset(seg_count_)) {
+}
+
+CMapTable::CMapFormat4::~CMapFormat4() {
+}
+
+int32_t CMapTable::CMapFormat4::GlyphId(int32_t character) {
+  int32_t segment = data_->SearchUShort(StartCodeOffset(seg_count_),
+                                        DataSize::kUSHORT,
+                                        Offset::kFormat4EndCount,
+                                        DataSize::kUSHORT,
+                                        seg_count_,
+                                        character);
+  if (segment == -1) {
+    return CMapTable::NOTDEF;
+  }
+  int32_t start_code = StartCode(segment);
+  return RetrieveGlyphId(segment, start_code, character);
+}
+
+int32_t CMapTable::CMapFormat4::RetrieveGlyphId(int32_t segment,
+                                                int32_t start_code,
+                                                int32_t character) {
+  if (ch