Backed out changeset a94b86bdf54b (bug 1193050)
authorWes Kocher <wkocher@mozilla.com>
Wed, 14 Oct 2015 09:04:38 -0700
changeset 267738 7c8c39371dbd7a52539f4c63587c754b54c89ad6
parent 267737 653d103fbf14ee5e770db2a9bf1980375e30facc
child 267739 41166ce51f0203350ad957a5b232f4bb56d69243
push id29530
push usercbook@mozilla.com
push dateThu, 15 Oct 2015 09:53:07 +0000
treeherdermozilla-central@e193b4da0a8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1193050
milestone44.0a1
backs outa94b86bdf54bf53fdfbed5063651e6cbf2f0255b
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset a94b86bdf54b (bug 1193050)
gfx/ots/README.mozilla
gfx/ots/include/opentype-sanitiser.h
gfx/ots/src/cff.cc
gfx/ots/src/cff_type2_charstring.cc
gfx/ots/src/cff_type2_charstring.h
gfx/ots/src/cmap.cc
gfx/ots/src/cvt.cc
gfx/ots/src/fpgm.cc
gfx/ots/src/gasp.cc
gfx/ots/src/gdef.cc
gfx/ots/src/glyf.cc
gfx/ots/src/gpos.cc
gfx/ots/src/gsub.cc
gfx/ots/src/hdmx.cc
gfx/ots/src/head.cc
gfx/ots/src/hhea.cc
gfx/ots/src/hmtx.cc
gfx/ots/src/kern.cc
gfx/ots/src/layout.cc
gfx/ots/src/layout.h
gfx/ots/src/loca.cc
gfx/ots/src/ltsh.cc
gfx/ots/src/math.cc
gfx/ots/src/maxp.cc
gfx/ots/src/metrics.cc
gfx/ots/src/metrics.h
gfx/ots/src/name.cc
gfx/ots/src/os2.cc
gfx/ots/src/os2.h
gfx/ots/src/ots.cc
gfx/ots/src/ots.h
gfx/ots/src/post.cc
gfx/ots/src/prep.cc
gfx/ots/src/vdmx.cc
gfx/ots/src/vhea.cc
gfx/ots/src/vmtx.cc
gfx/ots/src/vorg.cc
gfx/ots/src/woff2.cc
gfx/ots/src/woff2.h
gfx/ots/sync.sh
--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,11 +1,11 @@
 This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
 
 Our reference repository is https://github.com/khaledhosny/ots/.
 
-Current revision: e8039a2b0f1a8ac1d2b21c088d1cbf0cd53cfe94
+Current revision: e779d45e7a96d3b97ed3d2b76db7478cb86fdd8b
 
 Upstream files included: LICENSE, src/, include/
 
 Additional files: README.mozilla, src/moz.build
 
 Additional patch: ots-visibility.patch (bug 711079).
--- a/gfx/ots/include/opentype-sanitiser.h
+++ b/gfx/ots/include/opentype-sanitiser.h
@@ -44,77 +44,81 @@ typedef unsigned __int64 uint64_t;
 #include <stdint.h>
 #endif
 
 #include <algorithm>
 #include <cassert>
 #include <cstddef>
 #include <cstring>
 
-#define OTS_TAG(c1,c2,c3,c4) ((uint32_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4))))
-#define OTS_UNTAG(tag)       ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
-
 namespace ots {
 
 // -----------------------------------------------------------------------------
 // This is an interface for an abstract stream class which is used for writing
 // the serialised results out.
 // -----------------------------------------------------------------------------
 class OTSStream {
  public:
-  OTSStream() : chksum_(0) {}
+  OTSStream() {
+    ResetChecksum();
+  }
 
   virtual ~OTSStream() {}
 
   // This should be implemented to perform the actual write.
   virtual bool WriteRaw(const void *data, size_t length) = 0;
 
   bool Write(const void *data, size_t length) {
     if (!length) return false;
 
     const size_t orig_length = length;
     size_t offset = 0;
+    if (chksum_buffer_offset_) {
+      const size_t l =
+        std::min(length, static_cast<size_t>(4) - chksum_buffer_offset_);
+      std::memcpy(chksum_buffer_ + chksum_buffer_offset_, data, l);
+      chksum_buffer_offset_ += l;
+      offset += l;
+      length -= l;
+    }
 
-    size_t chksum_offset = Tell() & 3;
-    if (chksum_offset) {
-      const size_t l = std::min(length, static_cast<size_t>(4) - chksum_offset);
-      uint32_t tmp = 0;
-      std::memcpy(reinterpret_cast<uint8_t *>(&tmp) + chksum_offset, data, l);
+    if (chksum_buffer_offset_ == 4) {
+      uint32_t tmp;
+      std::memcpy(&tmp, chksum_buffer_, 4);
       chksum_ += ntohl(tmp);
-      length -= l;
-      offset += l;
+      chksum_buffer_offset_ = 0;
     }
 
     while (length >= 4) {
       uint32_t tmp;
       std::memcpy(&tmp, reinterpret_cast<const uint8_t *>(data) + offset,
         sizeof(uint32_t));
       chksum_ += ntohl(tmp);
       length -= 4;
       offset += 4;
     }
 
     if (length) {
+      if (chksum_buffer_offset_ != 0) return false;  // not reached
       if (length > 4) return false;  // not reached
-      uint32_t tmp = 0;
-      std::memcpy(&tmp,
-                  reinterpret_cast<const uint8_t*>(data) + offset, length);
-      chksum_ += ntohl(tmp);
+      std::memcpy(chksum_buffer_,
+             reinterpret_cast<const uint8_t*>(data) + offset, length);
+      chksum_buffer_offset_ = length;
     }
 
     return WriteRaw(data, orig_length);
   }
 
   virtual bool Seek(off_t position) = 0;
   virtual off_t Tell() const = 0;
 
   virtual bool Pad(size_t bytes) {
     static const uint32_t kZero = 0;
     while (bytes >= 4) {
-      if (!Write(&kZero, 4)) return false;
+      if (!WriteTag(kZero)) return false;
       bytes -= 4;
     }
     while (bytes) {
       static const uint8_t kZerob = 0;
       if (!Write(&kZerob, 1)) return false;
       bytes--;
     }
     return true;
@@ -148,27 +152,56 @@ class OTSStream {
     v = htonl(v);
     return Write(&v, sizeof(v));
   }
 
   bool WriteR64(uint64_t v) {
     return Write(&v, sizeof(v));
   }
 
+  bool WriteTag(uint32_t v) {
+    return Write(&v, sizeof(v));
+  }
+
   void ResetChecksum() {
-    assert((Tell() & 3) == 0);
     chksum_ = 0;
+    chksum_buffer_offset_ = 0;
   }
 
   uint32_t chksum() const {
+    assert(chksum_buffer_offset_ == 0);
     return chksum_;
   }
 
+  struct ChecksumState {
+    uint32_t chksum;
+    uint8_t chksum_buffer[4];
+    unsigned chksum_buffer_offset;
+  };
+
+  ChecksumState SaveChecksumState() const {
+    ChecksumState s;
+    s.chksum = chksum_;
+    s.chksum_buffer_offset = chksum_buffer_offset_;
+    std::memcpy(s.chksum_buffer, chksum_buffer_, 4);
+
+    return s;
+  }
+
+  void RestoreChecksum(const ChecksumState &s) {
+    assert(chksum_buffer_offset_ == 0);
+    chksum_ += s.chksum;
+    chksum_buffer_offset_ = s.chksum_buffer_offset;
+    std::memcpy(chksum_buffer_, s.chksum_buffer, 4);
+  }
+
  protected:
   uint32_t chksum_;
+  uint8_t chksum_buffer_[4];
+  unsigned chksum_buffer_offset_;
 };
 
 #ifdef __GCC__
 #define MSGFUNC_FMT_ATTR __attribute__((format(printf, 2, 3)))
 #else
 #define MSGFUNC_FMT_ATTR
 #endif
 
@@ -185,28 +218,26 @@ class OTS_API OTSContext {
     virtual ~OTSContext() {}
 
     // Process a given OpenType file and write out a sanitised version
     //   output: a pointer to an object implementing the OTSStream interface. The
     //     sanitisied output will be written to this. In the even of a failure,
     //     partial output may have been written.
     //   input: the OpenType file
     //   length: the size, in bytes, of |input|
-    //   index: if the input is a font collection and index is specified, then
-    //     the corresponding font will be returned, otherwise the whole
-    //     collection. Ignored for non-collection fonts.
-    bool Process(OTSStream *output, const uint8_t *input, size_t length, uint32_t index = -1);
+    bool Process(OTSStream *output, const uint8_t *input, size_t length);
 
     // This function will be called when OTS is reporting an error.
     //   level: the severity of the generated message:
     //     0: error messages in case OTS fails to sanitize the font.
     //     1: warning messages about issue OTS fixed in the sanitized font.
     virtual void Message(int level, const char *format, ...) MSGFUNC_FMT_ATTR {}
 
     // This function will be called when OTS needs to decide what to do for a
     // font table.
-    //   tag: table tag as a platform-native unsigned integer
+    //   tag: table tag as an integer in big-endian byte order, independent of
+    //   platform endianness
     virtual TableAction GetTableAction(uint32_t tag) { return ots::TABLE_ACTION_DEFAULT; }
 };
 
 }  // namespace ots
 
 #endif  // OPENTYPE_SANITISER_H_
--- a/gfx/ots/src/cff.cc
+++ b/gfx/ots/src/cff.cc
@@ -370,27 +370,21 @@ bool ParsePrivateDictData(
       continue;
     }
 
     // got operator
     const uint32_t op = operands.back().first;
     operands.pop_back();
 
     switch (op) {
-      // hints
+      // array
       case 6:  // BlueValues
       case 7:  // OtherBlues
       case 8:  // FamilyBlues
       case 9:  // FamilyOtherBlues
-        if (operands.empty() || (operands.size() % 2) != 0) {
-          return OTS_FAILURE();
-        }
-        break;
-
-      // array
       case (12U << 8) + 12:  // StemSnapH (delta)
       case (12U << 8) + 13:  // StemSnapV (delta)
         if (operands.empty()) {
           return OTS_FAILURE();
         }
         break;
 
       // number
@@ -899,24 +893,24 @@ bool ParseDictData(const uint8_t *data, 
   }
   return true;
 }
 
 }  // namespace
 
 namespace ots {
 
-bool ots_cff_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_cff_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
-  font->cff = new OpenTypeCFF;
-  font->cff->data = data;
-  font->cff->length = length;
-  font->cff->font_dict_length = 0;
-  font->cff->local_subrs = NULL;
+  file->cff = new OpenTypeCFF;
+  file->cff->data = data;
+  file->cff->length = length;
+  file->cff->font_dict_length = 0;
+  file->cff->local_subrs = NULL;
 
   // parse "6. Header" in the Adobe Compact Font Format Specification
   uint8_t major = 0;
   uint8_t minor = 0;
   uint8_t hdr_size = 0;
   uint8_t off_size = 0;
   if (!table.ReadU8(&major)) {
     return OTS_FAILURE();
@@ -944,17 +938,17 @@ bool ots_cff_parse(Font *font, const uin
   }
 
   // parse "7. Name INDEX"
   table.set_offset(hdr_size);
   CFFIndex name_index;
   if (!ParseIndex(&table, &name_index)) {
     return OTS_FAILURE();
   }
-  if (!ParseNameData(&table, name_index, &(font->cff->name))) {
+  if (!ParseNameData(&table, name_index, &(file->cff->name))) {
     return OTS_FAILURE();
   }
 
   // parse "8. Top DICT INDEX"
   table.set_offset(name_index.offset_to_next);
   CFFIndex top_dict_index;
   if (!ParseIndex(&table, &top_dict_index)) {
     return OTS_FAILURE();
@@ -968,85 +962,80 @@ bool ots_cff_parse(Font *font, const uin
   CFFIndex string_index;
   if (!ParseIndex(&table, &string_index)) {
     return OTS_FAILURE();
   }
   if (string_index.count >= 65000 - kNStdString) {
     return OTS_FAILURE();
   }
 
-  const uint16_t num_glyphs = font->maxp->num_glyphs;
+  const uint16_t num_glyphs = file->maxp->num_glyphs;
   const size_t sid_max = string_index.count + kNStdString;
   // string_index.count == 0 is allowed.
 
   // parse "9. Top DICT Data"
   if (!ParseDictData(data, length, top_dict_index,
                      num_glyphs, sid_max,
-                     DICT_DATA_TOPLEVEL, font->cff)) {
+                     DICT_DATA_TOPLEVEL, file->cff)) {
     return OTS_FAILURE();
   }
 
   // parse "16. Global Subrs INDEX"
   table.set_offset(string_index.offset_to_next);
   CFFIndex global_subrs_index;
   if (!ParseIndex(&table, &global_subrs_index)) {
     return OTS_FAILURE();
   }
 
   // Check if all fd_index in FDSelect are valid.
   std::map<uint16_t, uint8_t>::const_iterator iter;
-  std::map<uint16_t, uint8_t>::const_iterator end = font->cff->fd_select.end();
-  for (iter = font->cff->fd_select.begin(); iter != end; ++iter) {
-    if (iter->second >= font->cff->font_dict_length) {
+  std::map<uint16_t, uint8_t>::const_iterator end = file->cff->fd_select.end();
+  for (iter = file->cff->fd_select.begin(); iter != end; ++iter) {
+    if (iter->second >= file->cff->font_dict_length) {
       return OTS_FAILURE();
     }
   }
 
   // Check if all charstrings (font hinting code for each glyph) are valid.
-  for (size_t i = 0; i < font->cff->char_strings_array.size(); ++i) {
-    if (!ValidateType2CharStringIndex(font,
-                                      *(font->cff->char_strings_array.at(i)),
+  for (size_t i = 0; i < file->cff->char_strings_array.size(); ++i) {
+    if (!ValidateType2CharStringIndex(file,
+                                      *(file->cff->char_strings_array.at(i)),
                                       global_subrs_index,
-                                      font->cff->fd_select,
-                                      font->cff->local_subrs_per_font,
-                                      font->cff->local_subrs,
+                                      file->cff->fd_select,
+                                      file->cff->local_subrs_per_font,
+                                      file->cff->local_subrs,
                                       &table)) {
       return OTS_FAILURE_MSG("Failed validating charstring set %d", (int) i);
     }
   }
 
   return true;
 }
 
-bool ots_cff_should_serialise(Font *font) {
-  return font->cff != NULL;
+bool ots_cff_should_serialise(OpenTypeFile *file) {
+  return file->cff != NULL;
 }
 
-bool ots_cff_serialise(OTSStream *out, Font *font) {
+bool ots_cff_serialise(OTSStream *out, OpenTypeFile *file) {
   // TODO(yusukes): would be better to transcode the data,
   //                rather than simple memcpy.
-  if (!out->Write(font->cff->data, font->cff->length)) {
+  if (!out->Write(file->cff->data, file->cff->length)) {
     return OTS_FAILURE();
   }
   return true;
 }
 
-void ots_cff_reuse(Font *font, Font *other) {
-  font->cff = other->cff;
-  font->cff_reused = true;
-}
-
-void ots_cff_free(Font *font) {
-  if (font->cff) {
-    for (size_t i = 0; i < font->cff->char_strings_array.size(); ++i) {
-      delete (font->cff->char_strings_array)[i];
+void ots_cff_free(OpenTypeFile *file) {
+  if (file->cff) {
+    for (size_t i = 0; i < file->cff->char_strings_array.size(); ++i) {
+      delete (file->cff->char_strings_array)[i];
     }
-    for (size_t i = 0; i < font->cff->local_subrs_per_font.size(); ++i) {
-      delete (font->cff->local_subrs_per_font)[i];
+    for (size_t i = 0; i < file->cff->local_subrs_per_font.size(); ++i) {
+      delete (file->cff->local_subrs_per_font)[i];
     }
-    delete font->cff->local_subrs;
-    delete font->cff;
+    delete file->cff->local_subrs;
+    delete file->cff;
   }
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/cff_type2_charstring.cc
+++ b/gfx/ots/src/cff_type2_charstring.cc
@@ -25,17 +25,17 @@ const size_t kMaxCharStringLength = 6553
 const size_t kMaxArgumentStack = 48;
 const size_t kMaxNumberOfStemHints = 96;
 const size_t kMaxSubrNesting = 10;
 
 // |dummy_result| should be a huge positive integer so callsubr and callgsubr
 // will fail with the dummy value.
 const int32_t dummy_result = INT_MAX;
 
-bool ExecuteType2CharString(ots::Font *font,
+bool ExecuteType2CharString(ots::OpenTypeFile *file,
                             size_t call_depth,
                             const ots::CFFIndex& global_subrs_index,
                             const ots::CFFIndex& local_subrs_index,
                             ots::Buffer *cff_table,
                             ots::Buffer *char_string,
                             std::stack<int32_t> *argument_stack,
                             bool *out_found_endchar,
                             bool *out_found_width,
@@ -220,17 +220,17 @@ bool ReadNextNumberFromType2CharString(o
 
   return true;
 }
 
 // Executes |op| and updates |argument_stack|. Returns true if the execution
 // succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively
 // calls ExecuteType2CharString() function. The arguments other than |op| and
 // |argument_stack| are passed for that reason.
-bool ExecuteType2CharStringOperator(ots::Font *font,
+bool ExecuteType2CharStringOperator(ots::OpenTypeFile *file,
                                     int32_t op,
                                     size_t call_depth,
                                     const ots::CFFIndex& global_subrs_index,
                                     const ots::CFFIndex& local_subrs_index,
                                     ots::Buffer *cff_table,
                                     ots::Buffer *char_string,
                                     std::stack<int32_t> *argument_stack,
                                     bool *out_found_endchar,
@@ -285,17 +285,17 @@ bool ExecuteType2CharStringOperator(ots:
     }
     const size_t offset = subrs_index.offsets[subr_number];
     cff_table->set_offset(offset);
     if (!cff_table->Skip(length)) {
       return OTS_FAILURE();
     }
     ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length);
 
-    return ExecuteType2CharString(font,
+    return ExecuteType2CharString(file,
                                   call_depth + 1,
                                   global_subrs_index,
                                   local_subrs_index,
                                   cff_table,
                                   &char_string_to_jump,
                                   argument_stack,
                                   out_found_endchar,
                                   in_out_found_width,
@@ -724,17 +724,17 @@ bool ExecuteType2CharStringOperator(ots:
 // cff_table: A whole CFF table which contains all global and local subroutines.
 // char_string: A charstring we'll execute. |char_string| can be a main routine
 //              in CharString INDEX, or a subroutine in GlobalSubr/LocalSubr.
 // argument_stack: The stack which an operator in |char_string| operates.
 // out_found_endchar: true is set if |char_string| contains 'endchar'.
 // in_out_found_width: true is set if |char_string| contains 'width' byte (which
 //                     is 0 or 1 byte.)
 // in_out_num_stems: total number of hstems and vstems processed so far.
-bool ExecuteType2CharString(ots::Font *font,
+bool ExecuteType2CharString(ots::OpenTypeFile *file,
                             size_t call_depth,
                             const ots::CFFIndex& global_subrs_index,
                             const ots::CFFIndex& local_subrs_index,
                             ots::Buffer *cff_table,
                             ots::Buffer *char_string,
                             std::stack<int32_t> *argument_stack,
                             bool *out_found_endchar,
                             bool *in_out_found_width,
@@ -774,17 +774,17 @@ bool ExecuteType2CharString(ots::Font *f
       argument_stack->push(operator_or_operand);
       if (argument_stack->size() > kMaxArgumentStack) {
         return OTS_FAILURE();
       }
       continue;
     }
 
     // An operator is found. Execute it.
-    if (!ExecuteType2CharStringOperator(font,
+    if (!ExecuteType2CharStringOperator(file,
                                         operator_or_operand,
                                         call_depth,
                                         global_subrs_index,
                                         local_subrs_index,
                                         cff_table,
                                         char_string,
                                         argument_stack,
                                         out_found_endchar,
@@ -840,45 +840,47 @@ bool SelectLocalSubr(const std::map<uint
   return true;
 }
 
 }  // namespace
 
 namespace ots {
 
 bool ValidateType2CharStringIndex(
-    ots::Font *font,
+    ots::OpenTypeFile *file,
     const CFFIndex& char_strings_index,
     const CFFIndex& global_subrs_index,
     const std::map<uint16_t, uint8_t> &fd_select,
     const std::vector<CFFIndex *> &local_subrs_per_font,
     const CFFIndex *local_subrs,
     Buffer* cff_table) {
-  if (char_strings_index.offsets.size() == 0) {
+  const uint16_t num_offsets =
+      static_cast<uint16_t>(char_strings_index.offsets.size());
+  if (num_offsets != char_strings_index.offsets.size() || num_offsets == 0) {
     return OTS_FAILURE();  // no charstring.
   }
 
   // For each glyph, validate the corresponding charstring.
-  for (unsigned i = 1; i < char_strings_index.offsets.size(); ++i) {
+  for (uint16_t i = 1; i < num_offsets; ++i) {
     // Prepare a Buffer object, |char_string|, which contains the charstring
     // for the |i|-th glyph.
     const size_t length =
       char_strings_index.offsets[i] - char_strings_index.offsets[i - 1];
     if (length > kMaxCharStringLength) {
       return OTS_FAILURE();
     }
     const size_t offset = char_strings_index.offsets[i - 1];
     cff_table->set_offset(offset);
     if (!cff_table->Skip(length)) {
       return OTS_FAILURE();
     }
     Buffer char_string(cff_table->buffer() + offset, length);
 
     // Get a local subrs for the glyph.
-    const unsigned glyph_index = i - 1;  // index in the map is 0-origin.
+    const uint16_t glyph_index = i - 1;  // index in the map is 0-origin.
     const CFFIndex *local_subrs_to_use = NULL;
     if (!SelectLocalSubr(fd_select,
                          local_subrs_per_font,
                          local_subrs,
                          glyph_index,
                          &local_subrs_to_use)) {
       return OTS_FAILURE();
     }
@@ -888,17 +890,17 @@ bool ValidateType2CharStringIndex(
       local_subrs_to_use = &default_empty_subrs;
     }
 
     // Check a charstring for the |i|-th glyph.
     std::stack<int32_t> argument_stack;
     bool found_endchar = false;
     bool found_width = false;
     size_t num_stems = 0;
-    if (!ExecuteType2CharString(font,
+    if (!ExecuteType2CharString(file,
                                 0 /* initial call_depth is zero */,
                                 global_subrs_index, *local_subrs_to_use,
                                 cff_table, &char_string, &argument_stack,
                                 &found_endchar, &found_width, &num_stems)) {
       return OTS_FAILURE();
     }
     if (!found_endchar) {
       return OTS_FAILURE();
--- a/gfx/ots/src/cff_type2_charstring.h
+++ b/gfx/ots/src/cff_type2_charstring.h
@@ -30,17 +30,17 @@ namespace ots {
 //                      in |char_strings_index|.
 //  fd_select: A map from glyph # to font #.
 //  local_subrs_per_font: A list of Local Subrs associated with FDArrays. Can be
 //                        empty.
 //  local_subrs: A Local Subrs associated with Top DICT. Can be NULL.
 //  cff_table: A buffer which contains actual byte code of charstring, global
 //             subroutines and local subroutines.
 bool ValidateType2CharStringIndex(
-    Font *font,
+    OpenTypeFile *file,
     const CFFIndex &char_strings_index,
     const CFFIndex &global_subrs_index,
     const std::map<uint16_t, uint8_t> &fd_select,
     const std::vector<CFFIndex *> &local_subrs_per_font,
     const CFFIndex *local_subrs,
     Buffer *cff_table);
 
 // The list of Operators. See Appendix. A in Adobe Technical Note #5177.
--- a/gfx/ots/src/cmap.cc
+++ b/gfx/ots/src/cmap.cc
@@ -56,25 +56,25 @@ const uint32_t kMongolianVSStart = 0x180
 const uint32_t kMongolianVSEnd = 0x180D;
 const uint32_t kVSStart = 0xFE00;
 const uint32_t kVSEnd = 0xFE0F;
 const uint32_t kIVSStart = 0xE0100;
 const uint32_t kIVSEnd = 0xE01EF;
 const uint32_t kUVSUpperLimit = 0xFFFFFF;
 
 // Parses Format 4 tables
-bool ParseFormat4(ots::Font *font, int platform, int encoding,
+bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
               const uint8_t *data, size_t length, uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   // 0.3.4, 3.0.4 or 3.1.4 subtables are complex and, rather than expanding the
   // whole thing and recompacting it, we validate it and include it verbatim
   // in the output.
 
-  if (!font->os2) {
+  if (!file->os2) {
     return OTS_FAILURE_MSG("Required OS/2 table missing");
   }
 
   if (!subtable.Skip(4)) {
     return OTS_FAILURE_MSG("Can't read 4 bytes at start of cmap format 4 subtable");
   }
   uint16_t language = 0;
   if (!subtable.ReadU16(&language)) {
@@ -190,25 +190,25 @@ bool ParseFormat4(ots::Font *font, int p
       return OTS_FAILURE_MSG("Out of order end range (%d <= %d)", ranges[i].end_range, ranges[i-1].end_range);
     }
     if (ranges[i].start_range <= ranges[i - 1].end_range) {
       return OTS_FAILURE_MSG("out of order start range (%d <= %d)", ranges[i].start_range, ranges[i-1].end_range);
     }
 
     // On many fonts, the value of {first, last}_char_index are incorrect.
     // Fix them.
-    if (font->os2->first_char_index != 0xFFFF &&
+    if (file->os2->first_char_index != 0xFFFF &&
         ranges[i].start_range != 0xFFFF &&
-        font->os2->first_char_index > ranges[i].start_range) {
-      font->os2->first_char_index = ranges[i].start_range;
+        file->os2->first_char_index > ranges[i].start_range) {
+      file->os2->first_char_index = ranges[i].start_range;
     }
-    if (font->os2->last_char_index != 0xFFFF &&
+    if (file->os2->last_char_index != 0xFFFF &&
         ranges[i].end_range != 0xFFFF &&
-        font->os2->last_char_index < ranges[i].end_range) {
-      font->os2->last_char_index = ranges[i].end_range;
+        file->os2->last_char_index < ranges[i].end_range) {
+      file->os2->last_char_index = ranges[i].end_range;
     }
   }
 
   // The last range must end at 0xffff
   if (ranges[segcount - 1].start_range != 0xffff || ranges[segcount - 1].end_range != 0xffff) {
     return OTS_FAILURE_MSG("Final segment start and end must be 0xFFFF (0x%04X-0x%04X)",
                            ranges[segcount - 1].start_range, ranges[segcount - 1].end_range);
   }
@@ -244,32 +244,32 @@ bool ParseFormat4(ots::Font *font, int p
         }
       }
     }
   }
 
   // We accept the table.
   // TODO(yusukes): transcode the subtable.
   if (platform == 3 && encoding == 0) {
-    font->cmap->subtable_3_0_4_data = data;
-    font->cmap->subtable_3_0_4_length = length;
+    file->cmap->subtable_3_0_4_data = data;
+    file->cmap->subtable_3_0_4_length = length;
   } else if (platform == 3 && encoding == 1) {
-    font->cmap->subtable_3_1_4_data = data;
-    font->cmap->subtable_3_1_4_length = length;
+    file->cmap->subtable_3_1_4_data = data;
+    file->cmap->subtable_3_1_4_length = length;
   } else if (platform == 0 && encoding == 3) {
-    font->cmap->subtable_0_3_4_data = data;
-    font->cmap->subtable_0_3_4_length = length;
+    file->cmap->subtable_0_3_4_data = data;
+    file->cmap->subtable_0_3_4_length = length;
   } else {
     return OTS_FAILURE_MSG("Unknown cmap subtable type (platform=%d, encoding=%d)", platform, encoding);
   }
 
   return true;
 }
 
-bool Parse31012(ots::Font *font,
+bool Parse31012(ots::OpenTypeFile *file,
                 const uint8_t *data, size_t length, uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   // Format 12 tables are simple. We parse these and fully serialise them
   // later.
 
   if (!subtable.Skip(8)) {
     return OTS_FAILURE_MSG("failed to skip the first 8 bytes of format 12 subtable");
@@ -282,21 +282,21 @@ bool Parse31012(ots::Font *font,
     return OTS_FAILURE_MSG("format 12 subtable language should be zero (%d)", language);
   }
 
   uint32_t num_groups = 0;
   if (!subtable.ReadU32(&num_groups)) {
     return OTS_FAILURE_MSG("can't read number of format 12 subtable groups");
   }
   if (num_groups == 0 || num_groups > kMaxCMAPGroups) {
-    return OTS_FAILURE_MSG("Bad format 12 subtable group count %d", num_groups);
+    return OTS_FAILURE_MSG("bad format 12 subtable group count %d", num_groups);
   }
 
   std::vector<ots::OpenTypeCMAPSubtableRange> &groups
-      = font->cmap->subtable_3_10_12;
+      = file->cmap->subtable_3_10_12;
   groups.resize(num_groups);
 
   for (unsigned i = 0; i < num_groups; ++i) {
     if (!subtable.ReadU32(&groups[i].start_range) ||
         !subtable.ReadU32(&groups[i].end_range) ||
         !subtable.ReadU32(&groups[i].start_glyph_id)) {
       return OTS_FAILURE_MSG("can't read format 12 subtable group");
     }
@@ -345,17 +345,17 @@ bool Parse31012(ots::Font *font,
       return OTS_FAILURE_MSG("overlapping format 12 subtable groups (startCharCode=0x%4X <= endCharCode=0x%4X of previous group)",
                              groups[i].start_range, groups[i-1].end_range);
     }
   }
 
   return true;
 }
 
-bool Parse31013(ots::Font *font,
+bool Parse31013(ots::OpenTypeFile *file,
                 const uint8_t *data, size_t length, uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   // Format 13 tables are simple. We parse these and fully serialise them
   // later.
 
   if (!subtable.Skip(8)) {
     return OTS_FAILURE_MSG("Bad cmap subtable length");
@@ -371,21 +371,21 @@ bool Parse31013(ots::Font *font,
   uint32_t num_groups = 0;
   if (!subtable.ReadU32(&num_groups)) {
     return OTS_FAILURE_MSG("Can't read number of groups in a cmap subtable");
   }
 
   // We limit the number of groups in the same way as in 3.10.12 tables. See
   // the comment there in
   if (num_groups == 0 || num_groups > kMaxCMAPGroups) {
-    return OTS_FAILURE_MSG("Bad format 13 subtable group count %d", num_groups);
+    return OTS_FAILURE_MSG("Bad number of groups (%d) in a cmap subtable", num_groups);
   }
 
   std::vector<ots::OpenTypeCMAPSubtableRange> &groups
-      = font->cmap->subtable_3_10_13;
+      = file->cmap->subtable_3_10_13;
   groups.resize(num_groups);
 
   for (unsigned i = 0; i < num_groups; ++i) {
     if (!subtable.ReadU32(&groups[i].start_range) ||
         !subtable.ReadU32(&groups[i].end_range) ||
         !subtable.ReadU32(&groups[i].start_glyph_id)) {
       return OTS_FAILURE_MSG("Can't read subrange structure in a cmap subtable");
     }
@@ -411,17 +411,17 @@ bool Parse31013(ots::Font *font,
     if (groups[i].start_range <= groups[i - 1].end_range) {
       return OTS_FAILURE_MSG("Overlapping subranges (%d <= %d)", groups[i].start_range, groups[i-1].end_range);
     }
   }
 
   return true;
 }
 
-bool Parse0514(ots::Font *font,
+bool Parse0514(ots::OpenTypeFile *file,
                const uint8_t *data, size_t length, uint16_t num_glyphs) {
   // Unicode Variation Selector table
   ots::Buffer subtable(data, length);
 
   // Format 14 tables are simple. We parse these and fully serialise them
   // later.
 
   // Skip format (USHORT) and length (ULONG)
@@ -429,21 +429,21 @@ bool Parse0514(ots::Font *font,
     return OTS_FAILURE_MSG("Can't read start of cmap subtable");
   }
 
   uint32_t num_records = 0;
   if (!subtable.ReadU32(&num_records)) {
     return OTS_FAILURE_MSG("Can't read number of records in cmap subtable");
   }
   if (num_records == 0 || num_records > kMaxCMAPSelectorRecords) {
-    return OTS_FAILURE_MSG("Bad format 14 subtable records count %d", num_records);
+    return OTS_FAILURE_MSG("Bad number of records (%d) in cmap subtable", num_records);
   }
 
   std::vector<ots::OpenTypeCMAPSubtableVSRecord>& records
-      = font->cmap->subtable_0_5_14;
+      = file->cmap->subtable_0_5_14;
   records.resize(num_records);
 
   for (unsigned i = 0; i < num_records; ++i) {
     if (!subtable.ReadU24(&records[i].var_selector) ||
         !subtable.ReadU32(&records[i].default_offset) ||
         !subtable.ReadU32(&records[i].non_default_offset)) {
       return OTS_FAILURE_MSG("Can't read record structure of record %d in cmap subtale", i);
     }
@@ -478,18 +478,18 @@ bool Parse0514(ots::Font *font,
   for (unsigned i = 0; i < num_records; ++i) {
     // Checks default UVS table
     if (records[i].default_offset) {
       subtable.set_offset(records[i].default_offset);
       uint32_t num_ranges = 0;
       if (!subtable.ReadU32(&num_ranges)) {
         return OTS_FAILURE_MSG("Can't read number of ranges in record %d", i);
       }
-      if (num_ranges == 0 || num_ranges > kMaxCMAPGroups) {
-        return OTS_FAILURE_MSG("Bad number of ranges (%d) in record %d", num_ranges, i);
+      if (!num_ranges || num_ranges > kMaxCMAPGroups) {
+        return OTS_FAILURE_MSG("number of ranges too high (%d > %d) in record %d", num_ranges, kMaxCMAPGroups, i);
       }
 
       uint32_t last_unicode_value = 0;
       std::vector<ots::OpenTypeCMAPSubtableVSRange>& ranges
           = records[i].ranges;
       ranges.resize(num_ranges);
 
       for (unsigned j = 0; j < num_ranges; ++j) {
@@ -512,18 +512,18 @@ bool Parse0514(ots::Font *font,
 
     // Checks non default UVS table
     if (records[i].non_default_offset) {
       subtable.set_offset(records[i].non_default_offset);
       uint32_t num_mappings = 0;
       if (!subtable.ReadU32(&num_mappings)) {
         return OTS_FAILURE_MSG("Can't read number of mappings in variation selector record %d", i);
       }
-      if (num_mappings == 0) {
-        return OTS_FAILURE_MSG("Bad number of mappings (%d) in variation selector record %d", num_mappings, i);
+      if (!num_mappings || num_mappings > kMaxCMAPGroups) {
+        return OTS_FAILURE_MSG("Number of mappings too high (%d) in variation selector record %d", num_mappings, i);
       }
 
       uint32_t last_unicode_value = 0;
       std::vector<ots::OpenTypeCMAPSubtableVSMapping>& mappings
           = records[i].mappings;
       mappings.resize(num_mappings);
 
       for (unsigned j = 0; j < num_mappings; ++j) {
@@ -541,55 +541,55 @@ bool Parse0514(ots::Font *font,
         last_unicode_value = mappings[j].unicode_value;
       }
     }
   }
 
   if (subtable.offset() != length) {
     return OTS_FAILURE_MSG("Bad subtable offset (%ld != %ld)", subtable.offset(), length);
   }
-  font->cmap->subtable_0_5_14_length = subtable.offset();
+  file->cmap->subtable_0_5_14_length = subtable.offset();
   return true;
 }
 
-bool Parse100(ots::Font *font, const uint8_t *data, size_t length) {
+bool Parse100(ots::OpenTypeFile *file, const uint8_t *data, size_t length) {
   // Mac Roman table
   ots::Buffer subtable(data, length);
 
   if (!subtable.Skip(4)) {
     return OTS_FAILURE_MSG("Bad cmap subtable");
   }
   uint16_t language = 0;
   if (!subtable.ReadU16(&language)) {
     return OTS_FAILURE_MSG("Can't read language in cmap subtable");
   }
   if (language) {
     // simsun.ttf has non-zero language id.
     OTS_WARNING("language id should be zero: %u", language);
   }
 
-  font->cmap->subtable_1_0_0.reserve(kFormat0ArraySize);
+  file->cmap->subtable_1_0_0.reserve(kFormat0ArraySize);
   for (size_t i = 0; i < kFormat0ArraySize; ++i) {
     uint8_t glyph_id = 0;
     if (!subtable.ReadU8(&glyph_id)) {
       return OTS_FAILURE_MSG("Can't read glyph id at array[%ld] in cmap subtable", i);
     }
-    font->cmap->subtable_1_0_0.push_back(glyph_id);
+    file->cmap->subtable_1_0_0.push_back(glyph_id);
   }
 
   return true;
 }
 
 }  // namespace
 
 namespace ots {
 
-bool ots_cmap_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
-  font->cmap = new OpenTypeCMAP;
+  file->cmap = new OpenTypeCMAP;
 
   uint16_t version = 0;
   uint16_t num_tables = 0;
   if (!table.ReadU16(&version) ||
       !table.ReadU16(&num_tables)) {
     return OTS_FAILURE_MSG("Can't read structure of cmap");
   }
 
@@ -733,20 +733,20 @@ bool ots_cmap_parse(Font *font, const ui
     overlap_count += (overlap_checker[i].second ? 1 : -1);
     if (overlap_count > 1) {
       return OTS_FAILURE_MSG("Excessive overlap count %d", overlap_count);
     }
   }
 
   // we grab the number of glyphs in the file from the maxp table to make sure
   // that the character map isn't referencing anything beyound this range.
-  if (!font->maxp) {
+  if (!file->maxp) {
     return OTS_FAILURE_MSG("No maxp table in font! Needed by cmap.");
   }
-  const uint16_t num_glyphs = font->maxp->num_glyphs;
+  const uint16_t num_glyphs = file->maxp->num_glyphs;
 
   // We only support a subset of the possible character map tables. Microsoft
   // 'strongly recommends' that everyone supports the Unicode BMP table with
   // the UCS-4 table for non-BMP glyphs. We'll pass the following subtables:
   //   Platform ID   Encoding ID  Format
   //   0             0            4       (Unicode Default)
   //   0             1            4       (Unicode 1.1)
   //   0             3            4       (Unicode BMP)
@@ -773,104 +773,104 @@ bool ots_cmap_parse(Font *font, const ui
       // Unicode platform
 
       if ((subtable_headers[i].encoding == 0 || subtable_headers[i].encoding == 1) &&
           (subtable_headers[i].format == 4)) {
         // parse and output the 0-0-4 and 0-1-4 tables as 3-1-4 table. Sometimes the 0-0-4
         // table actually points to MS symbol data and thus should be parsed as
         // 3-0-4 table (e.g., marqueem.ttf and quixotic.ttf). This error will be
         // recovered in ots_cmap_serialise().
-        if (!ParseFormat4(font, 3, 1, data + subtable_headers[i].offset,
+        if (!ParseFormat4(file, 3, 1, data + subtable_headers[i].offset,
                       subtable_headers[i].length, num_glyphs)) {
           return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
         }
       } else if ((subtable_headers[i].encoding == 3) &&
                  (subtable_headers[i].format == 4)) {
         // parse and output the 0-3-4 table as 0-3-4 table.
-        if (!ParseFormat4(font, 0, 3, data + subtable_headers[i].offset,
+        if (!ParseFormat4(file, 0, 3, data + subtable_headers[i].offset,
                       subtable_headers[i].length, num_glyphs)) {
           return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
         }
       } else if ((subtable_headers[i].encoding == 3) &&
                  (subtable_headers[i].format == 12)) {
         // parse and output the 0-3-12 table as 3-10-12 table.
-        if (!Parse31012(font, data + subtable_headers[i].offset,
+        if (!Parse31012(file, data + subtable_headers[i].offset,
                         subtable_headers[i].length, num_glyphs)) {
           return OTS_FAILURE_MSG("Failed to parse format 12 cmap subtable %d", i);
         }
       } else if ((subtable_headers[i].encoding == 5) &&
                  (subtable_headers[i].format == 14)) {
-        if (!Parse0514(font, data + subtable_headers[i].offset,
+        if (!Parse0514(file, data + subtable_headers[i].offset,
                        subtable_headers[i].length, num_glyphs)) {
           return OTS_FAILURE_MSG("Failed to parse format 14 cmap subtable %d", i);
         }
       }
     } else if (subtable_headers[i].platform == 1) {
       // Mac platform
 
       if ((subtable_headers[i].encoding == 0) &&
           (subtable_headers[i].format == 0)) {
         // parse and output the 1-0-0 table.
-        if (!Parse100(font, data + subtable_headers[i].offset,
+        if (!Parse100(file, data + subtable_headers[i].offset,
                       subtable_headers[i].length)) {
           return OTS_FAILURE();
         }
       }
     } else if (subtable_headers[i].platform == 3) {
       // MS platform
 
       switch (subtable_headers[i].encoding) {
         case 0:
         case 1:
           if (subtable_headers[i].format == 4) {
             // parse 3-0-4 or 3-1-4 table.
-            if (!ParseFormat4(font, subtable_headers[i].platform,
+            if (!ParseFormat4(file, subtable_headers[i].platform,
                           subtable_headers[i].encoding,
                           data + subtable_headers[i].offset,
                           subtable_headers[i].length, num_glyphs)) {
               return OTS_FAILURE();
             }
           }
           break;
         case 10:
           if (subtable_headers[i].format == 12) {
-            font->cmap->subtable_3_10_12.clear();
-            if (!Parse31012(font, data + subtable_headers[i].offset,
+            file->cmap->subtable_3_10_12.clear();
+            if (!Parse31012(file, data + subtable_headers[i].offset,
                             subtable_headers[i].length, num_glyphs)) {
               return OTS_FAILURE();
             }
           } else if (subtable_headers[i].format == 13) {
-            font->cmap->subtable_3_10_13.clear();
-            if (!Parse31013(font, data + subtable_headers[i].offset,
+            file->cmap->subtable_3_10_13.clear();
+            if (!Parse31013(file, data + subtable_headers[i].offset,
                             subtable_headers[i].length, num_glyphs)) {
               return OTS_FAILURE();
             }
           }
           break;
       }
     }
   }
 
   return true;
 }
 
-bool ots_cmap_should_serialise(Font *font) {
-  return font->cmap != NULL;
+bool ots_cmap_should_serialise(OpenTypeFile *file) {
+  return file->cmap != NULL;
 }
 
-bool ots_cmap_serialise(OTSStream *out, Font *font) {
-  const bool have_034 = font->cmap->subtable_0_3_4_data != NULL;
-  const bool have_0514 = font->cmap->subtable_0_5_14.size() != 0;
-  const bool have_100 = font->cmap->subtable_1_0_0.size() != 0;
-  const bool have_304 = font->cmap->subtable_3_0_4_data != NULL;
+bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
+  const bool have_034 = file->cmap->subtable_0_3_4_data != NULL;
+  const bool have_0514 = file->cmap->subtable_0_5_14.size() != 0;
+  const bool have_100 = file->cmap->subtable_1_0_0.size() != 0;
+  const bool have_304 = file->cmap->subtable_3_0_4_data != NULL;
   // MS Symbol and MS Unicode tables should not co-exist.
   // See the comment above in 0-0-4 parser.
-  const bool have_314 = (!have_304) && font->cmap->subtable_3_1_4_data;
-  const bool have_31012 = font->cmap->subtable_3_10_12.size() != 0;
-  const bool have_31013 = font->cmap->subtable_3_10_13.size() != 0;
+  const bool have_314 = (!have_304) && file->cmap->subtable_3_1_4_data;
+  const bool have_31012 = file->cmap->subtable_3_10_12.size() != 0;
+  const bool have_31013 = file->cmap->subtable_3_10_13.size() != 0;
   const uint16_t num_subtables = static_cast<uint16_t>(have_034) +
                                  static_cast<uint16_t>(have_0514) +
                                  static_cast<uint16_t>(have_100) +
                                  static_cast<uint16_t>(have_304) +
                                  static_cast<uint16_t>(have_314) +
                                  static_cast<uint16_t>(have_31012) +
                                  static_cast<uint16_t>(have_31013);
   const off_t table_start = out->Tell();
@@ -888,29 +888,29 @@ bool ots_cmap_serialise(OTSStream *out, 
 
   const off_t record_offset = out->Tell();
   if (!out->Pad(num_subtables * 8)) {
     return OTS_FAILURE();
   }
 
   const off_t offset_034 = out->Tell();
   if (have_034) {
-    if (!out->Write(font->cmap->subtable_0_3_4_data,
-                    font->cmap->subtable_0_3_4_length)) {
+    if (!out->Write(file->cmap->subtable_0_3_4_data,
+                    file->cmap->subtable_0_3_4_length)) {
       return OTS_FAILURE();
     }
   }
 
   const off_t offset_0514 = out->Tell();
   if (have_0514) {
     const std::vector<ots::OpenTypeCMAPSubtableVSRecord> &records
-        = font->cmap->subtable_0_5_14;
+        = file->cmap->subtable_0_5_14;
     const unsigned num_records = records.size();
     if (!out->WriteU16(14) ||
-        !out->WriteU32(font->cmap->subtable_0_5_14_length) ||
+        !out->WriteU32(file->cmap->subtable_0_5_14_length) ||
         !out->WriteU32(num_records)) {
       return OTS_FAILURE();
     }
     for (unsigned i = 0; i < num_records; ++i) {
       if (!out->WriteU24(records[i].var_selector) ||
           !out->WriteU32(records[i].default_offset) ||
           !out->WriteU32(records[i].non_default_offset)) {
         return OTS_FAILURE();
@@ -952,41 +952,41 @@ bool ots_cmap_serialise(OTSStream *out, 
 
   const off_t offset_100 = out->Tell();
   if (have_100) {
     if (!out->WriteU16(0) ||  // format
         !out->WriteU16(6 + kFormat0ArraySize) ||  // length
         !out->WriteU16(0)) {  // language
       return OTS_FAILURE();
     }
-    if (!out->Write(&(font->cmap->subtable_1_0_0[0]), kFormat0ArraySize)) {
+    if (!out->Write(&(file->cmap->subtable_1_0_0[0]), kFormat0ArraySize)) {
       return OTS_FAILURE();
     }
   }
 
   const off_t offset_304 = out->Tell();
   if (have_304) {
-    if (!out->Write(font->cmap->subtable_3_0_4_data,
-                    font->cmap->subtable_3_0_4_length)) {
+    if (!out->Write(file->cmap->subtable_3_0_4_data,
+                    file->cmap->subtable_3_0_4_length)) {
       return OTS_FAILURE();
     }
   }
 
   const off_t offset_314 = out->Tell();
   if (have_314) {
-    if (!out->Write(font->cmap->subtable_3_1_4_data,
-                    font->cmap->subtable_3_1_4_length)) {
+    if (!out->Write(file->cmap->subtable_3_1_4_data,
+                    file->cmap->subtable_3_1_4_length)) {
       return OTS_FAILURE();
     }
   }
 
   const off_t offset_31012 = out->Tell();
   if (have_31012) {
     std::vector<OpenTypeCMAPSubtableRange> &groups
-        = font->cmap->subtable_3_10_12;
+        = file->cmap->subtable_3_10_12;
     const unsigned num_groups = groups.size();
     if (!out->WriteU16(12) ||
         !out->WriteU16(0) ||
         !out->WriteU32(num_groups * 12 + 16) ||
         !out->WriteU32(0) ||
         !out->WriteU32(num_groups)) {
       return OTS_FAILURE();
     }
@@ -998,17 +998,17 @@ bool ots_cmap_serialise(OTSStream *out, 
         return OTS_FAILURE();
       }
     }
   }
 
   const off_t offset_31013 = out->Tell();
   if (have_31013) {
     std::vector<OpenTypeCMAPSubtableRange> &groups
-        = font->cmap->subtable_3_10_13;
+        = file->cmap->subtable_3_10_13;
     const unsigned num_groups = groups.size();
     if (!out->WriteU16(13) ||
         !out->WriteU16(0) ||
         !out->WriteU32(num_groups * 12 + 16) ||
         !out->WriteU32(0) ||
         !out->WriteU32(num_groups)) {
       return OTS_FAILURE();
     }
@@ -1018,16 +1018,20 @@ bool ots_cmap_serialise(OTSStream *out, 
           !out->WriteU32(groups[i].end_range) ||
           !out->WriteU32(groups[i].start_glyph_id)) {
         return OTS_FAILURE();
       }
     }
   }
 
   const off_t table_end = out->Tell();
+  // We might have hanging bytes from the above's checksum which the OTSStream
+  // then merges into the table of offsets.
+  OTSStream::ChecksumState saved_checksum = out->SaveChecksumState();
+  out->ResetChecksum();
 
   // Now seek back and write the table of offsets
   if (!out->Seek(record_offset)) {
     return OTS_FAILURE();
   }
 
   if (have_034) {
     if (!out->WriteU16(0) ||
@@ -1083,24 +1087,20 @@ bool ots_cmap_serialise(OTSStream *out, 
         !out->WriteU32(offset_31013 - table_start)) {
       return OTS_FAILURE();
     }
   }
 
   if (!out->Seek(table_end)) {
     return OTS_FAILURE();
   }
+  out->RestoreChecksum(saved_checksum);
 
   return true;
 }
 
-void ots_cmap_reuse(Font *font, Font *other) {
-  font->cmap = other->cmap;
-  font->cmap_reused = true;
-}
-
-void ots_cmap_free(Font *font) {
-  delete font->cmap;
+void ots_cmap_free(OpenTypeFile *file) {
+  delete file->cmap;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/cvt.cc
+++ b/gfx/ots/src/cvt.cc
@@ -6,21 +6,21 @@
 
 // cvt - Control Value Table
 // http://www.microsoft.com/typography/otspec/cvt.htm
 
 #define TABLE_NAME "cvt"
 
 namespace ots {
 
-bool ots_cvt_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_cvt_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
   OpenTypeCVT *cvt = new OpenTypeCVT;
-  font->cvt = cvt;
+  file->cvt = cvt;
 
   if (length >= 128 * 1024u) {
     return OTS_FAILURE_MSG("Length (%d) > 120K");  // almost all cvt tables are less than 4k bytes.
   }
 
   if (length % 2 != 0) {
     return OTS_FAILURE_MSG("Uneven cvt length (%d)", length);
   }
@@ -29,37 +29,32 @@ bool ots_cvt_parse(Font *font, const uin
     return OTS_FAILURE_MSG("Length too high");
   }
 
   cvt->data = data;
   cvt->length = length;
   return true;
 }
 
-bool ots_cvt_should_serialise(Font *font) {
-  if (!font->glyf) {
+bool ots_cvt_should_serialise(OpenTypeFile *file) {
+  if (!file->glyf) {
     return false;  // this table is not for CFF fonts.
   }
-  return font->cvt != NULL;
+  return file->cvt != NULL;
 }
 
-bool ots_cvt_serialise(OTSStream *out, Font *font) {
-  const OpenTypeCVT *cvt = font->cvt;
+bool ots_cvt_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeCVT *cvt = file->cvt;
 
   if (!out->Write(cvt->data, cvt->length)) {
     return OTS_FAILURE_MSG("Failed to write CVT table");
   }
 
   return true;
 }
 
-void ots_cvt_reuse(Font *font, Font *other) {
-  font->cvt = other->cvt;
-  font->cvt_reused = true;
-}
-
-void ots_cvt_free(Font *font) {
-  delete font->cvt;
+void ots_cvt_free(OpenTypeFile *file) {
+  delete file->cvt;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/fpgm.cc
+++ b/gfx/ots/src/fpgm.cc
@@ -6,54 +6,49 @@
 
 // fpgm - Font Program
 // http://www.microsoft.com/typography/otspec/fpgm.htm
 
 #define TABLE_NAME "fpgm"
 
 namespace ots {
 
-bool ots_fpgm_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_fpgm_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
   OpenTypeFPGM *fpgm = new OpenTypeFPGM;
-  font->fpgm = fpgm;
+  file->fpgm = fpgm;
 
   if (length >= 128 * 1024u) {
     return OTS_FAILURE_MSG("length (%ld) > 120", length);  // almost all fpgm tables are less than 5k bytes.
   }
 
   if (!table.Skip(length)) {
     return OTS_FAILURE_MSG("Bad fpgm length");
   }
 
   fpgm->data = data;
   fpgm->length = length;
   return true;
 }
 
-bool ots_fpgm_should_serialise(Font *font) {
-  if (!font->glyf) return false;  // this table is not for CFF fonts.
-  return font->fpgm != NULL;
+bool ots_fpgm_should_serialise(OpenTypeFile *file) {
+  if (!file->glyf) return false;  // this table is not for CFF fonts.
+  return file->fpgm != NULL;
 }
 
-bool ots_fpgm_serialise(OTSStream *out, Font *font) {
-  const OpenTypeFPGM *fpgm = font->fpgm;
+bool ots_fpgm_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeFPGM *fpgm = file->fpgm;
 
   if (!out->Write(fpgm->data, fpgm->length)) {
     return OTS_FAILURE_MSG("Failed to write fpgm");
   }
 
   return true;
 }
 
-void ots_fpgm_reuse(Font *font, Font *other) {
-  font->fpgm = other->fpgm;
-  font->fpgm_reused = true;
-}
-
-void ots_fpgm_free(Font *font) {
-  delete font->fpgm;
+void ots_fpgm_free(OpenTypeFile *file) {
+  delete file->fpgm;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/gasp.cc
+++ b/gfx/ots/src/gasp.cc
@@ -6,29 +6,29 @@
 
 // gasp - Grid-fitting And Scan-conversion Procedure
 // http://www.microsoft.com/typography/otspec/gasp.htm
 
 #define TABLE_NAME "gasp"
 
 #define DROP_THIS_TABLE(...) \
   do { \
-    OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
+    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
     OTS_FAILURE_MSG("Table discarded"); \
-    delete font->gasp; \
-    font->gasp = 0; \
+    delete file->gasp; \
+    file->gasp = 0; \
   } while (0)
 
 namespace ots {
 
-bool ots_gasp_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_gasp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
   OpenTypeGASP *gasp = new OpenTypeGASP;
-  font->gasp = gasp;
+  file->gasp = gasp;
 
   uint16_t num_ranges = 0;
   if (!table.ReadU16(&gasp->version) ||
       !table.ReadU16(&num_ranges)) {
     return OTS_FAILURE_MSG("Failed to read table header");
   }
 
   if (gasp->version > 1) {
@@ -75,22 +75,22 @@ bool ots_gasp_parse(Font *font, const ui
     }
 
     gasp->gasp_ranges.push_back(std::make_pair(max_ppem, behavior));
   }
 
   return true;
 }
 
-bool ots_gasp_should_serialise(Font *font) {
-  return font->gasp != NULL;
+bool ots_gasp_should_serialise(OpenTypeFile *file) {
+  return file->gasp != NULL;
 }
 
-bool ots_gasp_serialise(OTSStream *out, Font *font) {
-  const OpenTypeGASP *gasp = font->gasp;
+bool ots_gasp_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeGASP *gasp = file->gasp;
 
   const uint16_t num_ranges = static_cast<uint16_t>(gasp->gasp_ranges.size());
   if (num_ranges != gasp->gasp_ranges.size() ||
       !out->WriteU16(gasp->version) ||
       !out->WriteU16(num_ranges)) {
     return OTS_FAILURE_MSG("failed to write gasp header");
   }
 
@@ -99,21 +99,16 @@ bool ots_gasp_serialise(OTSStream *out, 
         !out->WriteU16(gasp->gasp_ranges[i].second)) {
       return OTS_FAILURE_MSG("Failed to write gasp subtable %d", i);
     }
   }
 
   return true;
 }
 
-void ots_gasp_reuse(Font *font, Font *other) {
-  font->gasp = other->gasp;
-  font->gasp_reused = true;
-}
-
-void ots_gasp_free(Font *font) {
-  delete font->gasp;
+void ots_gasp_free(OpenTypeFile *file) {
+  delete file->gasp;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
 #undef DROP_THIS_TABLE
--- a/gfx/ots/src/gdef.cc
+++ b/gfx/ots/src/gdef.cc
@@ -23,23 +23,23 @@ namespace {
 const uint16_t kMaxClassDefValue = 0xFFFF;
 // The maximum class value in the glyph class definision table.
 const uint16_t kMaxGlyphClassDefValue = 4;
 // The maximum format number of caret value tables.
 // We don't support format 3 for now. See the comment in
 // ParseLigCaretListTable() for the reason.
 const uint16_t kMaxCaretValueFormat = 2;
 
-bool ParseGlyphClassDefTable(ots::Font *font, const uint8_t *data,
+bool ParseGlyphClassDefTable(ots::OpenTypeFile *file, const uint8_t *data,
                              size_t length, const uint16_t num_glyphs) {
-  return ots::ParseClassDefTable(font, data, length, num_glyphs,
+  return ots::ParseClassDefTable(file, data, length, num_glyphs,
                                  kMaxGlyphClassDefValue);
 }
 
-bool ParseAttachListTable(ots::Font *font, const uint8_t *data,
+bool ParseAttachListTable(ots::OpenTypeFile *file, const uint8_t *data,
                           size_t length, const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   uint16_t offset_coverage = 0;
   uint16_t glyph_count = 0;
   if (!subtable.ReadU16(&offset_coverage) ||
       !subtable.ReadU16(&glyph_count)) {
     return OTS_FAILURE_MSG("Failed to read gdef header");
@@ -65,17 +65,17 @@ bool ParseAttachListTable(ots::Font *fon
     }
     if (attach_points[i] >= length ||
         attach_points[i] < attach_points_end) {
       return OTS_FAILURE_MSG("Bad attachment point %d of %d", i, attach_points[i]);
     }
   }
 
   // Parse coverage table
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage, num_glyphs)) {
     return OTS_FAILURE_MSG("Bad coverage table");
   }
 
   // Parse attach point table
   for (unsigned i = 0; i < attach_points.size(); ++i) {
     subtable.set_offset(attach_points[i]);
     uint16_t point_count = 0;
@@ -97,17 +97,17 @@ bool ParseAttachListTable(ots::Font *fon
                     last_point_index, point_index);
       }
       last_point_index = point_index;
     }
   }
   return true;
 }
 
-bool ParseLigCaretListTable(ots::Font *font, const uint8_t *data,
+bool ParseLigCaretListTable(ots::OpenTypeFile *file, const uint8_t *data,
                             size_t length, const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
   uint16_t offset_coverage = 0;
   uint16_t lig_glyph_count = 0;
   if (!subtable.ReadU16(&offset_coverage) ||
       !subtable.ReadU16(&lig_glyph_count)) {
     return OTS_FAILURE_MSG("Can't read caret structure");
   }
@@ -131,17 +131,17 @@ bool ParseLigCaretListTable(ots::Font *f
       return OTS_FAILURE_MSG("Can't read ligature glyph location %d", i);
     }
     if (lig_glyphs[i] >= length || lig_glyphs[i] < lig_glyphs_end) {
       return OTS_FAILURE_MSG("Bad ligature glyph location %d in glyph %d", lig_glyphs[i], i);
     }
   }
 
   // Parse coverage table
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage, num_glyphs)) {
     return OTS_FAILURE_MSG("Can't parse caret coverage table");
   }
 
   // Parse ligature glyph table
   for (unsigned i = 0; i < lig_glyphs.size(); ++i) {
     subtable.set_offset(lig_glyphs[i]);
     uint16_t caret_count = 0;
@@ -182,22 +182,22 @@ bool ParseLigCaretListTable(ots::Font *f
       if (!subtable.Skip(2)) {
         return OTS_FAILURE_MSG("Bad caret value table structure %d in glyph %d", j, i);
       }
     }
   }
   return true;
 }
 
-bool ParseMarkAttachClassDefTable(ots::Font *font, const uint8_t *data,
+bool ParseMarkAttachClassDefTable(ots::OpenTypeFile *file, const uint8_t *data,
                                   size_t length, const uint16_t num_glyphs) {
-  return ots::ParseClassDefTable(font, data, length, num_glyphs, kMaxClassDefValue);
+  return ots::ParseClassDefTable(file, data, length, num_glyphs, kMaxClassDefValue);
 }
 
-bool ParseMarkGlyphSetsDefTable(ots::Font *font, const uint8_t *data,
+bool ParseMarkGlyphSetsDefTable(ots::OpenTypeFile *file, const uint8_t *data,
                                 size_t length, const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
   uint16_t format = 0;
   uint16_t mark_set_count = 0;
   if (!subtable.ReadU16(&format) ||
       !subtable.ReadU16(&mark_set_count)) {
     return OTS_FAILURE_MSG("Can' read mark glyph table structure");
   }
@@ -213,161 +213,176 @@ bool ParseMarkGlyphSetsDefTable(ots::Fon
     uint32_t offset_coverage = 0;
     if (!subtable.ReadU32(&offset_coverage)) {
       return OTS_FAILURE_MSG("Can't read covrage location for mark set %d", i);
     }
     if (offset_coverage >= length ||
         offset_coverage < mark_sets_end) {
       return OTS_FAILURE_MSG("Bad coverage location %d for mark set %d", offset_coverage, i);
     }
-    if (!ots::ParseCoverageTable(font, data + offset_coverage,
+    if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                  length - offset_coverage, num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse coverage table for mark set %d", i);
     }
   }
-  font->gdef->num_mark_glyph_sets = mark_set_count;
+  file->gdef->num_mark_glyph_sets = mark_set_count;
   return true;
 }
 
 }  // namespace
 
+#define DROP_THIS_TABLE(msg_) \
+  do { \
+    OTS_FAILURE_MSG(msg_ ", table discarded"); \
+    file->gdef->data = 0; \
+    file->gdef->length = 0; \
+  } while (0)
+
 namespace ots {
 
-bool ots_gdef_parse(Font *font, const uint8_t *data, size_t length) {
-  // Grab the number of glyphs in the font from the maxp table to check
+bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  // Grab the number of glyphs in the file from the maxp table to check
   // GlyphIDs in GDEF table.
-  if (!font->maxp) {
+  if (!file->maxp) {
     return OTS_FAILURE_MSG("No maxp table in font, needed by GDEF");
   }
-  const uint16_t num_glyphs = font->maxp->num_glyphs;
+  const uint16_t num_glyphs = file->maxp->num_glyphs;
 
   Buffer table(data, length);
 
   OpenTypeGDEF *gdef = new OpenTypeGDEF;
-  font->gdef = gdef;
+  file->gdef = gdef;
 
   uint32_t version = 0;
   if (!table.ReadU32(&version)) {
-    return OTS_FAILURE_MSG("Incomplete table");
+    DROP_THIS_TABLE("Incomplete table");
+    return true;
   }
   if (version < 0x00010000 || version == 0x00010001) {
-    return OTS_FAILURE_MSG("Bad version");
+    DROP_THIS_TABLE("Bad version");
+    return true;
   }
 
   if (version >= 0x00010002) {
     gdef->version_2 = true;
   }
 
   uint16_t offset_glyph_class_def = 0;
   uint16_t offset_attach_list = 0;
   uint16_t offset_lig_caret_list = 0;
   uint16_t offset_mark_attach_class_def = 0;
   if (!table.ReadU16(&offset_glyph_class_def) ||
       !table.ReadU16(&offset_attach_list) ||
       !table.ReadU16(&offset_lig_caret_list) ||
       !table.ReadU16(&offset_mark_attach_class_def)) {
-    return OTS_FAILURE_MSG("Incomplete table");
+    DROP_THIS_TABLE("Incomplete table");
+    return true;
   }
   uint16_t offset_mark_glyph_sets_def = 0;
   if (gdef->version_2) {
     if (!table.ReadU16(&offset_mark_glyph_sets_def)) {
-      return OTS_FAILURE_MSG("Incomplete table");
+      DROP_THIS_TABLE("Incomplete table");
+      return true;
     }
   }
 
   unsigned gdef_header_end = 4 + 4 * 2;
   if (gdef->version_2)
     gdef_header_end += 2;
 
   // Parse subtables
   if (offset_glyph_class_def) {
     if (offset_glyph_class_def >= length ||
         offset_glyph_class_def < gdef_header_end) {
-      return OTS_FAILURE_MSG("Invalid offset to glyph classes");
+      DROP_THIS_TABLE("Invalid offset to glyph classes");
+      return true;
     }
-    if (!ParseGlyphClassDefTable(font, data + offset_glyph_class_def,
+    if (!ParseGlyphClassDefTable(file, data + offset_glyph_class_def,
                                  length - offset_glyph_class_def,
                                  num_glyphs)) {
-      return OTS_FAILURE_MSG("Invalid glyph classes");
+      DROP_THIS_TABLE("Invalid glyph classes");
+      return true;
     }
     gdef->has_glyph_class_def = true;
   }
 
   if (offset_attach_list) {
     if (offset_attach_list >= length ||
         offset_attach_list < gdef_header_end) {
-      return OTS_FAILURE_MSG("Invalid offset to attachment list");
+      DROP_THIS_TABLE("Invalid offset to attachment list");
+      return true;
     }
-    if (!ParseAttachListTable(font, data + offset_attach_list,
+    if (!ParseAttachListTable(file, data + offset_attach_list,
                               length - offset_attach_list,
                               num_glyphs)) {
-      return OTS_FAILURE_MSG("Invalid attachment list");
+      DROP_THIS_TABLE("Invalid attachment list");
+      return true;
     }
   }
 
   if (offset_lig_caret_list) {
     if (offset_lig_caret_list >= length ||
         offset_lig_caret_list < gdef_header_end) {
-      return OTS_FAILURE_MSG("Invalid offset to ligature caret list");
+      DROP_THIS_TABLE("Invalid offset to ligature caret list");
+      return true;
     }
-    if (!ParseLigCaretListTable(font, data + offset_lig_caret_list,
+    if (!ParseLigCaretListTable(file, data + offset_lig_caret_list,
                               length - offset_lig_caret_list,
                               num_glyphs)) {
-      return OTS_FAILURE_MSG("Invalid ligature caret list");
+      DROP_THIS_TABLE("Invalid ligature caret list");
+      return true;
     }
   }
 
   if (offset_mark_attach_class_def) {
     if (offset_mark_attach_class_def >= length ||
         offset_mark_attach_class_def < gdef_header_end) {
       return OTS_FAILURE_MSG("Invalid offset to mark attachment list");
     }
-    if (!ParseMarkAttachClassDefTable(font,
+    if (!ParseMarkAttachClassDefTable(file,
                                       data + offset_mark_attach_class_def,
                                       length - offset_mark_attach_class_def,
                                       num_glyphs)) {
-      return OTS_FAILURE_MSG("Invalid mark attachment list");
+      DROP_THIS_TABLE("Invalid mark attachment list");
+      return true;
     }
     gdef->has_mark_attachment_class_def = true;
   }
 
   if (offset_mark_glyph_sets_def) {
     if (offset_mark_glyph_sets_def >= length ||
         offset_mark_glyph_sets_def < gdef_header_end) {
       return OTS_FAILURE_MSG("invalid offset to mark glyph sets");
     }
-    if (!ParseMarkGlyphSetsDefTable(font,
+    if (!ParseMarkGlyphSetsDefTable(file,
                                     data + offset_mark_glyph_sets_def,
                                     length - offset_mark_glyph_sets_def,
                                     num_glyphs)) {
-      return OTS_FAILURE_MSG("Invalid mark glyph sets");
+      DROP_THIS_TABLE("Invalid mark glyph sets");
+      return true;
     }
     gdef->has_mark_glyph_sets_def = true;
   }
   gdef->data = data;
   gdef->length = length;
   return true;
 }
 
-bool ots_gdef_should_serialise(Font *font) {
-  return font->gdef != NULL && font->gdef->data != NULL;
+bool ots_gdef_should_serialise(OpenTypeFile *file) {
+  return file->gdef != NULL && file->gdef->data != NULL;
 }
 
-bool ots_gdef_serialise(OTSStream *out, Font *font) {
-  if (!out->Write(font->gdef->data, font->gdef->length)) {
+bool ots_gdef_serialise(OTSStream *out, OpenTypeFile *file) {
+  if (!out->Write(file->gdef->data, file->gdef->length)) {
     return OTS_FAILURE_MSG("Failed to write GDEF table");
   }
 
   return true;
 }
 
-void ots_gdef_reuse(Font *font, Font *other) {
-  font->gdef = other->gdef;
-  font->gdef_reused = true;
-}
-
-void ots_gdef_free(Font *font) {
-  delete font->gdef;
+void ots_gdef_free(OpenTypeFile *file) {
+  delete file->gdef;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
+#undef DROP_THIS_TABLE
--- a/gfx/ots/src/glyf.cc
+++ b/gfx/ots/src/glyf.cc
@@ -13,17 +13,17 @@
 
 // glyf - Glyph Data
 // http://www.microsoft.com/typography/otspec/glyf.htm
 
 #define TABLE_NAME "glyf"
 
 namespace {
 
-bool ParseFlagsForSimpleGlyph(ots::Font *font,
+bool ParseFlagsForSimpleGlyph(ots::OpenTypeFile *file,
                               ots::Buffer *table,
                               uint32_t gly_length,
                               uint32_t num_flags,
                               uint32_t *flags_count_logical,
                               uint32_t *flags_count_physical,
                               uint32_t *xy_coordinates_length) {
   uint8_t flag = 0;
   if (!table->ReadU8(&flag)) {
@@ -59,32 +59,32 @@ bool ParseFlagsForSimpleGlyph(ots::Font 
     *flags_count_logical += repeat;
     if (*flags_count_logical >= num_flags) {
       return OTS_FAILURE_MSG("Count too high (%d >= %d)", *flags_count_logical, num_flags);
     }
     ++(*flags_count_physical);
   }
 
   if ((flag & (1u << 6)) || (flag & (1u << 7))) {  // reserved flags
-    return OTS_FAILURE_MSG("Bad glyph flag value (%d), reserved flags must be set to zero", flag);
+    return OTS_FAILURE_MSG("Bad flag value (%d)", flag);
   }
 
   *xy_coordinates_length += delta;
   if (gly_length < *xy_coordinates_length) {
     return OTS_FAILURE_MSG("Glyph coordinates length too low (%d < %d)", gly_length, *xy_coordinates_length);
   }
 
   return true;
 }
 
-bool ParseSimpleGlyph(ots::Font *font, const uint8_t *data,
+bool ParseSimpleGlyph(ots::OpenTypeFile *file, const uint8_t *data,
                       ots::Buffer *table, int16_t num_contours,
                       uint32_t gly_offset, uint32_t gly_length,
                       uint32_t *new_size) {
-  ots::OpenTypeGLYF *glyf = font->glyf;
+  ots::OpenTypeGLYF *glyf = file->glyf;
 
   // read the end-points array
   uint16_t num_flags = 0;
   for (int i = 0; i < num_contours; ++i) {
     uint16_t tmp_index = 0;
     if (!table->ReadU16(&tmp_index)) {
       return OTS_FAILURE_MSG("Can't read contour index %d", i);
     }
@@ -97,18 +97,18 @@ bool ParseSimpleGlyph(ots::Font *font, c
     }
     num_flags = tmp_index + 1;
   }
 
   uint16_t bytecode_length = 0;
   if (!table->ReadU16(&bytecode_length)) {
     return OTS_FAILURE_MSG("Can't read bytecode length");
   }
-  if ((font->maxp->version_1) &&
-      (font->maxp->max_size_glyf_instructions < bytecode_length)) {
+  if ((file->maxp->version_1) &&
+      (file->maxp->max_size_glyf_instructions < bytecode_length)) {
     return OTS_FAILURE_MSG("Bytecode length too high %d", bytecode_length);
   }
 
   const uint32_t gly_header_length = 10 + num_contours * 2 + 2;
   if (gly_length < (gly_header_length + bytecode_length)) {
     return OTS_FAILURE_MSG("Glyph header length too high %d", gly_header_length);
   }
 
@@ -120,17 +120,17 @@ bool ParseSimpleGlyph(ots::Font *font, c
     return OTS_FAILURE_MSG("Can't skip bytecode of length %d", bytecode_length);
   }
 
   uint32_t flags_count_physical = 0;  // on memory
   uint32_t xy_coordinates_length = 0;
   for (uint32_t flags_count_logical = 0;
        flags_count_logical < num_flags;
        ++flags_count_logical, ++flags_count_physical) {
-    if (!ParseFlagsForSimpleGlyph(font,
+    if (!ParseFlagsForSimpleGlyph(file,
                                   table,
                                   gly_length,
                                   num_flags,
                                   &flags_count_logical,
                                   &flags_count_physical,
                                   &xy_coordinates_length)) {
       return OTS_FAILURE_MSG("Failed to parse glyph flags %d", flags_count_logical);
     }
@@ -157,28 +157,28 @@ bool ParseSimpleGlyph(ots::Font *font, c
 
   return true;
 }
 
 }  // namespace
 
 namespace ots {
 
-bool ots_glyf_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
-  if (!font->maxp || !font->loca || !font->head) {
+  if (!file->maxp || !file->loca || !file->head) {
     return OTS_FAILURE_MSG("Missing maxp or loca or head table needed by glyf table");
   }
 
   OpenTypeGLYF *glyf = new OpenTypeGLYF;
-  font->glyf = glyf;
+  file->glyf = glyf;
 
-  const unsigned num_glyphs = font->maxp->num_glyphs;
-  std::vector<uint32_t> &offsets = font->loca->offsets;
+  const unsigned num_glyphs = file->maxp->num_glyphs;
+  std::vector<uint32_t> &offsets = file->loca->offsets;
 
   if (offsets.size() != num_glyphs + 1) {
     return OTS_FAILURE_MSG("Invalide glyph offsets size %ld != %d", offsets.size(), num_glyphs + 1);
   }
 
   std::vector<uint32_t> resulting_offsets(num_glyphs + 1);
   uint32_t current_offset = 0;
 
@@ -230,17 +230,17 @@ bool ots_glyf_parse(Font *font, const ui
 
     if (xmin > xmax || ymin > ymax) {
       return OTS_FAILURE_MSG("Bad bounding box values bl=(%d, %d), tr=(%d, %d) in glyph %d", xmin, ymin, xmax, ymax, i);
     }
 
     unsigned new_size = 0;
     if (num_contours >= 0) {
       // this is a simple glyph and might contain bytecode
-      if (!ParseSimpleGlyph(font, data, &table,
+      if (!ParseSimpleGlyph(file, data, &table,
                             num_contours, gly_offset, gly_length, &new_size)) {
         return OTS_FAILURE_MSG("Failed to parse glyph %d", i);
       }
     } else {
       // it's a composite glyph without any bytecode. Enqueue the whole thing
       glyf->iov.push_back(std::make_pair(data + gly_offset,
                                          static_cast<size_t>(gly_length)));
       new_size = gly_length;
@@ -259,45 +259,40 @@ bool ots_glyf_parse(Font *font, const ui
     }
     current_offset += new_size;
   }
   resulting_offsets[num_glyphs] = current_offset;
 
   const uint16_t max16 = std::numeric_limits<uint16_t>::max();
   if ((*std::max_element(resulting_offsets.begin(),
                          resulting_offsets.end()) >= (max16 * 2u)) &&
-      (font->head->index_to_loc_format != 1)) {
+      (file->head->index_to_loc_format != 1)) {
     OTS_WARNING("2-bytes indexing is not possible (due to the padding above)");
-    font->head->index_to_loc_format = 1;
+    file->head->index_to_loc_format = 1;
   }
 
-  font->loca->offsets = resulting_offsets;
+  file->loca->offsets = resulting_offsets;
   return true;
 }
 
-bool ots_glyf_should_serialise(Font *font) {
-  return font->glyf != NULL;
+bool ots_glyf_should_serialise(OpenTypeFile *file) {
+  return file->glyf != NULL;
 }
 
-bool ots_glyf_serialise(OTSStream *out, Font *font) {
-  const OpenTypeGLYF *glyf = font->glyf;
+bool ots_glyf_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeGLYF *glyf = file->glyf;
 
   for (unsigned i = 0; i < glyf->iov.size(); ++i) {
     if (!out->Write(glyf->iov[i].first, glyf->iov[i].second)) {
       return OTS_FAILURE_MSG("Falied to write glyph %d", i);
     }
   }
 
   return true;
 }
 
-void ots_glyf_reuse(Font *font, Font *other) {
-  font->glyf = other->glyf;
-  font->glyf_reused = true;
-}
-
-void ots_glyf_free(Font *font) {
-  delete font->glyf;
+void ots_glyf_free(OpenTypeFile *file) {
+  delete file->glyf;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/gpos.cc
+++ b/gfx/ots/src/gpos.cc
@@ -33,33 +33,33 @@ enum GPOS_TYPE {
 // The size of gpos header.
 const unsigned kGposHeaderSize = 10;
 // The maximum format number for anchor tables.
 const uint16_t kMaxAnchorFormat = 3;
 // The maximum number of class value.
 const uint16_t kMaxClassDefValue = 0xFFFF;
 
 // Lookup type parsers.
-bool ParseSingleAdjustment(const ots::Font *font,
+bool ParseSingleAdjustment(const ots::OpenTypeFile *file,
                            const uint8_t *data, const size_t length);
-bool ParsePairAdjustment(const ots::Font *font,
+bool ParsePairAdjustment(const ots::OpenTypeFile *file,
                          const uint8_t *data, const size_t length);
-bool ParseCursiveAttachment(const ots::Font *font,
+bool ParseCursiveAttachment(const ots::OpenTypeFile *file,
                             const uint8_t *data, const size_t length);
-bool ParseMarkToBaseAttachment(const ots::Font *font,
+bool ParseMarkToBaseAttachment(const ots::OpenTypeFile *file,
                                const uint8_t *data, const size_t length);
-bool ParseMarkToLigatureAttachment(const ots::Font *font,
+bool ParseMarkToLigatureAttachment(const ots::OpenTypeFile *file,
                                    const uint8_t *data, const size_t length);
-bool ParseMarkToMarkAttachment(const ots::Font *font,
+bool ParseMarkToMarkAttachment(const ots::OpenTypeFile *file,
                                const uint8_t *data, const size_t length);
-bool ParseContextPositioning(const ots::Font *font,
+bool ParseContextPositioning(const ots::OpenTypeFile *file,
                              const uint8_t *data, const size_t length);
-bool ParseChainedContextPositioning(const ots::Font *font,
+bool ParseChainedContextPositioning(const ots::OpenTypeFile *file,
                                     const uint8_t *data, const size_t length);
-bool ParseExtensionPositioning(const ots::Font *font,
+bool ParseExtensionPositioning(const ots::OpenTypeFile *file,
                                const uint8_t *data, const size_t length);
 
 const ots::LookupSubtableParser::TypeParser kGposTypeParsers[] = {
   {GPOS_TYPE_SINGLE_ADJUSTMENT, ParseSingleAdjustment},
   {GPOS_TYPE_PAIR_ADJUSTMENT, ParsePairAdjustment},
   {GPOS_TYPE_CURSIVE_ATTACHMENT, ParseCursiveAttachment},
   {GPOS_TYPE_MARK_TO_BASE_ATTACHMENT, ParseMarkToBaseAttachment},
   {GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT, ParseMarkToLigatureAttachment},
@@ -71,17 +71,17 @@ const ots::LookupSubtableParser::TypePar
 
 const ots::LookupSubtableParser kGposLookupSubtableParser = {
   arraysize(kGposTypeParsers),
   GPOS_TYPE_EXTENSION_POSITIONING, kGposTypeParsers
 };
 
 // Shared Tables: ValueRecord, Anchor Table, and MarkArray
 
-bool ParseValueRecord(const ots::Font *font,
+bool ParseValueRecord(const ots::OpenTypeFile *file,
                       ots::Buffer* subtable, const uint8_t *data,
                       const size_t length, const uint16_t value_format) {
   // Check existence of adjustment fields.
   for (unsigned i = 0; i < 4; ++i) {
     if ((value_format >> i) & 0x1) {
       // Just read the field since these fileds could take an arbitrary values.
       if (!subtable->Skip(2)) {
         return OTS_FAILURE_MSG("Failed to read value reacord component");
@@ -97,26 +97,26 @@ bool ParseValueRecord(const ots::Font *f
         return OTS_FAILURE_MSG("Failed to read value record offset");
       }
       if (offset) {
         // TODO(bashi): Is it possible that device tables locate before
         // this record? No fonts contain such offset AKAIF.
         if (offset >= length) {
           return OTS_FAILURE_MSG("Value record offset too high %d >= %ld", offset, length);
         }
-        if (!ots::ParseDeviceTable(font, data + offset, length - offset)) {
+        if (!ots::ParseDeviceTable(file, data + offset, length - offset)) {
           return OTS_FAILURE_MSG("Failed to parse device table in value record");
         }
       }
     }
   }
   return true;
 }
 
-bool ParseAnchorTable(const ots::Font *font,
+bool ParseAnchorTable(const ots::OpenTypeFile *file,
                       const uint8_t *data, const size_t length) {
   ots::Buffer subtable(data, length);
 
   uint16_t format = 0;
   // Read format and skip 2 2-byte fields that could be arbitrary values.
   if (!subtable.ReadU16(&format) ||
       !subtable.Skip(4)) {
     return OTS_FAILURE_MSG("Faled to read anchor table");
@@ -141,35 +141,35 @@ bool ParseAnchorTable(const ots::Font *f
         !subtable.ReadU16(&offset_y_device)) {
       return OTS_FAILURE_MSG("Failed to read device table offsets in format 3 anchor table");
     }
     const unsigned format_end = static_cast<unsigned>(10);
     if (offset_x_device) {
       if (offset_x_device < format_end || offset_x_device >= length) {
         return OTS_FAILURE_MSG("Bad x device table offset %d", offset_x_device);
       }
-      if (!ots::ParseDeviceTable(font, data + offset_x_device,
+      if (!ots::ParseDeviceTable(file, data + offset_x_device,
                                  length - offset_x_device)) {
         return OTS_FAILURE_MSG("Failed to parse device table in anchor table");
       }
     }
     if (offset_y_device) {
       if (offset_y_device < format_end || offset_y_device >= length) {
         return OTS_FAILURE_MSG("Bad y device table offset %d", offset_y_device);
       }
-      if (!ots::ParseDeviceTable(font, data + offset_y_device,
+      if (!ots::ParseDeviceTable(file, data + offset_y_device,
                                  length - offset_y_device)) {
         return OTS_FAILURE_MSG("Failed to parse device table in anchor table");
       }
     }
   }
   return true;
 }
 
-bool ParseMarkArrayTable(const ots::Font *font,
+bool ParseMarkArrayTable(const ots::OpenTypeFile *file,
                          const uint8_t *data, const size_t length,
                          const uint16_t class_count) {
   ots::Buffer subtable(data, length);
 
   uint16_t mark_count = 0;
   if (!subtable.ReadU16(&mark_count)) {
     return OTS_FAILURE_MSG("Can't read mark table length");
   }
@@ -187,73 +187,73 @@ bool ParseMarkArrayTable(const ots::Font
       return OTS_FAILURE_MSG("Can't read mark table %d", i);
     }
     // |class_value| may take arbitrary values including 0 here so we don't
     // check the value.
     if (offset_mark_anchor < mark_records_end ||
         offset_mark_anchor >= length) {
       return OTS_FAILURE_MSG("Bad mark anchor offset %d for mark table %d", offset_mark_anchor, i);
     }
-    if (!ParseAnchorTable(font, data + offset_mark_anchor,
+    if (!ParseAnchorTable(file, data + offset_mark_anchor,
                           length - offset_mark_anchor)) {
       return OTS_FAILURE_MSG("Faled to parse anchor table for mark table %d", i);
     }
   }
 
   return true;
 }
 
 // Lookup Type 1:
 // Single Adjustment Positioning Subtable
-bool ParseSingleAdjustment(const ots::Font *font, const uint8_t *data,
+bool ParseSingleAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
                            const size_t length) {
   ots::Buffer subtable(data, length);
 
   uint16_t format = 0;
   uint16_t offset_coverage = 0;
   uint16_t value_format = 0;
   if (!subtable.ReadU16(&format) ||
       !subtable.ReadU16(&offset_coverage) ||
       !subtable.ReadU16(&value_format)) {
     return OTS_FAILURE_MSG("Can't read single adjustment information");
   }
 
   if (format == 1) {
     // Format 1 exactly one value record.
-    if (!ParseValueRecord(font, &subtable, data, length, value_format)) {
+    if (!ParseValueRecord(file, &subtable, data, length, value_format)) {
       return OTS_FAILURE_MSG("Failed to parse format 1 single adjustment table");
     }
   } else if (format == 2) {
     uint16_t value_count = 0;
     if (!subtable.ReadU16(&value_count)) {
       return OTS_FAILURE_MSG("Failed to parse format 2 single adjustment table");
     }
     for (unsigned i = 0; i < value_count; ++i) {
-      if (!ParseValueRecord(font, &subtable, data, length, value_format)) {
+      if (!ParseValueRecord(file, &subtable, data, length, value_format)) {
         return OTS_FAILURE_MSG("Failed to parse value record %d in format 2 single adjustment table", i);
       }
     }
   } else {
     return OTS_FAILURE_MSG("Bad format %d in single adjustment table", format);
   }
 
   if (offset_coverage < subtable.offset() || offset_coverage >= length) {
     return OTS_FAILURE_MSG("Bad coverage offset %d in single adjustment table", offset_coverage);
   }
 
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage,
-                               font->maxp->num_glyphs)) {
+                               file->maxp->num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table in single adjustment table");
   }
 
   return true;
 }
 
-bool ParsePairSetTable(const ots::Font *font,
+bool ParsePairSetTable(const ots::OpenTypeFile *file,
                        const uint8_t *data, const size_t length,
                        const uint16_t value_format1,
                        const uint16_t value_format2,
                        const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   uint16_t value_count = 0;
   if (!subtable.ReadU16(&value_count)) {
@@ -263,27 +263,27 @@ bool ParsePairSetTable(const ots::Font *
     // Check pair value record.
     uint16_t glyph_id = 0;
     if (!subtable.ReadU16(&glyph_id)) {
       return OTS_FAILURE_MSG("Failed to read glyph in pair value record %d", i);
     }
     if (glyph_id >= num_glyphs) {
       return OTS_FAILURE_MSG("glyph id %d too high >= %d", glyph_id, num_glyphs);
     }
-    if (!ParseValueRecord(font, &subtable, data, length, value_format1)) {
+    if (!ParseValueRecord(file, &subtable, data, length, value_format1)) {
       return OTS_FAILURE_MSG("Failed to parse value record in format 1 pair set table");
     }
-    if (!ParseValueRecord(font, &subtable, data, length, value_format2)) {
+    if (!ParseValueRecord(file, &subtable, data, length, value_format2)) {
       return OTS_FAILURE_MSG("Failed to parse value record in format 2 pair set table");
     }
   }
   return true;
 }
 
-bool ParsePairPosFormat1(const ots::Font *font,
+bool ParsePairPosFormat1(const ots::OpenTypeFile *file,
                          const uint8_t *data, const size_t length,
                          const uint16_t value_format1,
                          const uint16_t value_format2,
                          const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   // Skip 8 bytes that are already read before.
   if (!subtable.Skip(8)) {
@@ -303,27 +303,27 @@ bool ParsePairPosFormat1(const ots::Font
     uint16_t pair_set_offset = 0;
     if (!subtable.ReadU16(&pair_set_offset)) {
       return OTS_FAILURE_MSG("Failed to read pair set offset for pair set %d", i);
     }
     if (pair_set_offset < pair_pos_end || pair_set_offset >= length) {
       return OTS_FAILURE_MSG("Bad pair set offset %d for pair set %d", pair_set_offset, i);
     }
     // Check pair set tables
-    if (!ParsePairSetTable(font, data + pair_set_offset, length - pair_set_offset,
+    if (!ParsePairSetTable(file, data + pair_set_offset, length - pair_set_offset,
                            value_format1, value_format2,
                            num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse pair set table %d", i);
     }
   }
 
   return true;
 }
 
-bool ParsePairPosFormat2(const ots::Font *font,
+bool ParsePairPosFormat2(const ots::OpenTypeFile *file,
                          const uint8_t *data, const size_t length,
                          const uint16_t value_format1,
                          const uint16_t value_format2,
                          const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   // Skip 8 bytes that are already read before.
   if (!subtable.Skip(8)) {
@@ -340,92 +340,92 @@ bool ParsePairPosFormat2(const ots::Font
       !subtable.ReadU16(&class2_count)) {
     return OTS_FAILURE_MSG("Failed to read pair pos format 2 data");
   }
 
   // Check class 1 records.
   for (unsigned i = 0; i < class1_count; ++i) {
     // Check class 2 records.
     for (unsigned j = 0; j < class2_count; ++j) {
-      if (value_format1 && !ParseValueRecord(font, &subtable, data, length,
+      if (value_format1 && !ParseValueRecord(file, &subtable, data, length,
                                              value_format1)) {
         return OTS_FAILURE_MSG("Failed to parse value record 1 %d and %d", j, i);
       }
-      if (value_format2 && !ParseValueRecord(font, &subtable, data, length,
+      if (value_format2 && !ParseValueRecord(file, &subtable, data, length,
                                              value_format2)) {
         return OTS_FAILURE_MSG("Falied to parse value record 2 %d and %d", j, i);
       }
     }
   }
 
   // Check class definition tables.
   if (offset_class_def1 < subtable.offset() || offset_class_def1 >= length ||
       offset_class_def2 < subtable.offset() || offset_class_def2 >= length) {
     return OTS_FAILURE_MSG("Bad class definition table offsets %d or %d", offset_class_def1, offset_class_def2);
   }
-  if (!ots::ParseClassDefTable(font, data + offset_class_def1,
+  if (!ots::ParseClassDefTable(file, data + offset_class_def1,
                                length - offset_class_def1,
                                num_glyphs, kMaxClassDefValue)) {
     return OTS_FAILURE_MSG("Failed to parse class definition table 1");
   }
-  if (!ots::ParseClassDefTable(font, data + offset_class_def2,
+  if (!ots::ParseClassDefTable(file, data + offset_class_def2,
                                length - offset_class_def2,
                                num_glyphs, kMaxClassDefValue)) {
     return OTS_FAILURE_MSG("Failed to parse class definition table 2");
   }
 
   return true;
 }
 
 // Lookup Type 2:
 // Pair Adjustment Positioning Subtable
-bool ParsePairAdjustment(const ots::Font *font, const uint8_t *data,
+bool ParsePairAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
                          const size_t length) {
   ots::Buffer subtable(data, length);
 
   uint16_t format = 0;
   uint16_t offset_coverage = 0;
   uint16_t value_format1 = 0;
   uint16_t value_format2 = 0;
   if (!subtable.ReadU16(&format) ||
       !subtable.ReadU16(&offset_coverage) ||
       !subtable.ReadU16(&value_format1) ||
       !subtable.ReadU16(&value_format2)) {
     return OTS_FAILURE_MSG("Failed to read pair adjustment structure");
   }
 
   if (format == 1) {
-    if (!ParsePairPosFormat1(font, data, length, value_format1, value_format2,
-                             font->maxp->num_glyphs)) {
+    if (!ParsePairPosFormat1(file, data, length, value_format1, value_format2,
+                             file->maxp->num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse pair pos format 1");
     }
   } else if (format == 2) {
-    if (!ParsePairPosFormat2(font, data, length, value_format1, value_format2,
-                             font->maxp->num_glyphs)) {
+    if (!ParsePairPosFormat2(file, data, length, value_format1, value_format2,
+                             file->maxp->num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse pair format 2");
     }
   } else {
     return OTS_FAILURE_MSG("Bad pos pair format %d", format);
   }
 
   if (offset_coverage < subtable.offset() || offset_coverage >= length) {
     return OTS_FAILURE_MSG("Bad pair pos offset coverage %d", offset_coverage);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage,
-                               font->maxp->num_glyphs)) {
+                               file->maxp->num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table");
   }
 
   return true;
 }
 
 // Lookup Type 3
 // Cursive Attachment Positioning Subtable
-bool ParseCursiveAttachment(const ots::Font *font, const uint8_t *data,
+bool ParseCursiveAttachment(const ots::OpenTypeFile *file, const uint8_t *data,
                             const size_t length) {
   ots::Buffer subtable(data, length);
 
   uint16_t format = 0;
   uint16_t offset_coverage = 0;
   uint16_t entry_exit_count = 0;
   if (!subtable.ReadU16(&format) ||
       !subtable.ReadU16(&offset_coverage) ||
@@ -451,46 +451,46 @@ bool ParseCursiveAttachment(const ots::F
       return OTS_FAILURE_MSG("Can't read entry exit record %d", i);
     }
     // These offsets could be NULL.
     if (offset_entry_anchor) {
       if (offset_entry_anchor < entry_exit_records_end ||
           offset_entry_anchor >= length) {
         return OTS_FAILURE_MSG("Bad entry anchor offset %d in entry exit record %d", offset_entry_anchor, i);
       }
-      if (!ParseAnchorTable(font, data + offset_entry_anchor,
+      if (!ParseAnchorTable(file, data + offset_entry_anchor,
                             length - offset_entry_anchor)) {
         return OTS_FAILURE_MSG("Failed to parse entry anchor table in entry exit record %d", i);
       }
     }
     if (offset_exit_anchor) {
       if (offset_exit_anchor < entry_exit_records_end ||
          offset_exit_anchor >= length) {
         return OTS_FAILURE_MSG("Bad exit anchor offset %d in entry exit record %d", offset_exit_anchor, i);
       }
-      if (!ParseAnchorTable(font, data + offset_exit_anchor,
+      if (!ParseAnchorTable(file, data + offset_exit_anchor,
                             length - offset_exit_anchor)) {
         return OTS_FAILURE_MSG("Failed to parse exit anchor table in entry exit record %d", i);
       }
     }
   }
 
   if (offset_coverage < subtable.offset() || offset_coverage >= length) {
     return OTS_FAILURE_MSG("Bad coverage offset in cursive attachment %d", offset_coverage);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage,
-                               font->maxp->num_glyphs)) {
+                               file->maxp->num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table in cursive attachment");
   }
 
   return true;
 }
 
-bool ParseAnchorArrayTable(const ots::Font *font,
+bool ParseAnchorArrayTable(const ots::OpenTypeFile *file,
                            const uint8_t *data, const size_t length,
                            const uint16_t class_count) {
   ots::Buffer subtable(data, length);
 
   uint16_t record_count = 0;
   if (!subtable.ReadU16(&record_count)) {
     return OTS_FAILURE_MSG("Can't read anchor array length");
   }
@@ -506,53 +506,53 @@ bool ParseAnchorArrayTable(const ots::Fo
       if (!subtable.ReadU16(&offset_record)) {
         return OTS_FAILURE_MSG("Can't read anchor array record offset for class %d and record %d", j, i);
       }
       // |offset_record| could be NULL.
       if (offset_record) {
         if (offset_record < anchor_array_end || offset_record >= length) {
           return OTS_FAILURE_MSG("Bad record offset %d in class %d, record %d", offset_record, j, i);
         }
-        if (!ParseAnchorTable(font, data + offset_record,
+        if (!ParseAnchorTable(file, data + offset_record,
                               length - offset_record)) {
           return OTS_FAILURE_MSG("Failed to parse anchor table for class %d, record %d", j, i);
         }
       }
     }
   }
   return true;
 }
 
-bool ParseLigatureArrayTable(const ots::Font *font,
+bool ParseLigatureArrayTable(const ots::OpenTypeFile *file,
                              const uint8_t *data, const size_t length,
                              const uint16_t class_count) {
   ots::Buffer subtable(data, length);
 
   uint16_t ligature_count = 0;
   if (!subtable.ReadU16(&ligature_count)) {
     return OTS_FAILURE_MSG("Failed to read ligature count");
   }
   for (unsigned i = 0; i < ligature_count; ++i) {
     uint16_t offset_ligature_attach = 0;
     if (!subtable.ReadU16(&offset_ligature_attach)) {
       return OTS_FAILURE_MSG("Can't read ligature offset %d", i);
     }
     if (offset_ligature_attach < 2 || offset_ligature_attach >= length) {
       return OTS_FAILURE_MSG("Bad ligature attachment offset %d in ligature %d", offset_ligature_attach, i);
     }
-    if (!ParseAnchorArrayTable(font, data + offset_ligature_attach,
+    if (!ParseAnchorArrayTable(file, data + offset_ligature_attach,
                                length - offset_ligature_attach, class_count)) {
       return OTS_FAILURE_MSG("Failed to parse anchor table for ligature %d", i);
     }
   }
   return true;
 }
 
 // Common parser for Lookup Type 4, 5 and 6.
-bool ParseMarkToAttachmentSubtables(const ots::Font *font,
+bool ParseMarkToAttachmentSubtables(const ots::OpenTypeFile *file,
                                     const uint8_t *data, const size_t length,
                                     const GPOS_TYPE type) {
   ots::Buffer subtable(data, length);
 
   uint16_t format = 0;
   uint16_t offset_coverage1 = 0;
   uint16_t offset_coverage2 = 0;
   uint16_t class_count = 0;
@@ -573,113 +573,120 @@ bool ParseMarkToAttachmentSubtables(cons
 
   const unsigned header_end = static_cast<unsigned>(subtable.offset());
   if (header_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE_MSG("Bad mark attachment subtable size ending at %d", header_end);
   }
   if (offset_coverage1 < header_end || offset_coverage1 >= length) {
     return OTS_FAILURE_MSG("Bad coverage 1 offset %d", offset_coverage1);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage1,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage1,
                                length - offset_coverage1,
-                               font->maxp->num_glyphs)) {
+                               file->maxp->num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse converge 1 table");
   }
   if (offset_coverage2 < header_end || offset_coverage2 >= length) {
     return OTS_FAILURE_MSG("Bad coverage 2 offset %d", offset_coverage2);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage2,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage2,
                                length - offset_coverage2,
-                               font->maxp->num_glyphs)) {
+                               file->maxp->num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table 2");
   }
 
   if (offset_mark_array < header_end || offset_mark_array >= length) {
     return OTS_FAILURE_MSG("Bad mark array offset %d", offset_mark_array);
   }
-  if (!ParseMarkArrayTable(font, data + offset_mark_array,
+  if (!ParseMarkArrayTable(file, data + offset_mark_array,
                            length - offset_mark_array, class_count)) {
     return OTS_FAILURE_MSG("Failed to parse mark array");
   }
 
   if (offset_type_specific_array < header_end ||
       offset_type_specific_array >= length) {
     return OTS_FAILURE_MSG("Bad type specific array offset %d", offset_type_specific_array);
   }
   if (type == GPOS_TYPE_MARK_TO_BASE_ATTACHMENT ||
       type == GPOS_TYPE_MARK_TO_MARK_ATTACHMENT) {
-    if (!ParseAnchorArrayTable(font, data + offset_type_specific_array,
+    if (!ParseAnchorArrayTable(file, data + offset_type_specific_array,
                                length - offset_type_specific_array,
                                class_count)) {
       return OTS_FAILURE_MSG("Failed to parse anchor array");
     }
   } else if (type == GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT) {
-    if (!ParseLigatureArrayTable(font, data + offset_type_specific_array,
+    if (!ParseLigatureArrayTable(file, data + offset_type_specific_array,
                                  length - offset_type_specific_array,
                                  class_count)) {
       return OTS_FAILURE_MSG("Failed to parse ligature array");
     }
   } else {
     return OTS_FAILURE_MSG("Bad attachment type %d", type);
   }
 
   return true;
 }
 
 // Lookup Type 4:
 // MarkToBase Attachment Positioning Subtable
-bool ParseMarkToBaseAttachment(const ots::Font *font,
+bool ParseMarkToBaseAttachment(const ots::OpenTypeFile *file,
                                const uint8_t *data, const size_t length) {
-  return ParseMarkToAttachmentSubtables(font, data, length,
+  return ParseMarkToAttachmentSubtables(file, data, length,
                                         GPOS_TYPE_MARK_TO_BASE_ATTACHMENT);
 }
 
 // Lookup Type 5:
 // MarkToLigature Attachment Positioning Subtable
-bool ParseMarkToLigatureAttachment(const ots::Font *font,
+bool ParseMarkToLigatureAttachment(const ots::OpenTypeFile *file,
                                    const uint8_t *data, const size_t length) {
-  return ParseMarkToAttachmentSubtables(font, data, length,
+  return ParseMarkToAttachmentSubtables(file, data, length,
                                         GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT);
 }
 
 // Lookup Type 6:
 // MarkToMark Attachment Positioning Subtable
-bool ParseMarkToMarkAttachment(const ots::Font *font,
+bool ParseMarkToMarkAttachment(const ots::OpenTypeFile *file,
                                const uint8_t *data, const size_t length) {
-  return ParseMarkToAttachmentSubtables(font, data, length,
+  return ParseMarkToAttachmentSubtables(file, data, length,
                                         GPOS_TYPE_MARK_TO_MARK_ATTACHMENT);
 }
 
 // Lookup Type 7:
 // Contextual Positioning Subtables
-bool ParseContextPositioning(const ots::Font *font,
+bool ParseContextPositioning(const ots::OpenTypeFile *file,
                              const uint8_t *data, const size_t length) {
-  return ots::ParseContextSubtable(font, data, length, font->maxp->num_glyphs,
-                                   font->gpos->num_lookups);
+  return ots::ParseContextSubtable(file, data, length, file->maxp->num_glyphs,
+                                   file->gpos->num_lookups);
 }
 
 // Lookup Type 8:
 // Chaining Contexual Positioning Subtable
-bool ParseChainedContextPositioning(const ots::Font *font,
+bool ParseChainedContextPositioning(const ots::OpenTypeFile *file,
                                     const uint8_t *data, const size_t length) {
-  return ots::ParseChainingContextSubtable(font, data, length,
-                                           font->maxp->num_glyphs,
-                                           font->gpos->num_lookups);
+  return ots::ParseChainingContextSubtable(file, data, length,
+                                           file->maxp->num_glyphs,
+                                           file->gpos->num_lookups);
 }
 
 // Lookup Type 9:
 // Extension Positioning
-bool ParseExtensionPositioning(const ots::Font *font,
+bool ParseExtensionPositioning(const ots::OpenTypeFile *file,
                                const uint8_t *data, const size_t length) {
-  return ots::ParseExtensionSubtable(font, data, length,
+  return ots::ParseExtensionSubtable(file, data, length,
                                      &kGposLookupSubtableParser);
 }
 
 }  // namespace
 
+#define DROP_THIS_TABLE(msg_) \
+  do { \
+    OTS_FAILURE_MSG(msg_ ", table discarded"); \
+    file->gpos->data = 0; \
+    file->gpos->length = 0; \
+  } while (0)
+
 namespace ots {
 
 // As far as I checked, following fonts contain invalid GPOS table and
 // OTS will drop their GPOS table.
 //
 // # invalid delta format in device table
 // samanata.ttf
 //
@@ -718,100 +725,104 @@ namespace ots {
 // GenBkBasB.ttf
 // GenBkBasR.ttf
 // Padauk-Bold.ttf
 // Padauk.ttf
 //
 // # Contour point indexes aren't sorted
 // Arial Unicode.ttf
 
-bool ots_gpos_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   // Parsing GPOS table requires num_glyphs which is contained in maxp table.
-  if (!font->maxp) {
+  if (!file->maxp) {
     return OTS_FAILURE_MSG("missing maxp table needed in GPOS");
   }
 
   Buffer table(data, length);
 
   OpenTypeGPOS *gpos = new OpenTypeGPOS;
-  font->gpos = gpos;
+  file->gpos = gpos;
 
   uint32_t version = 0;
   uint16_t offset_script_list = 0;
   uint16_t offset_feature_list = 0;
   uint16_t offset_lookup_list = 0;
   if (!table.ReadU32(&version) ||
       !table.ReadU16(&offset_script_list) ||
       !table.ReadU16(&offset_feature_list) ||
       !table.ReadU16(&offset_lookup_list)) {
-    return OTS_FAILURE_MSG("Incomplete table");
+    DROP_THIS_TABLE("Incomplete table");
+    return true;
   }
 
   if (version != 0x00010000) {
-    return OTS_FAILURE_MSG("Bad version");
+    DROP_THIS_TABLE("Bad version");
+    return true;
   }
 
   if (offset_lookup_list) {
     if (offset_lookup_list < kGposHeaderSize || offset_lookup_list >= length) {
-      return OTS_FAILURE_MSG("Bad lookup list offset in table header");
+      DROP_THIS_TABLE("Bad lookup list offset in table header");
+      return true;
     }
 
-    if (!ParseLookupListTable(font, data + offset_lookup_list,
+    if (!ParseLookupListTable(file, data + offset_lookup_list,
                               length - offset_lookup_list,
                               &kGposLookupSubtableParser,
                               &gpos->num_lookups)) {
-      return OTS_FAILURE_MSG("Failed to parse lookup list table");
+      DROP_THIS_TABLE("Failed to parse lookup list table");
+      return true;
     }
   }
 
   uint16_t num_features = 0;
   if (offset_feature_list) {
     if (offset_feature_list < kGposHeaderSize || offset_feature_list >= length) {
-      return OTS_FAILURE_MSG("Bad feature list offset in table header");
+      DROP_THIS_TABLE("Bad feature list offset in table header");
+      return true;
     }
 
-    if (!ParseFeatureListTable(font, data + offset_feature_list,
+    if (!ParseFeatureListTable(file, data + offset_feature_list,
                                length - offset_feature_list, gpos->num_lookups,
                                &num_features)) {
-      return OTS_FAILURE_MSG("Failed to parse feature list table");
+      DROP_THIS_TABLE("Failed to parse feature list table");
+      return true;
     }
   }
 
   if (offset_script_list) {
     if (offset_script_list < kGposHeaderSize || offset_script_list >= length) {
-      return OTS_FAILURE_MSG("Bad script list offset in table header");
+      DROP_THIS_TABLE("Bad script list offset in table header");
+      return true;
     }
 
-    if (!ParseScriptListTable(font, data + offset_script_list,
+    if (!ParseScriptListTable(file, data + offset_script_list,
                               length - offset_script_list, num_features)) {
-      return OTS_FAILURE_MSG("Failed to parse script list table");
+      DROP_THIS_TABLE("Failed to parse script list table");
+      return true;
     }
   }
 
   gpos->data = data;
   gpos->length = length;
   return true;
 }
 
-bool ots_gpos_should_serialise(Font *font) {
-  return font->gpos != NULL && font->gpos->data != NULL;
+bool ots_gpos_should_serialise(OpenTypeFile *file) {
+  return file->gpos != NULL && file->gpos->data != NULL;
 }
 
-bool ots_gpos_serialise(OTSStream *out, Font *font) {
-  if (!out->Write(font->gpos->data, font->gpos->length)) {
+bool ots_gpos_serialise(OTSStream *out, OpenTypeFile *file) {
+  if (!out->Write(file->gpos->data, file->gpos->length)) {
     return OTS_FAILURE_MSG("Failed to write GPOS table");
   }
 
   return true;
 }
 
-void ots_gpos_reuse(Font *font, Font *other) {
-  font->gpos = other->gpos;
-  font->gpos_reused = true;
-}
-
-void ots_gpos_free(Font *font) {
-  delete font->gpos;
+void ots_gpos_free(OpenTypeFile *file) {
+  delete file->gpos;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
+#undef DROP_THIS_TABLE
--- a/gfx/ots/src/gsub.cc
+++ b/gfx/ots/src/gsub.cc
@@ -28,33 +28,33 @@ enum GSUB_TYPE {
   GSUB_TYPE_CONTEXT = 5,
   GSUB_TYPE_CHANGING_CONTEXT = 6,
   GSUB_TYPE_EXTENSION_SUBSTITUTION = 7,
   GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE = 8,
   GSUB_TYPE_RESERVED = 9
 };
 
 // Lookup type parsers.
-bool ParseSingleSubstitution(const ots::Font *font,
+bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
                              const uint8_t *data, const size_t length);
-bool ParseMutipleSubstitution(const ots::Font *font,
+bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
                               const uint8_t *data, const size_t length);
-bool ParseAlternateSubstitution(const ots::Font *font,
+bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
                                 const uint8_t *data, const size_t length);
-bool ParseLigatureSubstitution(const ots::Font *font,
+bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
       const uint8_t *data, const size_t length);
-bool ParseContextSubstitution(const ots::Font *font,
+bool ParseContextSubstitution(const ots::OpenTypeFile *file,
                               const uint8_t *data, const size_t length);
-bool ParseChainingContextSubstitution(const ots::Font *font,
+bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
                                       const uint8_t *data,
                                       const size_t length);
-bool ParseExtensionSubstitution(const ots::Font *font,
+bool ParseExtensionSubstitution(const ots::OpenTypeFile *file,
                                 const uint8_t *data, const size_t length);
 bool ParseReverseChainingContextSingleSubstitution(
-    const ots::Font *font, const uint8_t *data, const size_t length);
+    const ots::OpenTypeFile *file, const uint8_t *data, const size_t length);
 
 const ots::LookupSubtableParser::TypeParser kGsubTypeParsers[] = {
   {GSUB_TYPE_SINGLE, ParseSingleSubstitution},
   {GSUB_TYPE_MULTIPLE, ParseMutipleSubstitution},
   {GSUB_TYPE_ALTERNATE, ParseAlternateSubstitution},
   {GSUB_TYPE_LIGATURE, ParseLigatureSubstitution},
   {GSUB_TYPE_CONTEXT, ParseContextSubstitution},
   {GSUB_TYPE_CHANGING_CONTEXT, ParseChainingContextSubstitution},
@@ -65,29 +65,29 @@ const ots::LookupSubtableParser::TypePar
 
 const ots::LookupSubtableParser kGsubLookupSubtableParser = {
   arraysize(kGsubTypeParsers),
   GSUB_TYPE_EXTENSION_SUBSTITUTION, kGsubTypeParsers
 };
 
 // Lookup Type 1:
 // Single Substitution Subtable
-bool ParseSingleSubstitution(const ots::Font *font,
+bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
                              const uint8_t *data, const size_t length) {
   ots::Buffer subtable(data, length);
 
   uint16_t format = 0;
   uint16_t offset_coverage = 0;
 
   if (!subtable.ReadU16(&format) ||
       !subtable.ReadU16(&offset_coverage)) {
     return OTS_FAILURE_MSG("Failed to read single subst table header");
   }
 
-  const uint16_t num_glyphs = font->maxp->num_glyphs;
+  const uint16_t num_glyphs = file->maxp->num_glyphs;
   if (format == 1) {
     // Parse SingleSubstFormat1
     int16_t delta_glyph_id = 0;
     if (!subtable.ReadS16(&delta_glyph_id)) {
       return OTS_FAILURE_MSG("Failed to read glyph shift from format 1 single subst table");
     }
     if (std::abs(delta_glyph_id) >= num_glyphs) {
       return OTS_FAILURE_MSG("bad glyph shift of %d in format 1 single subst table", delta_glyph_id);
@@ -112,25 +112,25 @@ bool ParseSingleSubstitution(const ots::
     }
   } else {
     return OTS_FAILURE_MSG("Bad single subst table format %d", format);
   }
 
   if (offset_coverage < subtable.offset() || offset_coverage >= length) {
     return OTS_FAILURE_MSG("Bad coverage offset %x", offset_coverage);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage, num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table");
   }
 
   return true;
 }
 
-bool ParseSequenceTable(const ots::Font *font,
+bool ParseSequenceTable(const ots::OpenTypeFile *file,
                         const uint8_t *data, const size_t length,
                         const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   uint16_t glyph_count = 0;
   if (!subtable.ReadU16(&glyph_count)) {
     return OTS_FAILURE_MSG("Failed to read glyph count in sequence table");
   }
@@ -147,17 +147,17 @@ bool ParseSequenceTable(const ots::Font 
     }
   }
 
   return true;
 }
 
 // Lookup Type 2:
 // Multiple Substitution Subtable
-bool ParseMutipleSubstitution(const ots::Font *font,
+bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
                               const uint8_t *data, const size_t length) {
   ots::Buffer subtable(data, length);
 
   uint16_t format = 0;
   uint16_t offset_coverage = 0;
   uint16_t sequence_count = 0;
 
   if (!subtable.ReadU16(&format) ||
@@ -165,48 +165,48 @@ bool ParseMutipleSubstitution(const ots:
       !subtable.ReadU16(&sequence_count)) {
     return OTS_FAILURE_MSG("Can't read header of multiple subst table");
   }
 
   if (format != 1) {
     return OTS_FAILURE_MSG("Bad multiple subst table format %d", format);
   }
 
-  const uint16_t num_glyphs = font->maxp->num_glyphs;
+  const uint16_t num_glyphs = file->maxp->num_glyphs;
   const unsigned sequence_end = static_cast<unsigned>(6) +
       sequence_count * 2;
   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE_MSG("Bad segence end %d, in multiple subst", sequence_end);
   }
   for (unsigned i = 0; i < sequence_count; ++i) {
     uint16_t offset_sequence = 0;
     if (!subtable.ReadU16(&offset_sequence)) {
       return OTS_FAILURE_MSG("Failed to read sequence offset for sequence %d", i);
     }
     if (offset_sequence < sequence_end || offset_sequence >= length) {
       return OTS_FAILURE_MSG("Bad sequence offset %d for sequence %d", offset_sequence, i);
     }
-    if (!ParseSequenceTable(font, data + offset_sequence, length - offset_sequence,
+    if (!ParseSequenceTable(file, data + offset_sequence, length - offset_sequence,
                             num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse sequence table %d", i);
     }
   }
 
   if (offset_coverage < sequence_end || offset_coverage >= length) {
     return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage, num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table");
   }
 
   return true;
 }
 
-bool ParseAlternateSetTable(const ots::Font *font,
+bool ParseAlternateSetTable(const ots::OpenTypeFile *file,
                             const uint8_t *data, const size_t length,
                             const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   uint16_t glyph_count = 0;
   if (!subtable.ReadU16(&glyph_count)) {
     return OTS_FAILURE_MSG("Failed to read alternate set header");
   }
@@ -222,17 +222,17 @@ bool ParseAlternateSetTable(const ots::F
       return OTS_FAILURE_MSG("Too large alternate: %u", alternate);
     }
   }
   return true;
 }
 
 // Lookup Type 3:
 // Alternate Substitution Subtable
-bool ParseAlternateSubstitution(const ots::Font *font,
+bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
                                 const uint8_t *data, const size_t length) {
   ots::Buffer subtable(data, length);
 
   uint16_t format = 0;
   uint16_t offset_coverage = 0;
   uint16_t alternate_set_count = 0;
 
   if (!subtable.ReadU16(&format) ||
@@ -240,50 +240,50 @@ bool ParseAlternateSubstitution(const ot
       !subtable.ReadU16(&alternate_set_count)) {
     return OTS_FAILURE_MSG("Can't read alternate subst header");
   }
 
   if (format != 1) {
     return OTS_FAILURE_MSG("Bad alternate subst table format %d", format);
   }
 
-  const uint16_t num_glyphs = font->maxp->num_glyphs;
+  const uint16_t num_glyphs = file->maxp->num_glyphs;
   const unsigned alternate_set_end = static_cast<unsigned>(6) +
       alternate_set_count * 2;
   if (alternate_set_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE_MSG("Bad end of alternate set %d", alternate_set_end);
   }
   for (unsigned i = 0; i < alternate_set_count; ++i) {
     uint16_t offset_alternate_set = 0;
     if (!subtable.ReadU16(&offset_alternate_set)) {
       return OTS_FAILURE_MSG("Can't read alternate set offset for set %d", i);
     }
     if (offset_alternate_set < alternate_set_end ||
         offset_alternate_set >= length) {
       return OTS_FAILURE_MSG("Bad alternate set offset %d for set %d", offset_alternate_set, i);
     }
-    if (!ParseAlternateSetTable(font, data + offset_alternate_set,
+    if (!ParseAlternateSetTable(file, data + offset_alternate_set,
                                 length - offset_alternate_set,
                                 num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse alternate set");
     }
   }
 
   if (offset_coverage < alternate_set_end || offset_coverage >= length) {
     return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage, num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table");
   }
 
   return true;
 }
 
-bool ParseLigatureTable(const ots::Font *font,
+bool ParseLigatureTable(const ots::OpenTypeFile *file,
                         const uint8_t *data, const size_t length,
                         const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   uint16_t lig_glyph = 0;
   uint16_t comp_count = 0;
 
   if (!subtable.ReadU16(&lig_glyph) ||
@@ -305,17 +305,17 @@ bool ParseLigatureTable(const ots::Font 
     if (component >= num_glyphs) {
       return OTS_FAILURE_MSG("Bad ligature component %d of %d", i, component);
     }
   }
 
   return true;
 }
 
-bool ParseLigatureSetTable(const ots::Font *font,
+bool ParseLigatureSetTable(const ots::OpenTypeFile *file,
                            const uint8_t *data, const size_t length,
                            const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   uint16_t ligature_count = 0;
 
   if (!subtable.ReadU16(&ligature_count)) {
     return OTS_FAILURE_MSG("Can't read ligature count in ligature set");
@@ -328,28 +328,28 @@ bool ParseLigatureSetTable(const ots::Fo
   for (unsigned i = 0; i < ligature_count; ++i) {
     uint16_t offset_ligature = 0;
     if (!subtable.ReadU16(&offset_ligature)) {
       return OTS_FAILURE_MSG("Failed to read ligature offset %d", i);
     }
     if (offset_ligature < ligature_end || offset_ligature >= length) {
       return OTS_FAILURE_MSG("Bad ligature offset %d for ligature %d", offset_ligature, i);
     }
-    if (!ParseLigatureTable(font, data + offset_ligature, length - offset_ligature,
+    if (!ParseLigatureTable(file, data + offset_ligature, length - offset_ligature,
                             num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse ligature %d", i);
     }
   }
 
   return true;
 }
 
 // Lookup Type 4:
 // Ligature Substitution Subtable
-bool ParseLigatureSubstitution(const ots::Font *font,
+bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
                                const uint8_t *data, const size_t length) {
   ots::Buffer subtable(data, length);
 
   uint16_t format = 0;
   uint16_t offset_coverage = 0;
   uint16_t lig_set_count = 0;
 
   if (!subtable.ReadU16(&format) ||
@@ -357,89 +357,89 @@ bool ParseLigatureSubstitution(const ots
       !subtable.ReadU16(&lig_set_count)) {
     return OTS_FAILURE_MSG("Failed to read ligature substitution header");
   }
 
   if (format != 1) {
     return OTS_FAILURE_MSG("Bad ligature substitution table format %d", format);
   }
 
-  const uint16_t num_glyphs = font->maxp->num_glyphs;
+  const uint16_t num_glyphs = file->maxp->num_glyphs;
   const unsigned ligature_set_end = static_cast<unsigned>(6) +
       lig_set_count * 2;
   if (ligature_set_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE_MSG("Bad end of ligature set %d in ligature substitution table", ligature_set_end);
   }
   for (unsigned i = 0; i < lig_set_count; ++i) {
     uint16_t offset_ligature_set = 0;
     if (!subtable.ReadU16(&offset_ligature_set)) {
       return OTS_FAILURE_MSG("Can't read ligature set offset %d", i);
     }
     if (offset_ligature_set < ligature_set_end ||
         offset_ligature_set >= length) {
       return OTS_FAILURE_MSG("Bad ligature set offset %d for set %d", offset_ligature_set, i);
     }
-    if (!ParseLigatureSetTable(font, data + offset_ligature_set,
+    if (!ParseLigatureSetTable(file, data + offset_ligature_set,
                                length - offset_ligature_set, num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse ligature set %d", i);
     }
   }
 
   if (offset_coverage < ligature_set_end || offset_coverage >= length) {
     return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage, num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table");
   }
 
   return true;
 }
 
 // Lookup Type 5:
 // Contextual Substitution Subtable
-bool ParseContextSubstitution(const ots::Font *font,
+bool ParseContextSubstitution(const ots::OpenTypeFile *file,
                               const uint8_t *data, const size_t length) {
-  return ots::ParseContextSubtable(font, data, length, font->maxp->num_glyphs,
-                                   font->gsub->num_lookups);
+  return ots::ParseContextSubtable(file, data, length, file->maxp->num_glyphs,
+                                   file->gsub->num_lookups);
 }
 
 // Lookup Type 6:
 // Chaining Contextual Substitution Subtable
-bool ParseChainingContextSubstitution(const ots::Font *font,
+bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
                                       const uint8_t *data,
                                       const size_t length) {
-  return ots::ParseChainingContextSubtable(font, data, length,
-                                           font->maxp->num_glyphs,
-                                           font->gsub->num_lookups);
+  return ots::ParseChainingContextSubtable(file, data, length,
+                                           file->maxp->num_glyphs,
+                                           file->gsub->num_lookups);
 }
 
 // Lookup Type 7:
 // Extension Substition
-bool ParseExtensionSubstitution(const ots::Font *font,
+bool ParseExtensionSubstitution(const ots::OpenTypeFile *file,
                                 const uint8_t *data, const size_t length) {
-  return ots::ParseExtensionSubtable(font, data, length,
+  return ots::ParseExtensionSubtable(file, data, length,
                                      &kGsubLookupSubtableParser);
 }
 
 // Lookup Type 8:
 // Reverse Chaining Contexual Single Substitution Subtable
 bool ParseReverseChainingContextSingleSubstitution(
-    const ots::Font *font, const uint8_t *data, const size_t length) {
+    const ots::OpenTypeFile *file, const uint8_t *data, const size_t length) {
   ots::Buffer subtable(data, length);
 
   uint16_t format = 0;
   uint16_t offset_coverage = 0;
 
   if (!subtable.ReadU16(&format) ||
       !subtable.ReadU16(&offset_coverage)) {
     return OTS_FAILURE_MSG("Failed to read reverse chaining header");
   }
 
-  const uint16_t num_glyphs = font->maxp->num_glyphs;
+  const uint16_t num_glyphs = file->maxp->num_glyphs;
 
   uint16_t backtrack_glyph_count = 0;
   if (!subtable.ReadU16(&backtrack_glyph_count)) {
     return OTS_FAILURE_MSG("Failed to read backtrack glyph count in reverse chaining table");
   }
   if (backtrack_glyph_count > num_glyphs) {
     return OTS_FAILURE_MSG("Bad backtrack glyph count of %d", backtrack_glyph_count);
   }
@@ -491,48 +491,55 @@ bool ParseReverseChainingContextSingleSu
       (backtrack_glyph_count + lookahead_glyph_count + glyph_count) * 2;
   if (substitute_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE_MSG("Bad substitute end offset in reverse chaining table");
   }
 
   if (offset_coverage < substitute_end || offset_coverage >= length) {
     return OTS_FAILURE_MSG("Bad coverage offset %d in reverse chaining table", offset_coverage);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage, num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table in reverse chaining table");
   }
 
   for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
     if (offsets_backtrack[i] < substitute_end ||
         offsets_backtrack[i] >= length) {
       return OTS_FAILURE_MSG("Bad backtrack offset %d for backtrack %d in reverse chaining table", offsets_backtrack[i], i);
     }
-    if (!ots::ParseCoverageTable(font, data + offsets_backtrack[i],
+    if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i],
                                  length - offsets_backtrack[i], num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse coverage table for backtrack %d in reverse chaining table", i);
     }
   }
 
   for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
     if (offsets_lookahead[i] < substitute_end ||
         offsets_lookahead[i] >= length) {
       return OTS_FAILURE_MSG("Bad lookahead offset %d for lookahead %d in reverse chaining table", offsets_lookahead[i], i);
     }
-    if (!ots::ParseCoverageTable(font, data + offsets_lookahead[i],
+    if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i],
                                  length - offsets_lookahead[i], num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in reverse chaining table", i);
     }
   }
 
   return true;
 }
 
 }  // namespace
 
+#define DROP_THIS_TABLE(msg_) \
+  do { \
+    OTS_FAILURE_MSG(msg_ ", table discarded"); \
+    file->gsub->data = 0; \
+    file->gsub->length = 0; \
+  } while (0)
+
 namespace ots {
 
 // As far as I checked, following fonts contain invalid values in GSUB table.
 // OTS will drop their GSUB table.
 //
 // # too large substitute (value is 0xFFFF)
 // kaiu.ttf
 // mingliub2.ttf
@@ -575,100 +582,104 @@ namespace ots {
 // KacstTitle.ttf
 // KacstArt.ttf
 // KacstPoster.ttf
 // KacstQurn.ttf
 // KacstDigital.ttf
 // KacstBook.ttf
 // KacstFarsi.ttf
 
-bool ots_gsub_parse(Font *font, const uint8_t *data, size_t length) {
-  // Parsing gsub table requires |font->maxp->num_glyphs|
-  if (!font->maxp) {
+bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  // Parsing gsub table requires |file->maxp->num_glyphs|
+  if (!file->maxp) {
     return OTS_FAILURE_MSG("Missing maxp table in font, needed by GSUB");
   }
 
   Buffer table(data, length);
 
   OpenTypeGSUB *gsub = new OpenTypeGSUB;
-  font->gsub = gsub;
+  file->gsub = gsub;
 
   uint32_t version = 0;
   uint16_t offset_script_list = 0;
   uint16_t offset_feature_list = 0;
   uint16_t offset_lookup_list = 0;
   if (!table.ReadU32(&version) ||
       !table.ReadU16(&offset_script_list) ||
       !table.ReadU16(&offset_feature_list) ||
       !table.ReadU16(&offset_lookup_list)) {
-    return OTS_FAILURE_MSG("Incomplete table");
+    DROP_THIS_TABLE("Incomplete table");
+    return true;
   }
 
   if (version != 0x00010000) {
-    return OTS_FAILURE_MSG("Bad version");
+    DROP_THIS_TABLE("Bad version");
+    return true;
   }
 
   if (offset_lookup_list) {
     if (offset_lookup_list < kGsubHeaderSize || offset_lookup_list >= length) {
-      return OTS_FAILURE_MSG("Bad lookup list offset in table header");
+      DROP_THIS_TABLE("Bad lookup list offset in table header");
+      return true;
     }
 
-    if (!ParseLookupListTable(font, data + offset_lookup_list,
+    if (!ParseLookupListTable(file, data + offset_lookup_list,
                               length - offset_lookup_list,
                               &kGsubLookupSubtableParser,
                               &gsub->num_lookups)) {
-      return OTS_FAILURE_MSG("Failed to parse lookup list table");
+      DROP_THIS_TABLE("Failed to parse lookup list table");
+      return true;
     }
   }
 
   uint16_t num_features = 0;
   if (offset_feature_list) {
     if (offset_feature_list < kGsubHeaderSize || offset_feature_list >= length) {
-      return OTS_FAILURE_MSG("Bad feature list offset in table header");
+      DROP_THIS_TABLE("Bad feature list offset in table header");
+      return true;
     }
 
-    if (!ParseFeatureListTable(font, data + offset_feature_list,
+    if (!ParseFeatureListTable(file, data + offset_feature_list,
                                length - offset_feature_list, gsub->num_lookups,
                                &num_features)) {
-      return OTS_FAILURE_MSG("Failed to parse feature list table");
+      DROP_THIS_TABLE("Failed to parse feature list table");
+      return true;
     }
   }
 
   if (offset_script_list) {
     if (offset_script_list < kGsubHeaderSize || offset_script_list >= length) {
-      return OTS_FAILURE_MSG("Bad script list offset in table header");
+      DROP_THIS_TABLE("Bad script list offset in table header");
+      return true;
     }
 
-    if (!ParseScriptListTable(font, data + offset_script_list,
+    if (!ParseScriptListTable(file, data + offset_script_list,
                               length - offset_script_list, num_features)) {
-      return OTS_FAILURE_MSG("Failed to parse script list table");
+      DROP_THIS_TABLE("Failed to parse script list table");
+      return true;
     }
   }
 
   gsub->data = data;
   gsub->length = length;
   return true;
 }
 
-bool ots_gsub_should_serialise(Font *font) {
-  return font->gsub != NULL && font->gsub->data != NULL;
+bool ots_gsub_should_serialise(OpenTypeFile *file) {
+  return file->gsub != NULL && file->gsub->data != NULL;
 }
 
-bool ots_gsub_serialise(OTSStream *out, Font *font) {
-  if (!out->Write(font->gsub->data, font->gsub->length)) {
+bool ots_gsub_serialise(OTSStream *out, OpenTypeFile *file) {
+  if (!out->Write(file->gsub->data, file->gsub->length)) {
     return OTS_FAILURE_MSG("Failed to write GSUB table");
   }
 
   return true;
 }
 
-void ots_gsub_reuse(Font *font, Font *other) {
-  font->gsub = other->gsub;
-  font->gsub_reused = true;
-}
-
-void ots_gsub_free(Font *font) {
-  delete font->gsub;
+void ots_gsub_free(OpenTypeFile *file) {
+  delete file->gsub;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
+#undef DROP_THIS_TABLE
--- a/gfx/ots/src/hdmx.cc
+++ b/gfx/ots/src/hdmx.cc
@@ -8,34 +8,34 @@
 
 // hdmx - Horizontal Device Metrics
 // http://www.microsoft.com/typography/otspec/hdmx.htm
 
 #define TABLE_NAME "hdmx"
 
 #define DROP_THIS_TABLE(...) \
   do { \
-    OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
+    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
     OTS_FAILURE_MSG("Table discarded"); \
-    delete font->hdmx; \
-    font->hdmx = 0; \
+    delete file->hdmx; \
+    file->hdmx = 0; \
   } while (0)
 
 namespace ots {
 
-bool ots_hdmx_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
-  font->hdmx = new OpenTypeHDMX;
-  OpenTypeHDMX * const hdmx = font->hdmx;
+  file->hdmx = new OpenTypeHDMX;
+  OpenTypeHDMX * const hdmx = file->hdmx;
 
-  if (!font->head || !font->maxp) {
+  if (!file->head || !file->maxp) {
     return OTS_FAILURE_MSG("Missing maxp or head tables in font, needed by hdmx");
   }
 
-  if ((font->head->flags & 0x14) == 0) {
+  if ((file->head->flags & 0x14) == 0) {
     // http://www.microsoft.com/typography/otspec/recom.htm
     DROP_THIS_TABLE("the table should not be present when bit 2 and 4 of the "
                     "head->flags are not set");
     return true;
   }
 
   int16_t num_recs;
   if (!table.ReadU16(&hdmx->version) ||
@@ -46,17 +46,17 @@ bool ots_hdmx_parse(Font *font, const ui
   if (hdmx->version != 0) {
     DROP_THIS_TABLE("bad version: %u", hdmx->version);
     return true;
   }
   if (num_recs <= 0) {
     DROP_THIS_TABLE("bad num_recs: %d", num_recs);
     return true;
   }
-  const int32_t actual_size_device_record = font->maxp->num_glyphs + 2;
+  const int32_t actual_size_device_record = file->maxp->num_glyphs + 2;
   if (hdmx->size_device_record < actual_size_device_record) {
     DROP_THIS_TABLE("bad hdmx->size_device_record: %d", hdmx->size_device_record);
     return true;
   }
 
   hdmx->pad_len = hdmx->size_device_record - actual_size_device_record;
   if (hdmx->pad_len > 3) {
     return OTS_FAILURE_MSG("Bad padding %d", hdmx->pad_len);
@@ -73,18 +73,18 @@ bool ots_hdmx_parse(Font *font, const ui
     }
     if ((i != 0) &&
         (rec.pixel_size <= last_pixel_size)) {
       DROP_THIS_TABLE("records are not sorted");
       return true;
     }
     last_pixel_size = rec.pixel_size;
 
-    rec.widths.reserve(font->maxp->num_glyphs);
-    for (unsigned j = 0; j < font->maxp->num_glyphs; ++j) {
+    rec.widths.reserve(file->maxp->num_glyphs);
+    for (unsigned j = 0; j < file->maxp->num_glyphs; ++j) {
       uint8_t width;
       if (!table.ReadU8(&width)) {
         return OTS_FAILURE_MSG("Failed to read glyph width %d in record %d", j, i);
       }
       rec.widths.push_back(width);
     }
 
     if ((hdmx->pad_len > 0) &&
@@ -93,24 +93,24 @@ bool ots_hdmx_parse(Font *font, const ui
     }
 
     hdmx->records.push_back(rec);
   }
 
   return true;
 }
 
-bool ots_hdmx_should_serialise(Font *font) {
-  if (!font->hdmx) return false;
-  if (!font->glyf) return false;  // this table is not for CFF fonts.
+bool ots_hdmx_should_serialise(OpenTypeFile *file) {
+  if (!file->hdmx) return false;
+  if (!file->glyf) return false;  // this table is not for CFF fonts.
   return true;
 }
 
-bool ots_hdmx_serialise(OTSStream *out, Font *font) {
-  OpenTypeHDMX * const hdmx = font->hdmx;
+bool ots_hdmx_serialise(OTSStream *out, OpenTypeFile *file) {
+  OpenTypeHDMX * const hdmx = file->hdmx;
 
   const int16_t num_recs = static_cast<int16_t>(hdmx->records.size());
   if (hdmx->records.size() >
           static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
       !out->WriteU16(hdmx->version) ||
       !out->WriteS16(num_recs) ||
       !out->WriteS32(hdmx->size_device_record)) {
     return OTS_FAILURE_MSG("Failed to write hdmx header");
@@ -127,21 +127,16 @@ bool ots_hdmx_serialise(OTSStream *out, 
         !out->Write((const uint8_t *)"\x00\x00\x00", hdmx->pad_len)) {
       return OTS_FAILURE_MSG("Failed to write hdmx padding of length %d", hdmx->pad_len);
     }
   }
 
   return true;
 }
 
-void ots_hdmx_reuse(Font *font, Font *other) {
-  font->hdmx = other->hdmx;
-  font->hdmx_reused = true;
-}
-
-void ots_hdmx_free(Font *font) {
-  delete font->hdmx;
+void ots_hdmx_free(OpenTypeFile *file) {
+  delete file->hdmx;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
 #undef DROP_THIS_TABLE
--- a/gfx/ots/src/head.cc
+++ b/gfx/ots/src/head.cc
@@ -8,152 +8,146 @@
 
 // head - Font Header
 // http://www.microsoft.com/typography/otspec/head.htm
 
 #define TABLE_NAME "head"
 
 namespace ots {
 
-bool ots_head_parse(Font* font, const uint8_t *data, size_t length) {
+bool ots_head_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
-  OpenTypeHEAD *head = new OpenTypeHEAD;
-  font->head = head;
+  file->head = new OpenTypeHEAD;
 
   uint32_t version = 0;
   if (!table.ReadU32(&version) ||
-      !table.ReadU32(&head->revision)) {
+      !table.ReadU32(&file->head->revision)) {
     return OTS_FAILURE_MSG("Failed to read head header");
   }
 
   if (version >> 16 != 1) {
     return OTS_FAILURE_MSG("Bad head table version of %d", version);
   }
 
   // Skip the checksum adjustment
   if (!table.Skip(4)) {
     return OTS_FAILURE_MSG("Failed to read checksum");
   }
 
   uint32_t magic;
-  if (!table.ReadU32(&magic) || magic != 0x5F0F3CF5) {
+  if (!table.ReadTag(&magic) ||
+      std::memcmp(&magic, "\x5F\x0F\x3C\xF5", 4)) {
     return OTS_FAILURE_MSG("Failed to read font magic number");
   }
 
-  if (!table.ReadU16(&head->flags)) {
+  if (!table.ReadU16(&file->head->flags)) {
     return OTS_FAILURE_MSG("Failed to read head flags");
   }
 
   // We allow bits 0..4, 11..13
-  head->flags &= 0x381f;
+  file->head->flags &= 0x381f;
 
-  if (!table.ReadU16(&head->ppem)) {
+  if (!table.ReadU16(&file->head->ppem)) {
     return OTS_FAILURE_MSG("Failed to read pixels per em");
   }
 
   // ppem must be in range
-  if (head->ppem < 16 ||
-      head->ppem > 16384) {
-    return OTS_FAILURE_MSG("Bad ppm of %d", head->ppem);
+  if (file->head->ppem < 16 ||
+      file->head->ppem > 16384) {
+    return OTS_FAILURE_MSG("Bad ppm of %d", file->head->ppem);
   }
 
   // ppem must be a power of two
 #if 0
   // We don't call ots_failure() for now since lots of TrueType fonts are
   // not following this rule. Putting OTS_WARNING here is too noisy.
-  if ((head->ppem - 1) & head->ppem) {
-    return OTS_FAILURE_MSG("ppm not a power of two: %d", head->ppem);
+  if ((file->head->ppem - 1) & file->head->ppem) {
+    return OTS_FAILURE_MSG("ppm not a power of two: %d", file->head->ppem);
   }
 #endif
 
-  if (!table.ReadR64(&head->created) ||
-      !table.ReadR64(&head->modified)) {
+  if (!table.ReadR64(&file->head->created) ||
+      !table.ReadR64(&file->head->modified)) {
     return OTS_FAILURE_MSG("Can't read font dates");
   }
 
-  if (!table.ReadS16(&head->xmin) ||
-      !table.ReadS16(&head->ymin) ||
-      !table.ReadS16(&head->xmax) ||
-      !table.ReadS16(&head->ymax)) {
+  if (!table.ReadS16(&file->head->xmin) ||
+      !table.ReadS16(&file->head->ymin) ||
+      !table.ReadS16(&file->head->xmax) ||
+      !table.ReadS16(&file->head->ymax)) {
     return OTS_FAILURE_MSG("Failed to read font bounding box");
   }
 
-  if (head->xmin > head->xmax) {
-    return OTS_FAILURE_MSG("Bad x dimension in the font bounding box (%d, %d)", head->xmin, head->xmax);
+  if (file->head->xmin > file->head->xmax) {
+    return OTS_FAILURE_MSG("Bad x dimension in the font bounding box (%d, %d)", file->head->xmin, file->head->xmax);
   }
-  if (head->ymin > head->ymax) {
-    return OTS_FAILURE_MSG("Bad y dimension in the font bounding box (%d, %d)", head->ymin, head->ymax);
+  if (file->head->ymin > file->head->ymax) {
+    return OTS_FAILURE_MSG("Bad y dimension in the font bounding box (%d, %d)", file->head->ymin, file->head->ymax);
   }
 
-  if (!table.ReadU16(&head->mac_style)) {
+  if (!table.ReadU16(&file->head->mac_style)) {
     return OTS_FAILURE_MSG("Failed to read font style");
   }
 
   // We allow bits 0..6
-  head->mac_style &= 0x7f;
+  file->head->mac_style &= 0x7f;
 
-  if (!table.ReadU16(&head->min_ppem)) {
+  if (!table.ReadU16(&file->head->min_ppem)) {
     return OTS_FAILURE_MSG("Failed to read font minimum ppm");
   }
 
   // We don't care about the font direction hint
   if (!table.Skip(2)) {
     return OTS_FAILURE_MSG("Failed to skip font direction hint");
   }
 
-  if (!table.ReadS16(&head->index_to_loc_format)) {
+  if (!table.ReadS16(&file->head->index_to_loc_format)) {
     return OTS_FAILURE_MSG("Failed to read index to loc format");
   }
-  if (head->index_to_loc_format < 0 ||
-      head->index_to_loc_format > 1) {
-    return OTS_FAILURE_MSG("Bad index to loc format %d", head->index_to_loc_format);
+  if (file->head->index_to_loc_format < 0 ||
+      file->head->index_to_loc_format > 1) {
+    return OTS_FAILURE_MSG("Bad index to loc format %d", file->head->index_to_loc_format);
   }
 
   int16_t glyph_data_format;
   if (!table.ReadS16(&glyph_data_format) ||
       glyph_data_format) {
     return OTS_FAILURE_MSG("Failed to read glyph data format");
   }
 
   return true;
 }
 
-bool ots_head_should_serialise(Font *font) {
-  return font->head != NULL;
+bool ots_head_should_serialise(OpenTypeFile *file) {
+  return file->head != NULL;
 }
 
-bool ots_head_serialise(OTSStream *out, Font *font) {
-  const OpenTypeHEAD *head = font->head;
+bool ots_head_serialise(OTSStream *out, OpenTypeFile *file) {
   if (!out->WriteU32(0x00010000) ||
-      !out->WriteU32(head->revision) ||
+      !out->WriteU32(file->head->revision) ||
       !out->WriteU32(0) ||  // check sum not filled in yet
       !out->WriteU32(0x5F0F3CF5) ||
-      !out->WriteU16(head->flags) ||
-      !out->WriteU16(head->ppem) ||
-      !out->WriteR64(head->created) ||
-      !out->WriteR64(head->modified) ||
-      !out->WriteS16(head->xmin) ||
-      !out->WriteS16(head->ymin) ||
-      !out->WriteS16(head->xmax) ||
-      !out->WriteS16(head->ymax) ||
-      !out->WriteU16(head->mac_style) ||
-      !out->WriteU16(head->min_ppem) ||
+      !out->WriteU16(file->head->flags) ||
+      !out->WriteU16(file->head->ppem) ||
+      !out->WriteR64(file->head->created) ||
+      !out->WriteR64(file->head->modified) ||
+      !out->WriteS16(file->head->xmin) ||
+      !out->WriteS16(file->head->ymin) ||
+      !out->WriteS16(file->head->xmax) ||
+      !out->WriteS16(file->head->ymax) ||
+      !out->WriteU16(file->head->mac_style) ||
+      !out->WriteU16(file->head->min_ppem) ||
       !out->WriteS16(2) ||
-      !out->WriteS16(head->index_to_loc_format) ||
+      !out->WriteS16(file->head->index_to_loc_format) ||
       !out->WriteS16(0)) {
     return OTS_FAILURE_MSG("Failed to write head table");
   }
 
   return true;
 }
 
-void ots_head_reuse(Font *font, Font *other) {
-  font->head = other->head;
-  font->head_reused = true;
-}
-
-void ots_head_free(Font *font) {
-  delete font->head;
+void ots_head_free(OpenTypeFile *file) {
+  delete file->head;
 }
 
 }  // namespace
 
 #undef TABLE_NAME
--- a/gfx/ots/src/hhea.cc
+++ b/gfx/ots/src/hhea.cc
@@ -9,50 +9,45 @@
 
 // hhea - Horizontal Header
 // http://www.microsoft.com/typography/otspec/hhea.htm
 
 #define TABLE_NAME "hhea"
 
 namespace ots {
 
-bool ots_hhea_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_hhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
   OpenTypeHHEA *hhea = new OpenTypeHHEA;
-  font->hhea = hhea;
+  file->hhea = hhea;
 
   if (!table.ReadU32(&hhea->header.version)) {
     return OTS_FAILURE_MSG("Failed to read hhea version");
   }
   if (hhea->header.version >> 16 != 1) {
     return OTS_FAILURE_MSG("Bad hhea version of %d", hhea->header.version);
   }
 
-  if (!ParseMetricsHeader(font, &table, &hhea->header)) {
+  if (!ParseMetricsHeader(file, &table, &hhea->header)) {
     return OTS_FAILURE_MSG("Failed to parse horizontal metrics");
   }
 
   return true;
 }
 
-bool ots_hhea_should_serialise(Font *font) {
-  return font->hhea != NULL;
+bool ots_hhea_should_serialise(OpenTypeFile *file) {
+  return file->hhea != NULL;
 }
 
-bool ots_hhea_serialise(OTSStream *out, Font *font) {
-  if (!SerialiseMetricsHeader(font, out, &font->hhea->header)) {
+bool ots_hhea_serialise(OTSStream *out, OpenTypeFile *file) {
+  if (!SerialiseMetricsHeader(file, out, &file->hhea->header)) {
     return OTS_FAILURE_MSG("Failed to serialise horizontal metrics");
   }
   return true;
 }
 
-void ots_hhea_reuse(Font *font, Font *other) {
-  font->hhea = other->hhea;
-  font->hhea_reused = true;
-}
-
-void ots_hhea_free(Font *font) {
-  delete font->hhea;
+void ots_hhea_free(OpenTypeFile *file) {
+  delete file->hhea;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/hmtx.cc
+++ b/gfx/ots/src/hmtx.cc
@@ -9,48 +9,43 @@
 
 // hmtx - Horizontal Metrics
 // http://www.microsoft.com/typography/otspec/hmtx.htm
 
 #define TABLE_NAME "hmtx"
 
 namespace ots {
 
-bool ots_hmtx_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_hmtx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
   OpenTypeHMTX *hmtx = new OpenTypeHMTX;
-  font->hmtx = hmtx;
+  file->hmtx = hmtx;
 
-  if (!font->hhea || !font->maxp) {
+  if (!file->hhea || !file->maxp) {
     return OTS_FAILURE_MSG("Missing hhea or maxp tables in font, needed by hmtx");
   }
 
-  if (!ParseMetricsTable(font, &table, font->maxp->num_glyphs,
-                         &font->hhea->header, &hmtx->metrics)) {
+  if (!ParseMetricsTable(file, &table, file->maxp->num_glyphs,
+                         &file->hhea->header, &hmtx->metrics)) {
     return OTS_FAILURE_MSG("Failed to parse hmtx metrics");
   }
 
   return true;
 }
 
-bool ots_hmtx_should_serialise(Font *font) {
-  return font->hmtx != NULL;
+bool ots_hmtx_should_serialise(OpenTypeFile *file) {
+  return file->hmtx != NULL;
 }
 
-bool ots_hmtx_serialise(OTSStream *out, Font *font) {
-  if (!SerialiseMetricsTable(font, out, &font->hmtx->metrics)) {
+bool ots_hmtx_serialise(OTSStream *out, OpenTypeFile *file) {
+  if (!SerialiseMetricsTable(file, out, &file->hmtx->metrics)) {
     return OTS_FAILURE_MSG("Failed to serialise htmx metrics");
   }
   return true;
 }
 
-void ots_hmtx_reuse(Font *font, Font *other) {
-  font->hmtx = other->hmtx;
-  font->hmtx_reused = true;
-}
-
-void ots_hmtx_free(Font *font) {
-  delete font->hmtx;
+void ots_hmtx_free(OpenTypeFile *file) {
+  delete file->hmtx;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/kern.cc
+++ b/gfx/ots/src/kern.cc
@@ -7,27 +7,27 @@
 // kern - Kerning
 // http://www.microsoft.com/typography/otspec/kern.htm
 
 #define TABLE_NAME "kern"
 
 #define DROP_THIS_TABLE(msg_) \
   do { \
     OTS_FAILURE_MSG(msg_ ", table discarded"); \
-    delete font->kern; \
-    font->kern = 0; \
+    delete file->kern; \
+    file->kern = 0; \
   } while (0)
 
 namespace ots {
 
-bool ots_kern_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
   OpenTypeKERN *kern = new OpenTypeKERN;
-  font->kern = kern;
+  file->kern = kern;
 
   uint16_t num_tables = 0;
   if (!table.ReadU16(&kern->version) ||
       !table.ReadU16(&num_tables)) {
     return OTS_FAILURE_MSG("Failed to read kern header");
   }
 
   if (kern->version > 0) {
@@ -65,17 +65,17 @@ bool ots_kern_parse(Font *font, const ui
     }
 
     if (!(subtable.coverage & 0x1)) {
       OTS_WARNING(
           "We don't support vertical data as the renderer doesn't support it.");
       continue;
     }
     if (subtable.coverage & 0xF0) {
-      DROP_THIS_TABLE("Reserved fields should zero-filled");
+      DROP_THIS_TABLE("Reserved fields should zero-filled.");
       return true;
     }
     const uint32_t format = (subtable.coverage & 0xFF00) >> 8;
     if (format != 0) {
       OTS_WARNING("Format %d is not supported.", format);
       continue;
     }
 
@@ -84,26 +84,26 @@ bool ots_kern_parse(Font *font, const ui
     if (!table.ReadU16(&num_pairs) ||
         !table.ReadU16(&subtable.search_range) ||
         !table.ReadU16(&subtable.entry_selector) ||
         !table.ReadU16(&subtable.range_shift)) {
       return OTS_FAILURE_MSG("Failed to read kern subtable %d format 0 fields", i);
     }
 
     if (!num_pairs) {
-      DROP_THIS_TABLE("Zero length subtable is found");
+      DROP_THIS_TABLE("Zero length subtable is found.");
       return true;
     }
 
     // Sanity checks for search_range, entry_selector, and range_shift. See the
     // comment in ots.cc for details.
     const size_t kFormat0PairSize = 6;  // left, right, and value. 2 bytes each.
     if (num_pairs > (65536 / kFormat0PairSize)) {
       // Some fonts (e.g. calibri.ttf, pykes_peak_zero.ttf) have pairs >= 10923.
-      DROP_THIS_TABLE("Too large subtable");
+      DROP_THIS_TABLE("Too large subtable.");
       return true;
     }
     unsigned max_pow2 = 0;
     while (1u << (max_pow2 + 1) <= num_pairs) {
       ++max_pow2;
     }
     const uint16_t expected_search_range = (1u << max_pow2) * kFormat0PairSize;
     if (subtable.search_range != expected_search_range) {
@@ -130,41 +130,41 @@ bool ots_kern_parse(Font *font, const ui
           !table.ReadS16(&kerning_pair.value)) {
         return OTS_FAILURE_MSG("Failed to read subtable %d kerning pair %d", i, j);
       }
       const uint32_t current_pair
           = (kerning_pair.left << 16) + kerning_pair.right;
       if (j != 0 && current_pair <= last_pair) {
         // Many free fonts don't follow this rule, so we don't call OTS_FAILURE
         // in order to support these fonts.
-        DROP_THIS_TABLE("Kerning pairs are not sorted");
+        DROP_THIS_TABLE("Kerning pairs are not sorted.");
         return true;
       }
       last_pair = current_pair;
       subtable.pairs.push_back(kerning_pair);
     }
 
     kern->subtables.push_back(subtable);
   }
 
   if (!kern->subtables.size()) {
-    DROP_THIS_TABLE("All subtables are removed");
+    DROP_THIS_TABLE("All subtables are removed.");
     return true;
   }
 
   return true;
 }
 
-bool ots_kern_should_serialise(Font *font) {
-  if (!font->glyf) return false;  // this table is not for CFF fonts.
-  return font->kern != NULL;
+bool ots_kern_should_serialise(OpenTypeFile *file) {
+  if (!file->glyf) return false;  // this table is not for CFF fonts.
+  return file->kern != NULL;
 }
 
-bool ots_kern_serialise(OTSStream *out, Font *font) {
-  const OpenTypeKERN *kern = font->kern;
+bool ots_kern_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeKERN *kern = file->kern;
 
   const uint16_t num_subtables = static_cast<uint16_t>(kern->subtables.size());
   if (num_subtables != kern->subtables.size() ||
       !out->WriteU16(kern->version) ||
       !out->WriteU16(num_subtables)) {
     return OTS_FAILURE_MSG("Can't write kern table header");
   }
 
@@ -188,21 +188,16 @@ bool ots_kern_serialise(OTSStream *out, 
         return OTS_FAILURE_MSG("Failed to write kern pair %d for subtable %d", j, i);
       }
     }
   }
 
   return true;
 }
 
-void ots_kern_reuse(Font *font, Font *other) {
-  font->kern = other->kern;
-  font->kern_reused = true;
-}
-
-void ots_kern_free(Font *font) {
-  delete font->kern;
+void ots_kern_free(OpenTypeFile *file) {
+  delete file->kern;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
 #undef DROP_THIS_TABLE
--- a/gfx/ots/src/layout.cc
+++ b/gfx/ots/src/layout.cc
@@ -41,108 +41,108 @@ struct LangSysRecord {
   uint16_t offset;
 };
 
 struct FeatureRecord {
   uint32_t tag;
   uint16_t offset;
 };
 
-bool ParseLangSysTable(const ots::Font *font,
+bool ParseLangSysTable(const ots::OpenTypeFile *file,
                        ots::Buffer *subtable, const uint32_t tag,
                        const uint16_t num_features) {
   uint16_t offset_lookup_order = 0;
   uint16_t req_feature_index = 0;
   uint16_t feature_count = 0;
   if (!subtable->ReadU16(&offset_lookup_order) ||
       !subtable->ReadU16(&req_feature_index) ||
       !subtable->ReadU16(&feature_count)) {
-    return OTS_FAILURE_MSG("Failed to read langsys header for tag %c%c%c%c", OTS_UNTAG(tag));
+    return OTS_FAILURE_MSG("Failed to read langsys header for tag %4.4s", (char *)&tag);
   }
   // |offset_lookup_order| is reserved and should be NULL.
   if (offset_lookup_order != 0) {
-    return OTS_FAILURE_MSG("Bad lookup offset order %d for langsys tag %c%c%c%c", offset_lookup_order, OTS_UNTAG(tag));
+    return OTS_FAILURE_MSG("Bad lookup offset order %d for langsys tag %4.4s", offset_lookup_order, (char *)&tag);
   }
   if (req_feature_index != kNoRequiredFeatureIndexDefined &&
       req_feature_index >= num_features) {
-    return OTS_FAILURE_MSG("Bad required features index %d for langsys tag %c%c%c%c", req_feature_index, OTS_UNTAG(tag));
+    return OTS_FAILURE_MSG("Bad required features index %d for langsys tag %4.4s", req_feature_index, (char *)&tag);
   }
   if (feature_count > num_features) {
-    return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %c%c%c%c", feature_count, OTS_UNTAG(tag));
+    return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %4.4s", feature_count, (char *)&tag);
   }
 
   for (unsigned i = 0; i < feature_count; ++i) {
     uint16_t feature_index = 0;
     if (!subtable->ReadU16(&feature_index)) {
-      return OTS_FAILURE_MSG("Failed to read feature index %d for langsys tag %c%c%c%c", i, OTS_UNTAG(tag));
+      return OTS_FAILURE_MSG("Failed to read feature index %d for langsys tag %4.4s", i, (char *)&tag);
     }
     if (feature_index >= num_features) {
-      return OTS_FAILURE_MSG("Bad feature index %d for feature %d for langsys tag %c%c%c%c", feature_index, i, OTS_UNTAG(tag));
+      return OTS_FAILURE_MSG("Bad feature index %d for feature %d for langsys tag %4.4s", feature_index, i, (char *)&tag);
     }
   }
   return true;
 }
 
-bool ParseScriptTable(const ots::Font *font,
+bool ParseScriptTable(const ots::OpenTypeFile *file,
                       const uint8_t *data, const size_t length,
                       const uint32_t tag, const uint16_t num_features) {
   ots::Buffer subtable(data, length);
 
   uint16_t offset_default_lang_sys = 0;
   uint16_t lang_sys_count = 0;
   if (!subtable.ReadU16(&offset_default_lang_sys) ||
       !subtable.ReadU16(&lang_sys_count)) {
-    return OTS_FAILURE_MSG("Failed to read script header for script tag %c%c%c%c", OTS_UNTAG(tag));
+    return OTS_FAILURE_MSG("Failed to read script header for script tag %4.4s", (char *)&tag);
   }
 
   // The spec requires a script table for 'DFLT' tag must contain non-NULL
   // |offset_default_lang_sys| and |lang_sys_count| == 0
   if (tag == kScriptTableTagDflt &&
       (offset_default_lang_sys == 0 || lang_sys_count != 0)) {
-    return OTS_FAILURE_MSG("DFLT table doesn't satisfy the spec. for script tag %c%c%c%c", OTS_UNTAG(tag));
+    return OTS_FAILURE_MSG("DFLT table doesn't satisfy the spec. for script tag %4.4s", (char *)&tag);
   }
 
   const unsigned lang_sys_record_end =
       6 * static_cast<unsigned>(lang_sys_count) + 4;
   if (lang_sys_record_end > std::numeric_limits<uint16_t>::max()) {
-    return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %c%c%c%c", lang_sys_record_end, OTS_UNTAG(tag));
+    return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %4.4s", lang_sys_record_end, (char *)&tag);
   }
 
   std::vector<LangSysRecord> lang_sys_records;
   lang_sys_records.resize(lang_sys_count);
   uint32_t last_tag = 0;
   for (unsigned i = 0; i < lang_sys_count; ++i) {
     if (!subtable.ReadU32(&lang_sys_records[i].tag) ||
         !subtable.ReadU16(&lang_sys_records[i].offset)) {
-      return OTS_FAILURE_MSG("Failed to read langsys record header %d for script tag %c%c%c%c", i, OTS_UNTAG(tag));
+      return OTS_FAILURE_MSG("Failed to read langsys record header %d for script tag %4.4s", i, (char *)&tag);
     }
     // The record array must store the records alphabetically by tag
     if (last_tag != 0 && last_tag > lang_sys_records[i].tag) {
-      return OTS_FAILURE_MSG("Bad last tag %d for langsys record %d for script tag %c%c%c%c", last_tag, i, OTS_UNTAG(tag));
+      return OTS_FAILURE_MSG("Bad last tag %d for langsys record %d for script tag %4.4s", last_tag, i, (char *)&tag);
     }
     if (lang_sys_records[i].offset < lang_sys_record_end ||
         lang_sys_records[i].offset >= length) {
       return OTS_FAILURE_MSG("bad offset to lang sys table: %x",
                   lang_sys_records[i].offset);
     }
     last_tag = lang_sys_records[i].tag;
   }
 
   // Check lang sys tables
   for (unsigned i = 0; i < lang_sys_count; ++i) {
     subtable.set_offset(lang_sys_records[i].offset);
-    if (!ParseLangSysTable(font, &subtable, lang_sys_records[i].tag, num_features)) {
-      return OTS_FAILURE_MSG("Failed to parse langsys table %d (%c%c%c%c) for script tag %c%c%c%c", i, OTS_UNTAG(lang_sys_records[i].tag), OTS_UNTAG(tag));
+    if (!ParseLangSysTable(file, &subtable, lang_sys_records[i].tag, num_features)) {
+      return OTS_FAILURE_MSG("Failed to parse langsys table %d (%4.4s) for script tag %4.4s", i, (char *)&lang_sys_records[i].tag, (char *)&tag);
     }
   }
 
   return true;
 }
 
-bool ParseFeatureTable(const ots::Font *font,
+bool ParseFeatureTable(const ots::OpenTypeFile *file,
                        const uint8_t *data, const size_t length,
                        const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t offset_feature_params = 0;
   uint16_t lookup_count = 0;
   if (!subtable.ReadU16(&offset_feature_params) ||
       !subtable.ReadU16(&lookup_count)) {
@@ -169,17 +169,17 @@ bool ParseFeatureTable(const ots::Font *
     // lookup index starts with 0.
     if (lookup_index >= num_lookups) {
       return OTS_FAILURE_MSG("Bad lookup index %d for lookup %d", lookup_index, i);
     }
   }
   return true;
 }
 
-bool ParseLookupTable(ots::Font *font, const uint8_t *data,
+bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data,
                       const size_t length,
                       const ots::LookupSubtableParser* parser) {
   ots::Buffer subtable(data, length);
 
   uint16_t lookup_type = 0;
   uint16_t lookup_flag = 0;
   uint16_t subtable_count = 0;
   if (!subtable.ReadU16(&lookup_type) ||
@@ -189,26 +189,26 @@ bool ParseLookupTable(ots::Font *font, c
   }
 
   if (lookup_type == 0 || lookup_type > parser->num_types) {
     return OTS_FAILURE_MSG("Bad lookup type %d", lookup_type);
   }
 
   // Check lookup flags.
   if ((lookup_flag & kGdefRequiredFlags) &&
-      (!font->gdef || !font->gdef->has_glyph_class_def)) {
+      (!file->gdef || !file->gdef->has_glyph_class_def)) {
     return OTS_FAILURE_MSG("Bad lookup flags %d", lookup_flag);
   }
   if ((lookup_flag & kMarkAttachmentTypeMask) &&
-      (!font->gdef || !font->gdef->has_mark_attachment_class_def)) {
+      (!file->gdef || !file->gdef->has_mark_attachment_class_def)) {
     return OTS_FAILURE_MSG("lookup flag asks for mark attachment that is bad %d", lookup_flag);
   }
   bool use_mark_filtering_set = false;
   if (lookup_flag & kUseMarkFilteringSetBit) {
-    if (!font->gdef || !font->gdef->has_mark_glyph_sets_def) {
+    if (!file->gdef || !file->gdef->has_mark_glyph_sets_def) {
       return OTS_FAILURE_MSG("lookup flag asks for mark filtering that is bad %d", lookup_flag);
     }
     use_mark_filtering_set = true;
   }
 
   std::vector<uint16_t> subtables;
   subtables.reserve(subtable_count);
   // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set,
@@ -233,33 +233,33 @@ bool ParseLookupTable(ots::Font *font, c
     return OTS_FAILURE_MSG("Bad subtable size %ld", subtables.size());
   }
 
   if (use_mark_filtering_set) {
     uint16_t mark_filtering_set = 0;
     if (!subtable.ReadU16(&mark_filtering_set)) {
       return OTS_FAILURE_MSG("Failed to read mark filtering set");
     }
-    if (font->gdef->num_mark_glyph_sets == 0 ||
-        mark_filtering_set >= font->gdef->num_mark_glyph_sets) {
+    if (file->gdef->num_mark_glyph_sets == 0 ||
+        mark_filtering_set >= file->gdef->num_mark_glyph_sets) {
       return OTS_FAILURE_MSG("Bad mark filtering set %d", mark_filtering_set);
     }
   }
 
   // Parse lookup subtables for this lookup type.
   for (unsigned i = 0; i < subtable_count; ++i) {
-    if (!parser->Parse(font, data + subtables[i], length - subtables[i],
+    if (!parser->Parse(file, data + subtables[i], length - subtables[i],
                        lookup_type)) {
       return OTS_FAILURE_MSG("Failed to parse subtable %d", i);
     }
   }
   return true;
 }
 
-bool ParseClassDefFormat1(const ots::Font *font,
+bool ParseClassDefFormat1(const ots::OpenTypeFile *file,
                           const uint8_t *data, size_t length,
                           const uint16_t num_glyphs,
                           const uint16_t num_classes) {
   ots::Buffer subtable(data, length);
 
   // Skip format field.
   if (!subtable.Skip(2)) {
     return OTS_FAILURE_MSG("Failed to skip class definition header");
@@ -288,17 +288,17 @@ bool ParseClassDefFormat1(const ots::Fon
     if (class_value > num_classes) {
       return OTS_FAILURE_MSG("Bad class value %d for glyph %d in class definition", class_value, i);
     }
   }
 
   return true;
 }
 
-bool ParseClassDefFormat2(const ots::Font *font,
+bool ParseClassDefFormat2(const ots::OpenTypeFile *file,
                           const uint8_t *data, size_t length,
                           const uint16_t num_glyphs,
                           const uint16_t num_classes) {
   ots::Buffer subtable(data, length);
 
   // Skip format field.
   if (!subtable.Skip(2)) {
     return OTS_FAILURE_MSG("Failed to skip format of class defintion header");
@@ -329,17 +329,17 @@ bool ParseClassDefFormat2(const ots::Fon
       return OTS_FAILURE_MSG("bad class value: %u", class_value);
     }
     last_end = end;
   }
 
   return true;
 }
 
-bool ParseCoverageFormat1(const ots::Font *font,
+bool ParseCoverageFormat1(const ots::OpenTypeFile *file,
                           const uint8_t *data, size_t length,
                           const uint16_t num_glyphs,
                           const uint16_t expected_num_glyphs) {
   ots::Buffer subtable(data, length);
 
   // Skip format field.
   if (!subtable.Skip(2)) {
     return OTS_FAILURE_MSG("Failed to skip coverage format");
@@ -364,17 +364,17 @@ bool ParseCoverageFormat1(const ots::Fon
 
   if (expected_num_glyphs && expected_num_glyphs != glyph_count) {
       return OTS_FAILURE_MSG("unexpected number of glyphs: %u", glyph_count);
   }
 
   return true;
 }
 
-bool ParseCoverageFormat2(const ots::Font *font,
+bool ParseCoverageFormat2(const ots::OpenTypeFile *file,
                           const uint8_t *data, size_t length,
                           const uint16_t num_glyphs,
                           const uint16_t expected_num_glyphs) {
   ots::Buffer subtable(data, length);
 
   // Skip format field.
   if (!subtable.Skip(2)) {
     return OTS_FAILURE_MSG("Failed to skip format of coverage type 2");
@@ -418,17 +418,17 @@ bool ParseCoverageFormat2(const ots::Fon
       return OTS_FAILURE_MSG("unexpected number of glyphs: %u", last_start_coverage_index);
   }
 
   return true;
 }
 
 // Parsers for Contextual subtables in GSUB/GPOS tables.
 
-bool ParseLookupRecord(const ots::Font *font,
+bool ParseLookupRecord(const ots::OpenTypeFile *file,
                        ots::Buffer *subtable, const uint16_t num_glyphs,
                        const uint16_t num_lookups) {
   uint16_t sequence_index = 0;
   uint16_t lookup_list_index = 0;
   if (!subtable->ReadU16(&sequence_index) ||
       !subtable->ReadU16(&lookup_list_index)) {
     return OTS_FAILURE_MSG("Failed to read header for lookup record");
   }
@@ -436,17 +436,17 @@ bool ParseLookupRecord(const ots::Font *
     return OTS_FAILURE_MSG("Bad sequence index %d in lookup record", sequence_index);
   }
   if (lookup_list_index >= num_lookups) {
     return OTS_FAILURE_MSG("Bad lookup list index %d in lookup record", lookup_list_index);
   }
   return true;
 }
 
-bool ParseRuleSubtable(const ots::Font *font,
+bool ParseRuleSubtable(const ots::OpenTypeFile *file,
                        const uint8_t *data, const size_t length,
                        const uint16_t num_glyphs,
                        const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t glyph_count = 0;
   uint16_t lookup_count = 0;
   if (!subtable.ReadU16(&glyph_count) ||
@@ -463,24 +463,24 @@ bool ParseRuleSubtable(const ots::Font *
       return OTS_FAILURE_MSG("Failed to read glyph %d", i);
     }
     if (glyph_id > num_glyphs) {
       return OTS_FAILURE_MSG("Bad glyph %d for entry %d", glyph_id, i);
     }
   }
 
   for (unsigned i = 0; i < lookup_count; ++i) {
-    if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
+    if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse lookup record %d", i);
     }
   }
   return true;
 }
 
-bool ParseRuleSetTable(const ots::Font *font,
+bool ParseRuleSetTable(const ots::OpenTypeFile *file,
                        const uint8_t *data, const size_t length,
                        const uint16_t num_glyphs,
                        const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t rule_count = 0;
   if (!subtable.ReadU16(&rule_count)) {
     return OTS_FAILURE_MSG("Failed to read rule count in rule set");
@@ -493,26 +493,26 @@ bool ParseRuleSetTable(const ots::Font *
   for (unsigned i = 0; i < rule_count; ++i) {
     uint16_t offset_rule = 0;
     if (!subtable.ReadU16(&offset_rule)) {
       return OTS_FAILURE_MSG("Failed to read rule offset for rule set %d", i);
     }
     if (offset_rule < rule_end || offset_rule >= length) {
       return OTS_FAILURE_MSG("Bad rule offset %d in set %d", offset_rule, i);
     }
-    if (!ParseRuleSubtable(font, data + offset_rule, length - offset_rule,
+    if (!ParseRuleSubtable(file, data + offset_rule, length - offset_rule,
                            num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse rule set %d", i);
     }
   }
 
   return true;
 }
 
-bool ParseContextFormat1(const ots::Font *font,
+bool ParseContextFormat1(const ots::OpenTypeFile *file,
                          const uint8_t *data, const size_t length,
                          const uint16_t num_glyphs,
                          const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t offset_coverage = 0;
   uint16_t rule_set_count = 0;
   // Skip format field.
@@ -525,39 +525,39 @@ bool ParseContextFormat1(const ots::Font
   const unsigned rule_set_end = static_cast<unsigned>(6) +
       rule_set_count * 2;
   if (rule_set_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE_MSG("Bad end of rule set %d of context format 1", rule_set_end);
   }
   if (offset_coverage < rule_set_end || offset_coverage >= length) {
     return OTS_FAILURE_MSG("Bad coverage offset %d in context format 1", offset_coverage);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage, num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table in context format 1");
   }
 
   for (unsigned i = 0; i < rule_set_count; ++i) {
     uint16_t offset_rule = 0;
     if (!subtable.ReadU16(&offset_rule)) {
       return OTS_FAILURE_MSG("Failed to read rule offset %d in context format 1", i);
     }
     if (offset_rule < rule_set_end || offset_rule >= length) {
       return OTS_FAILURE_MSG("Bad rule offset %d in rule %d in context format 1", offset_rule, i);
     }
-    if (!ParseRuleSetTable(font, data + offset_rule, length - offset_rule,
+    if (!ParseRuleSetTable(file, data + offset_rule, length - offset_rule,
                            num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse rule set %d in context format 1", i);
     }
   }
 
   return true;
 }
 
-bool ParseClassRuleTable(const ots::Font *font,
+bool ParseClassRuleTable(const ots::OpenTypeFile *file,
                          const uint8_t *data, const size_t length,
                          const uint16_t num_glyphs,
                          const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t glyph_count = 0;
   uint16_t lookup_count = 0;
   if (!subtable.ReadU16(&glyph_count) ||
@@ -572,24 +572,24 @@ bool ParseClassRuleTable(const ots::Font
   // ClassRule table contains an array of classes. Each value of classes
   // could take arbitrary values including zero so we don't check these value.
   const unsigned num_classes = glyph_count - static_cast<unsigned>(1);
   if (!subtable.Skip(2 * num_classes)) {
     return OTS_FAILURE_MSG("Failed to skip classes in class rule table");
   }
 
   for (unsigned i = 0; i < lookup_count; ++i) {
-    if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
+    if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse lookup record %d in class rule table", i);
     }
   }
   return true;
 }
 
-bool ParseClassSetTable(const ots::Font *font,
+bool ParseClassSetTable(const ots::OpenTypeFile *file,
                         const uint8_t *data, const size_t length,
                         const uint16_t num_glyphs,
                         const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t class_rule_count = 0;
   if (!subtable.ReadU16(&class_rule_count)) {
     return OTS_FAILURE_MSG("Failed to read class rule count in class set table");
@@ -602,27 +602,27 @@ bool ParseClassSetTable(const ots::Font 
   for (unsigned i = 0; i < class_rule_count; ++i) {
     uint16_t offset_class_rule = 0;
     if (!subtable.ReadU16(&offset_class_rule)) {
       return OTS_FAILURE_MSG("Failed to read class rule offset %d in class set table", i);
     }
     if (offset_class_rule < class_rule_end || offset_class_rule >= length) {
       return OTS_FAILURE_MSG("Bad class rule offset %d in class %d", offset_class_rule, i);
     }
-    if (!ParseClassRuleTable(font, data + offset_class_rule,
+    if (!ParseClassRuleTable(file, data + offset_class_rule,
                              length - offset_class_rule, num_glyphs,
                              num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse class rule table %d", i);
     }
   }
 
   return true;
 }
 
-bool ParseContextFormat2(const ots::Font *font,
+bool ParseContextFormat2(const ots::OpenTypeFile *file,
                          const uint8_t *data, const size_t length,
                          const uint16_t num_glyphs,
                          const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t offset_coverage = 0;
   uint16_t offset_class_def = 0;
   uint16_t class_set_cnt = 0;
@@ -636,51 +636,51 @@ bool ParseContextFormat2(const ots::Font
 
   const unsigned class_set_end = 2 * static_cast<unsigned>(class_set_cnt) + 8;
   if (class_set_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE_MSG("Bad end of class set %d for context format 2", class_set_end);
   }
   if (offset_coverage < class_set_end || offset_coverage >= length) {
     return OTS_FAILURE_MSG("Bad coverage offset %d in context format 2", offset_coverage);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage, num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table in context format 2");
   }
 
   if (offset_class_def < class_set_end || offset_class_def >= length) {
     return OTS_FAILURE_MSG("bad class definition offset %d in context format 2", offset_class_def);
   }
-  if (!ots::ParseClassDefTable(font, data + offset_class_def,
+  if (!ots::ParseClassDefTable(file, data + offset_class_def,
                                length - offset_class_def,
                                num_glyphs, kMaxClassDefValue)) {
     return OTS_FAILURE_MSG("Failed to parse class definition table in context format 2");
   }
 
   for (unsigned i = 0; i < class_set_cnt; ++i) {
     uint16_t offset_class_rule = 0;
     if (!subtable.ReadU16(&offset_class_rule)) {
       return OTS_FAILURE_MSG("Failed to read class rule offset %d in context format 2", i);
     }
     if (offset_class_rule) {
       if (offset_class_rule < class_set_end || offset_class_rule >= length) {
         return OTS_FAILURE_MSG("Bad class rule offset %d for rule %d in context format 2", offset_class_rule, i);
       }
-      if (!ParseClassSetTable(font, data + offset_class_rule,
+      if (!ParseClassSetTable(file, data + offset_class_rule,
                               length - offset_class_rule, num_glyphs,
                               num_lookups)) {
         return OTS_FAILURE_MSG("Failed to parse class set %d in context format 2", i);
       }
     }
   }
 
   return true;
 }
 
-bool ParseContextFormat3(const ots::Font *font,
+bool ParseContextFormat3(const ots::OpenTypeFile *file,
                          const uint8_t *data, const size_t length,
                          const uint16_t num_glyphs,
                          const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t glyph_count = 0;
   uint16_t lookup_count = 0;
   // Skip format field.
@@ -701,34 +701,34 @@ bool ParseContextFormat3(const ots::Font
   for (unsigned i = 0; i < glyph_count; ++i) {
     uint16_t offset_coverage = 0;
     if (!subtable.ReadU16(&offset_coverage)) {
       return OTS_FAILURE_MSG("Failed to read coverage offset %d in conxtext format 3", i);
     }
     if (offset_coverage < lookup_record_end || offset_coverage >= length) {
       return OTS_FAILURE_MSG("Bad coverage offset %d for glyph %d in context format 3", offset_coverage, i);
     }
-    if (!ots::ParseCoverageTable(font, data + offset_coverage,
+    if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                  length - offset_coverage, num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse coverage table for glyph %d in context format 3", i);
     }
   }
 
   for (unsigned i = 0; i < lookup_count; ++i) {
-    if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
+    if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse lookup record %d in context format 3", i);
     }
   }
 
   return true;
 }
 
 // Parsers for Chaning Contextual subtables in GSUB/GPOS tables.
 
-bool ParseChainRuleSubtable(const ots::Font *font,
+bool ParseChainRuleSubtable(const ots::OpenTypeFile *file,
                             const uint8_t *data, const size_t length,
                             const uint16_t num_glyphs,
                             const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t backtrack_count = 0;
   if (!subtable.ReadU16(&backtrack_count)) {
     return OTS_FAILURE_MSG("Failed to read backtrack count in chain rule subtable");
@@ -780,25 +780,25 @@ bool ParseChainRuleSubtable(const ots::F
     }
   }
 
   uint16_t lookup_count = 0;
   if (!subtable.ReadU16(&lookup_count)) {
     return OTS_FAILURE_MSG("Failed to read lookup count in chain rule subtable");
   }
   for (unsigned i = 0; i < lookup_count; ++i) {
-    if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
+    if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain rule subtable", i);
     }
   }
 
   return true;
 }
 
-bool ParseChainRuleSetTable(const ots::Font *font,
+bool ParseChainRuleSetTable(const ots::OpenTypeFile *file,
                             const uint8_t *data, const size_t length,
                             const uint16_t num_glyphs,
                             const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t chain_rule_count = 0;
   if (!subtable.ReadU16(&chain_rule_count)) {
     return OTS_FAILURE_MSG("Failed to read rule count in chain rule set");
@@ -811,27 +811,27 @@ bool ParseChainRuleSetTable(const ots::F
   for (unsigned i = 0; i < chain_rule_count; ++i) {
     uint16_t offset_chain_rule = 0;
     if (!subtable.ReadU16(&offset_chain_rule)) {
       return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain rule set", i);
     }
     if (offset_chain_rule < chain_rule_end || offset_chain_rule >= length) {
       return OTS_FAILURE_MSG("Bad chain rule offset %d for chain rule %d in chain rule set", offset_chain_rule, i);
     }
-    if (!ParseChainRuleSubtable(font, data + offset_chain_rule,
+    if (!ParseChainRuleSubtable(file, data + offset_chain_rule,
                                 length - offset_chain_rule,
                                 num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse chain rule %d in chain rule set", i);
     }
   }
 
   return true;
 }
 
-bool ParseChainContextFormat1(const ots::Font *font,
+bool ParseChainContextFormat1(const ots::OpenTypeFile *file,
                               const uint8_t *data, const size_t length,
                               const uint16_t num_glyphs,
                               const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t offset_coverage = 0;
   uint16_t chain_rule_set_count = 0;
   // Skip format field.
@@ -844,41 +844,41 @@ bool ParseChainContextFormat1(const ots:
   const unsigned chain_rule_set_end =
       2 * static_cast<unsigned>(chain_rule_set_count) + 6;
   if (chain_rule_set_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE_MSG("Bad chain rule end %d in chain context format 1", chain_rule_set_end);
   }
   if (offset_coverage < chain_rule_set_end || offset_coverage >= length) {
     return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 1", chain_rule_set_end);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage, num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table for chain context format 1");
   }
 
   for (unsigned i = 0; i < chain_rule_set_count; ++i) {
     uint16_t offset_chain_rule_set = 0;
     if (!subtable.ReadU16(&offset_chain_rule_set)) {
       return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain context format 1", i);
     }
     if (offset_chain_rule_set < chain_rule_set_end ||
         offset_chain_rule_set >= length) {
       return OTS_FAILURE_MSG("Bad chain rule set offset %d for chain rule set %d in chain context format 1", offset_chain_rule_set, i);
     }
-    if (!ParseChainRuleSetTable(font, data + offset_chain_rule_set,
+    if (!ParseChainRuleSetTable(file, data + offset_chain_rule_set,
                                    length - offset_chain_rule_set,
                                    num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse chain rule set %d in chain context format 1", i);
     }
   }
 
   return true;
 }
 
-bool ParseChainClassRuleSubtable(const ots::Font *font,
+bool ParseChainClassRuleSubtable(const ots::OpenTypeFile *file,
                                  const uint8_t *data, const size_t length,
                                  const uint16_t num_glyphs,
                                  const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   // In this subtable, we don't check the value of classes for now since
   // these could take arbitrary values.
 
@@ -915,25 +915,25 @@ bool ParseChainClassRuleSubtable(const o
     return OTS_FAILURE_MSG("Failed to skip lookahead offsets in chain class rule subtable");
   }
 
   uint16_t lookup_count = 0;
   if (!subtable.ReadU16(&lookup_count)) {
     return OTS_FAILURE_MSG("Failed to read lookup count in chain class rule subtable");
   }
   for (unsigned i = 0; i < lookup_count; ++i) {
-    if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
+    if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain class rule subtable", i);
     }
   }
 
   return true;
 }
 
-bool ParseChainClassSetTable(const ots::Font *font,
+bool ParseChainClassSetTable(const ots::OpenTypeFile *file,
                              const uint8_t *data, const size_t length,
                              const uint16_t num_glyphs,
                              const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t chain_class_rule_count = 0;
   if (!subtable.ReadU16(&chain_class_rule_count)) {
     return OTS_FAILURE_MSG("Failed to read rule count in chain class set");
@@ -947,27 +947,27 @@ bool ParseChainClassSetTable(const ots::
     uint16_t offset_chain_class_rule = 0;
     if (!subtable.ReadU16(&offset_chain_class_rule)) {
       return OTS_FAILURE_MSG("Failed to read chain class rule offset %d in chain class set", i);
     }
     if (offset_chain_class_rule < chain_class_rule_end ||
         offset_chain_class_rule >= length) {
       return OTS_FAILURE_MSG("Bad chain class rule offset %d for chain class %d in chain class set", offset_chain_class_rule, i);
     }
-    if (!ParseChainClassRuleSubtable(font, data + offset_chain_class_rule,
+    if (!ParseChainClassRuleSubtable(file, data + offset_chain_class_rule,
                                      length - offset_chain_class_rule,
                                      num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse chain class rule %d in chain class set", i);
     }
   }
 
   return true;
 }
 
-bool ParseChainContextFormat2(const ots::Font *font,
+bool ParseChainContextFormat2(const ots::OpenTypeFile *file,
                               const uint8_t *data, const size_t length,
                               const uint16_t num_glyphs,
                               const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t offset_coverage = 0;
   uint16_t offset_backtrack_class_def = 0;
   uint16_t offset_input_class_def = 0;
@@ -986,50 +986,50 @@ bool ParseChainContextFormat2(const ots:
   const unsigned chain_class_set_end =
       2 * static_cast<unsigned>(chain_class_set_count) + 12;
   if (chain_class_set_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE_MSG("Bad chain class set end %d in chain context format 2", chain_class_set_end);
   }
   if (offset_coverage < chain_class_set_end || offset_coverage >= length) {
     return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 2", offset_coverage);
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage, num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to parse coverage table in chain context format 2");
   }
 
   // Classes for backtrack/lookahead sequences might not be defined.
   if (offset_backtrack_class_def) {
     if (offset_backtrack_class_def < chain_class_set_end ||
         offset_backtrack_class_def >= length) {
       return OTS_FAILURE_MSG("Bad backtrack class offset %d in chain context format 2", offset_backtrack_class_def);
     }
-    if (!ots::ParseClassDefTable(font, data + offset_backtrack_class_def,
+    if (!ots::ParseClassDefTable(file, data + offset_backtrack_class_def,
                                  length - offset_backtrack_class_def,
                                  num_glyphs, kMaxClassDefValue)) {
       return OTS_FAILURE_MSG("Failed to parse backtrack class defn table in chain context format 2");
     }
   }
 
   if (offset_input_class_def < chain_class_set_end ||
       offset_input_class_def >= length) {
     return OTS_FAILURE_MSG("Bad input class defn offset %d in chain context format 2", offset_input_class_def);
   }
-  if (!ots::ParseClassDefTable(font, data + offset_input_class_def,
+  if (!ots::ParseClassDefTable(file, data + offset_input_class_def,
                                length - offset_input_class_def,
                                num_glyphs, kMaxClassDefValue)) {
     return OTS_FAILURE_MSG("Failed to parse input class defn in chain context format 2");
   }
 
   if (offset_lookahead_class_def) {
     if (offset_lookahead_class_def < chain_class_set_end ||
         offset_lookahead_class_def >= length) {
       return OTS_FAILURE_MSG("Bad lookahead class defn offset %d in chain context format 2", offset_lookahead_class_def);
     }
-    if (!ots::ParseClassDefTable(font, data + offset_lookahead_class_def,
+    if (!ots::ParseClassDefTable(file, data + offset_lookahead_class_def,
                                  length - offset_lookahead_class_def,
                                  num_glyphs, kMaxClassDefValue)) {
       return OTS_FAILURE_MSG("Failed to parse lookahead class defn in chain context format 2");
     }
   }
 
   for (unsigned i = 0; i < chain_class_set_count; ++i) {
     uint16_t offset_chain_class_set = 0;
@@ -1037,28 +1037,28 @@ bool ParseChainContextFormat2(const ots:
       return OTS_FAILURE_MSG("Failed to read chain class set offset %d", i);
     }
     // |offset_chain_class_set| could be NULL.
     if (offset_chain_class_set) {
       if (offset_chain_class_set < chain_class_set_end ||
           offset_chain_class_set >= length) {
         return OTS_FAILURE_MSG("Bad chain set class offset %d for chain set %d in chain context format 2", offset_chain_class_set, i);
       }
-      if (!ParseChainClassSetTable(font, data + offset_chain_class_set,
+      if (!ParseChainClassSetTable(file, data + offset_chain_class_set,
                                    length - offset_chain_class_set,
                                    num_glyphs, num_lookups)) {
         return OTS_FAILURE_MSG("Failed to parse chain class set table %d in chain context format 2", i);
       }
     }
   }
 
   return true;
 }
 
-bool ParseChainContextFormat3(const ots::Font *font,
+bool ParseChainContextFormat3(const ots::OpenTypeFile *file,
                               const uint8_t *data, const size_t length,
                               const uint16_t num_glyphs,
                               const uint16_t num_lookups) {
   ots::Buffer subtable(data, length);
 
   uint16_t backtrack_count = 0;
   // Skip format field.
   if (!subtable.Skip(2) ||
@@ -1122,17 +1122,17 @@ bool ParseChainContextFormat3(const ots:
     return OTS_FAILURE_MSG("Bad lookahead offsets size %ld in chain context format 3", offsets_lookahead.size());
   }
 
   uint16_t lookup_count = 0;
   if (!subtable.ReadU16(&lookup_count)) {
     return OTS_FAILURE_MSG("Failed to read lookup count in chain context format 3");
   }
   for (unsigned i = 0; i < lookup_count; ++i) {
-    if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
+    if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse lookup %d in chain context format 3", i);
     }
   }
 
   const unsigned lookup_record_end =
       2 * (static_cast<unsigned>(backtrack_count) +
            static_cast<unsigned>(input_count) +
            static_cast<unsigned>(lookahead_count)) +
@@ -1140,65 +1140,65 @@ bool ParseChainContextFormat3(const ots:
   if (lookup_record_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE_MSG("Bad end of lookup record %d in chain context format 3", lookup_record_end);
   }
   for (unsigned i = 0; i < backtrack_count; ++i) {
     if (offsets_backtrack[i] < lookup_record_end ||
         offsets_backtrack[i] >= length) {
       return OTS_FAILURE_MSG("Bad backtrack offset of %d for backtrack %d in chain context format 3", offsets_backtrack[i], i);
     }
-    if (!ots::ParseCoverageTable(font, data + offsets_backtrack[i],
+    if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i],
                                  length - offsets_backtrack[i], num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse backtrack coverage %d in chain context format 3", i);
     }
   }
   for (unsigned i = 0; i < input_count; ++i) {
     if (offsets_input[i] < lookup_record_end || offsets_input[i] >= length) {
       return OTS_FAILURE_MSG("Bad input offset %d for input %d in chain context format 3", offsets_input[i], i);
     }
-    if (!ots::ParseCoverageTable(font, data + offsets_input[i],
+    if (!ots::ParseCoverageTable(file, data + offsets_input[i],
                                  length - offsets_input[i], num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse input coverage table %d in chain context format 3", i);
     }
   }
   for (unsigned i = 0; i < lookahead_count; ++i) {
     if (offsets_lookahead[i] < lookup_record_end ||
         offsets_lookahead[i] >= length) {
       return OTS_FAILURE_MSG("Bad lookadhead offset %d for lookahead %d in chain context format 3", offsets_lookahead[i], i);
     }
-    if (!ots::ParseCoverageTable(font, data + offsets_lookahead[i],
+    if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i],
                                  length - offsets_lookahead[i], num_glyphs)) {
       return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in chain context format 3", i);
     }
   }
 
   return true;
 }
 
 }  // namespace
 
 namespace ots {
 
-bool LookupSubtableParser::Parse(const Font *font, const uint8_t *data,
+bool LookupSubtableParser::Parse(const OpenTypeFile *file, const uint8_t *data,
                                  const size_t length,
                                  const uint16_t lookup_type) const {
   for (unsigned i = 0; i < num_types; ++i) {
     if (parsers[i].type == lookup_type && parsers[i].parse) {
-      if (!parsers[i].parse(font, data, length)) {
+      if (!parsers[i].parse(file, data, length)) {
         return OTS_FAILURE_MSG("Failed to parse lookup subtable %d", i);
       }
       return true;
     }
   }
   return OTS_FAILURE_MSG("No lookup subtables to parse");
 }
 
 // Parsing ScriptListTable requires number of features so we need to
 // parse FeatureListTable before calling this function.
-bool ParseScriptListTable(const ots::Font *font,
+bool ParseScriptListTable(const ots::OpenTypeFile *file,
                           const uint8_t *data, const size_t length,
                           const uint16_t num_features) {
   Buffer subtable(data, length);
 
   uint16_t script_count = 0;
   if (!subtable.ReadU16(&script_count)) {
     return OTS_FAILURE_MSG("Failed to read script count in script list table");
   }
@@ -1221,39 +1221,39 @@ bool ParseScriptListTable(const ots::Fon
     if (last_tag != 0 && last_tag > record.tag) {
       // Several fonts don't arrange tags alphabetically.
       // It seems that the order of tags might not be a security issue
       // so we just warn it.
       OTS_WARNING("tags aren't arranged alphabetically.");
     }
     last_tag = record.tag;
     if (record.offset < script_record_end || record.offset >= length) {
-      return OTS_FAILURE_MSG("Bad record offset %d for script %c%c%c%c entry %d in script list table", record.offset, OTS_UNTAG(record.tag), i);
+      return OTS_FAILURE_MSG("Bad record offset %d for script %4.4s entry %d in script list table", record.offset, (char *)&record.tag, i);
     }
     script_list.push_back(record);
   }
   if (script_list.size() != script_count) {
     return OTS_FAILURE_MSG("Bad script list size %ld in script list table", script_list.size());
   }
 
   // Check script records.
   for (unsigned i = 0; i < script_count; ++i) {
-    if (!ParseScriptTable(font, data + script_list[i].offset,
+    if (!ParseScriptTable(file, data + script_list[i].offset,
                           length - script_list[i].offset,
                           script_list[i].tag, num_features)) {
       return OTS_FAILURE_MSG("Failed to parse script table %d", i);
     }
   }
 
   return true;
 }
 
 // Parsing FeatureListTable requires number of lookups so we need to parse
 // LookupListTable before calling this function.
-bool ParseFeatureListTable(const ots::Font *font,
+bool ParseFeatureListTable(const ots::OpenTypeFile *file,
                            const uint8_t *data, const size_t length,
                            const uint16_t num_lookups,
                            uint16_t* num_features) {
   Buffer subtable(data, length);
 
   uint16_t feature_count = 0;
   if (!subtable.ReadU16(&feature_count)) {
     return OTS_FAILURE_MSG("Failed to read feature count");
@@ -1277,34 +1277,34 @@ bool ParseFeatureListTable(const ots::Fo
       // Several fonts don't arrange tags alphabetically.
       // It seems that the order of tags might not be a security issue
       // so we just warn it.
       OTS_WARNING("tags aren't arranged alphabetically.");
     }
     last_tag = feature_records[i].tag;
     if (feature_records[i].offset < feature_record_end ||
         feature_records[i].offset >= length) {
-      return OTS_FAILURE_MSG("Bad feature offset %d for feature %d %c%c%c%c", feature_records[i].offset, i, OTS_UNTAG(feature_records[i].tag));
+      return OTS_FAILURE_MSG("Bad feature offset %d for feature %d %4.4s", feature_records[i].offset, i, (char *)&feature_records[i].tag);
     }
   }
 
   for (unsigned i = 0; i < feature_count; ++i) {
-    if (!ParseFeatureTable(font, data + feature_records[i].offset,
+    if (!ParseFeatureTable(file, data + feature_records[i].offset,
                            length - feature_records[i].offset, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse feature table %d", i);
     }
   }
   *num_features = feature_count;
   return true;
 }
 
 // For parsing GPOS/GSUB tables, this function should be called at first to
 // obtain the number of lookups because parsing FeatureTableList requires
 // the number.
-bool ParseLookupListTable(Font *font, const uint8_t *data,
+bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
                           const size_t length,
                           const LookupSubtableParser* parser,
                           uint16_t *num_lookups) {
   Buffer subtable(data, length);
 
   if (!subtable.ReadU16(num_lookups)) {
     return OTS_FAILURE_MSG("Failed to read number of lookups");
   }
@@ -1326,64 +1326,64 @@ bool ParseLookupListTable(Font *font, co
     }
     lookups.push_back(offset);
   }
   if (lookups.size() != *num_lookups) {
     return OTS_FAILURE_MSG("Bad lookup offsets list size %ld", lookups.size());
   }
 
   for (unsigned i = 0; i < *num_lookups; ++i) {
-    if (!ParseLookupTable(font, data + lookups[i], length - lookups[i],
+    if (!ParseLookupTable(file, data + lookups[i], length - lookups[i],
                           parser)) {
       return OTS_FAILURE_MSG("Failed to parse lookup %d", i);
     }
   }
 
   return true;
 }
 
-bool ParseClassDefTable(const ots::Font *font,
+bool ParseClassDefTable(const ots::OpenTypeFile *file,
                         const uint8_t *data, size_t length,
                         const uint16_t num_glyphs,
                         const uint16_t num_classes) {
   Buffer subtable(data, length);
 
   uint16_t format = 0;
   if (!subtable.ReadU16(&format)) {
     return OTS_FAILURE_MSG("Failed to read class defn format");
   }
   if (format == 1) {
-    return ParseClassDefFormat1(font, data, length, num_glyphs, num_classes);
+    return ParseClassDefFormat1(file, data, length, num_glyphs, num_classes);
   } else if (format == 2) {
-    return ParseClassDefFormat2(font, data, length, num_glyphs, num_classes);
+    return ParseClassDefFormat2(file, data, length, num_glyphs, num_classes);
   }
 
   return OTS_FAILURE_MSG("Bad class defn format %d", format);
 }
 
-bool ParseCoverageTable(const ots::Font *font,
+bool ParseCoverageTable(const ots::OpenTypeFile *file,
                         const uint8_t *data, size_t length,
                         const uint16_t num_glyphs,
                         const uint16_t expected_num_glyphs) {
   Buffer subtable(data, length);
 
   uint16_t format = 0;
   if (!subtable.ReadU16(&format)) {
     return OTS_FAILURE_MSG("Failed to read coverage table format");
   }
   if (format == 1) {
-    return ParseCoverageFormat1(font, data, length, num_glyphs, expected_num_glyphs);
+    return ParseCoverageFormat1(file, data, length, num_glyphs, expected_num_glyphs);
   } else if (format == 2) {
-    return ParseCoverageFormat2(font, data, length, num_glyphs, expected_num_glyphs);
+    return ParseCoverageFormat2(file, data, length, num_glyphs, expected_num_glyphs);
   }
 
   return OTS_FAILURE_MSG("Bad coverage table format %d", format);
 }
 
-bool ParseDeviceTable(const ots::Font *font,
+bool ParseDeviceTable(const ots::OpenTypeFile *file,
                       const uint8_t *data, size_t length) {
   Buffer subtable(data, length);
 
   uint16_t start_size = 0;
   uint16_t end_size = 0;
   uint16_t delta_format = 0;
   if (!subtable.ReadU16(&start_size) ||
       !subtable.ReadU16(&end_size) ||
@@ -1403,77 +1403,77 @@ bool ParseDeviceTable(const ots::Font *f
   // Just skip |num_units| * 2 bytes since the compressed data could take
   // arbitrary values.
   if (!subtable.Skip(num_units * 2)) {
     return OTS_FAILURE_MSG("Failed to skip data in device table");
   }
   return true;
 }
 
-bool ParseContextSubtable(const ots::Font *font,
+bool ParseContextSubtable(const ots::OpenTypeFile *file,
                           const uint8_t *data, const size_t length,
                           const uint16_t num_glyphs,
                           const uint16_t num_lookups) {
   Buffer subtable(data, length);
 
   uint16_t format = 0;
   if (!subtable.ReadU16(&format)) {
     return OTS_FAILURE_MSG("Failed to read context subtable format");
   }
 
   if (format == 1) {
-    if (!ParseContextFormat1(font, data, length, num_glyphs, num_lookups)) {
+    if (!ParseContextFormat1(file, data, length, num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse context format 1 subtable");
     }
   } else if (format == 2) {
-    if (!ParseContextFormat2(font, data, length, num_glyphs, num_lookups)) {
+    if (!ParseContextFormat2(file, data, length, num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse context format 2 subtable");
     }
   } else if (format == 3) {
-    if (!ParseContextFormat3(font, data, length, num_glyphs, num_lookups)) {
+    if (!ParseContextFormat3(file, data, length, num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse context format 3 subtable");
     }
   } else {
     return OTS_FAILURE_MSG("Bad context subtable format %d", format);
   }
 
   return true;
 }
 
-bool ParseChainingContextSubtable(const ots::Font *font,
+bool ParseChainingContextSubtable(const ots::OpenTypeFile *file,
                                   const uint8_t *data, const size_t length,
                                   const uint16_t num_glyphs,
                                   const uint16_t num_lookups) {
   Buffer subtable(data, length);
 
   uint16_t format = 0;
   if (!subtable.ReadU16(&format)) {
     return OTS_FAILURE_MSG("Failed to read chaining context subtable format");
   }
 
   if (format == 1) {
-    if (!ParseChainContextFormat1(font, data, length, num_glyphs, num_lookups)) {
+    if (!ParseChainContextFormat1(file, data, length, num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse chaining context format 1 subtable");
     }
   } else if (format == 2) {
-    if (!ParseChainContextFormat2(font, data, length, num_glyphs, num_lookups)) {
+    if (!ParseChainContextFormat2(file, data, length, num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse chaining context format 2 subtable");
     }
   } else if (format == 3) {
-    if (!ParseChainContextFormat3(font, data, length, num_glyphs, num_lookups)) {
+    if (!ParseChainContextFormat3(file, data, length, num_glyphs, num_lookups)) {
       return OTS_FAILURE_MSG("Failed to parse chaining context format 3 subtable");
     }
   } else {
     return OTS_FAILURE_MSG("Bad chaining context subtable format %d", format);
   }
 
   return true;
 }
 
-bool ParseExtensionSubtable(const Font *font,
+bool ParseExtensionSubtable(const OpenTypeFile *file,
                             const uint8_t *data, const size_t length,
                             const LookupSubtableParser* parser) {
   Buffer subtable(data, length);
 
   uint16_t format = 0;
   uint16_t lookup_type = 0;
   uint32_t offset_extension = 0;
   if (!subtable.ReadU16(&format) ||
@@ -1493,17 +1493,17 @@ bool ParseExtensionSubtable(const Font *
 
   const unsigned format_end = static_cast<unsigned>(8);
   if (offset_extension < format_end ||
       offset_extension >= length) {
     return OTS_FAILURE_MSG("Bad extension offset %d", offset_extension);
   }
 
   // Parse the extension subtable of |lookup_type|.
-  if (!parser->Parse(font, data + offset_extension, length - offset_extension,
+  if (!parser->Parse(file, data + offset_extension, length - offset_extension,
                      lookup_type)) {
     return OTS_FAILURE_MSG("Failed to parse lookup from extension lookup");
   }
 
   return true;
 }
 
 }  // namespace ots
--- a/gfx/ots/src/layout.h
+++ b/gfx/ots/src/layout.h
@@ -11,66 +11,66 @@
 // http://www.microsoft.com/typography/otspec/chapter2.htm
 
 namespace ots {
 
 
 struct LookupSubtableParser {
   struct TypeParser {
     uint16_t type;
-    bool (*parse)(const Font *font, const uint8_t *data,
+    bool (*parse)(const OpenTypeFile *file, const uint8_t *data,
                   const size_t length);
   };
   size_t num_types;
   uint16_t extension_type;
   const TypeParser *parsers;
 
-  bool Parse(const Font *font, const uint8_t *data,
+  bool Parse(const OpenTypeFile *file, const uint8_t *data,
              const size_t length, const uint16_t lookup_type) const;
 };
 
-bool ParseScriptListTable(const ots::Font *font,
+bool ParseScriptListTable(const ots::OpenTypeFile *file,
                           const uint8_t *data, const size_t length,
                           const uint16_t num_features);
 
-bool ParseFeatureListTable(const ots::Font *font,
+bool ParseFeatureListTable(const ots::OpenTypeFile *file,
                            const uint8_t *data, const size_t length,
                            const uint16_t num_lookups,
                            uint16_t *num_features);
 
-bool ParseLookupListTable(Font *font, const uint8_t *data,
+bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
                           const size_t length,
                           const LookupSubtableParser* parser,
                           uint16_t* num_lookups);
 
-bool ParseClassDefTable(const ots::Font *font,
+bool ParseClassDefTable(const ots::OpenTypeFile *file,
                         const uint8_t *data, size_t length,
                         const uint16_t num_glyphs,
                         const uint16_t num_classes);
 
-bool ParseCoverageTable(const ots::Font *font,
+bool ParseCoverageTable(const ots::OpenTypeFile *file,
                         const uint8_t *data, size_t length,
                         const uint16_t num_glyphs,
                         const uint16_t expected_num_glyphs = 0);
 
-bool ParseDeviceTable(const ots::Font *font,
+bool ParseDeviceTable(const ots::OpenTypeFile *file,
                       const uint8_t *data, size_t length);
 
 // Parser for 'Contextual' subtable shared by GSUB/GPOS tables.
-bool ParseContextSubtable(const ots::Font *font,
+bool ParseContextSubtable(const ots::OpenTypeFile *file,
                           const uint8_t *data, const size_t length,
                           const uint16_t num_glyphs,
                           const uint16_t num_lookups);
 
 // Parser for 'Chaining Contextual' subtable shared by GSUB/GPOS tables.
-bool ParseChainingContextSubtable(const ots::Font *font,
+bool ParseChainingContextSubtable(const ots::OpenTypeFile *file,
                                   const uint8_t *data, const size_t length,
                                   const uint16_t num_glyphs,
                                   const uint16_t num_lookups);
 
-bool ParseExtensionSubtable(const Font *font,
+bool ParseExtensionSubtable(const OpenTypeFile *file,
                             const uint8_t *data, const size_t length,
                             const LookupSubtableParser* parser);
 
 }  // namespace ots
 
 #endif  // OTS_LAYOUT_H_
 
--- a/gfx/ots/src/loca.cc
+++ b/gfx/ots/src/loca.cc
@@ -9,35 +9,35 @@
 
 // loca - Index to Location
 // http://www.microsoft.com/typography/otspec/loca.htm
 
 #define TABLE_NAME "loca"
 
 namespace ots {
 
-bool ots_loca_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_loca_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
   // We can't do anything useful in validating this data except to ensure that
   // the values are monotonically increasing.
 
   OpenTypeLOCA *loca = new OpenTypeLOCA;
-  font->loca = loca;
+  file->loca = loca;
 
-  if (!font->maxp || !font->head) {
+  if (!file->maxp || !file->head) {
     return OTS_FAILURE_MSG("maxp or head tables missing from font, needed by loca");
   }
 
-  const unsigned num_glyphs = font->maxp->num_glyphs;
+  const unsigned num_glyphs = file->maxp->num_glyphs;
   unsigned last_offset = 0;
   loca->offsets.resize(num_glyphs + 1);
   // maxp->num_glyphs is uint16_t, thus the addition never overflows.
 
-  if (font->head->index_to_loc_format == 0) {
+  if (file->head->index_to_loc_format == 0) {
     // Note that the <= here (and below) is correct. There is one more offset
     // than the number of glyphs in order to give the length of the final
     // glyph.
     for (unsigned i = 0; i <= num_glyphs; ++i) {
       uint16_t offset = 0;
       if (!table.ReadU16(&offset)) {
         return OTS_FAILURE_MSG("Failed to read offset for glyph %d", i);
       }
@@ -59,23 +59,23 @@ bool ots_loca_parse(Font *font, const ui
       last_offset = offset;
       loca->offsets[i] = offset;
     }
   }
 
   return true;
 }
 
-bool ots_loca_should_serialise(Font *font) {
-  return font->loca != NULL;
+bool ots_loca_should_serialise(OpenTypeFile *file) {
+  return file->loca != NULL;
 }
 
-bool ots_loca_serialise(OTSStream *out, Font *font) {
-  const OpenTypeLOCA *loca = font->loca;
-  const OpenTypeHEAD *head = font->head;
+bool ots_loca_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeLOCA *loca = file->loca;
+  const OpenTypeHEAD *head = file->head;
 
   if (!head) {
     return OTS_FAILURE_MSG("Missing head table in font needed by loca");
   }
 
   if (head->index_to_loc_format == 0) {
     for (unsigned i = 0; i < loca->offsets.size(); ++i) {
       const uint16_t offset = static_cast<uint16_t>(loca->offsets[i] >> 1);
@@ -90,20 +90,15 @@ bool ots_loca_serialise(OTSStream *out, 
         return OTS_FAILURE_MSG("Failed to write glyph offset for glyph %d", i);
       }
     }
   }
 
   return true;
 }
 
-void ots_loca_reuse(Font *font, Font *other) {
-  font->loca = other->loca;
-  font->loca_reused = true;
-}
-
-void ots_loca_free(Font *font) {
-  delete font->loca;
+void ots_loca_free(OpenTypeFile *file) {
+  delete file->loca;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/ltsh.cc
+++ b/gfx/ots/src/ltsh.cc
@@ -8,90 +8,85 @@
 
 // LTSH - Linear Threshold
 // http://www.microsoft.com/typography/otspec/ltsh.htm
 
 #define TABLE_NAME "LTSH"
 
 #define DROP_THIS_TABLE(...) \
   do { \
-    OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
+    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
     OTS_FAILURE_MSG("Table discarded"); \
-    delete font->ltsh; \
-    font->ltsh = 0; \
+    delete file->ltsh; \
+    file->ltsh = 0; \
   } while (0)
 
 namespace ots {
 
-bool ots_ltsh_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_ltsh_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
-  if (!font->maxp) {
+  if (!file->maxp) {
     return OTS_FAILURE_MSG("Missing maxp table from font needed by ltsh");
   }
 
   OpenTypeLTSH *ltsh = new OpenTypeLTSH;
-  font->ltsh = ltsh;
+  file->ltsh = ltsh;
 
   uint16_t num_glyphs = 0;
   if (!table.ReadU16(&ltsh->version) ||
       !table.ReadU16(&num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to read ltsh header");
   }
 
   if (ltsh->version != 0) {
     DROP_THIS_TABLE("bad version: %u", ltsh->version);
     return true;
   }
 
-  if (num_glyphs != font->maxp->num_glyphs) {
+  if (num_glyphs != file->maxp->num_glyphs) {
     DROP_THIS_TABLE("bad num_glyphs: %u", num_glyphs);
     return true;
   }
 
   ltsh->ypels.reserve(num_glyphs);
   for (unsigned i = 0; i < num_glyphs; ++i) {
     uint8_t pel = 0;
     if (!table.ReadU8(&pel)) {
       return OTS_FAILURE_MSG("Failed to read pixels for glyph %d", i);
     }
     ltsh->ypels.push_back(pel);
   }
 
   return true;
 }
 
-bool ots_ltsh_should_serialise(Font *font) {
-  if (!font->glyf) return false;  // this table is not for CFF fonts.
-  return font->ltsh != NULL;
+bool ots_ltsh_should_serialise(OpenTypeFile *file) {
+  if (!file->glyf) return false;  // this table is not for CFF fonts.
+  return file->ltsh != NULL;
 }
 
-bool ots_ltsh_serialise(OTSStream *out, Font *font) {
-  const OpenTypeLTSH *ltsh = font->ltsh;
+bool ots_ltsh_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeLTSH *ltsh = file->ltsh;
 
   const uint16_t num_ypels = static_cast<uint16_t>(ltsh->ypels.size());
   if (num_ypels != ltsh->ypels.size() ||
       !out->WriteU16(ltsh->version) ||
       !out->WriteU16(num_ypels)) {
     return OTS_FAILURE_MSG("Failed to write pels size");
   }
   for (uint16_t i = 0; i < num_ypels; ++i) {
     if (!out->Write(&(ltsh->ypels[i]), 1)) {
       return OTS_FAILURE_MSG("Failed to write pixel size for glyph %d", i);
     }
   }
 
   return true;
 }
 
-void ots_ltsh_reuse(Font *font, Font *other) {
-  font->ltsh = other->ltsh;
-  font->ltsh_reused = true;
-}
-
-void ots_ltsh_free(Font *font) {
-  delete font->ltsh;
+void ots_ltsh_free(OpenTypeFile *file) {
+  delete file->ltsh;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
 #undef DROP_THIS_TABLE
--- a/gfx/ots/src/math.cc
+++ b/gfx/ots/src/math.cc
@@ -45,42 +45,42 @@ const unsigned kMathValueRecordSize = 2 
 // StartConnectorLength
 // EndConnectorLength
 // FullAdvance
 // PartFlags
 const unsigned kGlyphPartRecordSize = 5 * 2;
 
 // Shared Table: MathValueRecord
 
-bool ParseMathValueRecord(const ots::Font *font,
+bool ParseMathValueRecord(const ots::OpenTypeFile *file,
                           ots::Buffer* subtable, const uint8_t *data,
                           const size_t length) {
   // Check the Value field.
   if (!subtable->Skip(2)) {
     return OTS_FAILURE();
   }
 
   // Check the offset to device table.
   uint16_t offset = 0;
   if (!subtable->ReadU16(&offset)) {
     return OTS_FAILURE();
   }
   if (offset) {
     if (offset >= length) {
       return OTS_FAILURE();
     }
-    if (!ots::ParseDeviceTable(font, data + offset, length - offset)) {
+    if (!ots::ParseDeviceTable(file, data + offset, length - offset)) {
       return OTS_FAILURE();
     }
   }
 
   return true;
 }
 
-bool ParseMathConstantsTable(const ots::Font *font,
+bool ParseMathConstantsTable(const ots::OpenTypeFile *file,
                              const uint8_t *data, size_t length) {
   ots::Buffer subtable(data, length);
 
   // Part 1: int16 or uint16 constants.
   //  ScriptPercentScaleDown
   //  ScriptScriptPercentScaleDown
   //  DelimitedSubFormulaMinHeight
   //  DisplayOperatorMinHeight
@@ -141,31 +141,31 @@ bool ParseMathConstantsTable(const ots::
   // RadicalVerticalGap
   // RadicalDisplayStyleVerticalGap
   // RadicalRuleThickness
   // RadicalExtraAscender
   // RadicalKernBeforeDegree
   //
   // RadicalKernAfterDegree
   for (unsigned i = 0; i < static_cast<unsigned>(51); ++i) {
-    if (!ParseMathValueRecord(font, &subtable, data, length)) {
+    if (!ParseMathValueRecord(file, &subtable, data, length)) {
       return OTS_FAILURE();
     }
   }
 
   // Part 3: uint16 constant
   // RadicalDegreeBottomRaisePercent
   if (!subtable.Skip(2)) {
     return OTS_FAILURE();
   }
 
   return true;
 }
 
-bool ParseMathValueRecordSequenceForGlyphs(const ots::Font *font,
+bool ParseMathValueRecordSequenceForGlyphs(const ots::OpenTypeFile *file,
                                            ots::Buffer* subtable,
                                            const uint8_t *data,
                                            const size_t length,
                                            const uint16_t num_glyphs) {
   // Check the header.
   uint16_t offset_coverage = 0;
   uint16_t sequence_count = 0;
   if (!subtable->ReadU16(&offset_coverage) ||
@@ -178,78 +178,78 @@ bool ParseMathValueRecordSequenceForGlyp
   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE();
   }
 
   // Check coverage table.
   if (offset_coverage < sequence_end || offset_coverage >= length) {
     return OTS_FAILURE();
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage,
                                num_glyphs, sequence_count)) {
     return OTS_FAILURE();
   }
 
   // Check sequence.
   for (unsigned i = 0; i < sequence_count; ++i) {
-    if (!ParseMathValueRecord(font, subtable, data, length)) {
+    if (!ParseMathValueRecord(file, subtable, data, length)) {
       return OTS_FAILURE();
     }
   }
 
   return true;
 }
 
-bool ParseMathItalicsCorrectionInfoTable(const ots::Font *font,
+bool ParseMathItalicsCorrectionInfoTable(const ots::OpenTypeFile *file,
                                          const uint8_t *data,
                                          size_t length,
                                          const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
-  return ParseMathValueRecordSequenceForGlyphs(font, &subtable, data, length,
+  return ParseMathValueRecordSequenceForGlyphs(file, &subtable, data, length,
                                                num_glyphs);
 }
 
-bool ParseMathTopAccentAttachmentTable(const ots::Font *font,
+bool ParseMathTopAccentAttachmentTable(const ots::OpenTypeFile *file,
                                        const uint8_t *data,
                                        size_t length,
                                        const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
-  return ParseMathValueRecordSequenceForGlyphs(font, &subtable, data, length,
+  return ParseMathValueRecordSequenceForGlyphs(file, &subtable, data, length,
                                                num_glyphs);
 }
 
-bool ParseMathKernTable(const ots::Font *font,
+bool ParseMathKernTable(const ots::OpenTypeFile *file,
                         const uint8_t *data, size_t length) {
   ots::Buffer subtable(data, length);
 
   // Check the Height count.
   uint16_t height_count = 0;
   if (!subtable.ReadU16(&height_count)) {
     return OTS_FAILURE();
   }
 
   // Check the Correction Heights.
   for (unsigned i = 0; i < height_count; ++i) {
-    if (!ParseMathValueRecord(font, &subtable, data, length)) {
+    if (!ParseMathValueRecord(file, &subtable, data, length)) {
       return OTS_FAILURE();
     }
   }
 
   // Check the Kern Values.
   for (unsigned i = 0; i <= height_count; ++i) {
-    if (!ParseMathValueRecord(font, &subtable, data, length)) {
+    if (!ParseMathValueRecord(file, &subtable, data, length)) {
       return OTS_FAILURE();
     }
   }
 
   return true;
 }
 
-bool ParseMathKernInfoTable(const ots::Font *font,
+bool ParseMathKernInfoTable(const ots::OpenTypeFile *file,
                             const uint8_t *data, size_t length,
                             const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   // Check the header.
   uint16_t offset_coverage = 0;
   uint16_t sequence_count = 0;
   if (!subtable.ReadU16(&offset_coverage) ||
@@ -262,43 +262,43 @@ bool ParseMathKernInfoTable(const ots::F
   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE();
   }
 
   // Check coverage table.
   if (offset_coverage < sequence_end || offset_coverage >= length) {
     return OTS_FAILURE();
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage, length - offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage, length - offset_coverage,
                                num_glyphs, sequence_count)) {
     return OTS_FAILURE();
   }
 
   // Check sequence of MathKernInfoRecord
   for (unsigned i = 0; i < sequence_count; ++i) {
     // Check TopRight, TopLeft, BottomRight and BottomLeft Math Kern.
     for (unsigned j = 0; j < 4; ++j) {
       uint16_t offset_math_kern = 0;
       if (!subtable.ReadU16(&offset_math_kern)) {
         return OTS_FAILURE();
       }
       if (offset_math_kern) {
         if (offset_math_kern < sequence_end || offset_math_kern >= length ||
-            !ParseMathKernTable(font, data + offset_math_kern,
+            !ParseMathKernTable(file, data + offset_math_kern,
                                 length - offset_math_kern)) {
           return OTS_FAILURE();
         }
       }
     }
   }
 
   return true;
 }
 
-bool ParseMathGlyphInfoTable(const ots::Font *font,
+bool ParseMathGlyphInfoTable(const ots::OpenTypeFile *file,
                              const uint8_t *data, size_t length,
                              const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   // Check Header.
   uint16_t offset_math_italics_correction_info = 0;
   uint16_t offset_math_top_accent_attachment = 0;
   uint16_t offset_extended_shaped_coverage = 0;
@@ -313,62 +313,62 @@ bool ParseMathGlyphInfoTable(const ots::
   // Check subtables.
   // The specification does not say whether the offsets for
   // MathItalicsCorrectionInfo, MathTopAccentAttachment and MathKernInfo may
   // be NULL, but that's the case in some fonts (e.g STIX) so we accept that.
   if (offset_math_italics_correction_info) {
     if (offset_math_italics_correction_info >= length ||
         offset_math_italics_correction_info < kMathGlyphInfoHeaderSize ||
         !ParseMathItalicsCorrectionInfoTable(
-            font, data + offset_math_italics_correction_info,
+            file, data + offset_math_italics_correction_info,
             length - offset_math_italics_correction_info,
             num_glyphs)) {
       return OTS_FAILURE();
     }
   }
   if (offset_math_top_accent_attachment) {
     if (offset_math_top_accent_attachment >= length ||
         offset_math_top_accent_attachment < kMathGlyphInfoHeaderSize ||
-        !ParseMathTopAccentAttachmentTable(font, data +
+        !ParseMathTopAccentAttachmentTable(file, data +
                                            offset_math_top_accent_attachment,
                                            length -
                                            offset_math_top_accent_attachment,
                                            num_glyphs)) {
       return OTS_FAILURE();
     }
   }
   if (offset_extended_shaped_coverage) {
     if (offset_extended_shaped_coverage >= length ||
         offset_extended_shaped_coverage < kMathGlyphInfoHeaderSize ||
-        !ots::ParseCoverageTable(font, data + offset_extended_shaped_coverage,
+        !ots::ParseCoverageTable(file, data + offset_extended_shaped_coverage,
                                  length - offset_extended_shaped_coverage,
                                  num_glyphs)) {
       return OTS_FAILURE();
     }
   }
   if (offset_math_kern_info) {
     if (offset_math_kern_info >= length ||
         offset_math_kern_info < kMathGlyphInfoHeaderSize ||
-        !ParseMathKernInfoTable(font, data + offset_math_kern_info,
+        !ParseMathKernInfoTable(file, data + offset_math_kern_info,
                                 length - offset_math_kern_info, num_glyphs)) {
       return OTS_FAILURE();
     }
   }
 
   return true;
 }
 
-bool ParseGlyphAssemblyTable(const ots::Font *font,
+bool ParseGlyphAssemblyTable(const ots::OpenTypeFile *file,
                              const uint8_t *data,
                              size_t length, const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   // Check the header.
   uint16_t part_count = 0;
-  if (!ParseMathValueRecord(font, &subtable, data, length) ||
+  if (!ParseMathValueRecord(file, &subtable, data, length) ||
       !subtable.ReadU16(&part_count)) {
     return OTS_FAILURE();
   }
 
   const unsigned sequence_end = kMathValueRecordSize +
     static_cast<unsigned>(2) + part_count * kGlyphPartRecordSize;
   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE();
@@ -389,17 +389,17 @@ bool ParseGlyphAssemblyTable(const ots::
     if (part_flags & ~0x00000001) {
       return OTS_FAILURE_MSG("unknown part flag: %u", part_flags);
     }
   }
 
   return true;
 }
 
-bool ParseMathGlyphConstructionTable(const ots::Font *font,
+bool ParseMathGlyphConstructionTable(const ots::OpenTypeFile *file,
                                      const uint8_t *data,
                                      size_t length, const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   // Check the header.
   uint16_t offset_glyph_assembly = 0;
   uint16_t variant_count = 0;
   if (!subtable.ReadU16(&offset_glyph_assembly) ||
@@ -414,17 +414,17 @@ bool ParseMathGlyphConstructionTable(con
   }
 
   // Check the GlyphAssembly offset.
   if (offset_glyph_assembly) {
     if (offset_glyph_assembly >= length ||
         offset_glyph_assembly < sequence_end) {
       return OTS_FAILURE();
     }
-    if (!ParseGlyphAssemblyTable(font, data + offset_glyph_assembly,
+    if (!ParseGlyphAssemblyTable(file, data + offset_glyph_assembly,
                                  length - offset_glyph_assembly, num_glyphs)) {
       return OTS_FAILURE();
     }
   }
 
   // Check the sequence of MathGlyphVariantRecord.
   for (unsigned i = 0; i < variant_count; ++i) {
     uint16_t glyph = 0;
@@ -435,53 +435,53 @@ bool ParseMathGlyphConstructionTable(con
     if (glyph >= num_glyphs) {
       return OTS_FAILURE_MSG("bad glyph ID: %u", glyph);
     }
   }
 
   return true;
 }
 
-bool ParseMathGlyphConstructionSequence(const ots::Font *font,
+bool ParseMathGlyphConstructionSequence(const ots::OpenTypeFile *file,
                                         ots::Buffer* subtable,
                                         const uint8_t *data,
                                         size_t length,
                                         const uint16_t num_glyphs,
                                         uint16_t offset_coverage,
                                         uint16_t glyph_count,
                                         const unsigned sequence_end) {
   // Check coverage table.
   if (offset_coverage < sequence_end || offset_coverage >= length) {
     return OTS_FAILURE();
   }
-  if (!ots::ParseCoverageTable(font, data + offset_coverage,
+  if (!ots::ParseCoverageTable(file, data + offset_coverage,
                                length - offset_coverage,
                                num_glyphs, glyph_count)) {
     return OTS_FAILURE();
   }
 
   // Check sequence of MathGlyphConstruction.
   for (unsigned i = 0; i < glyph_count; ++i) {
       uint16_t offset_glyph_construction = 0;
       if (!subtable->ReadU16(&offset_glyph_construction)) {
         return OTS_FAILURE();
       }
       if (offset_glyph_construction < sequence_end ||
           offset_glyph_construction >= length ||
-          !ParseMathGlyphConstructionTable(font, data + offset_glyph_construction,
+          !ParseMathGlyphConstructionTable(file, data + offset_glyph_construction,
                                            length - offset_glyph_construction,
                                            num_glyphs)) {
         return OTS_FAILURE();
       }
   }
 
   return true;
 }
 
-bool ParseMathVariantsTable(const ots::Font *font,
+bool ParseMathVariantsTable(const ots::OpenTypeFile *file,
                             const uint8_t *data,
                             size_t length, const uint16_t num_glyphs) {
   ots::Buffer subtable(data, length);
 
   // Check the header.
   uint16_t offset_vert_glyph_coverage = 0;
   uint16_t offset_horiz_glyph_coverage = 0;
   uint16_t vert_glyph_count = 0;
@@ -495,53 +495,53 @@ bool ParseMathVariantsTable(const ots::F
   }
 
   const unsigned sequence_end = 5 * 2 + vert_glyph_count * 2 +
     horiz_glyph_count * 2;
   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE();
   }
 
-  if (!ParseMathGlyphConstructionSequence(font, &subtable, data, length, num_glyphs,
+  if (!ParseMathGlyphConstructionSequence(file, &subtable, data, length, num_glyphs,
                                           offset_vert_glyph_coverage,
                                           vert_glyph_count,
                                           sequence_end) ||
-      !ParseMathGlyphConstructionSequence(font, &subtable, data, length, num_glyphs,
+      !ParseMathGlyphConstructionSequence(file, &subtable, data, length, num_glyphs,
                                           offset_horiz_glyph_coverage,
                                           horiz_glyph_count,
                                           sequence_end)) {
     return OTS_FAILURE();
   }
 
   return true;
 }
 
 }  // namespace
 
 #define DROP_THIS_TABLE(msg_) \
   do { \
     OTS_FAILURE_MSG(msg_ ", table discarded"); \
-    font->math->data = 0; \
-    font->math->length = 0; \
+    file->math->data = 0; \
+    file->math->length = 0; \
   } while (0)
 
 namespace ots {
 
-bool ots_math_parse(Font *font, const uint8_t *data, size_t length) {
-  // Grab the number of glyphs in the font from the maxp table to check
+bool ots_math_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  // Grab the number of glyphs in the file from the maxp table to check
   // GlyphIDs in MATH table.
-  if (!font->maxp) {
+  if (!file->maxp) {
     return OTS_FAILURE();
   }
-  const uint16_t num_glyphs = font->maxp->num_glyphs;
+  const uint16_t num_glyphs = file->maxp->num_glyphs;
 
   Buffer table(data, length);
 
   OpenTypeMATH* math = new OpenTypeMATH;
-  font->math = math;
+  file->math = math;
 
   uint32_t version = 0;
   if (!table.ReadU32(&version)) {
     return OTS_FAILURE();
   }
   if (version != 0x00010000) {
     DROP_THIS_TABLE("bad MATH version");
     return true;
@@ -561,54 +561,49 @@ bool ots_math_parse(Font *font, const ui
       offset_math_glyph_info >= length ||
       offset_math_glyph_info < kMathHeaderSize ||
       offset_math_variants >= length ||
       offset_math_variants < kMathHeaderSize) {
     DROP_THIS_TABLE("bad offset in MATH header");
     return true;
   }
 
-  if (!ParseMathConstantsTable(font, data + offset_math_constants,
+  if (!ParseMathConstantsTable(file, data + offset_math_constants,
                                length - offset_math_constants)) {
     DROP_THIS_TABLE("failed to parse MathConstants table");
     return true;
   }
-  if (!ParseMathGlyphInfoTable(font, data + offset_math_glyph_info,
+  if (!ParseMathGlyphInfoTable(file, data + offset_math_glyph_info,
                                length - offset_math_glyph_info, num_glyphs)) {
     DROP_THIS_TABLE("failed to parse MathGlyphInfo table");
     return true;
   }
-  if (!ParseMathVariantsTable(font, data + offset_math_variants,
+  if (!ParseMathVariantsTable(file, data + offset_math_variants,
                               length - offset_math_variants, num_glyphs)) {
     DROP_THIS_TABLE("failed to parse MathVariants table");
     return true;
   }
 
   math->data = data;
   math->length = length;
   return true;
 }
 
-bool ots_math_should_serialise(Font *font) {
-  return font->math != NULL && font->math->data != NULL;
+bool ots_math_should_serialise(OpenTypeFile *file) {
+  return file->math != NULL && file->math->data != NULL;
 }
 
-bool ots_math_serialise(OTSStream *out, Font *font) {
-  if (!out->Write(font->math->data, font->math->length)) {
+bool ots_math_serialise(OTSStream *out, OpenTypeFile *file) {
+  if (!out->Write(file->math->data, file->math->length)) {
     return OTS_FAILURE();
   }
 
   return true;
 }
 
-void ots_math_reuse(Font *font, Font *other) {
-  font->math = other->math;
-  font->math_reused = true;
-}
-
-void ots_math_free(Font *font) {
-  delete font->math;
+void ots_math_free(OpenTypeFile *file) {
+  delete file->math;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
 #undef DROP_THIS_TABLE
--- a/gfx/ots/src/maxp.cc
+++ b/gfx/ots/src/maxp.cc
@@ -6,21 +6,21 @@
 
 // maxp - Maximum Profile
 // http://www.microsoft.com/typography/otspec/maxp.htm
 
 #define TABLE_NAME "maxp"
 
 namespace ots {
 
-bool ots_maxp_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_maxp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
   OpenTypeMAXP *maxp = new OpenTypeMAXP;
-  font->maxp = maxp;
+  file->maxp = maxp;
 
   uint32_t version = 0;
   if (!table.ReadU32(&version)) {
     return OTS_FAILURE_MSG("Failed to read version of maxp table");
   }
 
   if (version >> 16 > 1) {
     return OTS_FAILURE_MSG("Bad maxp version %d", version);
@@ -67,22 +67,22 @@ bool ots_maxp_parse(Font *font, const ui
     }
   } else {
     maxp->version_1 = false;
   }
 
   return true;
 }
 
-bool ots_maxp_should_serialise(Font *font) {
-  return font->maxp != NULL;
+bool ots_maxp_should_serialise(OpenTypeFile *file) {
+  return file->maxp != NULL;
 }
 
-bool ots_maxp_serialise(OTSStream *out, Font *font) {
-  const OpenTypeMAXP *maxp = font->maxp;
+bool ots_maxp_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeMAXP *maxp = file->maxp;
 
   if (!out->WriteU32(maxp->version_1 ? 0x00010000 : 0x00005000) ||
       !out->WriteU16(maxp->num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to write maxp version or number of glyphs");
   }
 
   if (!maxp->version_1) return true;
 
@@ -106,20 +106,15 @@ bool ots_maxp_serialise(OTSStream *out, 
   if (!out->WriteU16(maxp->max_c_components) ||
       !out->WriteU16(maxp->max_c_depth)) {
     return OTS_FAILURE_MSG("Failed to write yet more maxp");
   }
 
   return true;
 }
 
-void ots_maxp_reuse(Font *font, Font *other) {
-  font->maxp = other->maxp;
-  font->maxp_reused = true;
-}
-
-void ots_maxp_free(Font *font) {
-  delete font->maxp;
+void ots_maxp_free(OpenTypeFile *file) {
+  delete file->maxp;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/metrics.cc
+++ b/gfx/ots/src/metrics.cc
@@ -10,17 +10,17 @@
 // OpenType horizontal and vertical common header format
 // http://www.microsoft.com/typography/otspec/hhea.htm
 // http://www.microsoft.com/typography/otspec/vhea.htm
 
 #define TABLE_NAME "metrics" // XXX: use individual table names
 
 namespace ots {
 
-bool ParseMetricsHeader(Font *font, Buffer *table,
+bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
                         OpenTypeMetricsHeader *header) {
   if (!table->ReadS16(&header->ascent) ||
       !table->ReadS16(&header->descent) ||
       !table->ReadS16(&header->linegap) ||
       !table->ReadU16(&header->adv_width_max) ||
       !table->ReadS16(&header->min_sb1) ||
       !table->ReadS16(&header->min_sb2) ||
       !table->ReadS16(&header->max_extent) ||
@@ -34,22 +34,22 @@ bool ParseMetricsHeader(Font *font, Buff
     OTS_WARNING("bad ascent: %d", header->ascent);
     header->ascent = 0;
   }
   if (header->linegap < 0) {
     OTS_WARNING("bad linegap: %d", header->linegap);
     header->linegap = 0;
   }
 
-  if (!font->head) {
+  if (!file->head) {
     return OTS_FAILURE_MSG("Missing head font table");
   }
 
   // if the font is non-slanted, caret_offset should be zero.
-  if (!(font->head->mac_style & 2) &&
+  if (!(file->head->mac_style & 2) &&
       (header->caret_offset != 0)) {
     OTS_WARNING("bad caret offset: %d", header->caret_offset);
     header->caret_offset = 0;
   }
 
   // skip the reserved bytes
   if (!table->Skip(8)) {
     return OTS_FAILURE_MSG("Failed to skip reserverd bytes");
@@ -62,28 +62,28 @@ bool ParseMetricsHeader(Font *font, Buff
   if (data_format) {
     return OTS_FAILURE_MSG("Bad data format %d", data_format);
   }
 
   if (!table->ReadU16(&header->num_metrics)) {
     return OTS_FAILURE_MSG("Failed to read number of metrics");
   }
 
-  if (!font->maxp) {
+  if (!file->maxp) {
     return OTS_FAILURE_MSG("Missing maxp font table");
   }
 
-  if (header->num_metrics > font->maxp->num_glyphs) {
+  if (header->num_metrics > file->maxp->num_glyphs) {
     return OTS_FAILURE_MSG("Bad number of metrics %d", header->num_metrics);
   }
 
   return true;
 }
 
-bool SerialiseMetricsHeader(const ots::Font *font,
+bool SerialiseMetricsHeader(const ots::OpenTypeFile *file,
                             OTSStream *out,
                             const OpenTypeMetricsHeader *header) {
   if (!out->WriteU32(header->version) ||
       !out->WriteS16(header->ascent) ||
       !out->WriteS16(header->descent) ||
       !out->WriteS16(header->linegap) ||
       !out->WriteU16(header->adv_width_max) ||
       !out->WriteS16(header->min_sb1) ||
@@ -96,17 +96,17 @@ bool SerialiseMetricsHeader(const ots::F
       !out->WriteS16(0) ||  // metric data format
       !out->WriteU16(header->num_metrics)) {
     return OTS_FAILURE_MSG("Failed to write metrics");
   }
 
   return true;
 }
 
-bool ParseMetricsTable(const ots::Font *font,
+bool ParseMetricsTable(const ots::OpenTypeFile *file,
                        Buffer *table,
                        const uint16_t num_glyphs,
                        const OpenTypeMetricsHeader *header,
                        OpenTypeMetricsTable *metrics) {
   // |num_metrics| is a uint16_t, so it's bounded < 65536. This limits that
   // amount of memory that we'll allocate for this to a sane amount.
   const unsigned num_metrics = header->num_metrics;
 
@@ -164,17 +164,17 @@ bool ParseMetricsTable(const ots::Font *
 #endif
 
     metrics->sbs.push_back(sb);
   }
 
   return true;
 }
 
-bool SerialiseMetricsTable(const ots::Font *font,
+bool SerialiseMetricsTable(const ots::OpenTypeFile *file,
                            OTSStream *out,
                            const OpenTypeMetricsTable *metrics) {
   for (unsigned i = 0; i < metrics->entries.size(); ++i) {
     if (!out->WriteU16(metrics->entries[i].first) ||
         !out->WriteS16(metrics->entries[i].second)) {
       return OTS_FAILURE_MSG("Failed to write metric %d", i);
     }
   }
--- a/gfx/ots/src/metrics.h
+++ b/gfx/ots/src/metrics.h
@@ -28,27 +28,27 @@ struct OpenTypeMetricsHeader {
   uint16_t num_metrics;
 };
 
 struct OpenTypeMetricsTable {
   std::vector<std::pair<uint16_t, int16_t> > entries;
   std::vector<int16_t> sbs;
 };
 
-bool ParseMetricsHeader(Font *font, Buffer *table,
+bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
                         OpenTypeMetricsHeader *header);
-bool SerialiseMetricsHeader(const ots::Font *font,
+bool SerialiseMetricsHeader(const ots::OpenTypeFile *file,
                             OTSStream *out,
                             const OpenTypeMetricsHeader *header);
 
-bool ParseMetricsTable(const ots::Font *font,
+bool ParseMetricsTable(const ots::OpenTypeFile *file,
                        Buffer *table,
                        const uint16_t num_glyphs,
                        const OpenTypeMetricsHeader *header,
                        OpenTypeMetricsTable *metrics);
-bool SerialiseMetricsTable(const ots::Font *font,
+bool SerialiseMetricsTable(const ots::OpenTypeFile *file,
                            OTSStream *out,
                            const OpenTypeMetricsTable *metrics);
 
 }  // namespace ots
 
 #endif  // OTS_METRICS_H_
 
--- a/gfx/ots/src/name.cc
+++ b/gfx/ots/src/name.cc
@@ -2,16 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "name.h"
 
 #include <algorithm>
 #include <cstring>
 
+#include "cff.h"
+
 // name - Naming Table
 // http://www.microsoft.com/typography/otspec/name.htm
 
 #define TABLE_NAME "name"
 
 namespace {
 
 bool ValidInPsName(char c) {
@@ -51,21 +53,21 @@ void AssignToUtf16BeFromAscii(std::strin
   }
 }
 
 }  // namespace
 
 
 namespace ots {
 
-bool ots_name_parse(Font *font, const uint8_t* data, size_t length) {
+bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
   Buffer table(data, length);
 
   OpenTypeNAME* name = new OpenTypeNAME;
-  font->name = name;
+  file->name = name;
 
   uint16_t format = 0;
   if (!table.ReadU16(&format) || format > 1) {
     return OTS_FAILURE_MSG("Failed to read name table format or bad format %d", format);
   }
 
   uint16_t count = 0;
   if (!table.ReadU16(&count)) {
@@ -74,16 +76,17 @@ bool ots_name_parse(Font *font, const ui
 
   uint16_t string_offset = 0;
   if (!table.ReadU16(&string_offset) || string_offset > length) {
     return OTS_FAILURE_MSG("Failed to read strings offset");
   }
   const char* string_base = reinterpret_cast<const char*>(data) +
       string_offset;
 
+  NameRecord prev_record;
   bool sort_required = false;
 
   // Read all the names, discarding any with invalid IDs,
   // and any where the offset/length would be outside the table.
   // A stricter alternative would be to reject the font if there
   // are invalid name records, but it's not clear that is necessary.
   for (unsigned i = 0; i < count; ++i) {
     NameRecord rec;
@@ -133,32 +136,37 @@ bool ots_name_parse(Font *font, const ui
       continue;
     }
     rec.text.resize(name_length);
     rec.text.assign(string_base + name_offset, name_length);
 
     if (rec.name_id == 6) {
       // PostScript name: check that it is valid, if not then discard it
       if (rec.platform_id == 1) {
-        if (!CheckPsNameAscii(rec.text)) {
+        if (file->cff && !file->cff->name.empty()) {
+          rec.text = file->cff->name;
+        } else if (!CheckPsNameAscii(rec.text)) {
           continue;
         }
       } else if (rec.platform_id == 0 || rec.platform_id == 3) {
-        if (!CheckPsNameUtf16Be(rec.text)) {
+        if (file->cff && !file->cff->name.empty()) {
+          AssignToUtf16BeFromAscii(&rec.text, file->cff->name);
+        } else if (!CheckPsNameUtf16Be(rec.text)) {
           continue;
         }
       }
     }
 
-    if (!name->names.empty() && !(name->names.back() < rec)) {
+    if ((i > 0) && !(prev_record < rec)) {
       OTS_WARNING("name records are not sorted.");
       sort_required = true;
     }
 
     name->names.push_back(rec);
+    prev_record = rec;
   }
 
   if (format == 1) {
     // extended name table format with language tags
     uint16_t lang_tag_count;
     if (!table.ReadU16(&lang_tag_count)) {
       return OTS_FAILURE_MSG("Failed to read language tag count");
     }
@@ -197,23 +205,29 @@ bool ots_name_parse(Font *font, const ui
     NULL,
     "OTS derived font",
     "Unspecified",
     NULL,
     "OTS derived font",
     "1.000",
     "OTS-derived-font"
   };
+  // The spec says that "In CFF OpenType fonts, these two name strings, when
+  // translated to ASCII, must also be identical to the font name as stored in
+  // the CFF's Name INDEX." And actually, Mac OS X's font parser requires that.
+  if (file->cff && !file->cff->name.empty()) {
+    kStdNames[6] = file->cff->name.c_str();
+  }
 
   // scan the names to check whether the required "standard" ones are present;
   // if not, we'll add our fixed versions here
   bool mac_name[kStdNameCount] = { 0 };
   bool win_name[kStdNameCount] = { 0 };
   for (std::vector<NameRecord>::iterator name_iter = name->names.begin();
-       name_iter != name->names.end(); ++name_iter) {
+       name_iter != name->names.end(); name_iter++) {
     const uint16_t id = name_iter->name_id;
     if (id >= kStdNameCount || kStdNames[id] == NULL) {
       continue;
     }
     if (name_iter->platform_id == 1) {
       mac_name[id] = true;
       continue;
     }
@@ -222,44 +236,45 @@ bool ots_name_parse(Font *font, const ui
       continue;
     }
   }
 
   for (uint16_t i = 0; i < kStdNameCount; ++i) {
     if (kStdNames[i] == NULL) {
       continue;
     }
-    if (!mac_name[i] && !win_name[i]) {
-      NameRecord mac_rec(1 /* platform_id */, 0 /* encoding_id */,
-                         0 /* language_id */ , i /* name_id */);
-      mac_rec.text.assign(kStdNames[i]);
-
-      NameRecord win_rec(3 /* platform_id */, 1 /* encoding_id */,
-                         1033 /* language_id */ , i /* name_id */);
-      AssignToUtf16BeFromAscii(&win_rec.text, std::string(kStdNames[i]));
-
-      name->names.push_back(mac_rec);
-      name->names.push_back(win_rec);
+    if (!mac_name[i]) {
+      NameRecord rec(1 /* platform_id */, 0 /* encoding_id */,
+                     0 /* language_id */ , i /* name_id */);
+      rec.text.assign(kStdNames[i]);
+      name->names.push_back(rec);
+      sort_required = true;
+    }
+    if (!win_name[i]) {
+      NameRecord rec(3 /* platform_id */, 1 /* encoding_id */,
+                     1033 /* language_id */ , i /* name_id */);
+      AssignToUtf16BeFromAscii(&rec.text, std::string(kStdNames[i]));
+      name->names.push_back(rec);
       sort_required = true;
     }
   }
 
   if (sort_required) {
     std::sort(name->names.begin(), name->names.end());
   }
 
   return true;
 }
 
-bool ots_name_should_serialise(Font *font) {
-  return font->name != NULL;
+bool ots_name_should_serialise(OpenTypeFile* file) {
+  return file->name != NULL;
 }
 
-bool ots_name_serialise(OTSStream* out, Font *font) {
-  const OpenTypeNAME* name = font->name;
+bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
+  const OpenTypeNAME* name = file->name;
 
   uint16_t name_count = static_cast<uint16_t>(name->names.size());
   uint16_t lang_tag_count = static_cast<uint16_t>(name->lang_tags.size());
   uint16_t format = 0;
   size_t string_offset = 6 + name_count * 12;
 
   if (name->lang_tags.size() > 0) {
     // lang tags require a format-1 name table
@@ -272,17 +287,17 @@ bool ots_name_serialise(OTSStream* out, 
   if (!out->WriteU16(format) ||
       !out->WriteU16(name_count) ||
       !out->WriteU16(static_cast<uint16_t>(string_offset))) {
     return OTS_FAILURE_MSG("Failed to write name header");
   }
 
   std::string string_data;
   for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin();
-       name_iter != name->names.end(); ++name_iter) {
+       name_iter != name->names.end(); name_iter++) {
     const NameRecord& rec = *name_iter;
     if (string_data.size() + rec.text.size() >
             std::numeric_limits<uint16_t>::max() ||
         !out->WriteU16(rec.platform_id) ||
         !out->WriteU16(rec.encoding_id) ||
         !out->WriteU16(rec.language_id) ||
         !out->WriteU16(rec.name_id) ||
         !out->WriteU16(static_cast<uint16_t>(rec.text.size())) ||
@@ -293,17 +308,17 @@ bool ots_name_serialise(OTSStream* out, 
   }
 
   if (format == 1) {
     if (!out->WriteU16(lang_tag_count)) {
       return OTS_FAILURE_MSG("Faile to write language tag count");
     }
     for (std::vector<std::string>::const_iterator tag_iter =
              name->lang_tags.begin();
-         tag_iter != name->lang_tags.end(); ++tag_iter) {
+         tag_iter != name->lang_tags.end(); tag_iter++) {
       if (string_data.size() + tag_iter->size() >
               std::numeric_limits<uint16_t>::max() ||
           !out->WriteU16(static_cast<uint16_t>(tag_iter->size())) ||
           !out->WriteU16(static_cast<uint16_t>(string_data.size()))) {
         return OTS_FAILURE_MSG("Failed to write string");
       }
       string_data.append(*tag_iter);
     }
@@ -311,20 +326,15 @@ bool ots_name_serialise(OTSStream* out, 
 
   if (!out->Write(string_data.data(), string_data.size())) {
     return OTS_FAILURE_MSG("Faile to write string data");
   }
 
   return true;
 }
 
-void ots_name_reuse(Font *font, Font *other) {
-  font->name = other->name;
-  font->name_reused = true;
-}
-
-void ots_name_free(Font *font) {
-  delete font->name;
+void ots_name_free(OpenTypeFile* file) {
+  delete file->name;
 }
 
 }  // namespace
 
 #undef TABLE_NAME
--- a/gfx/ots/src/os2.cc
+++ b/gfx/ots/src/os2.cc
@@ -9,21 +9,21 @@
 
 // OS/2 - OS/2 and Windows Metrics
 // http://www.microsoft.com/typography/otspec/os2.htm
 
 #define TABLE_NAME "OS/2"
 
 namespace ots {
 
-bool ots_os2_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
   OpenTypeOS2 *os2 = new OpenTypeOS2;
-  font->os2 = os2;
+  file->os2 = os2;
 
   if (!table.ReadU16(&os2->version) ||
       !table.ReadS16(&os2->avg_char_width) ||
       !table.ReadU16(&os2->weight_class) ||
       !table.ReadU16(&os2->width_class) ||
       !table.ReadU16(&os2->type) ||
       !table.ReadS16(&os2->subscript_x_size) ||
       !table.ReadS16(&os2->subscript_y_size) ||
@@ -34,17 +34,17 @@ bool ots_os2_parse(Font *font, const uin
       !table.ReadS16(&os2->superscript_x_offset) ||
       !table.ReadS16(&os2->superscript_y_offset) ||
       !table.ReadS16(&os2->strikeout_size) ||
       !table.ReadS16(&os2->strikeout_position) ||
       !table.ReadS16(&os2->family_class)) {
     return OTS_FAILURE_MSG("Error reading basic table elements");
   }
 
-  if (os2->version > 5) {
+  if (os2->version > 4) {
     return OTS_FAILURE_MSG("Unsupported table version: %u", os2->version);
   }
 
   // Follow WPF Font Selection Model's advice.
   if (1 <= os2->weight_class && os2->weight_class <= 9) {
     OTS_WARNING("Bad usWeightClass: %u, changing it to: %u", os2->weight_class, os2->weight_class * 100);
     os2->weight_class *= 100;
   }
@@ -126,42 +126,42 @@ bool ots_os2_parse(Font *font, const uin
 
   // If bit 6 is set, then bits 0 and 5 must be clear.
   if (os2->selection & 0x40) {
     os2->selection &= 0xffdeu;
   }
 
   // the settings of bits 0 and 1 must be reflected in the macStyle bits
   // in the 'head' table.
-  if (!font->head) {
+  if (!file->head) {
     return OTS_FAILURE_MSG("Needed head table is missing from the font");
   }
   if ((os2->selection & 0x1) &&
-      !(font->head->mac_style & 0x2)) {
+      !(file->head->mac_style & 0x2)) {
     OTS_WARNING("adjusting Mac style (italic)");
-    font->head->mac_style |= 0x2;
+    file->head->mac_style |= 0x2;
   }
   if ((os2->selection & 0x2) &&
-      !(font->head->mac_style & 0x4)) {
+      !(file->head->mac_style & 0x4)) {
     OTS_WARNING("adjusting Mac style (underscore)");
-    font->head->mac_style |= 0x4;
+    file->head->mac_style |= 0x4;
   }
 
   // While bit 6 on implies that bits 0 and 1 of macStyle are clear,
   // the reverse is not true.
   if ((os2->selection & 0x40) &&
-      (font->head->mac_style & 0x3)) {
+      (file->head->mac_style & 0x3)) {
     OTS_WARNING("adjusting Mac style (regular)");
-    font->head->mac_style &= 0xfffcu;
+    file->head->mac_style &= 0xfffcu;
   }
 
   if ((os2->version < 4) &&
       (os2->selection & 0x300)) {
     // bit 8 and 9 must be unset in OS/2 table versions less than 4.
-    return OTS_FAILURE_MSG("Version %d incompatible with selection %d", os2->version, os2->selection);
+    return OTS_FAILURE_MSG("OS2 version %d incompatible with selection %d", os2->version, os2->selection);
   }
 
   // mask reserved bits. use only 0..9 bits.
   os2->selection &= 0x3ff;
 
   if (os2->first_char_index > os2->last_char_index) {
     return OTS_FAILURE_MSG("first char index %d > last char index %d in os2", os2->first_char_index, os2->last_char_index);
   }
@@ -201,57 +201,37 @@ bool ots_os2_parse(Font *font, const uin
     return true;
   }
 
   if (!table.ReadS16(&os2->x_height) ||
       !table.ReadS16(&os2->cap_height) ||
       !table.ReadU16(&os2->default_char) ||
       !table.ReadU16(&os2->break_char) ||
       !table.ReadU16(&os2->max_context)) {
-    return OTS_FAILURE_MSG("Failed to read version 2-specific fields");
+    return OTS_FAILURE_MSG("Failed to read os2 version 2 information");
   }
 
   if (os2->x_height < 0) {
     OTS_WARNING("bad x_height: %d", os2->x_height);
     os2->x_height = 0;
   }
   if (os2->cap_height < 0) {
     OTS_WARNING("bad cap_height: %d", os2->cap_height);
     os2->cap_height = 0;
   }
 
-  if (os2->version < 5) {
-    // http://www.microsoft.com/typography/otspec/os2ver4.htm
-    return true;
-  }
-
-  if (!table.ReadU16(&os2->lower_optical_pointsize) ||
-      !table.ReadU16(&os2->upper_optical_pointsize)) {
-    return OTS_FAILURE_MSG("Failed to read version 5-specific fields");
-  }
-
-  if (os2->lower_optical_pointsize > 0xFFFE) {
-    OTS_WARNING("'usLowerOpticalPointSize' is bigger than 0xFFFE: %d", os2->lower_optical_pointsize);
-    os2->lower_optical_pointsize = 0xFFFE;
-  }
-
-  if (os2->upper_optical_pointsize < 2) {
-    OTS_WARNING("'usUpperOpticalPointSize' is lower than 2: %d", os2->upper_optical_pointsize);
-    os2->upper_optical_pointsize = 2;
-  }
-
   return true;
 }
 
-bool ots_os2_should_serialise(Font *font) {
-  return font->os2 != NULL;
+bool ots_os2_should_serialise(OpenTypeFile *file) {
+  return file->os2 != NULL;
 }
 
-bool ots_os2_serialise(OTSStream *out, Font *font) {
-  const OpenTypeOS2 *os2 = font->os2;
+bool ots_os2_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeOS2 *os2 = file->os2;
 
   if (!out->WriteU16(os2->version) ||
       !out->WriteS16(os2->avg_char_width) ||
       !out->WriteU16(os2->weight_class) ||
       !out->WriteU16(os2->width_class) ||
       !out->WriteU16(os2->type) ||
       !out->WriteS16(os2->subscript_x_size) ||
       !out->WriteS16(os2->subscript_y_size) ||
@@ -281,17 +261,17 @@ bool ots_os2_serialise(OTSStream *out, F
       !out->WriteU16(os2->selection) ||
       !out->WriteU16(os2->first_char_index) ||
       !out->WriteU16(os2->last_char_index) ||
       !out->WriteS16(os2->typo_ascender) ||
       !out->WriteS16(os2->typo_descender) ||
       !out->WriteS16(os2->typo_linegap) ||
       !out->WriteU16(os2->win_ascent) ||
       !out->WriteU16(os2->win_descent)) {
-    return OTS_FAILURE_MSG("Failed to write version 1-specific fields");
+    return OTS_FAILURE_MSG("Failed to write os2 version 1 information");
   }
 
   if (os2->version < 1) {
     return true;
   }
 
   if (!out->WriteU32(os2->code_page_range_1) ||
       !out->WriteU32(os2->code_page_range_2)) {
@@ -302,35 +282,21 @@ bool ots_os2_serialise(OTSStream *out, F
     return true;
   }
 
   if (!out->WriteS16(os2->x_height) ||
       !out->WriteS16(os2->cap_height) ||
       !out->WriteU16(os2->default_char) ||
       !out->WriteU16(os2->break_char) ||
       !out->WriteU16(os2->max_context)) {
-    return OTS_FAILURE_MSG("Failed to write version 2-specific fields");
-  }
-
-  if (os2->version < 5) {
-    return true;
-  }
-
-  if (!out->WriteU16(os2->lower_optical_pointsize) ||
-      !out->WriteU16(os2->upper_optical_pointsize)) {
-    return OTS_FAILURE_MSG("Failed to write version 5-specific fields");
+    return OTS_FAILURE_MSG("Failed to write os2 version 2 information");
   }
 
   return true;
 }
 
-void ots_os2_reuse(Font *font, Font *other) {
-  font->os2 = other->os2;
-  font->os2_reused = true;
-}
-
-void ots_os2_free(Font *font) {
-  delete font->os2;
+void ots_os2_free(OpenTypeFile *file) {
+  delete file->os2;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/os2.h
+++ b/gfx/ots/src/os2.h
@@ -42,15 +42,13 @@ struct OpenTypeOS2 {
   uint16_t win_descent;
   uint32_t code_page_range_1;
   uint32_t code_page_range_2;
   int16_t x_height;
   int16_t cap_height;
   uint16_t default_char;
   uint16_t break_char;
   uint16_t max_context;
-  uint16_t lower_optical_pointsize;
-  uint16_t upper_optical_pointsize;
 };
 
 }  // namespace ots
 
 #endif  // OTS_OS2_H_
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -41,16 +41,35 @@ bool CheckTag(uint32_t tag_value) {
     if (check < 32 || check > 126) {
       return false;  // non-ASCII character found.
     }
     tag_value >>= 8;
   }
   return true;
 }
 
+uint32_t Tag(const char *tag_str) {	
+  uint32_t ret;	
+  std::memcpy(&ret, tag_str, 4);	
+  return ret;	
+}
+
+struct OutputTable {
+  uint32_t tag;
+  size_t offset;
+  size_t length;
+  uint32_t chksum;
+
+  static bool SortByTag(const OutputTable& a, const OutputTable& b) {
+    const uint32_t atag = ntohl(a.tag);
+    const uint32_t btag = ntohl(b.tag);
+    return atag < btag;
+  }
+};
+
 struct Arena {
  public:
   ~Arena() {
     for (std::vector<uint8_t*>::iterator
          i = hunks_.begin(); i != hunks_.end(); ++i) {
       delete[] *i;
     }
   }
@@ -61,290 +80,200 @@ struct Arena {
     return p;
   }
 
  private:
   std::vector<uint8_t*> hunks_;
 };
 
 const struct {
-  uint32_t tag;
-  bool (*parse)(ots::Font *font, const uint8_t *data, size_t length);
-  bool (*serialise)(ots::OTSStream *out, ots::Font *font);
-  bool (*should_serialise)(ots::Font *font);
-  void (*reuse)(ots::Font *font, ots::Font *other);
+  const char* tag;
+  bool (*parse)(ots::OpenTypeFile *otf, const uint8_t *data, size_t length);
+  bool (*serialise)(ots::OTSStream *out, ots::OpenTypeFile *file);
+  bool (*should_serialise)(ots::OpenTypeFile *file);
+  void (*free)(ots::OpenTypeFile *file);
   bool required;
 } table_parsers[] = {
-  { OTS_TAG('m','a','x','p'), ots::ots_maxp_parse, ots::ots_maxp_serialise,
-    ots::ots_maxp_should_serialise, ots::ots_maxp_reuse, true },
-  { OTS_TAG('h','e','a','d'), ots::ots_head_parse, ots::ots_head_serialise,
-    ots::ots_head_should_serialise, ots::ots_head_reuse, true },
-  { OTS_TAG('O','S','/','2'), ots::ots_os2_parse, ots::ots_os2_serialise,
-    ots::ots_os2_should_serialise, ots::ots_os2_reuse, true },
-  { OTS_TAG('c','m','a','p'), ots::ots_cmap_parse, ots::ots_cmap_serialise,
-    ots::ots_cmap_should_serialise, ots::ots_cmap_reuse, true },
-  { OTS_TAG('h','h','e','a'), ots::ots_hhea_parse, ots::ots_hhea_serialise,
-    ots::ots_hhea_should_serialise, ots::ots_hhea_reuse, true },
-  { OTS_TAG('h','m','t','x'), ots::ots_hmtx_parse, ots::ots_hmtx_serialise,
-    ots::ots_hmtx_should_serialise, ots::ots_hmtx_reuse, true },
-  { OTS_TAG('n','a','m','e'), ots::ots_name_parse, ots::ots_name_serialise,
-    ots::ots_name_should_serialise, ots::ots_name_reuse, true },
-  { OTS_TAG('p','o','s','t'), ots::ots_post_parse, ots::ots_post_serialise,
-    ots::ots_post_should_serialise, ots::ots_post_reuse, true },
-  { OTS_TAG('l','o','c','a'), ots::ots_loca_parse, ots::ots_loca_serialise,
-    ots::ots_loca_should_serialise, ots::ots_loca_reuse, false },
-  { OTS_TAG('g','l','y','f'), ots::ots_glyf_parse, ots::ots_glyf_serialise,
-    ots::ots_glyf_should_serialise, ots::ots_glyf_reuse, false },
-  { OTS_TAG('C','F','F',' '), ots::ots_cff_parse, ots::ots_cff_serialise,
-    ots::ots_cff_should_serialise, ots::ots_cff_reuse, false },
-  { OTS_TAG('V','D','M','X'), ots::ots_vdmx_parse, ots::ots_vdmx_serialise,
-    ots::ots_vdmx_should_serialise, ots::ots_vdmx_reuse, false },
-  { OTS_TAG('h','d','m','x'), ots::ots_hdmx_parse, ots::ots_hdmx_serialise,
-    ots::ots_hdmx_should_serialise, ots::ots_hdmx_reuse, false },
-  { OTS_TAG('g','a','s','p'), ots::ots_gasp_parse, ots::ots_gasp_serialise,
-    ots::ots_gasp_should_serialise, ots::ots_gasp_reuse, false },
-  { OTS_TAG('c','v','t',' '), ots::ots_cvt_parse, ots::ots_cvt_serialise,
-    ots::ots_cvt_should_serialise, ots::ots_cvt_reuse, false },
-  { OTS_TAG('f','p','g','m'), ots::ots_fpgm_parse, ots::ots_fpgm_serialise,
-    ots::ots_fpgm_should_serialise, ots::ots_fpgm_reuse, false },
-  { OTS_TAG('p','r','e','p'), ots::ots_prep_parse, ots::ots_prep_serialise,
-    ots::ots_prep_should_serialise, ots::ots_prep_reuse, false },
-  { OTS_TAG('L','T','S','H'), ots::ots_ltsh_parse, ots::ots_ltsh_serialise,
-    ots::ots_ltsh_should_serialise, ots::ots_ltsh_reuse, false },
-  { OTS_TAG('V','O','R','G'), ots::ots_vorg_parse, ots::ots_vorg_serialise,
-    ots::ots_vorg_should_serialise, ots::ots_vorg_reuse, false },
-  { OTS_TAG('k','e','r','n'), ots::ots_kern_parse, ots::ots_kern_serialise,
-    ots::ots_kern_should_serialise, ots::ots_kern_reuse, false },
+  { "maxp", ots::ots_maxp_parse, ots::ots_maxp_serialise,
+    ots::ots_maxp_should_serialise, ots::ots_maxp_free, true },
+  { "head", ots::ots_head_parse, ots::ots_head_serialise,
+    ots::ots_head_should_serialise, ots::ots_head_free, true },
+  { "OS/2", ots::ots_os2_parse, ots::ots_os2_serialise,
+    ots::ots_os2_should_serialise, ots::ots_os2_free, true },
+  { "cmap", ots::ots_cmap_parse, ots::ots_cmap_serialise,
+    ots::ots_cmap_should_serialise, ots::ots_cmap_free, true },
+  { "hhea", ots::ots_hhea_parse, ots::ots_hhea_serialise,
+    ots::ots_hhea_should_serialise, ots::ots_hhea_free, true },
+  { "hmtx", ots::ots_hmtx_parse, ots::ots_hmtx_serialise,
+    ots::ots_hmtx_should_serialise, ots::ots_hmtx_free, true },
+  { "name", ots::ots_name_parse, ots::ots_name_serialise,
+    ots::ots_name_should_serialise, ots::ots_name_free, true },
+  { "post", ots::ots_post_parse, ots::ots_post_serialise,
+    ots::ots_post_should_serialise, ots::ots_post_free, true },
+  { "loca", ots::ots_loca_parse, ots::ots_loca_serialise,
+    ots::ots_loca_should_serialise, ots::ots_loca_free, false },
+  { "glyf", ots::ots_glyf_parse, ots::ots_glyf_serialise,
+    ots::ots_glyf_should_serialise, ots::ots_glyf_free, false },
+  { "CFF ", ots::ots_cff_parse, ots::ots_cff_serialise,
+    ots::ots_cff_should_serialise, ots::ots_cff_free, false },
+  { "VDMX", ots::ots_vdmx_parse, ots::ots_vdmx_serialise,
+    ots::ots_vdmx_should_serialise, ots::ots_vdmx_free, false },
+  { "hdmx", ots::ots_hdmx_parse, ots::ots_hdmx_serialise,
+    ots::ots_hdmx_should_serialise, ots::ots_hdmx_free, false },
+  { "gasp", ots::ots_gasp_parse, ots::ots_gasp_serialise,
+    ots::ots_gasp_should_serialise, ots::ots_gasp_free, false },
+  { "cvt ", ots::ots_cvt_parse, ots::ots_cvt_serialise,
+    ots::ots_cvt_should_serialise, ots::ots_cvt_free, false },
+  { "fpgm", ots::ots_fpgm_parse, ots::ots_fpgm_serialise,
+    ots::ots_fpgm_should_serialise, ots::ots_fpgm_free, false },
+  { "prep", ots::ots_prep_parse, ots::ots_prep_serialise,
+    ots::ots_prep_should_serialise, ots::ots_prep_free, false },
+  { "LTSH", ots::ots_ltsh_parse, ots::ots_ltsh_serialise,
+    ots::ots_ltsh_should_serialise, ots::ots_ltsh_free, false },
+  { "VORG", ots::ots_vorg_parse, ots::ots_vorg_serialise,
+    ots::ots_vorg_should_serialise, ots::ots_vorg_free, false },
+  { "kern", ots::ots_kern_parse, ots::ots_kern_serialise,
+    ots::ots_kern_should_serialise, ots::ots_kern_free, false },
   // We need to parse GDEF table in advance of parsing GSUB/GPOS tables
   // because they could refer GDEF table.
-  { OTS_TAG('G','D','E','F'), ots::ots_gdef_parse, ots::ots_gdef_serialise,
-    ots::ots_gdef_should_serialise, ots::ots_gdef_reuse, false },
-  { OTS_TAG('G','P','O','S'), ots::ots_gpos_parse, ots::ots_gpos_serialise,
-    ots::ots_gpos_should_serialise, ots::ots_gpos_reuse, false },
-  { OTS_TAG('G','S','U','B'), ots::ots_gsub_parse, ots::ots_gsub_serialise,
-    ots::ots_gsub_should_serialise, ots::ots_gsub_reuse, false },
-  { OTS_TAG('v','h','e','a'), ots::ots_vhea_parse, ots::ots_vhea_serialise,
-    ots::ots_vhea_should_serialise, ots::ots_vhea_reuse, false },
-  { OTS_TAG('v','m','t','x'), ots::ots_vmtx_parse, ots::ots_vmtx_serialise,
-    ots::ots_vmtx_should_serialise, ots::ots_vmtx_reuse, false },
-  { OTS_TAG('M','A','T','H'), ots::ots_math_parse, ots::ots_math_serialise,
-    ots::ots_math_should_serialise, ots::ots_math_reuse, false },
+  { "GDEF", ots::ots_gdef_parse, ots::ots_gdef_serialise,
+    ots::ots_gdef_should_serialise, ots::ots_gdef_free, false },
+  { "GPOS", ots::ots_gpos_parse, ots::ots_gpos_serialise,
+    ots::ots_gpos_should_serialise, ots::ots_gpos_free, false },
+  { "GSUB", ots::ots_gsub_parse, ots::ots_gsub_serialise,
+    ots::ots_gsub_should_serialise, ots::ots_gsub_free, false },
+  { "vhea", ots::ots_vhea_parse, ots::ots_vhea_serialise,
+    ots::ots_vhea_should_serialise, ots::ots_vhea_free, false },
+  { "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise,
+    ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false },
+  { "MATH", ots::ots_math_parse, ots::ots_math_serialise,
+    ots::ots_math_should_serialise, ots::ots_math_free, false },
+  // TODO(bashi): Support mort, base, and jstf tables.
   { 0, NULL, NULL, NULL, NULL, false },
 };
 
 bool ProcessGeneric(ots::OpenTypeFile *header,
-                    ots::Font *font,
                     uint32_t signature,
                     ots::OTSStream *output,
                     const uint8_t *data, size_t length,
                     const std::vector<OpenTypeTable>& tables,
                     ots::Buffer& file);
 
 bool ProcessTTF(ots::OpenTypeFile *header,
-                ots::Font *font,
-                ots::OTSStream *output, const uint8_t *data, size_t length,
-                uint32_t offset = 0) {
-  ots::Buffer file(data + offset, length - offset);
-
-  if (offset > length) {
-    return OTS_FAILURE_MSG_HDR("offset beyond end of file");
-  }
+                ots::OTSStream *output, const uint8_t *data, size_t length) {
+  ots::Buffer file(data, length);
 
   // we disallow all files > 1GB in size for sanity.
   if (length > 1024 * 1024 * 1024) {
     return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
   }
 
-  if (!file.ReadU32(&font->version)) {
+  if (!file.ReadTag(&header->version)) {
     return OTS_FAILURE_MSG_HDR("error reading version tag");
   }
-  if (!ots::IsValidVersionTag(font->version)) {
+  if (!ots::IsValidVersionTag(header->version)) {
       return OTS_FAILURE_MSG_HDR("invalid version tag");
   }
 
-  if (!file.ReadU16(&font->num_tables) ||
-      !file.ReadU16(&font->search_range) ||
-      !file.ReadU16(&font->entry_selector) ||
-      !file.ReadU16(&font->range_shift)) {
+  if (!file.ReadU16(&header->num_tables) ||
+      !file.ReadU16(&header->search_range) ||
+      !file.ReadU16(&header->entry_selector) ||
+      !file.ReadU16(&header->range_shift)) {
     return OTS_FAILURE_MSG_HDR("error reading table directory search header");
   }
 
   // search_range is (Maximum power of 2 <= numTables) x 16. Thus, to avoid
   // overflow num_tables is, at most, 2^16 / 16 = 2^12
-  if (font->num_tables >= 4096 || font->num_tables < 1) {
+  if (header->num_tables >= 4096 || header->num_tables < 1) {
     return OTS_FAILURE_MSG_HDR("excessive (or zero) number of tables");
   }
 
   unsigned max_pow2 = 0;
-  while (1u << (max_pow2 + 1) <= font->num_tables) {
+  while (1u << (max_pow2 + 1) <= header->num_tables) {
     max_pow2++;
   }
   const uint16_t expected_search_range = (1u << max_pow2) << 4;
 
   // Don't call ots_failure() here since ~25% of fonts (250+ fonts) in
   // http://www.princexml.com/fonts/ have unexpected search_range value.
-  if (font->search_range != expected_search_range) {
-    OTS_WARNING_MSG_HDR("bad search range");
-    font->search_range = expected_search_range;  // Fix the value.
+  if (header->search_range != expected_search_range) {
+    OTS_FAILURE_MSG_HDR("bad search range");
+    header->search_range = expected_search_range;  // Fix the value.
   }
 
   // entry_selector is Log2(maximum power of 2 <= numTables)
-  if (font->entry_selector != max_pow2) {
+  if (header->entry_selector != max_pow2) {
     return OTS_FAILURE_MSG_HDR("incorrect entrySelector for table directory");
   }
 
   // range_shift is NumTables x 16-searchRange. We know that 16*num_tables
   // doesn't over flow because we range checked it above. Also, we know that
-  // it's > font->search_range by construction of search_range.
+  // it's > header->search_range by construction of search_range.
   const uint16_t expected_range_shift =
-      16 * font->num_tables - font->search_range;
-  if (font->range_shift != expected_range_shift) {
-    OTS_WARNING_MSG_HDR("bad range shift");
-    font->range_shift = expected_range_shift;  // the same as above.
+      16 * header->num_tables - header->search_range;
+  if (header->range_shift != expected_range_shift) {
+    OTS_FAILURE_MSG_HDR("bad range shift");
+    header->range_shift = expected_range_shift;  // the same as above.
   }
 
   // Next up is the list of tables.
   std::vector<OpenTypeTable> tables;
 
-  for (unsigned i = 0; i < font->num_tables; ++i) {
+  for (unsigned i = 0; i < header->num_tables; ++i) {
     OpenTypeTable table;
-    if (!file.ReadU32(&table.tag) ||
+    if (!file.ReadTag(&table.tag) ||
         !file.ReadU32(&table.chksum) ||
         !file.ReadU32(&table.offset) ||
         !file.ReadU32(&table.length)) {
       return OTS_FAILURE_MSG_HDR("error reading table directory");
     }
 
     table.uncompressed_length = table.length;
     tables.push_back(table);
   }
 
-  return ProcessGeneric(header, font, font->version, output, data, length,
+  return ProcessGeneric(header, header->version, output, data, length,
                         tables, file);
 }
 
-bool ProcessTTC(ots::OpenTypeFile *header,
-                ots::OTSStream *output,
-                const uint8_t *data,
-                size_t length,
-                uint32_t index) {
-  ots::Buffer file(data, length);
-
-  // we disallow all files > 1GB in size for sanity.
-  if (length > 1024 * 1024 * 1024) {
-    return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
-  }
-
-  uint32_t ttc_tag;
-  if (!file.ReadU32(&ttc_tag)) {
-    return OTS_FAILURE_MSG_HDR("Error reading TTC tag");
-  }
-  if (ttc_tag != OTS_TAG('t','t','c','f')) {
-    return OTS_FAILURE_MSG_HDR("Invalid TTC tag");
-  }
-
-  uint32_t ttc_version;
-  if (!file.ReadU32(&ttc_version)) {
-    return OTS_FAILURE_MSG_HDR("Error reading TTC version");
-  }
-  if (ttc_version != 0x00010000 && ttc_version != 0x00020000) {
-    return OTS_FAILURE_MSG_HDR("Invalid TTC version");
-  }
-
-  uint32_t num_fonts;
-  if (!file.ReadU32(&num_fonts)) {
-    return OTS_FAILURE_MSG_HDR("Error reading number of TTC fonts");
-  }
-  // Limit the allowed number of subfonts to have same memory allocation.
-  if (num_fonts > 0x10000) {
-    return OTS_FAILURE_MSG_HDR("Too many fonts in TTC");
-  }
-
-  std::vector<uint32_t> offsets(num_fonts);
-  for (unsigned i = 0; i < num_fonts; i++) {
-    if (!file.ReadU32(&offsets[i])) {
-      return OTS_FAILURE_MSG_HDR("Error reading offset to OffsetTable");
-    }
-  }
-
-  if (ttc_version == 0x00020000) {
-    // We don't care about these fields of the header:
-    // uint32_t dsig_tag, dsig_length, dsig_offset
-    if (!file.Skip(3 * 4)) {
-      return OTS_FAILURE_MSG_HDR("Error reading DSIG offset and length in TTC font");
-    }
-  }
-
-  if (index == static_cast<uint32_t>(-1)) {
-    if (!output->WriteU32(ttc_tag) ||
-        !output->WriteU32(0x00010000) ||
-        !output->WriteU32(num_fonts) ||
-        !output->Seek((3 + num_fonts) * 4)) {
-      return OTS_FAILURE_MSG_HDR("Error writing output");
-    }
-
-    // Keep references to the fonts processed in the loop below, as we need
-    // them for reused tables.
-    std::vector<ots::Font> fonts(num_fonts, ots::Font(header));
-
-    for (unsigned i = 0; i < num_fonts; i++) {
-      uint32_t out_offset = output->Tell();
-      if (!output->Seek((3 + i) * 4) ||
-          !output->WriteU32(out_offset) ||
-          !output->Seek(out_offset)) {
-        return OTS_FAILURE_MSG_HDR("Error writing output");
-      }
-      if (!ProcessTTF(header, &fonts[i], output, data, length, offsets[i])) {
-        return false;
-      }
-    }
-
-    return true;
-  } else {
-    if (index >= num_fonts) {
-      return OTS_FAILURE_MSG_HDR("Requested font index is bigger than the number of fonts in the TTC file");
-    }
-
-    ots::Font font(header);
-    return ProcessTTF(header, &font, output, data, length, offsets[index]);
-  }
-}
-
 bool ProcessWOFF(ots::OpenTypeFile *header,
-                 ots::Font *font,
                  ots::OTSStream *output, const uint8_t *data, size_t length) {
   ots::Buffer file(data, length);
 
   // we disallow all files > 1GB in size for sanity.
   if (length > 1024 * 1024 * 1024) {
     return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
   }
 
   uint32_t woff_tag;
-  if (!file.ReadU32(&woff_tag)) {
+  if (!file.ReadTag(&woff_tag)) {
     return OTS_FAILURE_MSG_HDR("error reading WOFF marker");
   }
 
-  if (woff_tag != OTS_TAG('w','O','F','F')) {
+  if (woff_tag != Tag("wOFF")) {
     return OTS_FAILURE_MSG_HDR("invalid WOFF marker");
   }
 
-  if (!file.ReadU32(&font->version)) {
+  if (!file.ReadTag(&header->version)) {
     return OTS_FAILURE_MSG_HDR("error reading version tag");
   }
-  if (!ots::IsValidVersionTag(font->version)) {
+  if (!ots::IsValidVersionTag(header->version)) {
     return OTS_FAILURE_MSG_HDR("invalid version tag");
   }
 
+  header->search_range = 0;
+  header->entry_selector = 0;
+  header->range_shift = 0;
+
   uint32_t reported_length;
   if (!file.ReadU32(&reported_length) || length != reported_length) {
     return OTS_FAILURE_MSG_HDR("incorrect file size in WOFF header");
   }
 
-  if (!file.ReadU16(&font->num_tables) || !font->num_tables) {
+  if (!file.ReadU16(&header->num_tables) || !header->num_tables) {
     return OTS_FAILURE_MSG_HDR("error reading number of tables");
   }
 
   uint16_t reserved_value;
   if (!file.ReadU16(&reserved_value) || reserved_value) {
     return OTS_FAILURE_MSG_HDR("error in reserved field of WOFF header");
   }
 
@@ -388,20 +317,20 @@ bool ProcessWOFF(ots::OpenTypeFile *head
   }
 
   // Next up is the list of tables.
   std::vector<OpenTypeTable> tables;
 
   uint32_t first_index = 0;
   uint32_t last_index = 0;
   // Size of sfnt header plus size of table records.
-  uint64_t total_sfnt_size = 12 + 16 * font->num_tables;
-  for (unsigned i = 0; i < font->num_tables; ++i) {
+  uint64_t total_sfnt_size = 12 + 16 * header->num_tables;
+  for (unsigned i = 0; i < header->num_tables; ++i) {
     OpenTypeTable table;
-    if (!file.ReadU32(&table.tag) ||
+    if (!file.ReadTag(&table.tag) ||
         !file.ReadU32(&table.offset) ||
         !file.ReadU32(&table.length) ||
         !file.ReadU32(&table.uncompressed_length) ||
         !file.ReadU32(&table.chksum)) {
       return OTS_FAILURE_MSG_HDR("error reading table directory");
     }
 
     total_sfnt_size += ots::Round4(table.uncompressed_length);
@@ -455,62 +384,62 @@ bool ProcessWOFF(ots::OpenTypeFile *head
     if (block_end > std::numeric_limits<uint32_t>::max()) {
       return OTS_FAILURE_MSG_HDR("Invalid private block length");
     }
   }
   if (block_end != ots::Round4(length)) {
     return OTS_FAILURE_MSG_HDR("File length mismatch (trailing junk?)");
   }
 
-  return ProcessGeneric(header, font, woff_tag, output, data, length, tables, file);
+  return ProcessGeneric(header, woff_tag, output, data, length, tables, file);
 }
 
 bool ProcessWOFF2(ots::OpenTypeFile *header,
-                  ots::Font *font,
                   ots::OTSStream *output, const uint8_t *data, size_t length) {
   size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length);
-
   if (decompressed_size == 0) {
     return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 is set to 0");
   }
   // decompressed font must be <= 30MB
   if (decompressed_size > 30 * 1024 * 1024) {
     return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 font exceeds 30MB");
   }
 
   std::vector<uint8_t> decompressed_buffer(decompressed_size);
-  if (!ots::ConvertWOFF2ToSFNT(font, &decompressed_buffer[0], decompressed_size,
+  if (!ots::ConvertWOFF2ToSFNT(header, &decompressed_buffer[0], decompressed_size,
                                data, length)) {
     return OTS_FAILURE_MSG_HDR("Failed to convert WOFF 2.0 font to SFNT");
   }
-  return ProcessTTF(header, font, output, &decompressed_buffer[0], decompressed_size);
+  return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size);
 }
 
 ots::TableAction GetTableAction(ots::OpenTypeFile *header, uint32_t tag) {
-  ots::TableAction action = header->context->GetTableAction(tag);
+  ots::TableAction action = ots::TABLE_ACTION_DEFAULT;
+
+  action = header->context->GetTableAction(htonl(tag));
 
   if (action == ots::TABLE_ACTION_DEFAULT) {
     action = ots::TABLE_ACTION_DROP;
 
     for (unsigned i = 0; ; ++i) {
       if (table_parsers[i].parse == NULL) break;
 
-      if (table_parsers[i].tag == tag) {
+      if (Tag(table_parsers[i].tag) == tag) {
         action = ots::TABLE_ACTION_SANITIZE;
         break;
       }
     }
   }
 
   assert(action != ots::TABLE_ACTION_DEFAULT); // Should never return this.
   return action;
 }
 
 bool GetTableData(const uint8_t *data,
-                  const OpenTypeTable& table,
+                  const OpenTypeTable table,
                   Arena *arena,
                   size_t *table_length,
                   const uint8_t **table_data) {
   if (table.uncompressed_length != table.length) {
     // Compressed table. Need to uncompress into memory first.
     *table_length = table.uncompressed_length;
     *table_data = (*arena).Allocate(*table_length);
     uLongf dest_len = *table_length;
@@ -523,103 +452,101 @@ bool GetTableData(const uint8_t *data,
     // Uncompressed table. We can process directly from memory.
     *table_data = data + table.offset;
     *table_length = table.length;
   }
 
   return true;
 }
 
-bool ProcessGeneric(ots::OpenTypeFile *header,
-                    ots::Font *font,
-                    uint32_t signature,
+bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
                     ots::OTSStream *output,
                     const uint8_t *data, size_t length,
                     const std::vector<OpenTypeTable>& tables,
                     ots::Buffer& file) {
   const size_t data_offset = file.offset();
 
   uint32_t uncompressed_sum = 0;
 
-  for (unsigned i = 0; i < font->num_tables; ++i) {
+  for (unsigned i = 0; i < header->num_tables; ++i) {
     // the tables must be sorted by tag (when taken as big-endian numbers).
     // This also remove the possibility of duplicate tables.
     if (i) {
-      const uint32_t this_tag = tables[i].tag;
-      const uint32_t prev_tag = tables[i - 1].tag;
+      const uint32_t this_tag = ntohl(tables[i].tag);
+      const uint32_t prev_tag = ntohl(tables[i - 1].tag);
       if (this_tag <= prev_tag) {
         OTS_WARNING_MSG_HDR("Table directory is not correctly ordered");
       }
     }
 
     // all tag names must be built from printable ASCII characters
     if (!CheckTag(tables[i].tag)) {
-      return OTS_FAILURE_MSG_TAG("invalid table tag", tables[i].tag);
+      return OTS_FAILURE_MSG_TAG("invalid table tag", &tables[i].tag);
     }
 
     // tables must be 4-byte aligned
     if (tables[i].offset & 3) {
-      return OTS_FAILURE_MSG_TAG("misaligned table", tables[i].tag);
+      return OTS_FAILURE_MSG_TAG("misaligned table", &tables[i].tag);
     }
 
     // and must be within the file
     if (tables[i].offset < data_offset || tables[i].offset >= length) {
-      return OTS_FAILURE_MSG_TAG("invalid table offset", tables[i].tag);
+      return OTS_FAILURE_MSG_TAG("invalid table offset", &tables[i].tag);
     }
     // disallow all tables with a zero length
     if (tables[i].length < 1) {
       // Note: malayalam.ttf has zero length CVT table...
-      return OTS_FAILURE_MSG_TAG("zero-length table", tables[i].tag);
+      return OTS_FAILURE_MSG_TAG("zero-length table", &tables[i].tag);
     }
     // disallow all tables with a length > 1GB
     if (tables[i].length > 1024 * 1024 * 1024) {
-      return OTS_FAILURE_MSG_TAG("table length exceeds 1GB", tables[i].tag);
+      return OTS_FAILURE_MSG_TAG("table length exceeds 1GB", &tables[i].tag);
     }
     // disallow tables where the uncompressed size is < the compressed size.
     if (tables[i].uncompressed_length < tables[i].length) {
-      return OTS_FAILURE_MSG_TAG("invalid compressed table", tables[i].tag);
+      return OTS_FAILURE_MSG_TAG("invalid compressed table", &tables[i].tag);
     }
     if (tables[i].uncompressed_length > tables[i].length) {
       // We'll probably be decompressing this table.
 
       // disallow all tables which uncompress to > 30 MB
       if (tables[i].uncompressed_length > 30 * 1024 * 1024) {
-        return OTS_FAILURE_MSG_TAG("uncompressed length exceeds 30MB", tables[i].tag);
+        return OTS_FAILURE_MSG_TAG("uncompressed length exceeds 30MB", &tables[i].tag);
       }
       if (uncompressed_sum + tables[i].uncompressed_length < uncompressed_sum) {
-        return OTS_FAILURE_MSG_TAG("overflow of uncompressed sum", tables[i].tag);
+        return OTS_FAILURE_MSG_TAG("overflow of uncompressed sum", &tables[i].tag);
       }
 
       uncompressed_sum += tables[i].uncompressed_length;
     }
     // since we required that the file be < 1GB in length, and that the table
     // length is < 1GB, the following addtion doesn't overflow
     uint32_t end_byte = tables[i].offset + tables[i].length;
     // Tables in the WOFF file must be aligned 4-byte boundary.
-    if (signature == OTS_TAG('w','O','F','F')) {
+    if (signature == Tag("wOFF")) {
         end_byte = ots::Round4(end_byte);
     }
     if (!end_byte || end_byte > length) {
-      return OTS_FAILURE_MSG_TAG("table overruns end of file", tables[i].tag);
+      return OTS_FAILURE_MSG_TAG("table overruns end of file", &tables[i].tag);
     }
   }
 
   // All decompressed tables uncompressed must be <= 30MB.
   if (uncompressed_sum > 30 * 1024 * 1024) {
     return OTS_FAILURE_MSG_HDR("uncompressed sum exceeds 30MB");
   }
 
   std::map<uint32_t, OpenTypeTable> table_map;
-  for (unsigned i = 0; i < font->num_tables; ++i) {
+  for (unsigned i = 0; i < header->num_tables; ++i) {
     table_map[tables[i].tag] = tables[i];
   }
 
   // check that the tables are not overlapping.
   std::vector<std::pair<uint32_t, uint8_t> > overlap_checker;
-  for (unsigned i = 0; i < font->num_tables; ++i) {
+  for (unsigned i = 0; i < header->num_tables; ++i) {
     overlap_checker.push_back(
         std::make_pair(tables[i].offset, static_cast<uint8_t>(1) /* start */));
     overlap_checker.push_back(
         std::make_pair(tables[i].offset + tables[i].length,
                        static_cast<uint8_t>(0) /* end */));
   }
   std::sort(overlap_checker.begin(), overlap_checker.end());
   int overlap_count = 0;
@@ -630,205 +557,201 @@ bool ProcessGeneric(ots::OpenTypeFile *h
     }
   }
 
   Arena arena;
 
   for (unsigned i = 0; ; ++i) {
     if (table_parsers[i].parse == NULL) break;
 
-    uint32_t tag = table_parsers[i].tag;
+    uint32_t tag = Tag(table_parsers[i].tag);
     const std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.find(tag);
 
     ots::TableAction action = GetTableAction(header, tag);
     if (it == table_map.end()) {
       if (table_parsers[i].required && action == ots::TABLE_ACTION_SANITIZE) {
         return OTS_FAILURE_MSG_TAG("missing required table", table_parsers[i].tag);
       }
       continue;
     }
 
-    uint32_t input_offset = it->second.offset;
-    const ots::TableMap::const_iterator ot = header->tables.find(input_offset);
-    if (ot == header->tables.end()) {
-      const uint8_t* table_data;
-      size_t table_length;
+    const uint8_t* table_data;
+    size_t table_length;
 
-      if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
-        return OTS_FAILURE_MSG_TAG("uncompress failed", table_parsers[i].tag);
-      }
+    if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
+      return OTS_FAILURE_MSG_TAG("uncompress failed", table_parsers[i].tag);
+    }
 
-      if (action == ots::TABLE_ACTION_SANITIZE &&
-          !table_parsers[i].parse(font, table_data, table_length)) {
-        return OTS_FAILURE();
-      }
-    } else if (action == ots::TABLE_ACTION_SANITIZE) {
-      table_parsers[i].reuse(font, ot->second.first);
+    if (action == ots::TABLE_ACTION_SANITIZE &&
+        !table_parsers[i].parse(header, table_data, table_length)) {
+      // TODO: parsers should generate specific messages detailing the failure;
+      // once those are all added, we won't need a generic failure message here
+      return OTS_FAILURE_MSG_TAG("failed to parse table", table_parsers[i].tag);
     }
   }
 
-  if (font->cff) {
+  if (header->cff) {
     // font with PostScript glyph
-    if (font->version != OTS_TAG('O','T','T','O')) {
+    if (header->version != Tag("OTTO")) {
       return OTS_FAILURE_MSG_HDR("wrong font version for PostScript glyph data");
     }
-    if (font->glyf || font->loca) {
+    if (header->glyf || header->loca) {
       // mixing outline formats is not recommended
       return OTS_FAILURE_MSG_HDR("font contains both PS and TT glyphs");
     }
   } else {
-    if (!font->glyf || !font->loca) {
+    if (!header->glyf || !header->loca) {
       // No TrueType glyph found.
-#define PASSTHRU_TABLE(tag_) (table_map.find(tag_) != table_map.end() && \
-                              GetTableAction(header, tag_) == ots::TABLE_ACTION_PASSTHRU)
+#define PASSTHRU_TABLE(TAG) (table_map.find(Tag(TAG)) != table_map.end() && \
+                             GetTableAction(header, Tag(TAG)) == ots::TABLE_ACTION_PASSTHRU)
       // We don't sanitise bitmap table, but don't reject bitmap-only fonts if
       // we keep the tables.
-      if (!PASSTHRU_TABLE(OTS_TAG('C','B','D','T')) ||
-          !PASSTHRU_TABLE(OTS_TAG('C','B','L','C'))) {
+      if (!PASSTHRU_TABLE("CBDT") || !PASSTHRU_TABLE("CBLC")) {
         return OTS_FAILURE_MSG_HDR("no supported glyph shapes table(s) present");
       }
 #undef PASSTHRU_TABLE
     }
   }
 
   uint16_t num_output_tables = 0;
+  for (unsigned i = 0; ; ++i) {
+    if (table_parsers[i].parse == NULL) {
+      break;
+    }
+
+    if (table_parsers[i].should_serialise(header)) {
+      num_output_tables++;
+    }
+  }
+
   for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
        it != table_map.end(); ++it) {
     ots::TableAction action = GetTableAction(header, it->first);
     if (action == ots::TABLE_ACTION_PASSTHRU) {
       num_output_tables++;
-    } else {
-      for (unsigned i = 0; table_parsers[i].parse != NULL; ++i) {
-        if (table_parsers[i].tag == it->first &&
-            table_parsers[i].should_serialise(font)) {
-          num_output_tables++;
-          break;
-        }
-      }
     }
   }
 
   uint16_t max_pow2 = 0;
   while (1u << (max_pow2 + 1) <= num_output_tables) {
     max_pow2++;
   }
   const uint16_t output_search_range = (1u << max_pow2) << 4;
 
   // most of the errors here are highly unlikely - they'd only occur if the
   // output stream returns a failure, e.g. lack of space to write
   output->ResetChecksum();
-  if (!output->WriteU32(font->version) ||
+  if (!output->WriteTag(header->version) ||
       !output->WriteU16(num_output_tables) ||
       !output->WriteU16(output_search_range) ||
       !output->WriteU16(max_pow2) ||
       !output->WriteU16((num_output_tables << 4) - output_search_range)) {
     return OTS_FAILURE_MSG_HDR("error writing output");
   }
   const uint32_t offset_table_chksum = output->chksum();
 
   const size_t table_record_offset = output->Tell();
   if (!output->Pad(16 * num_output_tables)) {
     return OTS_FAILURE_MSG_HDR("error writing output");
   }
 
-  std::vector<ots::OutputTable> out_tables;
+  std::vector<OutputTable> out_tables;
 
   size_t head_table_offset = 0;
+  for (unsigned i = 0; ; ++i) {
+    if (table_parsers[i].parse == NULL) {
+      break;
+    }
+
+    if (!table_parsers[i].should_serialise(header)) {
+      continue;
+    }
+
+    OutputTable out;
+    uint32_t tag = Tag(table_parsers[i].tag);
+    out.tag = tag;
+    out.offset = output->Tell();
+
+    output->ResetChecksum();
+    if (tag == Tag("head")) {
+      head_table_offset = out.offset;
+    }
+    if (!table_parsers[i].serialise(output, header)) {
+      return OTS_FAILURE_MSG_TAG("failed to serialize table", table_parsers[i].tag);
+    }
+
+    const size_t end_offset = output->Tell();
+    if (end_offset <= out.offset) {
+      // paranoid check. |end_offset| is supposed to be greater than the offset,
+      // as long as the Tell() interface is implemented correctly.
+      return OTS_FAILURE_MSG_HDR("error writing output");
+    }
+    out.length = end_offset - out.offset;
+
+    // align tables to four bytes
+    if (!output->Pad((4 - (end_offset & 3)) % 4)) {
+      return OTS_FAILURE_MSG_HDR("error writing output");
+    }
+    out.chksum = output->chksum();
+    out_tables.push_back(out);
+  }
+
   for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
        it != table_map.end(); ++it) {
-    uint32_t input_offset = it->second.offset;
-    const ots::TableMap::const_iterator ot = header->tables.find(input_offset);
-    if (ot != header->tables.end()) {
-      ots::OutputTable out = ot->second.second;
-      if (out.tag == OTS_TAG('h','e','a','d')) {
-        head_table_offset = out.offset;
-      }
-      out_tables.push_back(out);
-    } else {
-      ots::OutputTable out;
-      out.tag = it->first;
+    ots::TableAction action = GetTableAction(header, it->first);
+    if (action == ots::TABLE_ACTION_PASSTHRU) {
+      OutputTable out;
+      out.tag = it->second.tag;
       out.offset = output->Tell();
 
-      if (out.tag == OTS_TAG('h','e','a','d')) {
+      output->ResetChecksum();
+      if (it->second.tag == Tag("head")) {
         head_table_offset = out.offset;
       }
 
-      ots::TableAction action = GetTableAction(header, it->first);
-      if (action == ots::TABLE_ACTION_PASSTHRU) {
-        output->ResetChecksum();
-        const uint8_t* table_data;
-        size_t table_length;
-
-        if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
-          return OTS_FAILURE_MSG_HDR("Failed to uncompress table");
-        }
+      const uint8_t* table_data;
+      size_t table_length;
 
-        if (!output->Write(table_data, table_length)) {
-          return OTS_FAILURE_MSG_HDR("Failed to serialize table");
-        }
+      if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
+        return OTS_FAILURE_MSG_HDR("Failed to uncompress table");
+      }
 
-        const size_t end_offset = output->Tell();
-        if (end_offset <= out.offset) {
-          // paranoid check. |end_offset| is supposed to be greater than the offset,
-          // as long as the Tell() interface is implemented correctly.
-          return OTS_FAILURE_MSG_HDR("error writing output");
-        }
-        out.length = end_offset - out.offset;
+      if (!output->Write(table_data, table_length)) {
+        return OTS_FAILURE_MSG_HDR("Failed to serialize table");
+      }
 
-        // align tables to four bytes
-        if (!output->Pad((4 - (end_offset & 3)) % 4)) {
-          return OTS_FAILURE_MSG_HDR("error writing output");
-        }
-        out.chksum = output->chksum();
-        out_tables.push_back(out);
-        header->tables[input_offset] = std::make_pair(font, out);
-      } else {
-        for (unsigned i = 0; table_parsers[i].parse != NULL; ++i) {
-          if (table_parsers[i].tag == it->first &&
-              table_parsers[i].should_serialise(font)) {
-            output->ResetChecksum();
-            if (!table_parsers[i].serialise(output, font)) {
-              return OTS_FAILURE_MSG_TAG("failed to serialize table", table_parsers[i].tag);
-            }
+      const size_t end_offset = output->Tell();
+      if (end_offset <= out.offset) {
+        // paranoid check. |end_offset| is supposed to be greater than the offset,
+        // as long as the Tell() interface is implemented correctly.
+        return OTS_FAILURE_MSG_HDR("error writing output");
+      }
+      out.length = end_offset - out.offset;
 
-            const size_t end_offset = output->Tell();
-            if (end_offset <= out.offset) {
-              // paranoid check. |end_offset| is supposed to be greater than the offset,
-              // as long as the Tell() interface is implemented correctly.
-              return OTS_FAILURE_MSG_HDR("error writing output");
-            }
-            out.length = end_offset - out.offset;
-
-            // align tables to four bytes
-            if (!output->Pad((4 - (end_offset & 3)) % 4)) {
-              return OTS_FAILURE_MSG_HDR("error writing output");
-            }
-            out.chksum = output->chksum();
-            out_tables.push_back(out);
-            header->tables[input_offset] = std::make_pair(font, out);
-
-            break;
-          }
-        }
+      // align tables to four bytes
+      if (!output->Pad((4 - (end_offset & 3)) % 4)) {
+        return OTS_FAILURE_MSG_HDR("error writing output");
       }
+      out.chksum = output->chksum();
+      out_tables.push_back(out);
     }
   }
 
   const size_t end_of_file = output->Tell();
 
   // Need to sort the output tables for inclusion in the file
-  std::sort(out_tables.begin(), out_tables.end());
+  std::sort(out_tables.begin(), out_tables.end(), OutputTable::SortByTag);
   if (!output->Seek(table_record_offset)) {
     return OTS_FAILURE_MSG_HDR("error writing output");
   }
 
   output->ResetChecksum();
   uint32_t tables_chksum = 0;
   for (unsigned i = 0; i < out_tables.size(); ++i) {
-    if (!output->WriteU32(out_tables[i].tag) ||
+    if (!output->WriteTag(out_tables[i].tag) ||
         !output->WriteU32(out_tables[i].chksum) ||
         !output->WriteU32(out_tables[i].offset) ||
         !output->WriteU32(out_tables[i].length)) {
       return OTS_FAILURE_MSG_HDR("error writing output");
     }
     tables_chksum += out_tables[i].chksum;
   }
   const uint32_t table_record_chksum = output->chksum();
@@ -856,43 +779,44 @@ bool ProcessGeneric(ots::OpenTypeFile *h
   return true;
 }
 
 }  // namespace
 
 namespace ots {
 
 bool IsValidVersionTag(uint32_t tag) {
-  return tag == 0x000010000 ||
+  return tag == Tag("\x00\x01\x00\x00") ||
          // OpenType fonts with CFF data have 'OTTO' tag.
-         tag == OTS_TAG('O','T','T','O') ||
+         tag == Tag("OTTO") ||
          // Older Mac fonts might have 'true' or 'typ1' tag.
-         tag == OTS_TAG('t','r','u','e') ||
-         tag == OTS_TAG('t','y','p','1');
+         tag == Tag("true") ||
+         tag == Tag("typ1");
 }
 
 bool OTSContext::Process(OTSStream *output,
                          const uint8_t *data,
-                         size_t length,
-                         uint32_t index) {
+                         size_t length) {
   OpenTypeFile header;
-  Font font(&header);
+
   header.context = this;
 
   if (length < 4) {
     return OTS_FAILURE_MSG_(&header, "file less than 4 bytes");
   }
 
   bool result;
   if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
-    result = ProcessWOFF(&header, &font, output, data, length);
+    result = ProcessWOFF(&header, output, data, length);
   } else if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == '2') {
-    result = ProcessWOFF2(&header, &font, output, data, length);
-  } else if (data[0] == 't' && data[1] == 't' && data[2] == 'c' && data[3] == 'f') {
-    result = ProcessTTC(&header, output, data, length, index);
+    result = ProcessWOFF2(&header, output, data, length);
   } else {
-    result = ProcessTTF(&header, &font, output, data, length);
+    result = ProcessTTF(&header, output, data, length);
   }
 
+  for (unsigned i = 0; ; ++i) {
+    if (table_parsers[i].parse == NULL) break;
+    table_parsers[i].free(&header);
+  }
   return result;
 }
 
 }  // namespace ots
--- a/gfx/ots/src/ots.h
+++ b/gfx/ots/src/ots.h
@@ -7,17 +7,16 @@
 
 #include <stddef.h>
 #include <cstdarg>
 #include <cstddef>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
 #include <limits>
-#include <map>
 
 #include "opentype-sanitiser.h"
 
 // arraysize borrowed from base/basictypes.h
 template <typename T, size_t N>
 char (&ArraySizeHelper(T (&array)[N]))[N];
 #define arraysize(array) (sizeof(ArraySizeHelper(array)))
 
@@ -51,24 +50,24 @@ namespace ots {
 #define OTS_FAILURE_MSG_(otf_,...) \
   (OTS_MESSAGE_(0,otf_,__VA_ARGS__), false)
 
 #define OTS_WARNING_MSG_(otf_,...) \
   OTS_MESSAGE_(1,otf_,__VA_ARGS__)
 
 // Generate a message with an associated table tag
 #define OTS_FAILURE_MSG_TAG_(otf_,msg_,tag_) \
-  (OTS_MESSAGE_(0,otf_,"%c%c%c%c: %s", OTS_UNTAG(tag_), msg_), false)
+  (OTS_MESSAGE_(0,otf_,"%4.4s: %s", tag_, msg_), false)
 
 // Convenience macros for use in files that only handle a single table tag,
 // defined as TABLE_NAME at the top of the file; the 'file' variable is
 // expected to be the current OpenTypeFile pointer.
-#define OTS_FAILURE_MSG(...) OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__)
+#define OTS_FAILURE_MSG(...) OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__)
 
-#define OTS_WARNING(...) OTS_WARNING_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__)
+#define OTS_WARNING(...) OTS_WARNING_MSG_(file, TABLE_NAME ": " __VA_ARGS__)
 
 // -----------------------------------------------------------------------------
 // Buffer helper class
 //
 // This class perform some trival buffer operations while checking for
 // out-of-bounds errors. As a family they return false if anything is amiss,
 // updating the current offset otherwise.
 // -----------------------------------------------------------------------------
@@ -141,16 +140,25 @@ class Buffer {
     offset_ += 4;
     return true;
   }
 
   bool ReadS32(int32_t *value) {
     return ReadU32(reinterpret_cast<uint32_t*>(value));
   }
 
+  bool ReadTag(uint32_t *value) {
+    if (offset_ + 4 > length_) {
+      return OTS_FAILURE();
+    }
+    std::memcpy(value, buffer_ + offset_, sizeof(uint32_t));
+    offset_ += 4;
+    return true;
+  }
+
   bool ReadR64(uint64_t *value) {
     if (offset_ + 8 > length_) {
       return OTS_FAILURE();
     }
     std::memcpy(value, buffer_ + offset_, sizeof(uint64_t));
     offset_ += 8;
     return true;
   }
@@ -212,82 +220,40 @@ bool IsValidVersionTag(uint32_t tag);
   F(vorg, VORG) \
   F(vhea, VHEA) \
   F(vmtx, VMTX)
 
 #define F(name, capname) struct OpenType##capname;
 FOR_EACH_TABLE_TYPE
 #undef F
 
-struct Font;
-struct OpenTypeFile;
-
-#define F(name, capname) \
-bool ots_##name##_parse(Font *f, const uint8_t *d, size_t l); \
-bool ots_##name##_should_serialise(Font *f); \
-bool ots_##name##_serialise(OTSStream *s, Font *f); \
-void ots_##name##_reuse(Font *f, Font *o);\
-void ots_##name##_free(Font *f);
-FOR_EACH_TABLE_TYPE
-#undef F
-
-struct Font {
-  explicit Font(const OpenTypeFile *f)
-      : file(f),
-        version(0),
-        num_tables(0),
-        search_range(0),
-        entry_selector(0),
-        range_shift(0) {
-#define F(name, capname) \
-    name = NULL; \
-    name##_reused = false;
+struct OpenTypeFile {
+  OpenTypeFile() {
+#define F(name, capname) name = NULL;
     FOR_EACH_TABLE_TYPE
 #undef F
   }
 
-  ~Font() {
-#define F(name, capname) \
-    if (!name##_reused) {\
-      ots_##name##_free(this); \
-    }
-    FOR_EACH_TABLE_TYPE
-#undef F
-  }
-
-  const OpenTypeFile *file;
-
   uint32_t version;
   uint16_t num_tables;
   uint16_t search_range;
   uint16_t entry_selector;
   uint16_t range_shift;
 
-#define F(name, capname) \
-  OpenType##capname *name; \
-  bool name##_reused;
+  OTSContext *context;
+
+#define F(name, capname) OpenType##capname *name;
 FOR_EACH_TABLE_TYPE
 #undef F
 };
 
-struct OutputTable {
-  uint32_t tag;
-  size_t offset;
-  size_t length;
-  uint32_t chksum;
-
-  bool operator<(const OutputTable& other) const {
-    return tag < other.tag;
-  }
-};
-
-typedef std::map<uint32_t, std::pair<Font*, OutputTable> > TableMap;
-
-struct OpenTypeFile {
-  OTSContext *context;
-  TableMap tables;
-};
+#define F(name, capname) \
+bool ots_##name##_parse(OpenTypeFile *f, const uint8_t *d, size_t l); \
+bool ots_##name##_should_serialise(OpenTypeFile *f); \
+bool ots_##name##_serialise(OTSStream *s, OpenTypeFile *f); \
+void ots_##name##_free(OpenTypeFile *f);
+// TODO(yusukes): change these function names to follow Chromium coding rule.
+FOR_EACH_TABLE_TYPE
+#undef F
 
 }  // namespace ots
 
-#undef FOR_EACH_TABLE_TYPE
-
 #endif  // OTS_H_
--- a/gfx/ots/src/post.cc
+++ b/gfx/ots/src/post.cc
@@ -8,21 +8,21 @@
 
 // post - PostScript
 // http://www.microsoft.com/typography/otspec/post.htm
 
 #define TABLE_NAME "post"
 
 namespace ots {
 
-bool ots_post_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
   OpenTypePOST *post = new OpenTypePOST;
-  font->post = post;
+  file->post = post;
 
   if (!table.ReadU32(&post->version) ||
       !table.ReadU32(&post->italic_angle) ||
       !table.ReadS16(&post->underline) ||
       !table.ReadS16(&post->underline_thickness) ||
       !table.ReadU32(&post->is_fixed_pitch)) {
     return OTS_FAILURE_MSG("Failed to read post header");
   }
@@ -48,32 +48,32 @@ bool ots_post_parse(Font *font, const ui
     return OTS_FAILURE_MSG("Failed to skip memory usage in post table");
   }
 
   uint16_t num_glyphs = 0;
   if (!table.ReadU16(&num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to read number of glyphs");
   }
 
-  if (!font->maxp) {
+  if (!file->maxp) {
     return OTS_FAILURE_MSG("No maxp table required by post table");
   }
 
   if (num_glyphs == 0) {
-    if (font->maxp->num_glyphs > 258) {
+    if (file->maxp->num_glyphs > 258) {
       return OTS_FAILURE_MSG("Can't have no glyphs in the post table if there are more than 256 glyphs in the font");
     }
     OTS_WARNING("table version is 1, but no glyf names are found");
     // workaround for fonts in http://www.fontsquirrel.com/fontface
     // (e.g., yataghan.ttf).
     post->version = 0x00010000;
     return true;
   }
 
-  if (num_glyphs != font->maxp->num_glyphs) {
+  if (num_glyphs != file->maxp->num_glyphs) {
     // Note: Fixedsys500c.ttf seems to have inconsistent num_glyphs values.
     return OTS_FAILURE_MSG("Bad number of glyphs in post table %d", num_glyphs);
   }
 
   post->glyph_name_index.resize(num_glyphs);
   for (unsigned i = 0; i < num_glyphs; ++i) {
     if (!table.ReadU16(&post->glyph_name_index[i])) {
       return OTS_FAILURE_MSG("Failed to read post information for glyph %d", i);
@@ -115,25 +115,25 @@ bool ots_post_parse(Font *font, const ui
     if (offset >= num_strings) {
       return OTS_FAILURE_MSG("Bad string index %d", offset);
     }
   }
 
   return true;
 }
 
-bool ots_post_should_serialise(Font *font) {
-  return font->post != NULL;
+bool ots_post_should_serialise(OpenTypeFile *file) {
+  return file->post != NULL;
 }
 
-bool ots_post_serialise(OTSStream *out, Font *font) {
-  const OpenTypePOST *post = font->post;
+bool ots_post_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypePOST *post = file->post;
 
   // OpenType with CFF glyphs must have v3 post table.
-  if (font->post && font->cff && font->post->version != 0x00030000) {
+  if (file->post && file->cff && file->post->version != 0x00030000) {
     return OTS_FAILURE_MSG("Bad post version %x", post->version);
   }
 
   if (!out->WriteU32(post->version) ||
       !out->WriteU32(post->italic_angle) ||
       !out->WriteS16(post->underline) ||
       !out->WriteS16(post->underline_thickness) ||
       !out->WriteU32(post->is_fixed_pitch) ||
@@ -174,20 +174,15 @@ bool ots_post_serialise(OTSStream *out, 
     if (string_length > 0 && !out->Write(s.data(), string_length)) {
       return OTS_FAILURE_MSG("Failed to write string length for string %d", i);
     }
   }
 
   return true;
 }
 
-void ots_post_reuse(Font *font, Font *other) {
-  font->post = other->post;
-  font->post_reused = true;
-}
-
-void ots_post_free(Font *font) {
-  delete font->post;
+void ots_post_free(OpenTypeFile *file) {
+  delete file->post;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/prep.cc
+++ b/gfx/ots/src/prep.cc
@@ -6,54 +6,49 @@
 
 // prep - Control Value Program
 // http://www.microsoft.com/typography/otspec/prep.htm
 
 #define TABLE_NAME "prep"
 
 namespace ots {
 
-bool ots_prep_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_prep_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
   OpenTypePREP *prep = new OpenTypePREP;
-  font->prep = prep;
+  file->prep = prep;
 
   if (length >= 128 * 1024u) {
     return OTS_FAILURE_MSG("table length %ld > 120K", length);  // almost all prep tables are less than 9k bytes.
   }
 
   if (!table.Skip(length)) {
     return OTS_FAILURE_MSG("Failed to read table of length %ld", length);
   }
 
   prep->data = data;
   prep->length = length;
   return true;
 }
 
-bool ots_prep_should_serialise(Font *font) {
-  if (!font->glyf) return false;  // this table is not for CFF fonts.
-  return font->prep != NULL;
+bool ots_prep_should_serialise(OpenTypeFile *file) {
+  if (!file->glyf) return false;  // this table is not for CFF fonts.
+  return file->prep != NULL;
 }
 
-bool ots_prep_serialise(OTSStream *out, Font *font) {
-  const OpenTypePREP *prep = font->prep;
+bool ots_prep_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypePREP *prep = file->prep;
 
   if (!out->Write(prep->data, prep->length)) {
     return OTS_FAILURE_MSG("Failed to write table length");
   }
 
   return true;
 }
 
-void ots_prep_reuse(Font *font, Font *other) {
-  font->prep = other->prep;
-  font->prep_reused = true;
-}
-
-void ots_prep_free(Font *font) {
-  delete font->prep;
+void ots_prep_free(OpenTypeFile *file) {
+  delete file->prep;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/vdmx.cc
+++ b/gfx/ots/src/vdmx.cc
@@ -6,28 +6,28 @@
 
 // VDMX - Vertical Device Metrics
 // http://www.microsoft.com/typography/otspec/vdmx.htm
 
 #define TABLE_NAME "VDMX"
 
 #define DROP_THIS_TABLE(...) \
   do { \
-    OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
+    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
     OTS_FAILURE_MSG("Table discarded"); \
-    delete font->vdmx; \
-    font->vdmx = 0; \
+    delete file->vdmx; \
+    file->vdmx = 0; \
   } while (0)
 
 namespace ots {
 
-bool ots_vdmx_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
-  font->vdmx = new OpenTypeVDMX;
-  OpenTypeVDMX * const vdmx = font->vdmx;
+  file->vdmx = new OpenTypeVDMX;
+  OpenTypeVDMX * const vdmx = file->vdmx;
 
   if (!table.ReadU16(&vdmx->version) ||
       !table.ReadU16(&vdmx->num_recs) ||
       !table.ReadU16(&vdmx->num_ratios)) {
     return OTS_FAILURE_MSG("Failed to read table header");
   }
 
   if (vdmx->version > 1) {
@@ -116,23 +116,23 @@ bool ots_vdmx_parse(Font *font, const ui
       group.entries.push_back(vt);
     }
     vdmx->groups.push_back(group);
   }
 
   return true;
 }
 
-bool ots_vdmx_should_serialise(Font *font) {
-  if (!font->glyf) return false;  // this table is not for CFF fonts.
-  return font->vdmx != NULL;
+bool ots_vdmx_should_serialise(OpenTypeFile *file) {
+  if (!file->glyf) return false;  // this table is not for CFF fonts.
+  return file->vdmx != NULL;
 }
 
-bool ots_vdmx_serialise(OTSStream *out, Font *font) {
-  OpenTypeVDMX * const vdmx = font->vdmx;
+bool ots_vdmx_serialise(OTSStream *out, OpenTypeFile *file) {
+  OpenTypeVDMX * const vdmx = file->vdmx;
 
   if (!out->WriteU16(vdmx->version) ||
       !out->WriteU16(vdmx->num_recs) ||
       !out->WriteU16(vdmx->num_ratios)) {
     return OTS_FAILURE_MSG("Failed to write table header");
   }
 
   for (unsigned i = 0; i < vdmx->rat_ranges.size(); ++i) {
@@ -166,21 +166,16 @@ bool ots_vdmx_serialise(OTSStream *out, 
         return OTS_FAILURE_MSG("Failed to write group %d entry %d", i, j);
       }
     }
   }
 
   return true;
 }
 
-void ots_vdmx_reuse(Font *font, Font *other) {
-  font->vdmx = other->vdmx;
-  font->vdmx_reused = true;
-}
-
-void ots_vdmx_free(Font *font) {
-  delete font->vdmx;
+void ots_vdmx_free(OpenTypeFile *file) {
+  delete file->vdmx;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
 #undef DROP_THIS_TABLE
--- a/gfx/ots/src/vhea.cc
+++ b/gfx/ots/src/vhea.cc
@@ -10,55 +10,50 @@
 
 // vhea - Vertical Header Table
 // http://www.microsoft.com/typography/otspec/vhea.htm
 
 #define TABLE_NAME "vhea"
 
 namespace ots {
 
-bool ots_vhea_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_vhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
   OpenTypeVHEA *vhea = new OpenTypeVHEA;
-  font->vhea = vhea;
+  file->vhea = vhea;
 
   if (!table.ReadU32(&vhea->header.version)) {
     return OTS_FAILURE_MSG("Failed to read version");
   }
   if (vhea->header.version != 0x00010000 &&
       vhea->header.version != 0x00011000) {
     return OTS_FAILURE_MSG("Bad vhea version %x", vhea->header.version);
   }
 
-  if (!ParseMetricsHeader(font, &table, &vhea->header)) {
+  if (!ParseMetricsHeader(file, &table, &vhea->header)) {
     return OTS_FAILURE_MSG("Failed to parse metrics in vhea");
   }
 
   return true;
 }
 
-bool ots_vhea_should_serialise(Font *font) {
+bool ots_vhea_should_serialise(OpenTypeFile *file) {
   // vhea should'nt serialise when vmtx doesn't exist.
   // Firefox developer pointed out that vhea/vmtx should serialise iff GSUB is
   // preserved. See http://crbug.com/77386
-  return font->vhea != NULL && font->vmtx != NULL &&
-      ots_gsub_should_serialise(font);
+  return file->vhea != NULL && file->vmtx != NULL &&
+      ots_gsub_should_serialise(file);
 }
 
-bool ots_vhea_serialise(OTSStream *out, Font *font) {
-  if (!SerialiseMetricsHeader(font, out, &font->vhea->header)) {
+bool ots_vhea_serialise(OTSStream *out, OpenTypeFile *file) {
+  if (!SerialiseMetricsHeader(file, out, &file->vhea->header)) {
     return OTS_FAILURE_MSG("Failed to write vhea metrics");
   }
   return true;
 }
 
-void ots_vhea_reuse(Font *font, Font *other) {
-  font->vhea = other->vhea;
-  font->vhea_reused = true;
-}
-
-void ots_vhea_free(Font *font) {
-  delete font->vhea;
+void ots_vhea_free(OpenTypeFile *file) {
+  delete file->vhea;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/vmtx.cc
+++ b/gfx/ots/src/vmtx.cc
@@ -10,51 +10,46 @@
 
 // vmtx - Vertical Metrics Table
 // http://www.microsoft.com/typography/otspec/vmtx.htm
 
 #define TABLE_NAME "vmtx"
 
 namespace ots {
 
-bool ots_vmtx_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_vmtx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
   OpenTypeVMTX *vmtx = new OpenTypeVMTX;
-  font->vmtx = vmtx;
+  file->vmtx = vmtx;
 
-  if (!font->vhea || !font->maxp) {
+  if (!file->vhea || !file->maxp) {
     return OTS_FAILURE_MSG("vhea or maxp table missing as needed by vmtx");
   }
 
-  if (!ParseMetricsTable(font, &table, font->maxp->num_glyphs,
-                         &font->vhea->header, &vmtx->metrics)) {
+  if (!ParseMetricsTable(file, &table, file->maxp->num_glyphs,
+                         &file->vhea->header, &vmtx->metrics)) {
     return OTS_FAILURE_MSG("Failed to parse vmtx metrics");
   }
 
   return true;
 }
 
-bool ots_vmtx_should_serialise(Font *font) {
+bool ots_vmtx_should_serialise(OpenTypeFile *file) {
   // vmtx should serialise when vhea and GSUB are preserved.
   // See the comment in ots_vhea_should_serialise().
-  return font->vmtx != NULL && font->vhea != NULL &&
-      ots_gsub_should_serialise(font);
+  return file->vmtx != NULL && file->vhea != NULL &&
+      ots_gsub_should_serialise(file);
 }
 
-bool ots_vmtx_serialise(OTSStream *out, Font *font) {
-  if (!SerialiseMetricsTable(font, out, &font->vmtx->metrics)) {
+bool ots_vmtx_serialise(OTSStream *out, OpenTypeFile *file) {
+  if (!SerialiseMetricsTable(file, out, &file->vmtx->metrics)) {
     return OTS_FAILURE_MSG("Failed to write vmtx metrics");
   }
   return true;
 }
 
-void ots_vmtx_reuse(Font *font, Font *other) {
-  font->vmtx = other->vmtx;
-  font->vmtx_reused = true;
-}
-
-void ots_vmtx_free(Font *font) {
-  delete font->vmtx;
+void ots_vmtx_free(OpenTypeFile *file) {
+  delete file->vmtx;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
--- a/gfx/ots/src/vorg.cc
+++ b/gfx/ots/src/vorg.cc
@@ -8,28 +8,28 @@
 
 // VORG - Vertical Origin Table
 // http://www.microsoft.com/typography/otspec/vorg.htm
 
 #define TABLE_NAME "VORG"
 
 #define DROP_THIS_TABLE(...) \
   do { \
-    OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
+    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
     OTS_FAILURE_MSG("Table discarded"); \
-    delete font->vorg; \
-    font->vorg = 0; \
+    delete file->vorg; \
+    file->vorg = 0; \
   } while (0)
 
 namespace ots {
 
-bool ots_vorg_parse(Font *font, const uint8_t *data, size_t length) {
+bool ots_vorg_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
-  font->vorg = new OpenTypeVORG;
-  OpenTypeVORG * const vorg = font->vorg;
+  file->vorg = new OpenTypeVORG;
+  OpenTypeVORG * const vorg = file->vorg;
 
   uint16_t num_recs;
   if (!table.ReadU16(&vorg->major_version) ||
       !table.ReadU16(&vorg->minor_version) ||
       !table.ReadS16(&vorg->default_vert_origin_y) ||
       !table.ReadU16(&num_recs)) {
     return OTS_FAILURE_MSG("Failed to read header");
   }
@@ -63,23 +63,23 @@ bool ots_vorg_parse(Font *font, const ui
     last_glyph_index = rec.glyph_index;
 
     vorg->metrics.push_back(rec);
   }
 
   return true;
 }
 
-bool ots_vorg_should_serialise(Font *font) {
-  if (!font->cff) return false;  // this table is not for fonts with TT glyphs.
-  return font->vorg != NULL;
+bool ots_vorg_should_serialise(OpenTypeFile *file) {
+  if (!file->cff) return false;  // this table is not for fonts with TT glyphs.
+  return file->vorg != NULL;
 }
 
-bool ots_vorg_serialise(OTSStream *out, Font *font) {
-  OpenTypeVORG * const vorg = font->vorg;
+bool ots_vorg_serialise(OTSStream *out, OpenTypeFile *file) {
+  OpenTypeVORG * const vorg = file->vorg;
   
   const uint16_t num_metrics = static_cast<uint16_t>(vorg->metrics.size());
   if (num_metrics != vorg->metrics.size() ||
       !out->WriteU16(vorg->major_version) ||
       !out->WriteU16(vorg->minor_version) ||
       !out->WriteS16(vorg->default_vert_origin_y) ||
       !out->WriteU16(num_metrics)) {
     return OTS_FAILURE_MSG("Failed to write table header");
@@ -91,21 +91,16 @@ bool ots_vorg_serialise(OTSStream *out, 
         !out->WriteS16(rec.vert_origin_y)) {
       return OTS_FAILURE_MSG("Failed to write record %d", i);
     }
   }
 
   return true;
 }
 
-void ots_vorg_reuse(Font *font, Font *other) {
-  font->vorg = other->vorg;
-  font->vorg_reused = true;
-}
-
-void ots_vorg_free(Font *font) {
-  delete font->vorg;
+void ots_vorg_free(OpenTypeFile *file) {
+  delete file->vorg;
 }
 
 }  // namespace ots
 
 #undef TABLE_NAME
 #undef DROP_THIS_TABLE
--- a/gfx/ots/src/woff2.cc
+++ b/gfx/ots/src/woff2.cc
@@ -38,82 +38,86 @@ const int FLAG_WE_HAVE_INSTRUCTIONS = 1 
 
 const size_t kSfntHeaderSize = 12;
 const size_t kSfntEntrySize = 16;
 const size_t kCheckSumAdjustmentOffset = 8;
 
 const size_t kEndPtsOfContoursOffset = 10;
 const size_t kCompositeGlyphBegin = 10;
 
+// Note that the byte order is big-endian, not the same as ots.cc
+#define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d)
+#define CHR(t)           (t >> 24),  (t >> 16),  (t >> 8), (t >> 0)
+
 const unsigned int kWoff2FlagsTransform = 1 << 5;
 
 const uint32_t kKnownTags[] = {
-  OTS_TAG('c','m','a','p'),  // 0
-  OTS_TAG('h','e','a','d'),  // 1
-  OTS_TAG('h','h','e','a'),  // 2
-  OTS_TAG('h','m','t','x'),  // 3
-  OTS_TAG('m','a','x','p'),  // 4
-  OTS_TAG('n','a','m','e'),  // 5
-  OTS_TAG('O','S','/','2'),  // 6
-  OTS_TAG('p','o','s','t'),  // 7
-  OTS_TAG('c','v','t',' '),  // 8
-  OTS_TAG('f','p','g','m'),  // 9
-  OTS_TAG('g','l','y','f'),  // 10
-  OTS_TAG('l','o','c','a'),  // 11
-  OTS_TAG('p','r','e','p'),  // 12
-  OTS_TAG('C','F','F',' '),  // 13
-  OTS_TAG('V','O','R','G'),  // 14
-  OTS_TAG('E','B','D','T'),  // 15
-  OTS_TAG('E','B','L','C'),  // 16
-  OTS_TAG('g','a','s','p'),  // 17
-  OTS_TAG('h','d','m','x'),  // 18
-  OTS_TAG('k','e','r','n'),  // 19
-  OTS_TAG('L','T','S','H'),  // 20
-  OTS_TAG('P','C','L','T'),  // 21
-  OTS_TAG('V','D','M','X'),  // 22
-  OTS_TAG('v','h','e','a'),  // 23
-  OTS_TAG('v','m','t','x'),  // 24
-  OTS_TAG('B','A','S','E'),  // 25
-  OTS_TAG('G','D','E','F'),  // 26
-  OTS_TAG('G','P','O','S'),  // 27
-  OTS_TAG('G','S','U','B'),  // 28
-  OTS_TAG('E','B','S','C'),  // 29
-  OTS_TAG('J','S','T','F'),  // 30
-  OTS_TAG('M','A','T','H'),  // 31
-  OTS_TAG('C','B','D','T'),  // 32
-  OTS_TAG('C','B','L','C'),  // 33
-  OTS_TAG('C','O','L','R'),  // 34
-  OTS_TAG('C','P','A','L'),  // 35
-  OTS_TAG('S','V','G',' '),  // 36
-  OTS_TAG('s','b','i','x'),  // 37
-  OTS_TAG('a','c','n','t'),  // 38
-  OTS_TAG('a','v','a','r'),  // 39
-  OTS_TAG('b','d','a','t'),  // 40
-  OTS_TAG('b','l','o','c'),  // 41
-  OTS_TAG('b','s','l','n'),  // 42
-  OTS_TAG('c','v','a','r'),  // 43
-  OTS_TAG('f','d','s','c'),  // 44
-  OTS_TAG('f','e','a','t'),  // 45
-  OTS_TAG('f','m','t','x'),  // 46
-  OTS_TAG('f','v','a','r'),  // 47
-  OTS_TAG('g','v','a','r'),  // 48
-  OTS_TAG('h','s','t','y'),  // 49
-  OTS_TAG('j','u','s','t'),  // 50
-  OTS_TAG('l','c','a','r'),  // 51
-  OTS_TAG('m','o','r','t'),  // 52
-  OTS_TAG('m','o','r','x'),  // 53
-  OTS_TAG('o','p','b','d'),  // 54
-  OTS_TAG('p','r','o','p'),  // 55
-  OTS_TAG('t','r','a','k'),  // 56
-  OTS_TAG('Z','a','p','f'),  // 57
-  OTS_TAG('S','i','l','f'),  // 58
-  OTS_TAG('G','l','a','t'),  // 59
-  OTS_TAG('G','l','o','c'),  // 60
-  OTS_TAG('F','e','a','t'),  // 61
-  OTS_TAG('S','i','l','l'),  // 62
+  TAG('c', 'm', 'a', 'p'),  // 0
+  TAG('h', 'e', 'a', 'd'),  // 1
+  TAG('h', 'h', 'e', 'a'),  // 2
+  TAG('h', 'm', 't', 'x'),  // 3
+  TAG('m', 'a', 'x', 'p'),  // 4
+  TAG('n', 'a', 'm', 'e'),  // 5
+  TAG('O', 'S', '/', '2'),  // 6
+  TAG('p', 'o', 's', 't'),  // 7
+  TAG('c', 'v', 't', ' '),  // 8
+  TAG('f', 'p', 'g', 'm'),  // 9
+  TAG('g', 'l', 'y', 'f'),  // 10
+  TAG('l', 'o', 'c', 'a'),  // 11
+  TAG('p', 'r', 'e', 'p'),  // 12
+  TAG('C', 'F', 'F', ' '),  // 13
+  TAG('V', 'O', 'R', 'G'),  // 14
+  TAG('E', 'B', 'D', 'T'),  // 15
+  TAG('E', 'B', 'L', 'C'),  // 16
+  TAG('g', 'a', 's', 'p'),  // 17
+  TAG('h', 'd', 'm', 'x'),  // 18
+  TAG('k', 'e', 'r', 'n'),  // 19
+  TAG('L', 'T', 'S', 'H'),  // 20
+  TAG('P', 'C', 'L', 'T'),  // 21
+  TAG('V', 'D', 'M', 'X'),  // 22
+  TAG('v', 'h', 'e', 'a'),  // 23
+  TAG('v', 'm', 't', 'x'),  // 24
+  TAG('B', 'A', 'S', 'E'),  // 25
+  TAG('G', 'D', 'E', 'F'),  // 26
+  TAG('G', 'P', 'O', 'S'),  // 27
+  TAG('G', 'S', 'U', 'B'),  // 28
+  TAG('E', 'B', 'S', 'C'),  // 29
+  TAG('J', 'S', 'T', 'F'),  // 30
+  TAG('M', 'A', 'T', 'H'),  // 31
+  TAG('C', 'B', 'D', 'T'),  // 32
+  TAG('C', 'B', 'L', 'C'),  // 33
+  TAG('C', 'O', 'L', 'R'),  // 34
+  TAG('C', 'P', 'A', 'L'),  // 35
+  TAG('S', 'V', 'G', ' '),  // 36
+  TAG('s', 'b', 'i', 'x'),  // 37
+  TAG('a', 'c', 'n', 't'),  // 38
+  TAG('a', 'v', 'a', 'r'),  // 39
+  TAG('b', 'd', 'a', 't'),  // 40
+  TAG('b', 'l', 'o', 'c'),  // 41
+  TAG('b', 's', 'l', 'n'),  // 42
+  TAG('c', 'v', 'a', 'r'),  // 43
+  TAG('f', 'd', 's', 'c'),  // 44
+  TAG('f', 'e', 'a', 't'),  // 45
+  TAG('f', 'm', 't', 'x'),  // 46
+  TAG('f', 'v', 'a', 'r'),  // 47
+  TAG('g', 'v', 'a', 'r'),  // 48
+  TAG('h', 's', 't', 'y'),  // 49
+  TAG('j', 'u', 's', 't'),  // 50
+  TAG('l', 'c', 'a', 'r'),  // 51
+  TAG('m', 'o', 'r', 't'),  // 52
+  TAG('m', 'o', 'r', 'x'),  // 53
+  TAG('o', 'p', 'b', 'd'),  // 54
+  TAG('p', 'r', 'o', 'p'),  // 55
+  TAG('t', 'r', 'a', 'k'),  // 56
+  TAG('Z', 'a', 'p', 'f'),  // 57
+  TAG('S', 'i', 'l', 'f'),  // 58
+  TAG('G', 'l', 'a', 't'),  // 59
+  TAG('G', 'l', 'o', 'c'),  // 60
+  TAG('F', 'e', 'a', 't'),  // 61
+  TAG('S', 'i', 'l', 'l'),  // 62
 };
 
 struct Point {
   int16_t x;
   int16_t y;
   bool on_curve;
 };
 
@@ -177,19 +181,16 @@ bool Read255UShort(ots::Buffer* buf, uin
 
 bool ReadBase128(ots::Buffer* buf, uint32_t* value) {
   uint32_t result = 0;
   for (size_t i = 0; i < 5; ++i) {
     uint8_t code = 0;
     if (!buf->ReadU8(&code)) {
       return OTS_FAILURE();
     }
-    if (i == 0 && code == 0x80) {
-      return OTS_FAILURE();
-    }
     // If any of the top seven bits are set then we're about to overflow.
     if (result & 0xfe000000U) {
       return OTS_FAILURE();
     }
     result = (result << 7) | (code & 0x7f);
     if ((code & 0x80) == 0) {
       *value = result;
       return true;
@@ -508,17 +509,17 @@ bool StoreLoca(const std::vector<uint32_
     } else {
       offset = StoreU16(dst, offset, static_cast<uint16_t>(value >> 1));
     }
   }
   return true;
 }
 
 // Reconstruct entire glyf table based on transformed original
-bool ReconstructGlyf(ots::Font *font,
+bool ReconstructGlyf(ots::OpenTypeFile* file,
     const uint8_t* data, size_t data_size,
     uint8_t* dst, size_t dst_size,
     uint8_t* loca_buf, size_t loca_size) {
   static const int kNumSubStreams = 7;
   ots::Buffer buffer(data, data_size);
   uint32_t version;
   std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
 
@@ -558,30 +559,26 @@ bool ReconstructGlyf(ots::Font *font,
   ots::Buffer instruction_stream(substreams.at(6).first,
                                  substreams.at(6).second);
 
   std::vector<uint32_t> loca_values;
   loca_values.reserve(num_glyphs + 1);
   std::vector<uint16_t> n_points_vec;
   std::vector<Point> points;
   uint32_t loca_offset = 0;
-  const uint8_t* bbox_bitmap = bbox_stream.buffer();
   for (unsigned int i = 0; i < num_glyphs; ++i) {
     size_t glyph_size = 0;
     uint16_t n_contours = 0;
     if (!n_contour_stream.ReadU16(&n_contours)) {
       return OTS_FAILURE_MSG("Filed to read 'numberOfContours' of glyph %d from transformed 'glyf' table", i);
     }
     uint8_t* glyf_dst = dst + loca_offset;
     size_t glyf_dst_size = dst_size - loca_offset;
     if (n_contours == 0xffff) {
       // composite glyph
-      if (!(bbox_bitmap[i >> 3] & (0x80 >> (i & 7)))) {
-        return OTS_FAILURE_MSG("Composite glyph %d without bbox", i);
-      }
       bool have_instructions = false;
       uint16_t instruction_size = 0;
       if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size,
             &glyph_size, &have_instructions)) {
         return OTS_FAILURE_MSG("Filed to process composite glyph %d from transformed 'glyf' table", i);
       }
       if (have_instructions) {
         if (!Read255UShort(&glyph_stream, &instruction_size)) {
@@ -699,40 +696,40 @@ const Table* FindTable(const std::vector
   for (size_t i = 0; i < n_tables; ++i) {
     if (tables.at(i).tag == tag) {
       return &tables.at(i);
     }
   }
   return NULL;
 }
 
-bool ReconstructTransformed(ots::Font *font,
+bool ReconstructTransformed(ots::OpenTypeFile* file,
     const std::vector<Table>& tables, uint32_t tag,
     const uint8_t* transformed_buf, size_t transformed_size,
     uint8_t* dst, size_t dst_length) {
-  if (tag == OTS_TAG('g','l','y','f')) {
+  if (tag == TAG('g', 'l', 'y', 'f')) {
     const Table* glyf_table = FindTable(tables, tag);
-    const Table* loca_table = FindTable(tables, OTS_TAG('l','o','c','a'));
+    const Table* loca_table = FindTable(tables, TAG('l', 'o', 'c', 'a'));
     if (glyf_table == NULL || loca_table == NULL) {
       return OTS_FAILURE();
     }
     if (static_cast<uint64_t>(glyf_table->dst_offset) + glyf_table->dst_length >
         dst_length) {
       return OTS_FAILURE();
     }
     if (static_cast<uint64_t>(loca_table->dst_offset) + loca_table->dst_length >
         dst_length) {
       return OTS_FAILURE();
     }
-    return ReconstructGlyf(font, transformed_buf, transformed_size,
+    return ReconstructGlyf(file, transformed_buf, transformed_size,
         dst + glyf_table->dst_offset, glyf_table->dst_length,
         dst + loca_table->dst_offset, loca_table->dst_length);
-  } else if (tag == OTS_TAG('l','o','c','a')) {
+  } else if (tag == TAG('l', 'o', 'c', 'a')) {
     // processing was already done by glyf table, but validate
-    if (!FindTable(tables, OTS_TAG('g','l','y','f'))) {
+    if (!FindTable(tables, TAG('g', 'l', 'y', 'f'))) {
       return OTS_FAILURE();
     }
   } else {
     // transform for the tag is not known
     return OTS_FAILURE();
   }
   return true;
 }
@@ -743,17 +740,17 @@ uint32_t ComputeChecksum(const uint8_t* 
     // We assume the addition is mod 2^32, which is valid because unsigned
     checksum += (buf[i] << 24) | (buf[i + 1] << 16) |
       (buf[i + 2] << 8) | buf[i + 3];
   }
   return checksum;
 }
 
 bool FixChecksums(const std::vector<Table>& tables, uint8_t* dst) {
-  const Table* head_table = FindTable(tables, OTS_TAG('h','e','a','d'));
+  const Table* head_table = FindTable(tables, TAG('h', 'e', 'a', 'd'));
   if (head_table == NULL ||
       head_table->dst_length < kCheckSumAdjustmentOffset + 4) {
     return OTS_FAILURE();
   }
   size_t adjustment_offset = head_table->dst_offset + kCheckSumAdjustmentOffset;
   if (adjustment_offset < head_table->dst_offset) {
     return OTS_FAILURE();
   }
@@ -770,17 +767,28 @@ bool FixChecksums(const std::vector<Tabl
   }
   file_checksum += ComputeChecksum(dst,
       kSfntHeaderSize + kSfntEntrySize * n_tables);
   uint32_t checksum_adjustment = 0xb1b0afba - file_checksum;
   StoreU32(dst, adjustment_offset, checksum_adjustment);
   return true;
 }
 
-bool ReadTableDirectory(ots::Font *font,
+bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
+    const uint8_t* src_buf, size_t src_size) {
+  size_t uncompressed_size = dst_size;
+  int ok = BrotliDecompressBuffer(src_size, src_buf,
+                                  &uncompressed_size, dst_buf);
+  if (!ok || uncompressed_size != dst_size) {
+    return OTS_FAILURE();
+  }
+  return true;
+}
+
+bool ReadTableDirectory(ots::OpenTypeFile* file,
     ots::Buffer* buffer, std::vector<Table>* tables,
     size_t num_tables) {
   for (size_t i = 0; i < num_tables; ++i) {
     Table* table = &tables->at(i);
     uint8_t flag_byte;
     if (!buffer->ReadU8(&flag_byte)) {
       return OTS_FAILURE_MSG("Failed to read the flags of table directory entry %d", i);
     }
@@ -793,32 +801,28 @@ bool ReadTableDirectory(ots::Font *font,
       tag = kKnownTags[flag_byte & 0x3f];
     }
     // Bits 6 and 7 are reserved and must be 0.
     if ((flag_byte & 0xc0) != 0) {
       return OTS_FAILURE_MSG("Bits 6 and 7 are not 0 for table directory entry %d", i);
     }
     uint32_t flags = 0;
     // Always transform the glyf and loca tables
-    if (tag == OTS_TAG('g','l','y','f') ||
-        tag == OTS_TAG('l','o','c','a')) {
+    if (tag == TAG('g', 'l', 'y', 'f') ||
+        tag == TAG('l', 'o', 'c', 'a')) {
       flags |= kWoff2FlagsTransform;
     }
     uint32_t dst_length;
     if (!ReadBase128(buffer, &dst_length)) {
-      return OTS_FAILURE_MSG("Failed to read 'origLength' for table '%c%c%c%c'", OTS_UNTAG(tag));
+      return OTS_FAILURE_MSG("Failed to read 'origLength' for table '%c%c%c%c'", CHR(tag));
     }
     uint32_t transform_length = dst_length;
     if ((flags & kWoff2FlagsTransform) != 0) {
       if (!ReadBase128(buffer, &transform_length)) {
-        return OTS_FAILURE_MSG("Failed to read 'transformLength' for table '%c%c%c%c'", OTS_UNTAG(tag));
-      }
-
-      if (tag == OTS_TAG('l','o','c','a') && transform_length != 0) {
-        return OTS_FAILURE_MSG("The 'transformLength' of 'loca' table must be zero: %d", transform_length);
+        return OTS_FAILURE_MSG("Failed to read 'transformLength' for table '%c%c%c%c'", CHR(tag));
       }
     }
     // Disallow huge numbers (> 1GB) for sanity.
     if (transform_length > 1024 * 1024 * 1024 ||
         dst_length > 1024 * 1024 * 1024) {
       return OTS_FAILURE_MSG("'origLength' or 'transformLength' > 1GB");
     }
     table->tag = tag;
@@ -839,30 +843,30 @@ size_t ComputeWOFF2FinalSize(const uint8
 
   if (!file.Skip(16) ||
       !file.ReadU32(&total_length)) {
     return 0;
   }
   return total_length;
 }
 
-bool ConvertWOFF2ToSFNT(ots::Font *font,
+bool ConvertWOFF2ToSFNT(ots::OpenTypeFile* file,
                         uint8_t* result, size_t result_length,
                         const uint8_t* data, size_t length) {
   static const uint32_t kWoff2Signature = 0x774f4632;  // "wOF2"
   ots::Buffer buffer(data, length);
 
   uint32_t signature;
   uint32_t flavor = 0;
   if (!buffer.ReadU32(&signature) || signature != kWoff2Signature ||
       !buffer.ReadU32(&flavor)) {
     return OTS_FAILURE_MSG("Failed to read 'signature' or 'flavor', or not WOFF2 signature");
   }
 
-  if (!IsValidVersionTag(flavor)) {
+  if (!IsValidVersionTag(ntohl(flavor))) {
     return OTS_FAILURE_MSG("Invalid 'flavor'");
   }
 
   uint32_t reported_length;
   if (!buffer.ReadU32(&reported_length) || length != reported_length) {
     return OTS_FAILURE_MSG("Failed to read 'length' or it does not match the actual file size");
   }
   uint16_t num_tables;
@@ -918,17 +922,17 @@ bool ConvertWOFF2ToSFNT(ots::Font *font,
   }
   if (priv_offset) {
     if (priv_offset >= length || length - priv_offset < priv_length) {
       return OTS_FAILURE_MSG("Invalid private block offset or length");
     }
   }
 
   std::vector<Table> tables(num_tables);
-  if (!ReadTableDirectory(font, &buffer, &tables, num_tables)) {
+  if (!ReadTableDirectory(file, &buffer, &tables, num_tables)) {
     return OTS_FAILURE_MSG("Failed to read table directory");
   }
   uint64_t compressed_offset = buffer.offset();
   if (compressed_offset > std::numeric_limits<uint32_t>::max()) {
     return OTS_FAILURE();
   }
   uint64_t dst_offset = kSfntHeaderSize +
       kSfntEntrySize * static_cast<uint64_t>(num_tables);
@@ -1011,26 +1015,23 @@ bool ConvertWOFF2ToSFNT(ots::Font *font,
     if (total_size > std::numeric_limits<uint32_t>::max()) {
       return OTS_FAILURE();
     }
   }
   // Enforce same 30M limit on uncompressed tables as OTS
   if (total_size > 30 * 1024 * 1024) {
     return OTS_FAILURE();
   }
-  size_t uncompressed_size = static_cast<size_t>(total_size);
-  uncompressed_buf.resize(uncompressed_size);
-  const uint8_t* compressed_buf = data + compressed_offset;
-  if (!BrotliDecompressBuffer(compressed_length, compressed_buf,
-                              &uncompressed_size, &uncompressed_buf[0])) {
+  const size_t total_size_size_t = static_cast<size_t>(total_size);
+  uncompressed_buf.resize(total_size_size_t);
+  const uint8_t* src_buf = data + compressed_offset;
+  if (!Woff2Uncompress(&uncompressed_buf[0], total_size_size_t,
+      src_buf, compressed_length)) {
     return OTS_FAILURE_MSG("Failed to uncompress font data");
   }
-  if (uncompressed_size != static_cast<size_t>(total_size)) {
-    return OTS_FAILURE_MSG("Decompressed font data size does not match the sum of 'origLength' and 'transformLength'");
-  }
   transform_buf = &uncompressed_buf[0];
 
   for (uint16_t i = 0; i < num_tables; ++i) {
     const Table* table = &tables.at(i);
     uint32_t flags = table->flags;
     size_t transform_length = table->transform_length;
 
     if ((flags & kWoff2FlagsTransform) == 0) {
@@ -1039,19 +1040,19 @@ bool ConvertWOFF2ToSFNT(ots::Font *font,
       }
       if (static_cast<uint64_t>(table->dst_offset) + transform_length >
           result_length) {
         return OTS_FAILURE();
       }
       std::memcpy(result + table->dst_offset, transform_buf,
           transform_length);
     } else {
-      if (!ReconstructTransformed(font, tables, table->tag,
+      if (!ReconstructTransformed(file, tables, table->tag,
             transform_buf, transform_length, result, result_length)) {
-        return OTS_FAILURE_MSG("Failed to reconstruct '%c%c%c%c' table", OTS_UNTAG(table->tag));
+        return OTS_FAILURE_MSG("Failed to reconstruct '%c%c%c%c' table", CHR(table->tag));
       }
     }
 
     transform_buf += transform_length;
     if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) {
       return OTS_FAILURE();
     }
   }
--- a/gfx/ots/src/woff2.h
+++ b/gfx/ots/src/woff2.h
@@ -8,13 +8,13 @@
 namespace ots {
 
 // Compute the size of the final uncompressed font, or 0 on error.
 size_t ComputeWOFF2FinalSize(const uint8_t *data, size_t length);
 
 // Decompresses the font into the target buffer. The result_length should
 // be the same as determined by ComputeFinalSize(). Returns true on successful
 // decompression.
-bool ConvertWOFF2ToSFNT(Font *font, uint8_t *result, size_t result_length,
+bool ConvertWOFF2ToSFNT(OpenTypeFile *file, uint8_t *result, size_t result_length,
                         const uint8_t *data, size_t length);
 }
 
 #endif  // OTS_WOFF2_H_
--- a/gfx/ots/sync.sh
+++ b/gfx/ots/sync.sh
@@ -17,13 +17,12 @@ cp -r $1/src/* .
 cd ..
 
 echo "Updating include..."
 rm -rf include/
 cp -r $1/include .
 
 echo "Updating README.mozilla..."
 REVISION=`cd $1; git log | head -1 | sed "s/commit //"`
-sed -e "s/\(Current revision: \).*/\1$REVISION/" README.mozilla > README.tmp
-mv README.tmp README.mozilla
+sed -e "s/\(Current revision: \).*/\1$REVISION/" -i "" README.mozilla
 
 echo "Applying ots-visibility.patch..."
 patch -p3 < ots-visibility.patch