bug 527276 - part 1 - OTS source code from google (svn r.35). r=roc,cjones a=blocking2.0
authorJonathan Kew <jfkthame@gmail.com>
Thu, 07 Oct 2010 08:59:18 +0100
changeset 55080 6d49509b28a42a6c71be97963db37adc7b94ddc9
parent 55079 c1e91a637f5780faf5fa7872ca41f2fee3828723
child 55081 88ff5f0a9681a0d87d684a563c3a5ea375b87699
push idunknown
push userunknown
push dateunknown
reviewersroc, cjones, blocking2
bugs527276
milestone2.0b8pre
bug 527276 - part 1 - OTS source code from google (svn r.35). r=roc,cjones a=blocking2.0
gfx/ots/LICENSE
gfx/ots/include/opentype-sanitiser.h
gfx/ots/include/ots-memory-stream.h
gfx/ots/src/cff.cc
gfx/ots/src/cff.h
gfx/ots/src/cff_type2_charstring.cc
gfx/ots/src/cff_type2_charstring.h
gfx/ots/src/cmap.cc
gfx/ots/src/cmap.h
gfx/ots/src/cvt.cc
gfx/ots/src/cvt.h
gfx/ots/src/fpgm.cc
gfx/ots/src/fpgm.h
gfx/ots/src/gasp.cc
gfx/ots/src/gasp.h
gfx/ots/src/glyf.cc
gfx/ots/src/glyf.h
gfx/ots/src/hdmx.cc
gfx/ots/src/hdmx.h
gfx/ots/src/head.cc
gfx/ots/src/head.h
gfx/ots/src/hhea.cc
gfx/ots/src/hhea.h
gfx/ots/src/hmtx.cc
gfx/ots/src/hmtx.h
gfx/ots/src/kern.cc
gfx/ots/src/kern.h
gfx/ots/src/loca.cc
gfx/ots/src/loca.h
gfx/ots/src/ltsh.cc
gfx/ots/src/ltsh.h
gfx/ots/src/maxp.cc
gfx/ots/src/maxp.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/post.h
gfx/ots/src/prep.cc
gfx/ots/src/prep.h
gfx/ots/src/vdmx.cc
gfx/ots/src/vdmx.h
gfx/ots/src/vorg.cc
gfx/ots/src/vorg.h
new file mode 100644
--- /dev/null
+++ b/gfx/ots/LICENSE
@@ -0,0 +1,27 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
new file mode 100644
--- /dev/null
+++ b/gfx/ots/include/opentype-sanitiser.h
@@ -0,0 +1,181 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OPENTYPE_SANITISER_H_
+#define OPENTYPE_SANITISER_H_
+
+#if defined(_MSC_VER)
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#include <Winsock2.h>  // for htons/ntohs
+#else
+#include <arpa/inet.h>
+#include <stdint.h>
+#endif
+
+#include <algorithm>  // for std::min
+#include <cassert>
+#include <cstring>
+
+namespace ots {
+
+// -----------------------------------------------------------------------------
+// This is an interface for an abstract stream class which is used for writing
+// the serialised results out.
+// -----------------------------------------------------------------------------
+class OTSStream {
+ public:
+  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;
+    }
+
+    if (chksum_buffer_offset_ == 4) {
+      // TODO(yusukes): This cast breaks the strict-aliasing rule.
+      chksum_ += ntohl(*reinterpret_cast<const uint32_t*>(chksum_buffer_));
+      chksum_buffer_offset_ = 0;
+    }
+
+    while (length >= 4) {
+      chksum_ += ntohl(*reinterpret_cast<const uint32_t*>(
+          reinterpret_cast<const uint8_t*>(data) + offset));
+      length -= 4;
+      offset += 4;
+    }
+
+    if (length) {
+      if (chksum_buffer_offset_ != 0) return false;  // not reached
+      if (length > 4) return false;  // not reached
+      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 (!WriteTag(kZero)) return false;
+      bytes -= 4;
+    }
+    while (bytes) {
+      static const uint8_t kZerob = 0;
+      if (!Write(&kZerob, 1)) return false;
+      bytes--;
+    }
+    return true;
+  }
+
+  bool WriteU16(uint16_t v) {
+    v = htons(v);
+    return Write(&v, sizeof(v));
+  }
+
+  bool WriteS16(int16_t v) {
+    v = htons(v);
+    return Write(&v, sizeof(v));
+  }
+
+  bool WriteU32(uint32_t v) {
+    v = htonl(v);
+    return Write(&v, sizeof(v));
+  }
+
+  bool WriteS32(int32_t v) {
+    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() {
+    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_;
+};
+
+// -----------------------------------------------------------------------------
+// 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|
+// -----------------------------------------------------------------------------
+bool Process(OTSStream *output, const uint8_t *input, size_t length);
+
+// Force to disable debug output even when the library is compiled with
+// -DOTS_DEBUG.
+void DisableDebugOutput();
+
+}  // namespace ots
+
+#endif  // OPENTYPE_SANITISER_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/include/ots-memory-stream.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_MEMORY_STREAM_H_
+#define OTS_MEMORY_STREAM_H_
+
+#include <cstring>
+#include <limits>
+
+#include "opentype-sanitiser.h"
+
+namespace ots {
+
+class MemoryStream : public OTSStream {
+ public:
+  MemoryStream(void *ptr, size_t length)
+      : ptr_(ptr), length_(length), off_(0) {
+  }
+
+  bool WriteRaw(const void *data, size_t length) {
+    if ((off_ + length > length_) ||
+        (length > std::numeric_limits<size_t>::max() - off_)) {
+      return false;
+    }
+    std::memcpy(static_cast<char*>(ptr_) + off_, data, length);
+    off_ += length;
+    return true;
+  }
+
+  bool Seek(off_t position) {
+    if (position < 0) return false;
+    if (static_cast<size_t>(position) > length_) return false;
+    off_ = position;
+    return true;
+  }
+
+  off_t Tell() const {
+    return off_;
+  }
+
+ private:
+  void* const ptr_;
+  size_t length_;
+  off_t off_;
+};
+
+class ExpandingMemoryStream : public OTSStream {
+ public:
+  ExpandingMemoryStream(size_t initial, size_t limit)
+      : length_(initial), limit_(limit), off_(0) {
+    ptr_ = new uint8_t[length_];
+  }
+
+  ~ExpandingMemoryStream() {
+    delete[] static_cast<uint8_t*>(ptr_);
+  }
+
+  void* get() const {
+    return ptr_;
+  }
+
+  bool WriteRaw(const void *data, size_t length) {
+    if ((off_ + length > length_) ||
+        (length > std::numeric_limits<size_t>::max() - off_)) {
+      if (length_ == limit_)
+        return false;
+      size_t new_length = (length_ + 1) * 2;
+      if (new_length < length_)
+        return false;
+      if (new_length > limit_)
+        new_length = limit_;
+      uint8_t* new_buf = new uint8_t[new_length];
+      memcpy(new_buf, ptr_, length_);
+      length_ = new_length;
+      delete[] static_cast<uint8_t*>(ptr_);
+      ptr_ = new_buf;
+      return WriteRaw(data, length);
+    }
+    std::memcpy(static_cast<char*>(ptr_) + off_, data, length);
+    off_ += length;
+    return true;
+  }
+
+  bool Seek(off_t position) {
+    if (position < 0) return false;
+    if (static_cast<size_t>(position) > length_) return false;
+    off_ = position;
+    return true;
+  }
+
+  off_t Tell() const {
+    return off_;
+  }
+
+ private:
+  void* ptr_;
+  size_t length_;
+  const size_t limit_;
+  off_t off_;
+};
+
+}  // namespace ots
+
+#endif  // OTS_MEMORY_STREAM_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/cff.cc
@@ -0,0 +1,1003 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cff.h"
+
+#include <cstring>
+#include <utility>  // std::pair
+#include <vector>
+
+#include "cff_type2_charstring.h"
+
+// CFF - PostScript font program (Compact Font Format) table
+// http://www.microsoft.com/opentype/otspec/cff.htm
+// http://www.microsoft.com/opentype/otspec/5176.CFF.pdf
+
+namespace {
+
+enum DICT_OPERAND_TYPE {
+  DICT_OPERAND_INTEGER,
+  DICT_OPERAND_REAL,
+  DICT_OPERATOR,
+};
+
+enum DICT_DATA_TYPE {
+  DICT_DATA_TOPLEVEL,
+  DICT_DATA_FDARRAY,
+};
+
+// see Appendix. A
+const size_t kNStdString = 390;
+
+bool ReadOffset(ots::Buffer *table, uint8_t off_size, uint32_t *offset) {
+  if (off_size > 4) {
+    return OTS_FAILURE();
+  }
+
+  uint32_t tmp32 = 0;
+  for (unsigned i = 0; i < off_size; ++i) {
+    uint8_t tmp8 = 0;
+    if (!table->ReadU8(&tmp8)) {
+      return OTS_FAILURE();
+    }
+    tmp32 <<= 8;
+    tmp32 += tmp8;
+  }
+  *offset = tmp32;
+  return true;
+}
+
+bool ParseIndex(ots::Buffer *table, ots::CFFIndex *index) {
+  index->off_size = 0;
+  index->offsets.clear();
+
+  if (!table->ReadU16(&(index->count))) {
+    return OTS_FAILURE();
+  }
+  if (index->count == 0) {
+    // An empty INDEX.
+    index->offset_to_next = table->offset() + sizeof(index->count);
+    return true;
+  }
+
+  if (!table->ReadU8(&(index->off_size))) {
+    return OTS_FAILURE();
+  }
+  if ((index->off_size == 0) ||
+      (index->off_size > 4)) {
+    return OTS_FAILURE();
+  }
+
+  const size_t array_size = (index->count + 1) * index->off_size;
+  // less than ((64k + 1) * 4), thus does not overflow.
+  const size_t object_data_offset = table->offset() + array_size;
+  // does not overflow too, since offset() <= 1GB.
+
+  if (object_data_offset >= table->length()) {
+    return OTS_FAILURE();
+  }
+
+  for (unsigned i = 0; i <= index->count; ++i) {  // '<=' is not a typo.
+    uint32_t rel_offset = 0;
+    if (!ReadOffset(table, index->off_size, &rel_offset)) {
+      return OTS_FAILURE();
+    }
+    if (rel_offset < 1) {
+      return OTS_FAILURE();
+    }
+    if (i == 0 && rel_offset != 1) {
+      return OTS_FAILURE();
+    }
+
+    if (rel_offset > table->length()) {
+      return OTS_FAILURE();
+    }
+
+    // does not underflow.
+    if (object_data_offset > table->length() - (rel_offset - 1)) {
+      return OTS_FAILURE();
+    }
+
+    index->offsets.push_back(
+        object_data_offset + (rel_offset - 1));  // less than length(), 1GB.
+  }
+
+  for (unsigned i = 1; i < index->offsets.size(); ++i) {
+    if (index->offsets[i] <= index->offsets[i - 1]) {
+      return OTS_FAILURE();
+    }
+  }
+
+  index->offset_to_next = index->offsets.back();
+  return true;
+}
+
+bool ParseNameData(
+    ots::Buffer *table, const ots::CFFIndex &index, std::string* out_name) {
+  uint8_t name[256] = {0};
+  if (index.offsets.size() == 0) {  // just in case.
+    return OTS_FAILURE();
+  }
+  for (unsigned i = 1; i < index.offsets.size(); ++i) {
+    const size_t length = index.offsets[i] - index.offsets[i - 1];
+    // font names should be no longer than 127 characters.
+    if (length > 127) {
+      return OTS_FAILURE();
+    }
+
+    table->set_offset(index.offsets[i - 1]);
+    if (!table->Read(name, length)) {
+      return OTS_FAILURE();
+    }
+
+    for (size_t j = 0; j < length; ++j) {
+      // setting the first byte to NUL is allowed.
+      if (j == 0 && name[j] == 0) continue;
+      // non-ASCII characters are not recommended (except the first character).
+      if (name[j] < 33 || name[j] > 126) {
+        return OTS_FAILURE();
+      }
+      // [, ], ... are not allowed.
+      if (std::strchr("[](){}<>/% ", name[j])) {
+        return OTS_FAILURE();
+      }
+    }
+  }
+
+  *out_name = reinterpret_cast<char *>(name);
+  return true;
+}
+
+bool CheckOffset(const std::pair<uint32_t, DICT_OPERAND_TYPE>& operand,
+                 size_t table_length) {
+  if (operand.second != DICT_OPERAND_INTEGER) {
+    return OTS_FAILURE();
+  }
+  if (operand.first >= table_length) {
+    return OTS_FAILURE();
+  }
+  return true;
+}
+
+bool CheckSid(const std::pair<uint32_t, DICT_OPERAND_TYPE>& operand,
+              size_t sid_max) {
+  if (operand.second != DICT_OPERAND_INTEGER) {
+    return OTS_FAILURE();
+  }
+  if (operand.first > sid_max) {
+    return OTS_FAILURE();
+  }
+  return true;
+}
+
+bool ParseDictDataBcd(
+    ots::Buffer *table,
+    std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > *operands) {
+  bool read_decimal_point = false;
+  bool read_e = false;
+
+  uint8_t nibble = 0;
+  size_t count = 0;
+  while (true) {
+    if (!table->ReadU8(&nibble)) {
+      return OTS_FAILURE();
+    }
+    if ((nibble & 0xf0) == 0xf0) {
+      if ((nibble & 0xf) == 0xf) {
+        // TODO(yusukes): would be better to store actual double value,
+        // rather than the dummy integer.
+        operands->push_back(std::make_pair(0, DICT_OPERAND_REAL));
+        return true;
+      }
+      return OTS_FAILURE();
+    }
+    if ((nibble & 0x0f) == 0x0f) {
+      operands->push_back(std::make_pair(0, DICT_OPERAND_REAL));
+      return true;
+    }
+
+    // check number format
+    uint8_t nibbles[2];
+    nibbles[0] = (nibble & 0xf0) >> 8;
+    nibbles[1] = (nibble & 0x0f);
+    for (unsigned i = 0; i < 2; ++i) {
+      if (nibbles[i] == 0xd) {  // reserved number
+        return OTS_FAILURE();
+      }
+      if ((nibbles[i] == 0xe) &&  // minus
+          ((count > 0) || (i > 0))) {
+        return OTS_FAILURE();  // minus sign should be the first character.
+      }
+      if (nibbles[i] == 0xa) {  // decimal point
+        if (!read_decimal_point) {
+          read_decimal_point = true;
+        } else {
+          return OTS_FAILURE();  // two or more points.
+        }
+      }
+      if ((nibbles[i] == 0xb) ||  // E+
+          (nibbles[i] == 0xc)) {  // E-
+        if (!read_e) {
+          read_e = true;
+        } else {
+          return OTS_FAILURE();  // two or more E's.
+        }
+      }
+    }
+    ++count;
+  }
+}
+
+bool ParseDictDataEscapedOperator(
+    ots::Buffer *table,
+    std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > *operands) {
+  uint8_t op = 0;
+  if (!table->ReadU8(&op)) {
+    return OTS_FAILURE();
+  }
+
+  if ((op <= 14) ||
+      (op >= 17 && op <= 23) ||
+      (op >= 30 && op <= 38)) {
+    operands->push_back(std::make_pair((12U << 8) + op, DICT_OPERATOR));
+    return true;
+  }
+
+  // reserved area.
+  return OTS_FAILURE();
+}
+
+bool ParseDictDataNumber(
+    ots::Buffer *table, uint8_t b0,
+    std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > *operands) {
+  uint8_t b1 = 0;
+  uint8_t b2 = 0;
+  uint8_t b3 = 0;
+  uint8_t b4 = 0;
+
+  switch (b0) {
+    case 28:  // shortint
+      if (!table->ReadU8(&b1) ||
+          !table->ReadU8(&b2)) {
+        return OTS_FAILURE();
+      }
+      operands->push_back(std::make_pair((b1 << 8) + b2, DICT_OPERAND_INTEGER));
+      return true;
+
+    case 29:  // longint
+      if (!table->ReadU8(&b1) ||
+          !table->ReadU8(&b2) ||
+          !table->ReadU8(&b3) ||
+          !table->ReadU8(&b4)) {
+        return OTS_FAILURE();
+      }
+      operands->push_back(std::make_pair(
+          (b1 << 24) + (b2 << 16) + (b3 << 8) + b4, DICT_OPERAND_INTEGER));
+      return true;
+
+    case 30:  // binary coded decimal
+      return ParseDictDataBcd(table, operands);
+
+    default:
+      break;
+  }
+
+  uint32_t result;
+  if (b0 >=32 && b0 <=246) {
+    result = b0 - 139;
+  } else if (b0 >=247 && b0 <= 250) {
+    if (!table->ReadU8(&b1)) {
+      return OTS_FAILURE();
+    }
+    result = (b0 - 247) * 256 + b1 + 108;
+  } else if (b0 >= 251 && b0 <= 254) {
+    if (!table->ReadU8(&b1)) {
+      return OTS_FAILURE();
+    }
+    result = -(b0 - 251) * 256 + b1 - 108;
+  } else {
+    return OTS_FAILURE();
+  }
+
+  operands->push_back(std::make_pair(result, DICT_OPERAND_INTEGER));
+  return true;
+}
+
+bool ParseDictDataReadNext(
+    ots::Buffer *table,
+    std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > *operands) {
+  uint8_t op = 0;
+  if (!table->ReadU8(&op)) {
+    return OTS_FAILURE();
+  }
+  if (op <= 21) {
+    if (op == 12) {
+      return ParseDictDataEscapedOperator(table, operands);
+    }
+    operands->push_back(std::make_pair(op, DICT_OPERATOR));
+    return true;
+  } else if (op <= 27 || op == 31 || op == 255) {
+    // reserved area.
+    return OTS_FAILURE();
+  }
+
+  return ParseDictDataNumber(table, op, operands);
+}
+
+bool ParsePrivateDictData(
+    const uint8_t *data,
+    size_t table_length, size_t offset, size_t dict_length,
+    DICT_DATA_TYPE type, ots::OpenTypeCFF *out_cff) {
+  ots::Buffer table(data + offset, dict_length);
+  std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > operands;
+
+  // Since a Private DICT for FDArray might not have a Local Subr (e.g. Hiragino
+  // Kaku Gothic Std W8), we create an empty Local Subr here to match the size
+  // of FDArray the size of |local_subrs_per_font|.
+  if (type == DICT_DATA_FDARRAY) {
+    out_cff->local_subrs_per_font.push_back(new ots::CFFIndex);
+  }
+
+  while (table.offset() < dict_length) {
+    if (!ParseDictDataReadNext(&table, &operands)) {
+      return OTS_FAILURE();
+    }
+    if (operands.empty()) {
+      return OTS_FAILURE();
+    }
+    if (operands.size() > 48) {
+      // An operator may be preceded by up to a maximum of 48 operands.
+      return OTS_FAILURE();
+    }
+    if (operands.back().second != DICT_OPERATOR) {
+      continue;
+    }
+
+    // got operator
+    const uint32_t op = operands.back().first;
+    operands.pop_back();
+
+    switch (op) {
+      // array
+      case 6:  // BlueValues
+      case 7:  // OtherBlues
+      case 8:  // FamilyBlues
+      case 9:  // FamilyOtherBlues
+      case (12U << 8) + 12:  // StemSnapH (delta)
+      case (12U << 8) + 13:  // StemSnapV (delta)
+        if (operands.empty()) {
+          return OTS_FAILURE();
+        }
+        break;
+
+      // number
+      case 10:  // StdHW
+      case 11:  // StdVW
+      case 20:  // defaultWidthX
+      case 21:  // nominalWidthX
+      case (12U << 8) + 9:   // BlueScale
+      case (12U << 8) + 10:  // BlueShift
+      case (12U << 8) + 11:  // BlueFuzz
+      case (12U << 8) + 17:  // LanguageGroup
+      case (12U << 8) + 18:  // ExpansionFactor
+      case (12U << 8) + 19:  // initialRandomSeed
+        if (operands.size() != 1) {
+          return OTS_FAILURE();
+        }
+        break;
+
+      // Local Subrs INDEX, offset(self)
+      case 19: {
+        if (operands.size() != 1) {
+          return OTS_FAILURE();
+        }
+        if (operands.back().second != DICT_OPERAND_INTEGER) {
+          return OTS_FAILURE();
+        }
+        if (operands.back().first >= 1024 * 1024 * 1024) {
+          return OTS_FAILURE();
+        }
+        if (operands.back().first + offset >= table_length) {
+          return OTS_FAILURE();
+        }
+        // parse "16. Local Subrs INDEX"
+        ots::Buffer table(data, table_length);
+        table.set_offset(operands.back().first + offset);
+        ots::CFFIndex *local_subrs_index = NULL;
+        if (type == DICT_DATA_FDARRAY) {
+          if (out_cff->local_subrs_per_font.empty()) {
+            return OTS_FAILURE();  // not reached.
+          }
+          local_subrs_index = out_cff->local_subrs_per_font.back();
+        } else if (type == DICT_DATA_TOPLEVEL) {
+          if (out_cff->local_subrs) {
+            return OTS_FAILURE();  // two or more local_subrs?
+          }
+          local_subrs_index = new ots::CFFIndex;
+          out_cff->local_subrs = local_subrs_index;
+        }
+        if (!ParseIndex(&table, local_subrs_index)) {
+          return OTS_FAILURE();
+        }
+        break;
+      }
+
+      // boolean
+      case (12U << 8) + 14:  // ForceBold
+        if (operands.size() != 1) {
+          return OTS_FAILURE();
+        }
+        if (operands.back().second != DICT_OPERAND_INTEGER) {
+          return OTS_FAILURE();
+        }
+        if (operands.back().first >= 2) {
+          return OTS_FAILURE();
+        }
+        break;
+
+      default:
+        return OTS_FAILURE();
+    }
+    operands.clear();
+  }
+
+  return true;
+}
+
+bool ParseDictData(const uint8_t *data, size_t table_length,
+                   const ots::CFFIndex &index, size_t sid_max,
+                   DICT_DATA_TYPE type, ots::OpenTypeCFF *out_cff) {
+  for (unsigned i = 1; i < index.offsets.size(); ++i) {
+    if (type == DICT_DATA_TOPLEVEL) {
+      out_cff->char_strings_array.push_back(new ots::CFFIndex);
+    }
+    size_t dict_length = index.offsets[i] - index.offsets[i - 1];
+    ots::Buffer table(data + index.offsets[i - 1], dict_length);
+
+    std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > operands;
+
+    bool have_ros = false;
+    size_t glyphs = 0;
+    size_t charset_offset = 0;
+
+    while (table.offset() < dict_length) {
+      if (!ParseDictDataReadNext(&table, &operands)) {
+        return OTS_FAILURE();
+      }
+      if (operands.empty()) {
+        return OTS_FAILURE();
+      }
+      if (operands.size() > 48) {
+        // An operator may be preceded by up to a maximum of 48 operands.
+        return OTS_FAILURE();
+      }
+      if (operands.back().second != DICT_OPERATOR) continue;
+
+      // got operator
+      const uint32_t op = operands.back().first;
+      operands.pop_back();
+
+      switch (op) {
+        // SID
+        case 0:   // version
+        case 1:   // Notice
+        case 2:   // Copyright
+        case 3:   // FullName
+        case 4:   // FamilyName
+        case (12U << 8) + 0:   // Copyright
+        case (12U << 8) + 21:  // PostScript
+        case (12U << 8) + 22:  // BaseFontName
+        case (12U << 8) + 38:  // FontName
+          if (operands.size() != 1) {
+            return OTS_FAILURE();
+          }
+          if (!CheckSid(operands.back(), sid_max)) {
+            return OTS_FAILURE();
+          }
+          break;
+
+        // array
+        case 5:   // FontBBox
+        case 14:  // XUID
+        case (12U << 8) + 7:   // FontMatrix
+        case (12U << 8) + 23:  // BaseFontBlend (delta)
+          if (operands.empty()) {
+            return OTS_FAILURE();
+          }
+          break;
+
+        // number
+        case 13:  // UniqueID
+        case (12U << 8) + 2:   // ItalicAngle
+        case (12U << 8) + 3:   // UnderlinePosition
+        case (12U << 8) + 4:   // UnderlineThickness
+        case (12U << 8) + 5:   // PaintType
+        case (12U << 8) + 8:   // StrokeWidth
+        case (12U << 8) + 20:  // SyntheticBase
+        case (12U << 8) + 31:  // CIDFontVersion
+        case (12U << 8) + 32:  // CIDFontRevision
+        case (12U << 8) + 33:  // CIDFontType
+        case (12U << 8) + 34:  // CIDCount
+        case (12U << 8) + 35:  // UIDBase
+          if (operands.size() != 1) {
+            return OTS_FAILURE();
+          }
+          break;
+        case (12U << 8) + 6:   // CharstringType
+          if (operands.size() != 1) {
+            return OTS_FAILURE();
+          }
+          if(operands.back().second != DICT_OPERAND_INTEGER) {
+            return OTS_FAILURE();
+          }
+          if (operands.back().first != 2) {
+            // We only support the "Type 2 Charstring Format."
+            // TODO(yusukes): Support Type 1 format? Is that still in use?
+            return OTS_FAILURE();
+          }
+          break;
+
+        // boolean
+        case (12U << 8) + 1:   // isFixedPitch
+          if (operands.size() != 1) {
+            return OTS_FAILURE();
+          }
+          if (operands.back().second != DICT_OPERAND_INTEGER) {
+            return OTS_FAILURE();
+          }
+          if (operands.back().first >= 2) {
+            return OTS_FAILURE();
+          }
+          break;
+
+        // offset(0)
+        case 15:  // charset
+          if (operands.size() != 1) {
+            return OTS_FAILURE();
+          }
+          if (operands.back().first <= 2) {
+            // predefined charset, ISOAdobe, Expert or ExpertSubset, is used.
+            break;
+          }
+          if (!CheckOffset(operands.back(), table_length)) {
+            return OTS_FAILURE();
+          }
+          if (charset_offset) {
+            return OTS_FAILURE();  // multiple charset tables?
+          }
+          charset_offset = operands.back().first;
+          break;
+
+        case 16: {  // Encoding
+          if (operands.size() != 1) {
+            return OTS_FAILURE();
+          }
+          if (operands.back().first <= 1) {
+            break;  // predefined encoding, "Standard" or "Expert", is used.
+          }
+          if (!CheckOffset(operands.back(), table_length)) {
+            return OTS_FAILURE();
+          }
+
+          // parse sub dictionary INDEX.
+          ots::Buffer table(data, table_length);
+          table.set_offset(operands.back().first);
+          uint8_t format = 0;
+          if (!table.ReadU8(&format)) {
+            return OTS_FAILURE();
+          }
+          if (format & 0x80) {
+            // supplemental encoding is not supported at the moment.
+            return OTS_FAILURE();
+          }
+          // TODO(yusukes): support & parse supplemental encoding tables.
+          break;
+        }
+
+        case 17: {  // CharStrings
+          if (type != DICT_DATA_TOPLEVEL) {
+            return OTS_FAILURE();
+          }
+          if (operands.size() != 1) {
+            return OTS_FAILURE();
+          }
+          if (!CheckOffset(operands.back(), table_length)) {
+            return OTS_FAILURE();
+          }
+          // parse "14. CharStrings INDEX"
+          ots::Buffer table(data, table_length);
+          table.set_offset(operands.back().first);
+          ots::CFFIndex *charstring_index = out_cff->char_strings_array.back();
+          if (!ParseIndex(&table, charstring_index)) {
+            return OTS_FAILURE();
+          }
+          if (charstring_index->count < 2) {
+            return OTS_FAILURE();
+          }
+          if (glyphs) {
+            return OTS_FAILURE();  // multiple charstring tables?
+          }
+          glyphs = charstring_index->count;
+          break;
+        }
+
+        case (12U << 8) + 36: {  // FDArray
+          if (type != DICT_DATA_TOPLEVEL) {
+            return OTS_FAILURE();
+          }
+          if (operands.size() != 1) {
+            return OTS_FAILURE();
+          }
+          if (!CheckOffset(operands.back(), table_length)) {
+            return OTS_FAILURE();
+          }
+
+          // parse sub dictionary INDEX.
+          ots::Buffer table(data, table_length);
+          table.set_offset(operands.back().first);
+          ots::CFFIndex sub_dict_index;
+          if (!ParseIndex(&table, &sub_dict_index)) {
+            return OTS_FAILURE();
+          }
+          if (!ParseDictData(data, table_length,
+                             sub_dict_index, sid_max, DICT_DATA_FDARRAY,
+                             out_cff)) {
+            return OTS_FAILURE();
+          }
+          if (out_cff->font_dict_length != 0) {
+            return OTS_FAILURE();  // two or more FDArray found.
+          }
+          out_cff->font_dict_length = sub_dict_index.count;
+          break;
+        }
+
+        case (12U << 8) + 37: {  // FDSelect
+          if (type != DICT_DATA_TOPLEVEL) {
+            return OTS_FAILURE();
+          }
+          if (operands.size() != 1) {
+            return OTS_FAILURE();
+          }
+          if (!CheckOffset(operands.back(), table_length)) {
+            return OTS_FAILURE();
+          }
+
+          // parse FDSelect data structure
+          ots::Buffer table(data, table_length);
+          table.set_offset(operands.back().first);
+          uint8_t format = 0;
+          if (!table.ReadU8(&format)) {
+            return OTS_FAILURE();
+          }
+          if (format == 0) {
+            for (size_t j = 0; j < glyphs; ++j) {
+              uint8_t fd_index = 0;
+              if (!table.ReadU8(&fd_index)) {
+                return OTS_FAILURE();
+              }
+              (out_cff->fd_select)[j] = fd_index;
+            }
+          } else if (format == 3) {
+            uint16_t n_ranges = 0;
+            if (!table.ReadU16(&n_ranges)) {
+              return OTS_FAILURE();
+            }
+            if (n_ranges == 0) {
+              return OTS_FAILURE();
+            }
+
+            uint16_t last_gid = 0;
+            uint8_t fd_index = 0;
+            for (unsigned j = 0; j < n_ranges; ++j) {
+              uint16_t first = 0;  // GID
+              if (!table.ReadU16(&first)) {
+                return OTS_FAILURE();
+              }
+
+              // Sanity checks.
+              if ((j == 0) && (first != 0)) {
+                return OTS_FAILURE();
+              }
+              if ((j != 0) && (last_gid >= first)) {
+                return OTS_FAILURE();  // not increasing order.
+              }
+
+              // Copy the mapping to |out_cff->fd_select|.
+              if (j != 0) {
+                for (uint16_t k = last_gid; k < first; ++k) {
+                  if (!out_cff->fd_select.insert(
+                          std::make_pair(k, fd_index)).second) {
+                    return OTS_FAILURE();
+                  }
+                }
+              }
+
+              if (!table.ReadU8(&fd_index)) {
+                return OTS_FAILURE();
+              }
+              last_gid = first;
+              // TODO(yusukes): check GID?
+            }
+            uint16_t sentinel = 0;
+            if (!table.ReadU16(&sentinel)) {
+              return OTS_FAILURE();
+            }
+            if (last_gid >= sentinel) {
+              return OTS_FAILURE();
+            }
+            for (uint16_t k = last_gid; k < sentinel; ++k) {
+              if (!out_cff->fd_select.insert(
+                      std::make_pair(k, fd_index)).second) {
+                return OTS_FAILURE();
+              }
+            }
+          } else {
+            // unknown format
+            return OTS_FAILURE();
+          }
+          break;
+        }
+
+        // Private DICT (2 * number)
+        case 18: {
+          if (operands.size() != 2) {
+            return OTS_FAILURE();
+          }
+          if (operands.back().second != DICT_OPERAND_INTEGER) {
+            return OTS_FAILURE();
+          }
+          const uint32_t private_offset = operands.back().first;
+          operands.pop_back();
+          if (operands.back().second != DICT_OPERAND_INTEGER) {
+            return OTS_FAILURE();
+          }
+          const uint32_t private_length = operands.back().first;
+          if (private_offset >= table_length) {
+            return OTS_FAILURE();
+          }
+          if (private_length >= table_length) {
+            return OTS_FAILURE();
+          }
+          if (private_length + private_offset > table_length) {
+            // does not overflow since table_length < 1GB
+            return OTS_FAILURE();
+          }
+          // parse "15. Private DICT Data"
+          if (!ParsePrivateDictData(data, table_length,
+                                    private_offset, private_length,
+                                    type, out_cff)) {
+            return OTS_FAILURE();
+          }
+          break;
+        }
+
+        // ROS
+        case (12U << 8) + 30:
+          if (type != DICT_DATA_TOPLEVEL) {
+            return OTS_FAILURE();
+          }
+          if (operands.size() != 3) {
+            return OTS_FAILURE();
+          }
+          // check SIDs
+          operands.pop_back();  // ignore the first number.
+          if (!CheckSid(operands.back(), sid_max)) {
+            return OTS_FAILURE();
+          }
+          operands.pop_back();
+          if (!CheckSid(operands.back(), sid_max)) {
+            return OTS_FAILURE();
+          }
+          if (have_ros) {
+            return OTS_FAILURE();  // multiple ROS tables?
+          }
+          have_ros = true;
+          break;
+
+        default:
+          return OTS_FAILURE();
+      }
+      operands.clear();
+    }
+
+    // parse "13. Charsets"
+    if (charset_offset) {
+      ots::Buffer table(data, table_length);
+      table.set_offset(charset_offset);
+      uint8_t format = 0;
+      if (!table.ReadU8(&format)) {
+        return OTS_FAILURE();
+      }
+      switch (format) {
+        case 0:
+          for (unsigned j = 1 /* .notdef is omitted */; j < glyphs; ++j) {
+            uint16_t sid = 0;
+            if (!table.ReadU16(&sid)) {
+              return OTS_FAILURE();
+            }
+            if (!have_ros && (sid > sid_max)) {
+              return OTS_FAILURE();
+            }
+            // TODO(yusukes): check CIDs when have_ros is true.
+          }
+          break;
+
+        case 1:
+        case 2: {
+          uint32_t total = 1;  // .notdef is omitted.
+          while (total < glyphs) {
+            uint16_t sid = 0;
+            if (!table.ReadU16(&sid)) {
+              return OTS_FAILURE();
+            }
+            if (!have_ros && (sid > sid_max)) {
+              return OTS_FAILURE();
+            }
+            // TODO(yusukes): check CIDs when have_ros is true.
+
+            if (format == 1) {
+              uint8_t left = 0;
+              if (!table.ReadU8(&left)) {
+                return OTS_FAILURE();
+              }
+              total += (left + 1);
+            } else {
+              uint16_t left = 0;
+              if (!table.ReadU16(&left)) {
+                return OTS_FAILURE();
+              }
+              total += (left + 1);
+            }
+          }
+          break;
+        }
+
+        default:
+          return OTS_FAILURE();
+      }
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
+namespace ots {
+
+bool ots_cff_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+
+  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();
+  }
+  if (!table.ReadU8(&minor)) {
+    return OTS_FAILURE();
+  }
+  if (!table.ReadU8(&hdr_size)) {
+    return OTS_FAILURE();
+  }
+  if (!table.ReadU8(&off_size)) {
+    return OTS_FAILURE();
+  }
+  if ((off_size == 0) || (off_size > 4)) {
+    return OTS_FAILURE();
+  }
+
+  if ((major != 1) ||
+      (minor != 0) ||
+      (hdr_size != 4)) {
+    return OTS_FAILURE();
+  }
+  if (hdr_size >= length) {
+    return OTS_FAILURE();
+  }
+
+  // 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, &(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();
+  }
+  if (name_index.count != top_dict_index.count) {
+    return OTS_FAILURE();
+  }
+
+  // parse "10. String INDEX"
+  table.set_offset(top_dict_index.offset_to_next);
+  CFFIndex string_index;
+  if (!ParseIndex(&table, &string_index)) {
+    return OTS_FAILURE();
+  }
+  if (string_index.count >= 65000 - kNStdString) {
+    return OTS_FAILURE();
+  }
+
+  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,
+                     sid_max, 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 = 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 < file->cff->char_strings_array.size(); ++i) {
+    if (!ValidateType2CharStringIndex(*(file->cff->char_strings_array.at(i)),
+                                      global_subrs_index,
+                                      file->cff->fd_select,
+                                      file->cff->local_subrs_per_font,
+                                      file->cff->local_subrs,
+                                      &table)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  return true;
+}
+
+bool ots_cff_should_serialise(OpenTypeFile *file) {
+  return file->cff;
+}
+
+bool ots_cff_serialise(OTSStream *out, OpenTypeFile *file) {
+  // TODO(yusukes): would be better to transcode the data,
+  //                rather than simple memcpy.
+  if (!out->Write(file->cff->data, file->cff->length)) {
+    return OTS_FAILURE();
+  }
+  return true;
+}
+
+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 < file->cff->local_subrs_per_font.size(); ++i) {
+      delete (file->cff->local_subrs_per_font)[i];
+    }
+    delete file->cff->local_subrs;
+    delete file->cff;
+  }
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/cff.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_CFF_H_
+#define OTS_CFF_H_
+
+#include "ots.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace ots {
+
+struct CFFIndex {
+  CFFIndex()
+      : count(0), off_size(0), offset_to_next(0) {}
+  uint16_t count;
+  uint8_t off_size;
+  std::vector<uint32_t> offsets;
+  uint32_t offset_to_next;
+};
+
+struct OpenTypeCFF {
+  const uint8_t *data;
+  size_t length;
+  // Name INDEX. This name is used in name.cc as a postscript font name.
+  std::string name;
+
+  // The number of fonts the file has.
+  size_t font_dict_length;
+  // A map from glyph # to font #.
+  std::map<uint16_t, uint8_t> fd_select;
+
+  // A list of char strings.
+  std::vector<CFFIndex *> char_strings_array;
+  // A list of Local Subrs associated with FDArrays. Can be empty.
+  std::vector<CFFIndex *> local_subrs_per_font;
+  // A Local Subrs associated with Top DICT. Can be NULL.
+  CFFIndex *local_subrs;
+};
+
+}  // namespace ots
+
+#endif  // OTS_CFF_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/cff_type2_charstring.cc
@@ -0,0 +1,889 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A parser for the Type 2 Charstring Format.
+// http://www.adobe.com/devnet/font/pdfs/5177.Type2.pdf
+
+#include "cff_type2_charstring.h"
+
+#include <climits>
+#include <cstdio>
+#include <cstring>
+#include <stack>
+#include <string>
+#include <utility>
+
+namespace {
+
+// Type 2 Charstring Implementation Limits. See Appendix. B in Adobe Technical
+// Note #5177.
+const int32_t kMaxSubrsCount = 65536;
+const size_t kMaxCharStringLength = 65535;
+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(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,
+                            size_t *in_out_num_stems);
+
+// Converts |op| to a string and returns it.
+const char *Type2CharStringOperatorToString(ots::Type2CharStringOperator op) {
+  switch (op) {
+  case ots::kHStem:
+    return "HStem";
+  case ots::kVStem:
+    return "VStem";
+  case ots::kVMoveTo:
+    return "VMoveTo";
+  case ots::kRLineTo:
+    return "RLineTo";
+  case ots::kHLineTo:
+    return "HLineTo";
+  case ots::kVLineTo:
+    return "VLineTo";
+  case ots::kRRCurveTo:
+    return "RRCurveTo";
+  case ots::kCallSubr:
+    return "CallSubr";
+  case ots::kReturn:
+    return "Return";
+  case ots::kEndChar:
+    return "EndChar";
+  case ots::kHStemHm:
+    return "HStemHm";
+  case ots::kHintMask:
+    return "HintMask";
+  case ots::kCntrMask:
+    return "CntrMask";
+  case ots::kRMoveTo:
+    return "RMoveTo";
+  case ots::kHMoveTo:
+    return "HMoveTo";
+  case ots::kVStemHm:
+    return "VStemHm";
+  case ots::kRCurveLine:
+    return "RCurveLine";
+  case ots::kRLineCurve:
+    return "RLineCurve";
+  case ots::kVVCurveTo:
+    return "VVCurveTo";
+  case ots::kHHCurveTo:
+    return "HHCurveTo";
+  case ots::kCallGSubr:
+    return "CallGSubr";
+  case ots::kVHCurveTo:
+    return "VHCurveTo";
+  case ots::kHVCurveTo:
+    return "HVCurveTo";
+  case ots::kAnd:
+    return "And";
+  case ots::kOr:
+    return "Or";
+  case ots::kNot:
+    return "Not";
+  case ots::kAbs:
+    return "Abs";
+  case ots::kAdd:
+    return "Add";
+  case ots::kSub:
+    return "Sub";
+  case ots::kDiv:
+    return "Div";
+  case ots::kNeg:
+    return "Neg";
+  case ots::kEq:
+    return "Eq";
+  case ots::kDrop:
+    return "Drop";
+  case ots::kPut:
+    return "Put";
+  case ots::kGet:
+    return "Get";
+  case ots::kIfElse:
+    return "IfElse";
+  case ots::kRandom:
+    return "Random";
+  case ots::kMul:
+    return "Mul";
+  case ots::kSqrt:
+    return "Sqrt";
+  case ots::kDup:
+    return "Dup";
+  case ots::kExch:
+    return "Exch";
+  case ots::kIndex:
+    return "Index";
+  case ots::kRoll:
+    return "Roll";
+  case ots::kHFlex:
+    return "HFlex";
+  case ots::kFlex:
+    return "Flex";
+  case ots::kHFlex1:
+    return "HFlex1";
+  case ots::kFlex1:
+    return "Flex1";
+  }
+
+  return "UNKNOWN";
+}
+
+// Read one or more bytes from the |char_string| buffer and stores the number
+// read on |out_number|. If the number read is an operator (ex 'vstem'), sets
+// true on |out_is_operator|. Returns true if the function read a number.
+bool ReadNextNumberFromType2CharString(ots::Buffer *char_string,
+                                       int32_t *out_number,
+                                       bool *out_is_operator) {
+  uint8_t v = 0;
+  if (!char_string->ReadU8(&v)) {
+    return OTS_FAILURE();
+  }
+  *out_is_operator = false;
+
+  // The conversion algorithm is described in Adobe Technical Note #5177, page
+  // 13, Table 1.
+  if (v <= 11) {
+    *out_number = v;
+    *out_is_operator = true;
+  } else if (v == 12) {
+    uint16_t result = (v << 8);
+    if (!char_string->ReadU8(&v)) {
+      return OTS_FAILURE();
+    }
+    result += v;
+    *out_number = result;
+    *out_is_operator = true;
+  } else if (v <= 27) {
+    // Special handling for v==19 and v==20 are implemented in
+    // ExecuteType2CharStringOperator().
+    *out_number = v;
+    *out_is_operator = true;
+  } else if (v == 28) {
+    if (!char_string->ReadU8(&v)) {
+      return OTS_FAILURE();
+    }
+    uint16_t result = (v << 8);
+    if (!char_string->ReadU8(&v)) {
+      return OTS_FAILURE();
+    }
+    result += v;
+    *out_number = result;
+  } else if (v <= 31) {
+    *out_number = v;
+    *out_is_operator = true;
+  } else if (v <= 246) {
+    *out_number = static_cast<int32_t>(v) - 139;
+  } else if (v <= 250) {
+    uint8_t w = 0;
+    if (!char_string->ReadU8(&w)) {
+      return OTS_FAILURE();
+    }
+    *out_number = ((static_cast<int32_t>(v) - 247) * 256) +
+        static_cast<int32_t>(w) + 108;
+  } else if (v <= 254) {
+    uint8_t w = 0;
+    if (!char_string->ReadU8(&w)) {
+      return OTS_FAILURE();
+    }
+    *out_number = -((static_cast<int32_t>(v) - 251) * 256) -
+        static_cast<int32_t>(w) - 108;
+  } else if (v == 255) {
+    // TODO(yusukes): We should not skip the 4 bytes. Note that when v is 255,
+    // we should treat the following 4-bytes as a 16.16 fixed-point number
+    // rather than 32bit signed int.
+    if (!char_string->Skip(4)) {
+      return OTS_FAILURE();
+    }
+    *out_number = dummy_result;
+  } else {
+    return OTS_FAILURE();
+  }
+
+  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(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,
+                                    bool *in_out_found_width,
+                                    size_t *in_out_num_stems) {
+  const size_t stack_size = argument_stack->size();
+
+  switch (op) {
+  case ots::kCallSubr:
+  case ots::kCallGSubr: {
+    const ots::CFFIndex& subrs_index =
+        (op == ots::kCallSubr ? local_subrs_index : global_subrs_index);
+
+    if (stack_size < 1) {
+      return OTS_FAILURE();
+    }
+    int32_t subr_number = argument_stack->top();
+    argument_stack->pop();
+    if (subr_number == dummy_result) {
+      // For safety, we allow subr calls only with immediate subr numbers for
+      // now. For example, we allow "123 callgsubr", but does not allow "100 12
+      // add callgsubr". Please note that arithmetic and conditional operators
+      // always push the |dummy_result| in this implementation.
+      return OTS_FAILURE();
+    }
+
+    // See Adobe Technical Note #5176 (CFF), "16. Local/GlobalSubrs INDEXes."
+    int32_t bias = 32768;
+    if (subrs_index.count < 1240) {
+      bias = 107;
+    } else if (subrs_index.count < 33900) {
+      bias = 1131;
+    }
+    subr_number += bias;
+
+    // Sanity checks of |subr_number|.
+    if (subr_number < 0) {
+      return OTS_FAILURE();
+    }
+    if (subr_number >= kMaxSubrsCount) {
+      return OTS_FAILURE();
+    }
+    if (subrs_index.offsets.size() <= static_cast<size_t>(subr_number + 1)) {
+      return OTS_FAILURE();  // The number is out-of-bounds.
+    }
+
+    // Prepare ots::Buffer where we're going to jump.
+    const size_t length =
+      subrs_index.offsets[subr_number + 1] - subrs_index.offsets[subr_number];
+    if (length > kMaxCharStringLength) {
+      return OTS_FAILURE();
+    }
+    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(call_depth + 1,
+                                  global_subrs_index,
+                                  local_subrs_index,
+                                  cff_table,
+                                  &char_string_to_jump,
+                                  argument_stack,
+                                  out_found_endchar,
+                                  in_out_found_width,
+                                  in_out_num_stems);
+  }
+
+  case ots::kReturn:
+    return true;
+
+  case ots::kEndChar:
+    *out_found_endchar = true;
+    *in_out_found_width = true;  // just in case.
+    return true;
+
+  case ots::kHStem:
+  case ots::kVStem:
+  case ots::kHStemHm:
+  case ots::kVStemHm: {
+    bool successful = false;
+    if (stack_size < 2) {
+      return OTS_FAILURE();
+    }
+    if ((stack_size % 2) == 0) {
+      successful = true;
+    } else if ((!(*in_out_found_width)) && (((stack_size - 1) % 2) == 0)) {
+      // The -1 is for "width" argument. For details, see Adobe Technical Note
+      // #5177, page 16, note 4.
+      successful = true;
+    }
+    (*in_out_num_stems) += (stack_size / 2);
+    if ((*in_out_num_stems) > kMaxNumberOfStemHints) {
+      return OTS_FAILURE();
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    *in_out_found_width = true;  // always set true since "w" might be 0 byte.
+    return successful ? true : OTS_FAILURE();
+  }
+
+  case ots::kRMoveTo: {
+    bool successful = false;
+    if (stack_size == 2) {
+      successful = true;
+    } else if ((!(*in_out_found_width)) && (stack_size - 1 == 2)) {
+      successful = true;
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    *in_out_found_width = true;
+    return successful ? true : OTS_FAILURE();
+  }
+
+  case ots::kVMoveTo:
+  case ots::kHMoveTo: {
+    bool successful = false;
+    if (stack_size == 1) {
+      successful = true;
+    } else if ((!(*in_out_found_width)) && (stack_size - 1 == 1)) {
+      successful = true;
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    *in_out_found_width = true;
+    return successful ? true : OTS_FAILURE();
+  }
+
+  case ots::kHintMask:
+  case ots::kCntrMask: {
+    bool successful = false;
+    if (stack_size == 0) {
+      successful = true;
+    } else if ((!(*in_out_found_width)) && (stack_size == 1)) {
+      // A number for "width" is found.
+      successful = true;
+    } else if ((!(*in_out_found_width)) ||  // in this case, any sizes are ok.
+               ((stack_size % 2) == 0)) {
+      // The numbers are vstem definition.
+      // See Adobe Technical Note #5177, page 24, hintmask.
+      (*in_out_num_stems) += (stack_size / 2);
+      if ((*in_out_num_stems) > kMaxNumberOfStemHints) {
+        return OTS_FAILURE();
+      }
+      successful = true;
+    }
+    if (!successful) {
+       return OTS_FAILURE();
+    }
+
+    if ((*in_out_num_stems) == 0) {
+      return OTS_FAILURE();
+    }
+    const size_t mask_bytes = (*in_out_num_stems + 7) / 8;
+    if (!char_string->Skip(mask_bytes)) {
+      return OTS_FAILURE();
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    *in_out_found_width = true;
+    return true;
+  }
+
+  case ots::kRLineTo:
+    if (!(*in_out_found_width)) {
+      // The first stack-clearing operator should be one of hstem, hstemhm,
+      // vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto, rmoveto, or
+      // endchar. For details, see Adobe Technical Note #5177, page 16, note 4.
+      return OTS_FAILURE();
+    }
+    if (stack_size < 2) {
+      return OTS_FAILURE();
+    }
+    if ((stack_size % 2) != 0) {
+      return OTS_FAILURE();
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    return true;
+
+  case ots::kHLineTo:
+  case ots::kVLineTo:
+    if (!(*in_out_found_width)) {
+      return OTS_FAILURE();
+    }
+    if (stack_size < 1) {
+      return OTS_FAILURE();
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    return true;
+
+  case ots::kRRCurveTo:
+    if (!(*in_out_found_width)) {
+      return OTS_FAILURE();
+    }
+    if (stack_size < 6) {
+      return OTS_FAILURE();
+    }
+    if ((stack_size % 6) != 0) {
+      return OTS_FAILURE();
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    return true;
+
+  case ots::kRCurveLine:
+    if (!(*in_out_found_width)) {
+      return OTS_FAILURE();
+    }
+    if (stack_size < 8) {
+      return OTS_FAILURE();
+    }
+    if (((stack_size - 2) % 6) != 0) {
+      return OTS_FAILURE();
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    return true;
+
+  case ots::kRLineCurve:
+    if (!(*in_out_found_width)) {
+      return OTS_FAILURE();
+    }
+    if (stack_size < 8) {
+      return OTS_FAILURE();
+    }
+    if (((stack_size - 6) % 2) != 0) {
+      return OTS_FAILURE();
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    return true;
+
+  case ots::kVVCurveTo:
+    if (!(*in_out_found_width)) {
+      return OTS_FAILURE();
+    }
+    if (stack_size < 4) {
+      return OTS_FAILURE();
+    }
+    if (((stack_size % 4) != 0) &&
+        (((stack_size - 1) % 4) != 0)) {
+      return OTS_FAILURE();
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    return true;
+
+  case ots::kHHCurveTo: {
+    bool successful = false;
+    if (!(*in_out_found_width)) {
+      return OTS_FAILURE();
+    }
+    if (stack_size < 4) {
+      return OTS_FAILURE();
+    }
+    if ((stack_size % 4) == 0) {
+      // {dxa dxb dyb dxc}+
+      successful = true;
+    } else if (((stack_size - 1) % 4) == 0) {
+      // dy1? {dxa dxb dyb dxc}+
+      successful = true;
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    return successful ? true : OTS_FAILURE();
+  }
+
+  case ots::kVHCurveTo:
+  case ots::kHVCurveTo: {
+    bool successful = false;
+    if (!(*in_out_found_width)) {
+      return OTS_FAILURE();
+    }
+    if (stack_size < 4) {
+      return OTS_FAILURE();
+    }
+    if (((stack_size - 4) % 8) == 0) {
+      // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}*
+      successful = true;
+    } else if ((stack_size >= 5) &&
+               ((stack_size - 5) % 8) == 0) {
+      // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf
+      successful = true;
+    } else if ((stack_size >= 8) &&
+               ((stack_size - 8) % 8) == 0) {
+      // {dxa dxb dyb dyc dyd dxe dye dxf}+
+      successful = true;
+    } else if ((stack_size >= 9) &&
+               ((stack_size - 9) % 8) == 0) {
+      // {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
+      successful = true;
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    return successful ? true : OTS_FAILURE();
+  }
+
+  case ots::kAnd:
+  case ots::kOr:
+  case ots::kEq:
+  case ots::kAdd:
+  case ots::kSub:
+    if (stack_size < 2) {
+      return OTS_FAILURE();
+    }
+    argument_stack->pop();
+    argument_stack->pop();
+    argument_stack->push(dummy_result);
+    // TODO(yusukes): Implement this. We should push a real value for all
+    // arithmetic and conditional operations.
+    return true;
+
+  case ots::kNot:
+  case ots::kAbs:
+  case ots::kNeg:
+    if (stack_size < 1) {
+      return OTS_FAILURE();
+    }
+    argument_stack->pop();
+    argument_stack->push(dummy_result);
+    // TODO(yusukes): Implement this. We should push a real value for all
+    // arithmetic and conditional operations.
+    return true;
+
+  case ots::kDiv:
+    // TODO(yusukes): Should detect div-by-zero errors.
+    if (stack_size < 2) {
+      return OTS_FAILURE();
+    }
+    argument_stack->pop();
+    argument_stack->pop();
+    argument_stack->push(dummy_result);
+    // TODO(yusukes): Implement this. We should push a real value for all
+    // arithmetic and conditional operations.
+    return true;
+
+  case ots::kDrop:
+    if (stack_size < 1) {
+      return OTS_FAILURE();
+    }
+    argument_stack->pop();
+    return true;
+
+  case ots::kPut:
+  case ots::kGet:
+  case ots::kIndex:
+    // For now, just call OTS_FAILURE since there is no way to check whether the
+    // index argument, |i|, is out-of-bounds or not. Fortunately, no OpenType
+    // fonts I have (except malicious ones!) use the operators.
+    // TODO(yusukes): Implement them in a secure way.
+    return OTS_FAILURE();
+
+  case ots::kRoll:
+    // Likewise, just call OTS_FAILURE for kRoll since there is no way to check
+    // whether |N| is smaller than the current stack depth or not.
+    // TODO(yusukes): Implement them in a secure way.
+    return OTS_FAILURE();
+
+  case ots::kRandom:
+    // For now, we don't handle the 'random' operator since the operator makes
+    // it hard to analyze hinting code statically.
+    return OTS_FAILURE();
+
+  case ots::kIfElse:
+    if (stack_size < 4) {
+      return OTS_FAILURE();
+    }
+    argument_stack->pop();
+    argument_stack->pop();
+    argument_stack->pop();
+    argument_stack->pop();
+    argument_stack->push(dummy_result);
+    // TODO(yusukes): Implement this. We should push a real value for all
+    // arithmetic and conditional operations.
+    return true;
+
+  case ots::kMul:
+    // TODO(yusukes): Should detect overflows.
+    if (stack_size < 2) {
+      return OTS_FAILURE();
+    }
+    argument_stack->pop();
+    argument_stack->pop();
+    argument_stack->push(dummy_result);
+    // TODO(yusukes): Implement this. We should push a real value for all
+    // arithmetic and conditional operations.
+    return true;
+
+  case ots::kSqrt:
+    // TODO(yusukes): Should check if the argument is negative.
+    if (stack_size < 1) {
+      return OTS_FAILURE();
+    }
+    argument_stack->pop();
+    argument_stack->push(dummy_result);
+    // TODO(yusukes): Implement this. We should push a real value for all
+    // arithmetic and conditional operations.
+    return true;
+
+  case ots::kDup:
+    if (stack_size < 1) {
+      return OTS_FAILURE();
+    }
+    argument_stack->pop();
+    argument_stack->push(dummy_result);
+    argument_stack->push(dummy_result);
+    if (argument_stack->size() > kMaxArgumentStack) {
+      return OTS_FAILURE();
+    }
+    // TODO(yusukes): Implement this. We should push a real value for all
+    // arithmetic and conditional operations.
+    return true;
+
+  case ots::kExch:
+    if (stack_size < 2) {
+      return OTS_FAILURE();
+    }
+    argument_stack->pop();
+    argument_stack->pop();
+    argument_stack->push(dummy_result);
+    argument_stack->push(dummy_result);
+    // TODO(yusukes): Implement this. We should push a real value for all
+    // arithmetic and conditional operations.
+    return true;
+
+  case ots::kHFlex:
+    if (!(*in_out_found_width)) {
+      return OTS_FAILURE();
+    }
+    if (stack_size != 7) {
+      return OTS_FAILURE();
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    return true;
+
+  case ots::kFlex:
+    if (!(*in_out_found_width)) {
+      return OTS_FAILURE();
+    }
+    if (stack_size != 13) {
+      return OTS_FAILURE();
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    return true;
+
+  case ots::kHFlex1:
+    if (!(*in_out_found_width)) {
+      return OTS_FAILURE();
+    }
+    if (stack_size != 9) {
+      return OTS_FAILURE();
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    return true;
+
+  case ots::kFlex1:
+    if (!(*in_out_found_width)) {
+      return OTS_FAILURE();
+    }
+    if (stack_size != 11) {
+      return OTS_FAILURE();
+    }
+    while (!argument_stack->empty())
+      argument_stack->pop();
+    return true;
+  }
+
+  OTS_WARNING("Undefined operator: %d (0x%x)", op, op);
+  return OTS_FAILURE();
+}
+
+// Executes |char_string| and updates |argument_stack|.
+//
+// call_depth: The current call depth. Initial value is zero.
+// global_subrs_index: Global subroutines.
+// local_subrs_index: Local subroutines for the current glyph.
+// 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(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,
+                            size_t *in_out_num_stems) {
+  if (call_depth > kMaxSubrNesting) {
+    return OTS_FAILURE();
+  }
+  *out_found_endchar = false;
+
+  const size_t length = char_string->length();
+  while (char_string->offset() < length) {
+    int32_t operator_or_operand = 0;
+    bool is_operator = false;
+    if (!ReadNextNumberFromType2CharString(char_string,
+                                           &operator_or_operand,
+                                           &is_operator)) {
+      return OTS_FAILURE();
+    }
+
+    /*
+      You can dump all operators and operands (except mask bytes for hintmask
+      and cntrmask) by the following code:
+
+      if (!is_operator) {
+        std::fprintf(stderr, "#%d# ", operator_or_operand);
+      } else {
+        std::fprintf(stderr, "#%s#\n",
+           Type2CharStringOperatorToString(
+               Type2CharStringOperator(operator_or_operand)),
+           operator_or_operand);
+      }
+    */
+
+    if (!is_operator) {
+      argument_stack->push(operator_or_operand);
+      if (argument_stack->size() > kMaxArgumentStack) {
+        return OTS_FAILURE();
+      }
+      continue;
+    }
+
+    // An operator is found. Execute it.
+    if (!ExecuteType2CharStringOperator(operator_or_operand,
+                                        call_depth,
+                                        global_subrs_index,
+                                        local_subrs_index,
+                                        cff_table,
+                                        char_string,
+                                        argument_stack,
+                                        out_found_endchar,
+                                        in_out_found_width,
+                                        in_out_num_stems)) {
+      return OTS_FAILURE();
+    }
+    if (*out_found_endchar) {
+      return true;
+    }
+    if (operator_or_operand == ots::kReturn) {
+      return true;
+    }
+  }
+
+  // No endchar operator is found.
+  return OTS_FAILURE();
+}
+
+// Selects a set of subroutings for |glyph_index| from |cff| and sets it on
+// |out_local_subrs_to_use|. Returns true on success.
+bool SelectLocalSubr(const std::map<uint16_t, uint8_t> &fd_select,
+                     const std::vector<ots::CFFIndex *> &local_subrs_per_font,
+                     const ots::CFFIndex *local_subrs,
+                     uint16_t glyph_index,  // 0-origin
+                     const ots::CFFIndex **out_local_subrs_to_use) {
+  *out_local_subrs_to_use = NULL;
+
+  // First, find local subrs from |local_subrs_per_font|.
+  if ((fd_select.size() > 0) &&
+      (!local_subrs_per_font.empty())) {
+    // Look up FDArray index for the glyph.
+    std::map<uint16_t, uint8_t>::const_iterator iter =
+        fd_select.find(glyph_index);
+    if (iter == fd_select.end()) {
+      return OTS_FAILURE();
+    }
+    const uint8_t fd_index = iter->second;
+    if (fd_index >= local_subrs_per_font.size()) {
+      return OTS_FAILURE();
+    }
+    *out_local_subrs_to_use = local_subrs_per_font.at(fd_index);
+  } else if (local_subrs) {
+    // Second, try to use |local_subrs|. Most Latin fonts don't have FDSelect
+    // entries. If The font has a local subrs index associated with the Top
+    // DICT (not FDArrays), use it.
+    *out_local_subrs_to_use = local_subrs;
+  } else {
+    // Just return NULL.
+    *out_local_subrs_to_use = NULL;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+namespace ots {
+
+bool ValidateType2CharStringIndex(
+    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) {
+    return OTS_FAILURE();  // no charstring.
+  }
+
+  // For each glyph, validate the corresponding charstring.
+  for (unsigned i = 1; i < char_strings_index.offsets.size(); ++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 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();
+    }
+    // If |local_subrs_to_use| is still NULL, use an empty one.
+    CFFIndex default_empty_subrs;
+    if (!local_subrs_to_use){
+      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(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();
+    }
+  }
+  return true;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/cff_type2_charstring.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_CFF_TYPE2_CHARSTRING_H_
+#define OTS_CFF_TYPE2_CHARSTRING_H_
+
+#include "cff.h"
+#include "ots.h"
+
+#include <map>
+#include <vector>
+
+namespace ots {
+
+// Validates all charstrings in |char_strings_index|. Charstring is a small
+// language for font hinting defined in Adobe Technical Note #5177.
+// http://www.adobe.com/devnet/font/pdfs/5177.Type2.pdf
+//
+// The validation will fail if one of the following conditions is met:
+//  1. The code uses more than 48 values of argument stack.
+//  2. The code uses deeply nested subroutine calls (more than 10 levels.)
+//  3. The code passes invalid number of operands to an operator.
+//  4. The code calls an undefined global or local subroutine.
+//  5. The code uses one of the following operators that are unlikely used in
+//     an ordinary fonts, and could be dangerous: random, put, get, index, roll.
+//
+// Arguments:
+//  global_subrs_index: Global subroutines which could be called by a charstring
+//                      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(
+    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.
+enum Type2CharStringOperator {
+  kHStem = 1,
+  kVStem = 3,
+  kVMoveTo = 4,
+  kRLineTo = 5,
+  kHLineTo = 6,
+  kVLineTo = 7,
+  kRRCurveTo = 8,
+  kCallSubr = 10,
+  kReturn = 11,
+  kEndChar = 14,
+  kHStemHm = 18,
+  kHintMask = 19,
+  kCntrMask = 20,
+  kRMoveTo = 21,
+  kHMoveTo = 22,
+  kVStemHm = 23,
+  kRCurveLine = 24,
+  kRLineCurve = 25,
+  kVVCurveTo = 26,
+  kHHCurveTo = 27,
+  kCallGSubr = 29,
+  kVHCurveTo = 30,
+  kHVCurveTo = 31,
+  kAnd = (12 << 8) + 3,
+  kOr = (12 << 8) + 4,
+  kNot = (12 << 8) + 5,
+  kAbs = (12 << 8) + 9,
+  kAdd = (12 << 8) + 10,
+  kSub = (12 << 8) + 11,
+  kDiv = (12 << 8) + 12,
+  kNeg = (12 << 8) + 14,
+  kEq = (12 << 8) + 15,
+  kDrop = (12 << 8) + 18,
+  kPut = (12 << 8) + 20,
+  kGet = (12 << 8) + 21,
+  kIfElse = (12 << 8) + 22,
+  kRandom = (12 << 8) + 23,
+  kMul = (12 << 8) + 24,
+  kSqrt = (12 << 8) + 26,
+  kDup = (12 << 8) + 27,
+  kExch = (12 << 8) + 28,
+  kIndex = (12 << 8) + 29,
+  kRoll = (12 << 8) + 30,
+  kHFlex = (12 << 8) + 34,
+  kFlex = (12 << 8) + 35,
+  kHFlex1 = (12 << 8) + 36,
+  kFlex1 = (12 << 8) + 37,
+  // Operators that are obsoleted or undocumented, such as 'blend', will be
+  // rejected.
+};
+
+}  // namespace ots
+
+#endif  // OTS_CFF_TYPE2_CHARSTRING_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/cmap.cc
@@ -0,0 +1,832 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cmap.h"
+
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "maxp.h"
+#include "os2.h"
+
+// cmap - Character To Glyph Index Mapping Table
+// http://www.microsoft.com/opentype/otspec/cmap.htm
+
+namespace {
+
+struct CMAPSubtableHeader {
+  uint16_t platform;
+  uint16_t encoding;
+  uint32_t offset;
+  uint16_t format;
+  uint32_t length;
+};
+
+struct Subtable314Range {
+  uint16_t start_range;
+  uint16_t end_range;
+  int16_t id_delta;
+  uint16_t id_range_offset;
+  uint32_t id_range_offset_offset;
+};
+
+// The maximum number of groups in format 12 or 13 subtables.
+// Note: 0xFFFF is the maximum number of glyphs in a single font file.
+const unsigned kMaxCMAPGroups = 0xFFFF;
+
+// Glyph array size for the Mac Roman (format 0) table.
+const size_t kFormat0ArraySize = 256;
+
+// The upper limit of the Unicode code point.
+const uint32_t kUnicodeUpperLimit = 0x10FFFF;
+
+// Parses either 3.0.4 or 3.1.4 tables.
+bool Parse3x4(ots::OpenTypeFile *file, int encoding,
+              const uint8_t *data, size_t length, uint16_t num_glyphs) {
+  ots::Buffer subtable(data, length);
+
+  // 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 (!file->os2) {
+    return OTS_FAILURE();
+  }
+
+  if (!subtable.Skip(4)) {
+    return OTS_FAILURE();
+  }
+  uint16_t language = 0;
+  if (!subtable.ReadU16(&language)) {
+    return OTS_FAILURE();
+  }
+  if (language) {
+    // Platform ID 3 (windows) subtables should have language '0'.
+    return OTS_FAILURE();
+  }
+
+  uint16_t segcountx2, search_range, entry_selector, range_shift;
+  segcountx2 = search_range = entry_selector = range_shift = 0;
+  if (!subtable.ReadU16(&segcountx2) ||
+      !subtable.ReadU16(&search_range) ||
+      !subtable.ReadU16(&entry_selector) ||
+      !subtable.ReadU16(&range_shift)) {
+    return OTS_FAILURE();
+  }
+
+  if (segcountx2 & 1 || search_range & 1) {
+    return OTS_FAILURE();
+  }
+  const uint16_t segcount = segcountx2 >> 1;
+  // There must be at least one segment according the spec.
+  if (segcount < 1) {
+    return OTS_FAILURE();
+  }
+
+  // log2segcount is the maximal x s.t. 2^x < segcount
+  unsigned log2segcount = 0;
+  while (1u << (log2segcount + 1) <= segcount) {
+    log2segcount++;
+  }
+
+  const uint16_t expected_search_range = 2 * 1u << log2segcount;
+  if (expected_search_range != search_range) {
+    return OTS_FAILURE();
+  }
+
+  if (entry_selector != log2segcount) {
+    return OTS_FAILURE();
+  }
+
+  const uint16_t expected_range_shift = segcountx2 - search_range;
+  if (range_shift != expected_range_shift) {
+    return OTS_FAILURE();
+  }
+
+  std::vector<Subtable314Range> ranges(segcount);
+
+  for (unsigned i = 0; i < segcount; ++i) {
+    if (!subtable.ReadU16(&ranges[i].end_range)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  uint16_t padding;
+  if (!subtable.ReadU16(&padding)) {
+    return OTS_FAILURE();
+  }
+  if (padding) {
+    return OTS_FAILURE();
+  }
+
+  for (unsigned i = 0; i < segcount; ++i) {
+    if (!subtable.ReadU16(&ranges[i].start_range)) {
+      return OTS_FAILURE();
+    }
+  }
+  for (unsigned i = 0; i < segcount; ++i) {
+    if (!subtable.ReadS16(&ranges[i].id_delta)) {
+      return OTS_FAILURE();
+    }
+  }
+  for (unsigned i = 0; i < segcount; ++i) {
+    ranges[i].id_range_offset_offset = subtable.offset();
+    if (!subtable.ReadU16(&ranges[i].id_range_offset)) {
+      return OTS_FAILURE();
+    }
+
+    if (ranges[i].id_range_offset & 1) {
+      // Some font generators seem to put 65535 on id_range_offset
+      // for 0xFFFF-0xFFFF range.
+      // (e.g., many fonts in http://www.princexml.com/fonts/)
+      if (i == segcount - 1u) {
+        OTS_WARNING("bad id_range_offset");
+        ranges[i].id_range_offset = 0;
+        // The id_range_offset value in the transcoded font will not change
+        // since this table is not actually "transcoded" yet.
+      } else {
+        return OTS_FAILURE();
+      }
+    }
+  }
+
+  // ranges must be ascending order, based on the end_code. Ranges may not
+  // overlap.
+  for (unsigned i = 1; i < segcount; ++i) {
+    if ((i == segcount - 1u) &&
+        (ranges[i - 1].start_range == 0xffff) &&
+        (ranges[i - 1].end_range == 0xffff) &&
+        (ranges[i].start_range == 0xffff) &&
+        (ranges[i].end_range == 0xffff)) {
+      // Some fonts (e.g., Germania.ttf) have multiple 0xffff terminators.
+      // We'll accept them as an exception.
+      OTS_WARNING("multiple 0xffff terminators found");
+      continue;
+    }
+
+    // Note: some Linux fonts (e.g., LucidaSansOblique.ttf, bsmi00lp.ttf) have
+    // unsorted table...
+    if (ranges[i].end_range <= ranges[i - 1].end_range) {
+      return OTS_FAILURE();
+    }
+    if (ranges[i].start_range <= ranges[i - 1].end_range) {
+      return OTS_FAILURE();
+    }
+
+    // On many fonts, the value of {first, last}_char_index are incorrect.
+    // Fix them.
+    if (file->os2->first_char_index != 0xFFFF &&
+        ranges[i].start_range != 0xFFFF &&
+        file->os2->first_char_index > ranges[i].start_range) {
+      file->os2->first_char_index = ranges[i].start_range;
+    }
+    if (file->os2->last_char_index != 0xFFFF &&
+        ranges[i].end_range != 0xFFFF &&
+        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].end_range != 0xffff) {
+    return OTS_FAILURE();
+  }
+
+  // A format 4 CMAP subtable is complex. To be safe we simulate a lookup of
+  // each code-point defined in the table and make sure that they are all valid
+  // glyphs and that we don't access anything out-of-bounds.
+  for (unsigned i = 1; i < segcount; ++i) {
+    for (unsigned cp = ranges[i].start_range; cp <= ranges[i].end_range; ++cp) {
+      const uint16_t code_point = cp;
+      if (ranges[i].id_range_offset == 0) {
+        // this is explictly allowed to overflow in the spec
+        const uint16_t glyph = code_point + ranges[i].id_delta;
+        if (glyph >= num_glyphs) {
+          return OTS_FAILURE();
+        }
+      } else {
+        const uint16_t range_delta = code_point - ranges[i].start_range;
+        // this might seem odd, but it's true. The offset is relative to the
+        // location of the offset value itself.
+        const uint32_t glyph_id_offset = ranges[i].id_range_offset_offset +
+                                         ranges[i].id_range_offset +
+                                         range_delta * 2;
+        // We need to be able to access a 16-bit value from this offset
+        if (glyph_id_offset + 1 >= length) {
+          return OTS_FAILURE();
+        }
+        uint16_t glyph;
+        memcpy(&glyph, data + glyph_id_offset, 2);
+        glyph = ntohs(glyph);
+        if (glyph >= num_glyphs) {
+          return OTS_FAILURE();
+        }
+      }
+    }
+  }
+
+  // We accept the table.
+  // TODO(yusukes): transcode the subtable.
+  if (encoding == 0) {
+    file->cmap->subtable_3_0_4_data = data;
+    file->cmap->subtable_3_0_4_length = length;
+  } else if (encoding == 1) {
+    file->cmap->subtable_3_1_4_data = data;
+    file->cmap->subtable_3_1_4_length = length;
+  } else {
+    return OTS_FAILURE();
+  }
+
+  return true;
+}
+
+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();
+  }
+  uint32_t language = 0;
+  if (!subtable.ReadU32(&language)) {
+    return OTS_FAILURE();
+  }
+  if (language) {
+    return OTS_FAILURE();
+  }
+
+  uint32_t num_groups = 0;
+  if (!subtable.ReadU32(&num_groups)) {
+    return OTS_FAILURE();
+  }
+  if (num_groups == 0 || num_groups > kMaxCMAPGroups) {
+    return OTS_FAILURE();
+  }
+
+  std::vector<ots::OpenTypeCMAPSubtableRange> &groups
+      = 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();
+    }
+
+    if (groups[i].start_range > kUnicodeUpperLimit ||
+        groups[i].end_range > kUnicodeUpperLimit ||
+        groups[i].start_glyph_id > 0xFFFF) {
+      return OTS_FAILURE();
+    }
+
+    // [0xD800, 0xDFFF] are surrogate code points.
+    if (groups[i].start_range >= 0xD800 &&
+        groups[i].start_range <= 0xDFFF) {
+      return OTS_FAILURE();
+    }
+    if (groups[i].end_range >= 0xD800 &&
+        groups[i].end_range <= 0xDFFF) {
+      return OTS_FAILURE();
+    }
+    if (groups[i].start_range < 0xD800 &&
+        groups[i].end_range > 0xDFFF) {
+      return OTS_FAILURE();
+    }
+
+    // We assert that the glyph value is within range. Because of the range
+    // limits, above, we don't need to worry about overflow.
+    if (groups[i].end_range < groups[i].start_range) {
+      return OTS_FAILURE();
+    }
+    if ((groups[i].end_range - groups[i].start_range) +
+        groups[i].start_glyph_id > num_glyphs) {
+      return OTS_FAILURE();
+    }
+  }
+
+  // the groups must be sorted by start code and may not overlap
+  for (unsigned i = 1; i < num_groups; ++i) {
+    if (groups[i].start_range <= groups[i - 1].start_range) {
+      return OTS_FAILURE();
+    }
+    if (groups[i].start_range <= groups[i - 1].end_range) {
+      return OTS_FAILURE();
+    }
+  }
+
+  return true;
+}
+
+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();
+  }
+  uint16_t language = 0;
+  if (!subtable.ReadU16(&language)) {
+    return OTS_FAILURE();
+  }
+  if (language) {
+    return OTS_FAILURE();
+  }
+
+  uint32_t num_groups = 0;
+  if (!subtable.ReadU32(&num_groups)) {
+    return OTS_FAILURE();
+  }
+
+  // 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();
+  }
+
+  std::vector<ots::OpenTypeCMAPSubtableRange> &groups
+      = 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();
+    }
+
+    // We conservatively limit all of the values to protect some parsers from
+    // overflows
+    if (groups[i].start_range > kUnicodeUpperLimit ||
+        groups[i].end_range > kUnicodeUpperLimit ||
+        groups[i].start_glyph_id > 0xFFFF) {
+      return OTS_FAILURE();
+    }
+
+    if (groups[i].start_glyph_id >= num_glyphs) {
+      return OTS_FAILURE();
+    }
+  }
+
+  // the groups must be sorted by start code and may not overlap
+  for (unsigned i = 1; i < num_groups; ++i) {
+    if (groups[i].start_range <= groups[i - 1].start_range) {
+      return OTS_FAILURE();
+    }
+    if (groups[i].start_range <= groups[i - 1].end_range) {
+      return OTS_FAILURE();
+    }
+  }
+
+  return true;
+}
+
+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();
+  }
+  uint16_t language = 0;
+  if (!subtable.ReadU16(&language)) {
+    return OTS_FAILURE();
+  }
+  if (language) {
+    // simsun.ttf has non-zero language id.
+    OTS_WARNING("language id should be zero: %u", language);
+  }
+
+  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();
+    }
+    file->cmap->subtable_1_0_0.push_back(glyph_id);
+  }
+
+  return true;
+}
+
+}  // namespace
+
+namespace ots {
+
+bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+  file->cmap = new OpenTypeCMAP;
+
+  uint16_t version = 0;
+  uint16_t num_tables = 0;
+  if (!table.ReadU16(&version) ||
+      !table.ReadU16(&num_tables)) {
+    return OTS_FAILURE();
+  }
+
+  if (version != 0) {
+    return OTS_FAILURE();
+  }
+  if (!num_tables) {
+    return OTS_FAILURE();
+  }
+
+  std::vector<CMAPSubtableHeader> subtable_headers;
+
+  // read the subtable headers
+  subtable_headers.reserve(num_tables);
+  for (unsigned i = 0; i < num_tables; ++i) {
+    CMAPSubtableHeader subt;
+
+    if (!table.ReadU16(&subt.platform) ||
+        !table.ReadU16(&subt.encoding) ||
+        !table.ReadU32(&subt.offset)) {
+      return OTS_FAILURE();
+    }
+
+    subtable_headers.push_back(subt);
+  }
+
+  const size_t data_offset = table.offset();
+
+  // make sure that all the offsets are valid.
+  uint32_t last_id = 0;
+  for (unsigned i = 0; i < num_tables; ++i) {
+    if (subtable_headers[i].offset > 1024 * 1024 * 1024) {
+      return OTS_FAILURE();
+    }
+    if (subtable_headers[i].offset < data_offset ||
+        subtable_headers[i].offset >= length) {
+      return OTS_FAILURE();
+    }
+
+    // check if the table is sorted first by platform ID, then by encoding ID.
+    uint32_t current_id
+        = (subtable_headers[i].platform << 16) + subtable_headers[i].encoding;
+    if ((i != 0) && (last_id >= current_id)) {
+      return OTS_FAILURE();
+    }
+    last_id = current_id;
+  }
+
+  // the format of the table is the first couple of bytes in the table. The
+  // length of the table is stored in a format-specific way.
+  for (unsigned i = 0; i < num_tables; ++i) {
+    table.set_offset(subtable_headers[i].offset);
+    if (!table.ReadU16(&subtable_headers[i].format)) {
+      return OTS_FAILURE();
+    }
+
+    uint16_t len = 0;
+    switch (subtable_headers[i].format) {
+      case 0:
+      case 4:
+        if (!table.ReadU16(&len)) {
+          return OTS_FAILURE();
+        }
+        subtable_headers[i].length = len;
+        break;
+      case 12:
+      case 13:
+        if (!table.Skip(2)) {
+          return OTS_FAILURE();
+        }
+        if (!table.ReadU32(&subtable_headers[i].length)) {
+          return OTS_FAILURE();
+        }
+        break;
+      default:
+        subtable_headers[i].length = 0;
+        break;
+    }
+  }
+
+  // Now, verify that all the lengths are sane
+  for (unsigned i = 0; i < num_tables; ++i) {
+    if (!subtable_headers[i].length) continue;
+    if (subtable_headers[i].length > 1024 * 1024 * 1024) {
+      return OTS_FAILURE();
+    }
+    // We know that both the offset and length are < 1GB, so the following
+    // addition doesn't overflow
+    const uint32_t end_byte
+        = subtable_headers[i].offset + subtable_headers[i].length;
+    if (end_byte > length) {
+      return OTS_FAILURE();
+    }
+  }
+
+  // check that the cmap subtables are not overlapping.
+  std::set<std::pair<uint32_t, uint32_t> > uniq_checker;
+  std::vector<std::pair<uint32_t, uint8_t> > overlap_checker;
+  for (unsigned i = 0; i < num_tables; ++i) {
+    const uint32_t end_byte
+        = subtable_headers[i].offset + subtable_headers[i].length;
+
+    if (!uniq_checker.insert(std::make_pair(subtable_headers[i].offset,
+                                            end_byte)).second) {
+      // Sometimes Unicode table and MS table share exactly the same data.
+      // We'll allow this.
+      continue;
+    }
+    overlap_checker.push_back(
+        std::make_pair(subtable_headers[i].offset, 1 /* start */));
+    overlap_checker.push_back(
+        std::make_pair(end_byte, 0 /* end */));
+  }
+  std::sort(overlap_checker.begin(), overlap_checker.end());
+  int overlap_count = 0;
+  for (unsigned i = 0; i < overlap_checker.size(); ++i) {
+    overlap_count += (overlap_checker[i].second ? 1 : -1);
+    if (overlap_count > 1) {
+      return OTS_FAILURE();
+    }
+  }
+
+  // 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 (!file->maxp) {
+    return OTS_FAILURE();
+  }
+  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             3            4       (Unicode BMP)
+  //   0             3            12      (Unicode UCS-4)
+  //   1             0            0       (Mac Roman)
+  //   3             0            4       (MS Symbol)
+  //   3             1            4       (MS Unicode BMP)
+  //   3             10           12      (MS Unicode UCS-4)
+  //   3             10           13      (MS UCS-4 Fallback mapping)
+  //
+  // Note:
+  //  * 0-0-4 table is (usually) written as a 3-1-4 table. If 3-1-4 table
+  //    also exists, the 0-0-4 table is ignored.
+  //  * 0-3-4 table is written as a 3-1-4 table. If 3-1-4 table also exists,
+  //    the 0-3-4 table is ignored.
+  //  * 0-3-12 table is written as a 3-10-12 table. If 3-10-12 table also
+  //    exists, the 0-3-12 table is ignored.
+  //
+
+  for (unsigned i = 0; i < num_tables; ++i) {
+    if (subtable_headers[i].platform == 0) {
+      // Unicode platform
+
+      if ((subtable_headers[i].encoding == 0) &&
+          (subtable_headers[i].format == 4)) {
+        // parse and output the 0-0-4 table 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 (!Parse3x4(file, 1, data + subtable_headers[i].offset,
+                      subtable_headers[i].length, num_glyphs)) {
+          return OTS_FAILURE();
+        }
+      } else if ((subtable_headers[i].encoding == 3) &&
+                 (subtable_headers[i].format == 4)) {
+        // parse and output the 0-3-4 table as 3-1-4 table.
+        if (!Parse3x4(file, 1, data + subtable_headers[i].offset,
+                      subtable_headers[i].length, num_glyphs)) {
+          return OTS_FAILURE();
+        }
+      } 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(file, data + subtable_headers[i].offset,
+                        subtable_headers[i].length, num_glyphs)) {
+          return OTS_FAILURE();
+        }
+      }
+
+    } 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(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 (!Parse3x4(file, 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) {
+            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) {
+            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(OpenTypeFile *file) {
+  return file->cmap;
+}
+
+bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
+  const bool have_100 = file->cmap->subtable_1_0_0.size();
+  const bool have_304 = file->cmap->subtable_3_0_4_data;
+  // 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) && file->cmap->subtable_3_1_4_data;
+  const bool have_31012 = file->cmap->subtable_3_10_12.size();
+  const bool have_31013 = file->cmap->subtable_3_10_13.size();
+  const unsigned num_subtables = static_cast<unsigned>(have_100) +
+                                 static_cast<unsigned>(have_304) +
+                                 static_cast<unsigned>(have_314) +
+                                 static_cast<unsigned>(have_31012) +
+                                 static_cast<unsigned>(have_31013);
+  const off_t table_start = out->Tell();
+
+  // Some fonts don't have 3-0-4 MS Symbol nor 3-1-4 Unicode BMP tables
+  // (e.g., old fonts for Mac). We don't support them.
+  if (!have_304 && !have_314) {
+    return OTS_FAILURE();
+  }
+
+  if (!out->WriteU16(0) ||
+      !out->WriteU16(num_subtables)) {
+    return OTS_FAILURE();
+  }
+
+  const off_t record_offset = out->Tell();
+  if (!out->Pad(num_subtables * 8)) {
+    return OTS_FAILURE();
+  }
+
+  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(&(file->cmap->subtable_1_0_0[0]), kFormat0ArraySize)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  const off_t offset_304 = out->Tell();
+  if (have_304) {
+    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(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
+        = 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();
+    }
+
+    for (unsigned i = 0; i < num_groups; ++i) {
+      if (!out->WriteU32(groups[i].start_range) ||
+          !out->WriteU32(groups[i].end_range) ||
+          !out->WriteU32(groups[i].start_glyph_id)) {
+        return OTS_FAILURE();
+      }
+    }
+  }
+
+  const off_t offset_31013 = out->Tell();
+  if (have_31013) {
+    std::vector<OpenTypeCMAPSubtableRange> &groups
+        = file->cmap->subtable_3_10_13;
+    const unsigned num_groups = groups.size();
+    if (!out->WriteU16(13) ||
+        !out->WriteU16(0) ||
+        !out->WriteU32(num_groups * 12 + 14) ||
+        !out->WriteU32(0) ||
+        !out->WriteU32(num_groups)) {
+      return OTS_FAILURE();
+    }
+
+    for (unsigned i = 0; i < num_groups; ++i) {
+      if (!out->WriteU32(groups[i].start_range) ||
+          !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_100) {
+    if (!out->WriteU16(1) ||
+        !out->WriteU16(0) ||
+        !out->WriteU32(offset_100 - table_start)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  if (have_304) {
+    if (!out->WriteU16(3) ||
+        !out->WriteU16(0) ||
+        !out->WriteU32(offset_304 - table_start)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  if (have_314) {
+    if (!out->WriteU16(3) ||
+        !out->WriteU16(1) ||
+        !out->WriteU32(offset_314 - table_start)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  if (have_31012) {
+    if (!out->WriteU16(3) ||
+        !out->WriteU16(10) ||
+        !out->WriteU32(offset_31012 - table_start)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  if (have_31013) {
+    if (!out->WriteU16(3) ||
+        !out->WriteU16(10) ||
+        !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_free(OpenTypeFile *file) {
+  delete file->cmap;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/cmap.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_CMAP_H_
+#define OTS_CMAP_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeCMAPSubtableRange {
+  uint32_t start_range;
+  uint32_t end_range;
+  uint32_t start_glyph_id;
+};
+
+struct OpenTypeCMAP {
+  OpenTypeCMAP()
+      : subtable_3_0_4_data(NULL),
+        subtable_3_0_4_length(0),
+        subtable_3_1_4_data(NULL),
+        subtable_3_1_4_length(0) {
+  }
+
+  // Platform 3, Encoding 0, Format 4, MS Symbol table.
+  const uint8_t *subtable_3_0_4_data;
+  size_t subtable_3_0_4_length;
+  // Platform 3, Encoding 1, Format 4, MS Unicode BMP table.
+  const uint8_t *subtable_3_1_4_data;
+  size_t subtable_3_1_4_length;
+
+  // Platform 3, Encoding 10, Format 12, MS Unicode UCS-4 table.
+  std::vector<OpenTypeCMAPSubtableRange> subtable_3_10_12;
+  // Platform 3, Encoding 10, Format 13, MS UCS-4 Fallback table.
+  std::vector<OpenTypeCMAPSubtableRange> subtable_3_10_13;
+  // Platform 1, Encoding 0, Format 0, Mac Roman table.
+  std::vector<uint8_t> subtable_1_0_0;
+};
+
+}  // namespace ots
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/cvt.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cvt.h"
+
+// cvt - Control Value Table
+// http://www.microsoft.com/opentype/otspec/cvt.htm
+
+namespace ots {
+
+bool ots_cvt_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+
+  OpenTypeCVT *cvt = new OpenTypeCVT;
+  file->cvt = cvt;
+
+  if (length >= 128 * 1024u) {
+    return OTS_FAILURE();  // almost all cvt tables are less than 4k bytes.
+  }
+
+  if (length % 2 != 0) {
+    return OTS_FAILURE();
+  }
+
+  if (!table.Skip(length)) {
+    return OTS_FAILURE();
+  }
+
+  cvt->data = data;
+  cvt->length = length;
+  return true;
+}
+
+bool ots_cvt_should_serialise(OpenTypeFile *file) {
+  if (!file->glyf) {
+    return false;  // this table is not for CFF fonts.
+  }
+  return g_transcode_hints && file->cvt;
+}
+
+bool ots_cvt_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeCVT *cvt = file->cvt;
+
+  if (!out->Write(cvt->data, cvt->length)) {
+    return OTS_FAILURE();
+  }
+
+  return true;
+}
+
+void ots_cvt_free(OpenTypeFile *file) {
+  delete file->cvt;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/cvt.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_CVT_H_
+#define OTS_CVT_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeCVT {
+  const uint8_t *data;
+  uint32_t length;
+};
+
+}  // namespace ots
+
+#endif  // OTS_CVT_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/fpgm.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "fpgm.h"
+
+// fpgm - Font Program
+// http://www.microsoft.com/opentype/otspec/fpgm.htm
+
+namespace ots {
+
+bool ots_fpgm_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+
+  OpenTypeFPGM *fpgm = new OpenTypeFPGM;
+  file->fpgm = fpgm;
+
+  if (length >= 128 * 1024u) {
+    return OTS_FAILURE();  // almost all fpgm tables are less than 5k bytes.
+  }
+
+  if (!table.Skip(length)) {
+    return OTS_FAILURE();
+  }
+
+  fpgm->data = data;
+  fpgm->length = length;
+  return true;
+}
+
+bool ots_fpgm_should_serialise(OpenTypeFile *file) {
+  if (!file->glyf) return false;  // this table is not for CFF fonts.
+  return g_transcode_hints && file->fpgm;
+}
+
+bool ots_fpgm_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeFPGM *fpgm = file->fpgm;
+
+  if (!out->Write(fpgm->data, fpgm->length)) {
+    return OTS_FAILURE();
+  }
+
+  return true;
+}
+
+void ots_fpgm_free(OpenTypeFile *file) {
+  delete file->fpgm;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/fpgm.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_FPGM_H_
+#define OTS_FPGM_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeFPGM {
+  const uint8_t *data;
+  uint32_t length;
+};
+
+}  // namespace ots
+
+#endif  // OTS_FPGM_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/gasp.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gasp.h"
+
+// gasp - Grid-fitting And Scan-conversion Procedure
+// http://www.microsoft.com/opentype/otspec/gasp.htm
+
+#define DROP_THIS_TABLE \
+  do { delete file->gasp; file->gasp = 0; } while (0)
+
+namespace ots {
+
+bool ots_gasp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+
+  OpenTypeGASP *gasp = new OpenTypeGASP;
+  file->gasp = gasp;
+
+  uint16_t num_ranges = 0;
+  if (!table.ReadU16(&gasp->version) ||
+      !table.ReadU16(&num_ranges)) {
+    return OTS_FAILURE();
+  }
+
+  if (gasp->version > 1) {
+    // Lots of Linux fonts have bad version numbers...
+    OTS_WARNING("bad version: %u", gasp->version);
+    DROP_THIS_TABLE;
+    return true;
+  }
+
+  if (num_ranges == 0) {
+    OTS_WARNING("num_ranges is zero");
+    DROP_THIS_TABLE;
+    return true;
+  }
+
+  gasp->gasp_ranges.reserve(num_ranges);
+  for (unsigned i = 0; i < num_ranges; ++i) {
+    uint16_t max_ppem = 0;
+    uint16_t behavior = 0;
+    if (!table.ReadU16(&max_ppem) ||
+        !table.ReadU16(&behavior)) {
+      return OTS_FAILURE();
+    }
+    if ((i > 0) && (gasp->gasp_ranges[i - 1].first >= max_ppem)) {
+      // The records in the gaspRange[] array must be sorted in order of
+      // increasing rangeMaxPPEM value.
+      OTS_WARNING("ranges are not sorted");
+      DROP_THIS_TABLE;
+      return true;
+    }
+    if ((i == num_ranges - 1u) &&  // never underflow.
+        (max_ppem != 0xffffu)) {
+      OTS_WARNING("The last record should be 0xFFFF as a sentinel value "
+                  "for rangeMaxPPEM");
+      DROP_THIS_TABLE;
+      return true;
+    }
+
+    if (behavior >> 8) {
+      OTS_WARNING("undefined bits are used: %x", behavior);
+      // mask undefined bits.
+      behavior &= 0x000fu;
+    }
+
+    if (gasp->version == 0 && (behavior >> 2) != 0) {
+      OTS_WARNING("changed the version number to 1");
+      gasp->version = 1;
+    }
+
+    gasp->gasp_ranges.push_back(std::make_pair(max_ppem, behavior));
+  }
+
+  return true;
+}
+
+bool ots_gasp_should_serialise(OpenTypeFile *file) {
+  return file->gasp;
+}
+
+bool ots_gasp_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeGASP *gasp = file->gasp;
+
+  if (!out->WriteU16(gasp->version) ||
+      !out->WriteU16(gasp->gasp_ranges.size())) {
+    return OTS_FAILURE();
+  }
+
+  for (unsigned i = 0; i < gasp->gasp_ranges.size(); ++i) {
+    if (!out->WriteU16(gasp->gasp_ranges[i].first) ||
+        !out->WriteU16(gasp->gasp_ranges[i].second)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  return true;
+}
+
+void ots_gasp_free(OpenTypeFile *file) {
+  delete file->gasp;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/gasp.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_GASP_H_
+#define OTS_GASP_H_
+
+#include <utility>  // std::pair
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeGASP {
+  uint16_t version;
+  // A array of (max PPEM, GASP behavior) pairs.
+  std::vector<std::pair<uint16_t, uint16_t> > gasp_ranges;
+};
+
+}  // namespace ots
+
+#endif  // OTS_GASP_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/glyf.cc
@@ -0,0 +1,300 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "glyf.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "head.h"
+#include "loca.h"
+#include "maxp.h"
+
+// glyf - Glyph Data
+// http://www.microsoft.com/opentype/otspec/glyf.htm
+
+namespace {
+
+bool ParseFlagsForSimpleGlyph(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)) {
+    return OTS_FAILURE();
+  }
+
+  uint32_t delta = 0;
+  if (flag & (1u << 1)) {  // x-Short
+    ++delta;
+  } else if (!(flag & (1u << 4))) {
+    delta += 2;
+  }
+
+  if (flag & (1u << 2)) {  // y-Short
+    ++delta;
+  } else if (!(flag & (1u << 5))) {
+    delta += 2;
+  }
+
+  if (flag & (1u << 3)) {  // repeat
+    if (*flags_count_logical + 1 >= num_flags) {
+      return OTS_FAILURE();
+    }
+    uint8_t repeat = 0;
+    if (!table->ReadU8(&repeat)) {
+      return OTS_FAILURE();
+    }
+    if (repeat == 0) {
+      return OTS_FAILURE();
+    }
+    delta += (delta * repeat);
+
+    *flags_count_logical += repeat;
+    if (*flags_count_logical >= num_flags) {
+      return OTS_FAILURE();
+    }
+    ++(*flags_count_physical);
+  }
+
+  if ((flag & (1u << 6)) || (flag & (1u << 7))) {  // reserved flags
+    return OTS_FAILURE();
+  }
+
+  *xy_coordinates_length += delta;
+  if (gly_length < *xy_coordinates_length) {
+    return OTS_FAILURE();
+  }
+
+  return true;
+}
+
+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 = 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();
+    }
+    if (tmp_index == 0xffffu) {
+      return OTS_FAILURE();
+    }
+    // check if the indices are monotonically increasing
+    if (i && (tmp_index + 1 <= num_flags)) {
+      return OTS_FAILURE();
+    }
+    num_flags = tmp_index + 1;
+  }
+
+  uint16_t bytecode_length = 0;
+  if (!table->ReadU16(&bytecode_length)) {
+    return OTS_FAILURE();
+  }
+  if ((file->maxp->version_1) &&
+      (file->maxp->max_size_glyf_instructions < bytecode_length)) {
+    return OTS_FAILURE();
+  }
+
+  const uint32_t gly_header_length = 10 + num_contours * 2 + 2;
+  if (gly_length < (gly_header_length + bytecode_length)) {
+    return OTS_FAILURE();
+  }
+
+  if (ots::g_transcode_hints) {
+    glyf->iov.push_back(std::make_pair(
+        data + gly_offset, gly_header_length + bytecode_length));
+  } else {
+    // enqueue two vectors: the glyph data up to the bytecode length, then
+    // a pointer to a static uint16_t 0 to overwrite the length.
+    glyf->iov.push_back(std::make_pair(
+        data + gly_offset, gly_header_length - 2));
+    glyf->iov.push_back(std::make_pair((const uint8_t*) "\x00\x00", 2));
+  }
+
+  if (!table->Skip(bytecode_length)) {
+    return OTS_FAILURE();
+  }
+
+  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(table,
+                                  gly_length,
+                                  num_flags,
+                                  &flags_count_logical,
+                                  &flags_count_physical,
+                                  &xy_coordinates_length)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  if (gly_length < (gly_header_length + bytecode_length +
+                    flags_count_physical + xy_coordinates_length)) {
+    return OTS_FAILURE();
+  }
+
+  if (gly_length - (gly_header_length + bytecode_length +
+                    flags_count_physical + xy_coordinates_length) > 3) {
+    // We allow 0-3 bytes difference since gly_length is 4-bytes aligned,
+    // zero-padded length.
+    return OTS_FAILURE();
+  }
+
+  glyf->iov.push_back(std::make_pair(
+      data + gly_offset + gly_header_length + bytecode_length,
+      flags_count_physical + xy_coordinates_length));
+
+  *new_size
+      = gly_header_length + flags_count_physical + xy_coordinates_length;
+  if (ots::g_transcode_hints) {
+    *new_size += bytecode_length;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+namespace ots {
+
+bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+
+  if (!file->maxp || !file->loca || !file->head) {
+    return OTS_FAILURE();
+  }
+
+  OpenTypeGLYF *glyf = new OpenTypeGLYF;
+  file->glyf = glyf;
+
+  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();
+  }
+
+  std::vector<uint32_t> resulting_offsets(num_glyphs + 1);
+  uint32_t current_offset = 0;
+
+  for (unsigned i = 0; i < num_glyphs; ++i) {
+    const unsigned gly_offset = offsets[i];
+    // The LOCA parser checks that these values are monotonic
+    const unsigned gly_length = offsets[i + 1] - offsets[i];
+    if (!gly_length) {
+      // this glyph has no outline (e.g. the space charactor)
+      resulting_offsets[i] = current_offset;
+      continue;
+    }
+
+    if (gly_offset >= length) {
+      return OTS_FAILURE();
+    }
+    // Since these are unsigned types, the compiler is not allowed to assume
+    // that they never overflow.
+    if (gly_offset + gly_length < gly_offset) {
+      return OTS_FAILURE();
+    }
+    if (gly_offset + gly_length > length) {
+      return OTS_FAILURE();
+    }
+
+    table.set_offset(gly_offset);
+    int16_t num_contours, xmin, ymin, xmax, ymax;
+    if (!table.ReadS16(&num_contours) ||
+        !table.ReadS16(&xmin) ||
+        !table.ReadS16(&ymin) ||
+        !table.ReadS16(&xmax) ||
+        !table.ReadS16(&ymax)) {
+      return OTS_FAILURE();
+    }
+
+    if (num_contours <= -2) {
+      // -2, -3, -4, ... are reserved for future use.
+      return OTS_FAILURE();
+    }
+
+    // workaround for fonts in http://www.princexml.com/fonts/
+    if ((xmin == 32767) &&
+        (xmax == -32767) &&
+        (ymin == 32767) &&
+        (ymax == -32767)) {
+      OTS_WARNING("bad xmin/xmax/ymin/ymax values");
+      xmin = xmax = ymin = ymax = 0;
+    }
+
+    if (xmin > xmax || ymin > ymax) {
+      return OTS_FAILURE();
+    }
+
+    unsigned new_size = 0;
+    if (num_contours >= 0) {
+      // this is a simple glyph and might contain bytecode
+      if (!ParseSimpleGlyph(file, data, &table,
+                            num_contours, gly_offset, gly_length, &new_size)) {
+        return OTS_FAILURE();
+      }
+    } else {
+      // it's a composite glyph without any bytecode. Enqueue the whole thing
+      glyf->iov.push_back(std::make_pair(data + gly_offset, gly_length));
+      new_size = gly_length;
+    }
+
+    resulting_offsets[i] = current_offset;
+    // glyphs must be four byte aligned
+    // TODO(yusukes): investigate whether this padding is really necessary.
+    //                Which part of the spec requires this?
+    const unsigned padding = (4 - (new_size & 3)) % 4;
+    if (padding) {
+      glyf->iov.push_back(std::make_pair(
+          reinterpret_cast<const uint8_t*>("\x00\x00\x00\x00"), padding));
+      new_size += padding;
+    }
+    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)) &&
+      (file->head->index_to_loc_format != 1)) {
+    OTS_WARNING("2-bytes indexing is not possible (due to the padding above)");
+    file->head->index_to_loc_format = 1;
+  }
+
+  file->loca->offsets = resulting_offsets;
+  return true;
+}
+
+bool ots_glyf_should_serialise(OpenTypeFile *file) {
+  return file->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();
+    }
+  }
+
+  return true;
+}
+
+void ots_glyf_free(OpenTypeFile *file) {
+  delete file->glyf;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/glyf.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_GLYF_H_
+#define OTS_GLYF_H_
+
+#include <utility>  // std::pair
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeGLYF {
+  std::vector<std::pair<const uint8_t*, size_t> > iov;
+};
+
+}  // namespace ots
+
+#endif  // OTS_GLYF_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/hdmx.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "hdmx.h"
+#include "head.h"
+#include "maxp.h"
+
+// hdmx - Horizontal Device Metrics
+// http://www.microsoft.com/opentype/otspec/hdmx.htm
+
+#define DROP_THIS_TABLE \
+  do { delete file->hdmx; file->hdmx = 0; } while (0)
+
+namespace ots {
+
+bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+  file->hdmx = new OpenTypeHDMX;
+  OpenTypeHDMX * const hdmx = file->hdmx;
+
+  if (!file->head || !file->maxp) {
+    return OTS_FAILURE();
+  }
+
+  if ((file->head->flags & 0x14) == 0) {
+    // http://www.microsoft.com/typography/otspec/recom.htm
+    OTS_WARNING("the table should not be present when bit 2 and 4 of the "
+                "head->flags are not set");
+    DROP_THIS_TABLE;
+    return true;
+  }
+
+  int16_t num_recs;
+  if (!table.ReadU16(&hdmx->version) ||
+      !table.ReadS16(&num_recs) ||
+      !table.ReadS32(&hdmx->size_device_record)) {
+    return OTS_FAILURE();
+  }
+  if (hdmx->version != 0) {
+    OTS_WARNING("bad version: %u", hdmx->version);
+    DROP_THIS_TABLE;
+    return true;
+  }
+  if (num_recs <= 0) {
+    OTS_WARNING("bad num_recs: %d", num_recs);
+    DROP_THIS_TABLE;
+    return true;
+  }
+  const int32_t actual_size_device_record = file->maxp->num_glyphs + 2;
+  if (hdmx->size_device_record < actual_size_device_record) {
+    OTS_WARNING("bad hdmx->size_device_record: %d", hdmx->size_device_record);
+    DROP_THIS_TABLE;
+    return true;
+  }
+
+  hdmx->pad_len = hdmx->size_device_record - actual_size_device_record;
+  if (hdmx->pad_len > 3) {
+    return OTS_FAILURE();
+  }
+
+  uint8_t last_pixel_size = 0;
+  hdmx->records.reserve(num_recs);
+  for (int i = 0; i < num_recs; ++i) {
+    OpenTypeHDMXDeviceRecord rec;
+
+    if (!table.ReadU8(&rec.pixel_size) ||
+        !table.ReadU8(&rec.max_width)) {
+      return OTS_FAILURE();
+    }
+    if ((i != 0) &&
+        (rec.pixel_size <= last_pixel_size)) {
+      OTS_WARNING("records are not sorted");
+      DROP_THIS_TABLE;
+      return true;
+    }
+    last_pixel_size = rec.pixel_size;
+
+    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();
+      }
+      rec.widths.push_back(width);
+    }
+
+    if ((hdmx->pad_len > 0) &&
+        !table.Skip(hdmx->pad_len)) {
+      return OTS_FAILURE();
+    }
+
+    hdmx->records.push_back(rec);
+  }
+
+  return true;
+}
+
+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, OpenTypeFile *file) {
+  OpenTypeHDMX * const hdmx = file->hdmx;
+
+  if (!out->WriteU16(hdmx->version) ||
+      !out->WriteS16(hdmx->records.size()) ||
+      !out->WriteS32(hdmx->size_device_record)) {
+    return OTS_FAILURE();
+  }
+
+  for (unsigned i = 0; i < hdmx->records.size(); ++i) {
+    const OpenTypeHDMXDeviceRecord& rec = hdmx->records[i];
+    if (!out->Write(&rec.pixel_size, 1) ||
+        !out->Write(&rec.max_width, 1) ||
+        !out->Write(&rec.widths[0], rec.widths.size())) {
+      return OTS_FAILURE();
+    }
+    if ((hdmx->pad_len > 0) &&
+        !out->Write((const uint8_t *)"\x00\x00\x00", hdmx->pad_len)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  return true;
+}
+
+void ots_hdmx_free(OpenTypeFile *file) {
+  delete file->hdmx;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/hdmx.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_HDMX_H_
+#define OTS_HDMX_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeHDMXDeviceRecord {
+  uint8_t pixel_size;
+  uint8_t max_width;
+  std::vector<uint8_t> widths;
+};
+
+struct OpenTypeHDMX {
+  uint16_t version;
+  int32_t size_device_record;
+  int32_t pad_len;
+  std::vector<OpenTypeHDMXDeviceRecord> records;
+};
+
+}  // namespace ots
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/head.cc
@@ -0,0 +1,149 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "head.h"
+
+#include <cstring>
+
+// head - Font Header
+// http://www.microsoft.com/opentype/otspec/head.htm
+
+namespace ots {
+
+bool ots_head_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+  file->head = new OpenTypeHEAD;
+
+  uint32_t version = 0;
+  if (!table.ReadU32(&version) ||
+      !table.ReadU32(&file->head->revision)) {
+    return OTS_FAILURE();
+  }
+
+  if (version >> 16 != 1) {
+    return OTS_FAILURE();
+  }
+
+  // Skip the checksum adjustment
+  if (!table.Skip(4)) {
+    return OTS_FAILURE();
+  }
+
+  uint32_t magic;
+  if (!table.ReadTag(&magic) ||
+      std::memcmp(&magic, "\x5F\x0F\x3C\xF5", 4)) {
+    return OTS_FAILURE();
+  }
+
+  if (!table.ReadU16(&file->head->flags)) {
+    return OTS_FAILURE();
+  }
+
+  // We allow bits 0..4, 11..13
+  file->head->flags &= 0x381f;
+
+  if (!table.ReadU16(&file->head->ppem)) {
+    return OTS_FAILURE();
+  }
+
+  // ppem must be in range
+  if (file->head->ppem < 16 ||
+      file->head->ppem > 16384) {
+    return OTS_FAILURE();
+  }
+
+  // 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 ((file->head->ppem - 1) & file->head->ppem) {
+    return OTS_FAILURE();
+  }
+#endif
+
+  if (!table.ReadR64(&file->head->created) ||
+      !table.ReadR64(&file->head->modified)) {
+    return OTS_FAILURE();
+  }
+
+  if (!table.ReadS16(&file->head->xmin) ||
+      !table.ReadS16(&file->head->ymin) ||
+      !table.ReadS16(&file->head->xmax) ||
+      !table.ReadS16(&file->head->ymax)) {
+    return OTS_FAILURE();
+  }
+
+  if (file->head->xmin > file->head->xmax) {
+    return OTS_FAILURE();
+  }
+  if (file->head->ymin > file->head->ymax) {
+    return OTS_FAILURE();
+  }
+
+  if (!table.ReadU16(&file->head->mac_style)) {
+    return OTS_FAILURE();
+  }
+
+  // We allow bits 0..6
+  file->head->mac_style &= 0x7f;
+
+  if (!table.ReadU16(&file->head->min_ppem)) {
+    return OTS_FAILURE();
+  }
+
+  // We don't care about the font direction hint
+  if (!table.Skip(2)) {
+    return OTS_FAILURE();
+  }
+
+  if (!table.ReadS16(&file->head->index_to_loc_format)) {
+    return OTS_FAILURE();
+  }
+  if (file->head->index_to_loc_format < 0 ||
+      file->head->index_to_loc_format > 1) {
+    return OTS_FAILURE();
+  }
+
+  int16_t glyph_data_format;
+  if (!table.ReadS16(&glyph_data_format) ||
+      glyph_data_format) {
+    return OTS_FAILURE();
+  }
+
+  return true;
+}
+
+bool ots_head_should_serialise(OpenTypeFile *file) {
+  return file->head;
+}
+
+bool ots_head_serialise(OTSStream *out, OpenTypeFile *file) {
+  if (!out->WriteU32(0x00010000) ||
+      !out->WriteU32(file->head->revision) ||
+      !out->WriteU32(0) ||  // check sum not filled in yet
+      !out->WriteU32(0x5F0F3CF5) ||
+      !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(file->head->index_to_loc_format) ||
+      !out->WriteS16(0)) {
+    return OTS_FAILURE();
+  }
+
+  return true;
+}
+
+void ots_head_free(OpenTypeFile *file) {
+  delete file->head;
+}
+
+}  // namespace
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/head.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_HEAD_H_
+#define OTS_HEAD_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeHEAD {
+  uint32_t revision;
+  uint16_t flags;
+  uint16_t ppem;
+  uint64_t created;
+  uint64_t modified;
+
+  int16_t xmin, xmax;
+  int16_t ymin, ymax;
+
+  uint16_t mac_style;
+  uint16_t min_ppem;
+  int16_t index_to_loc_format;
+};
+
+}  // namespace ots
+
+#endif  // OTS_HEAD_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/hhea.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "hhea.h"
+
+#include "head.h"
+#include "maxp.h"
+
+// hhea - Horizontal Header
+// http://www.microsoft.com/opentype/otspec/hhea.htm
+
+namespace ots {
+
+bool ots_hhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+  OpenTypeHHEA *hhea = new OpenTypeHHEA;
+  file->hhea = hhea;
+
+  uint32_t version = 0;
+  if (!table.ReadU32(&version)) {
+    return OTS_FAILURE();
+  }
+  if (version >> 16 != 1) {
+    return OTS_FAILURE();
+  }
+
+  if (!table.ReadS16(&hhea->ascent) ||
+      !table.ReadS16(&hhea->descent) ||
+      !table.ReadS16(&hhea->linegap) ||
+      !table.ReadU16(&hhea->adv_width_max) ||
+      !table.ReadS16(&hhea->min_lsb) ||
+      !table.ReadS16(&hhea->min_rsb) ||
+      !table.ReadS16(&hhea->x_max_extent) ||
+      !table.ReadS16(&hhea->caret_slope_rise) ||
+      !table.ReadS16(&hhea->caret_slope_run) ||
+      !table.ReadS16(&hhea->caret_offset)) {
+    return OTS_FAILURE();
+  }
+
+  if (hhea->ascent < 0) {
+    OTS_WARNING("bad ascent: %d", hhea->ascent);
+    hhea->ascent = 0;
+  }
+  if (hhea->linegap < 0) {
+    OTS_WARNING("bad linegap: %d", hhea->linegap);
+    hhea->linegap = 0;
+  }
+
+  if (!file->head) {
+    return OTS_FAILURE();
+  }
+
+  // if the font is non-slanted, caret_offset should be zero.
+  if (!(file->head->mac_style & 2) &&
+      (hhea->caret_offset != 0)) {
+    OTS_WARNING("bad caret offset: %d", hhea->caret_offset);
+    hhea->caret_offset = 0;
+  }
+
+  // skip the reserved bytes
+  if (!table.Skip(8)) {
+    return OTS_FAILURE();
+  }
+
+  int16_t data_format;
+  if (!table.ReadS16(&data_format)) {
+    return OTS_FAILURE();
+  }
+  if (data_format) {
+    return OTS_FAILURE();
+  }
+
+  if (!table.ReadU16(&hhea->num_hmetrics)) {
+    return OTS_FAILURE();
+  }
+
+  if (!file->maxp) {
+    return OTS_FAILURE();
+  }
+
+  if (hhea->num_hmetrics > file->maxp->num_glyphs) {
+    return OTS_FAILURE();
+  }
+
+  return true;
+}
+
+bool ots_hhea_should_serialise(OpenTypeFile *file) {
+  return file->hhea;
+}
+
+bool ots_hhea_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeHHEA *hhea = file->hhea;
+
+  if (!out->WriteU32(0x00010000) ||
+      !out->WriteS16(hhea->ascent) ||
+      !out->WriteS16(hhea->descent) ||
+      !out->WriteS16(hhea->linegap) ||
+      !out->WriteU16(hhea->adv_width_max) ||
+      !out->WriteS16(hhea->min_lsb) ||
+      !out->WriteS16(hhea->min_rsb) ||
+      !out->WriteS16(hhea->x_max_extent) ||
+      !out->WriteS16(hhea->caret_slope_rise) ||
+      !out->WriteS16(hhea->caret_slope_run) ||
+      !out->WriteS16(hhea->caret_offset) ||
+      !out->WriteR64(0) ||  // reserved
+      !out->WriteS16(0) ||  // metric data format
+      !out->WriteU16(hhea->num_hmetrics)) {
+    return OTS_FAILURE();
+  }
+
+  return true;
+}
+
+void ots_hhea_free(OpenTypeFile *file) {
+  delete file->hhea;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/hhea.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_HHEA_H_
+#define OTS_HHEA_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeHHEA {
+  int16_t ascent;
+  int16_t descent;
+  int16_t linegap;
+  uint16_t adv_width_max;
+  int16_t min_lsb;
+  int16_t min_rsb;
+  int16_t x_max_extent;
+  int16_t caret_slope_rise;
+  int16_t caret_slope_run;
+  int16_t caret_offset;
+  uint16_t num_hmetrics;
+};
+
+}  // namespace ots
+
+#endif  // OTS_HHEA_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/hmtx.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "hmtx.h"
+
+#include "hhea.h"
+#include "maxp.h"
+
+// hmtx - Horizontal Metrics
+// http://www.microsoft.com/opentype/otspec/hmtx.htm
+
+namespace ots {
+
+bool ots_hmtx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+  OpenTypeHMTX *hmtx = new OpenTypeHMTX;
+  file->hmtx = hmtx;
+
+  if (!file->hhea || !file->maxp) {
+    return OTS_FAILURE();
+  }
+
+  // |num_hmetrics| 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_hmetrics = file->hhea->num_hmetrics;
+
+  if (num_hmetrics > file->maxp->num_glyphs) {
+    return OTS_FAILURE();
+  }
+  if (!num_hmetrics) {
+    return OTS_FAILURE();
+  }
+  const unsigned num_lsbs = file->maxp->num_glyphs - num_hmetrics;
+
+  hmtx->metrics.reserve(num_hmetrics);
+  for (unsigned i = 0; i < num_hmetrics; ++i) {
+    uint16_t adv = 0;
+    int16_t lsb = 0;
+    if (!table.ReadU16(&adv) || !table.ReadS16(&lsb)) {
+      return OTS_FAILURE();
+    }
+
+    // Since so many fonts don't have proper value on |adv| and |lsb|,
+    // we should not call ots_failure() here. For example, about 20% of fonts
+    // in http://www.princexml.com/fonts/ (200+ fonts) fails these tests.
+    if (adv > file->hhea->adv_width_max) {
+      OTS_WARNING("bad adv: %u > %u", adv, file->hhea->adv_width_max);
+      adv = file->hhea->adv_width_max;
+    }
+    if (lsb < file->hhea->min_lsb) {
+      OTS_WARNING("bad lsb: %d < %d", lsb, file->hhea->min_lsb);
+      lsb = file->hhea->min_lsb;
+    }
+
+    hmtx->metrics.push_back(std::make_pair(adv, lsb));
+  }
+
+  hmtx->lsbs.reserve(num_lsbs);
+  for (unsigned i = 0; i < num_lsbs; ++i) {
+    int16_t lsb;
+    if (!table.ReadS16(&lsb)) {
+      // Some Japanese fonts (e.g., mona.ttf) fail this test.
+      return OTS_FAILURE();
+    }
+
+    if (lsb < file->hhea->min_lsb) {
+      // The same as above. Three fonts in http://www.fontsquirrel.com/fontface
+      // (e.g., Notice2Std.otf) have weird lsb values.
+      OTS_WARNING("bad lsb: %d < %d", lsb, file->hhea->min_lsb);
+      lsb = file->hhea->min_lsb;
+    }
+
+    hmtx->lsbs.push_back(lsb);
+  }
+
+  return true;
+}
+
+bool ots_hmtx_should_serialise(OpenTypeFile *file) {
+  return file->hmtx;
+}
+
+bool ots_hmtx_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeHMTX *hmtx = file->hmtx;
+
+  for (unsigned i = 0; i < hmtx->metrics.size(); ++i) {
+    if (!out->WriteU16(hmtx->metrics[i].first) ||
+        !out->WriteS16(hmtx->metrics[i].second)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  for (unsigned i = 0; i < hmtx->lsbs.size(); ++i) {
+    if (!out->WriteS16(hmtx->lsbs[i])) {
+      return OTS_FAILURE();
+    }
+  }
+
+  return true;
+}
+
+void ots_hmtx_free(OpenTypeFile *file) {
+  delete file->hmtx;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/hmtx.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_HMTX_H_
+#define OTS_HMTX_H_
+
+#include <utility>  // std::pair
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeHMTX {
+  std::vector<std::pair<uint16_t, int16_t> > metrics;
+  std::vector<int16_t> lsbs;
+};
+
+}  // namespace ots
+
+#endif  // OTS_HMTX_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/kern.cc
@@ -0,0 +1,196 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "kern.h"
+
+// kern - Kerning
+// http://www.microsoft.com/opentype/otspec/kern.htm
+
+#define DROP_THIS_TABLE \
+  do { delete file->kern; file->kern = 0; } while (0)
+
+namespace ots {
+
+bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+
+  OpenTypeKERN *kern = new OpenTypeKERN;
+  file->kern = kern;
+
+  uint16_t num_tables = 0;
+  if (!table.ReadU16(&kern->version) ||
+      !table.ReadU16(&num_tables)) {
+    return OTS_FAILURE();
+  }
+
+  if (kern->version > 0) {
+    DROP_THIS_TABLE;
+    return true;
+  }
+
+  if (num_tables == 0) {
+    OTS_WARNING("num_tables is zero");
+    DROP_THIS_TABLE;
+    return true;
+  }
+
+  kern->subtables.reserve(num_tables);
+  for (unsigned i = 0; i < num_tables; ++i) {
+    OpenTypeKERNFormat0 subtable;
+    uint16_t sub_length = 0;
+
+    if (!table.ReadU16(&subtable.version) ||
+        !table.ReadU16(&sub_length)) {
+      return OTS_FAILURE();
+    }
+
+    if (subtable.version > 0) {
+      OTS_WARNING("Bad subtable version: %d", subtable.version);
+      continue;
+    }
+
+    const size_t current_offset = table.offset();
+    if (current_offset - 4 + sub_length > length) {
+      return OTS_FAILURE();
+    }
+
+    if (!table.ReadU16(&subtable.coverage)) {
+      return OTS_FAILURE();
+    }
+
+    if (!(subtable.coverage & 0x1)) {
+      OTS_WARNING(
+          "We don't support vertical data as the renderer doesn't support it.");
+      continue;
+    }
+    if (subtable.coverage & 0xF0) {
+      OTS_WARNING("Reserved fields should zero-filled.");
+      DROP_THIS_TABLE;
+      return true;
+    }
+    const uint32_t format = (subtable.coverage & 0xFF00) >> 8;
+    if (format != 0) {
+      OTS_WARNING("Format %d is not supported.", format);
+      continue;
+    }
+
+    // Parse the format 0 field.
+    uint16_t num_pairs = 0;
+    if (!table.ReadU16(&num_pairs) ||
+        !table.ReadU16(&subtable.search_range) ||
+        !table.ReadU16(&subtable.entry_selector) ||
+        !table.ReadU16(&subtable.range_shift)) {
+      return OTS_FAILURE();
+    }
+
+    if (!num_pairs) {
+      OTS_WARNING("Zero length subtable is found.");
+      DROP_THIS_TABLE;
+      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.
+      OTS_WARNING("Too large subtable.");
+      DROP_THIS_TABLE;
+      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) {
+      OTS_WARNING("bad search range");
+      subtable.search_range = expected_search_range;
+    }
+    if (subtable.entry_selector != max_pow2) {
+      return OTS_FAILURE();
+    }
+    const uint32_t expected_range_shift
+        = kFormat0PairSize * num_pairs - subtable.search_range;
+    if (subtable.range_shift != expected_range_shift) {
+      OTS_WARNING("bad range shift");
+      subtable.range_shift = expected_range_shift;
+    }
+
+    // Read kerning pairs.
+    subtable.pairs.reserve(num_pairs);
+    uint32_t last_pair = 0;
+    for (unsigned j = 0; j < num_pairs; ++j) {
+      OpenTypeKERNFormat0Pair kerning_pair;
+      if (!table.ReadU16(&kerning_pair.left) ||
+          !table.ReadU16(&kerning_pair.right) ||
+          !table.ReadS16(&kerning_pair.value)) {
+        return OTS_FAILURE();
+      }
+      const uint32_t current_pair
+          = (kerning_pair.left << 16) + kerning_pair.right;
+      if (j != 0 && current_pair <= last_pair) {
+        OTS_WARNING("Kerning pairs are not sorted.");
+        // Many free fonts don't follow this rule, so we don't call OTS_FAILURE
+        // in order to support these fonts.
+        DROP_THIS_TABLE;
+        return true;
+      }
+      last_pair = current_pair;
+      subtable.pairs.push_back(kerning_pair);
+    }
+
+    kern->subtables.push_back(subtable);
+  }
+
+  if (!kern->subtables.size()) {
+    OTS_WARNING("All subtables are removed.");
+    DROP_THIS_TABLE;
+    return true;
+  }
+
+  return true;
+}
+
+bool ots_kern_should_serialise(OpenTypeFile *file) {
+  if (!file->glyf) return false;  // this table is not for CFF fonts.
+  return file->kern;
+}
+
+bool ots_kern_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeKERN *kern = file->kern;
+
+  if (!out->WriteU16(kern->version) ||
+      !out->WriteU16(kern->subtables.size())) {
+    return OTS_FAILURE();
+  }
+
+  for (unsigned i = 0; i < kern->subtables.size(); ++i) {
+    const uint16_t length = 14 + (6 * kern->subtables[i].pairs.size());
+    if (!out->WriteU16(kern->subtables[i].version) ||
+        !out->WriteU16(length) ||
+        !out->WriteU16(kern->subtables[i].coverage) ||
+        !out->WriteU16(kern->subtables[i].pairs.size()) ||
+        !out->WriteU16(kern->subtables[i].search_range) ||
+        !out->WriteU16(kern->subtables[i].entry_selector) ||
+        !out->WriteU16(kern->subtables[i].range_shift)) {
+      return OTS_FAILURE();
+    }
+    for (unsigned j = 0; j < kern->subtables[i].pairs.size(); ++j) {
+      if (!out->WriteU16(kern->subtables[i].pairs[j].left) ||
+          !out->WriteU16(kern->subtables[i].pairs[j].right) ||
+          !out->WriteS16(kern->subtables[i].pairs[j].value)) {
+        return OTS_FAILURE();
+      }
+    }
+  }
+
+  return true;
+}
+
+void ots_kern_free(OpenTypeFile *file) {
+  delete file->kern;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/kern.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_KERN_H_
+#define OTS_KERN_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeKERNFormat0Pair {
+  uint16_t left;
+  uint16_t right;
+  int16_t value;
+};
+
+struct OpenTypeKERNFormat0 {
+  uint16_t version;
+  uint16_t coverage;
+  uint16_t search_range;
+  uint16_t entry_selector;
+  uint16_t range_shift;
+  std::vector<OpenTypeKERNFormat0Pair> pairs;
+};
+
+// Format 2 is not supported. Since the format is not supported by Windows,
+// WebFonts unlikely use it. I've checked thousands of proprietary fonts and
+// free fonts, and found no font uses the format.
+
+struct OpenTypeKERN {
+  uint16_t version;
+  std::vector<OpenTypeKERNFormat0> subtables;
+};
+
+}  // namespace ots
+
+#endif  // OTS_KERN_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/loca.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "loca.h"
+
+#include "head.h"
+#include "maxp.h"
+
+// loca - Index to Location
+// http://www.microsoft.com/opentype/otspec/loca.htm
+
+namespace ots {
+
+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;
+  file->loca = loca;
+
+  if (!file->maxp || !file->head) {
+    return OTS_FAILURE();
+  }
+
+  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 (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();
+      }
+      if (offset < last_offset) {
+        return OTS_FAILURE();
+      }
+      last_offset = offset;
+      loca->offsets[i] = offset * 2;
+    }
+  } else {
+    for (unsigned i = 0; i <= num_glyphs; ++i) {
+      uint32_t offset = 0;
+      if (!table.ReadU32(&offset)) {
+        return OTS_FAILURE();
+      }
+      if (offset < last_offset) {
+        return OTS_FAILURE();
+      }
+      last_offset = offset;
+      loca->offsets[i] = offset;
+    }
+  }
+
+  return true;
+}
+
+bool ots_loca_should_serialise(OpenTypeFile *file) {
+  return file->loca;
+}
+
+bool ots_loca_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeLOCA *loca = file->loca;
+  const OpenTypeHEAD *head = file->head;
+
+  if (!head) {
+    return OTS_FAILURE();
+  }
+
+  if (head->index_to_loc_format == 0) {
+    for (unsigned i = 0; i < loca->offsets.size(); ++i) {
+      if (!out->WriteU16(loca->offsets[i] >> 1)) {
+        return OTS_FAILURE();
+      }
+    }
+  } else {
+    for (unsigned i = 0; i < loca->offsets.size(); ++i) {
+      if (!out->WriteU32(loca->offsets[i])) {
+        return OTS_FAILURE();
+      }
+    }
+  }
+
+  return true;
+}
+
+void ots_loca_free(OpenTypeFile *file) {
+  delete file->loca;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/loca.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_LOCA_H_
+#define OTS_LOCA_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeLOCA {
+  std::vector<uint32_t> offsets;
+};
+
+}  // namespace ots
+
+#endif  // OTS_LOCA_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/ltsh.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ltsh.h"
+
+#include "maxp.h"
+
+// LTSH - Linear Threshold
+// http://www.microsoft.com/typography/otspec/ltsh.htm
+
+#define DROP_THIS_TABLE \
+  do { delete file->ltsh; file->ltsh = 0; } while (0)
+
+namespace ots {
+
+bool ots_ltsh_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+
+  if (!file->maxp) {
+    return OTS_FAILURE();
+  }
+
+  OpenTypeLTSH *ltsh = new OpenTypeLTSH;
+  file->ltsh = ltsh;
+
+  uint16_t num_glyphs = 0;
+  if (!table.ReadU16(&ltsh->version) ||
+      !table.ReadU16(&num_glyphs)) {
+    return OTS_FAILURE();
+  }
+
+  if (ltsh->version != 0) {
+    OTS_WARNING("bad version: %u", ltsh->version);
+    DROP_THIS_TABLE;
+    return true;
+  }
+
+  if (num_glyphs != file->maxp->num_glyphs) {
+    OTS_WARNING("bad num_glyphs: %u", num_glyphs);
+    DROP_THIS_TABLE;
+    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();
+    }
+    ltsh->ypels.push_back(pel);
+  }
+
+  return true;
+}
+
+bool ots_ltsh_should_serialise(OpenTypeFile *file) {
+  if (!file->glyf) return false;  // this table is not for CFF fonts.
+  return file->ltsh;
+}
+
+bool ots_ltsh_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypeLTSH *ltsh = file->ltsh;
+
+  if (!out->WriteU16(ltsh->version) ||
+      !out->WriteU16(ltsh->ypels.size())) {
+    return OTS_FAILURE();
+  }
+  for (unsigned i = 0; i < ltsh->ypels.size(); ++i) {
+    if (!out->Write(&(ltsh->ypels[i]), 1)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  return true;
+}
+
+void ots_ltsh_free(OpenTypeFile *file) {
+  delete file->ltsh;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/ltsh.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_LTSH_H_
+#define OTS_LTSH_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeLTSH {
+  uint16_t version;
+  std::vector<uint8_t> ypels;
+};
+
+}  // namespace ots
+
+#endif  // OTS_LTSH_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/maxp.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "maxp.h"
+
+// maxp - Maximum Profile
+// http://www.microsoft.com/opentype/otspec/maxp.htm
+
+namespace ots {
+
+bool ots_maxp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+
+  OpenTypeMAXP *maxp = new OpenTypeMAXP;
+  file->maxp = maxp;
+
+  uint32_t version = 0;
+  if (!table.ReadU32(&version)) {
+    return OTS_FAILURE();
+  }
+
+  if (version >> 16 > 1) {
+    return OTS_FAILURE();
+  }
+
+  if (!table.ReadU16(&maxp->num_glyphs)) {
+    return OTS_FAILURE();
+  }
+
+  if (!maxp->num_glyphs) {
+    return OTS_FAILURE();
+  }
+
+  if (version >> 16 == 1) {
+    maxp->version_1 = true;
+    if (!table.ReadU16(&maxp->max_points) ||
+        !table.ReadU16(&maxp->max_contours) ||
+        !table.ReadU16(&maxp->max_c_points) ||
+        !table.ReadU16(&maxp->max_c_contours) ||
+        !table.ReadU16(&maxp->max_zones) ||
+        !table.ReadU16(&maxp->max_t_points) ||
+        !table.ReadU16(&maxp->max_storage) ||
+        !table.ReadU16(&maxp->max_fdefs) ||
+        !table.ReadU16(&maxp->max_idefs) ||
+        !table.ReadU16(&maxp->max_stack) ||
+        !table.ReadU16(&maxp->max_size_glyf_instructions) ||
+        !table.ReadU16(&maxp->max_c_components) ||
+        !table.ReadU16(&maxp->max_c_depth)) {
+      return OTS_FAILURE();
+    }
+
+    if (maxp->max_zones == 0) {
+      // workaround for ipa*.ttf Japanese fonts.
+      OTS_WARNING("bad max_zones: %u", maxp->max_zones);
+      maxp->max_zones = 1;
+    } else if (maxp->max_zones == 3) {
+      // workaround for Ecolier-*.ttf fonts.
+      OTS_WARNING("bad max_zones: %u", maxp->max_zones);
+      maxp->max_zones = 2;
+    }
+
+    if ((maxp->max_zones != 1) && (maxp->max_zones != 2)) {
+      return OTS_FAILURE();
+    }
+  } else {
+    maxp->version_1 = false;
+  }
+
+  return true;
+}
+
+bool ots_maxp_should_serialise(OpenTypeFile *file) {
+  return file->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();
+  }
+
+  if (!maxp->version_1) return true;
+
+  if (!out->WriteU16(maxp->max_points) ||
+      !out->WriteU16(maxp->max_contours) ||
+      !out->WriteU16(maxp->max_c_points) ||
+      !out->WriteU16(maxp->max_c_contours)) {
+    return OTS_FAILURE();
+  }
+
+  if (g_transcode_hints) {
+    if (!out->WriteU16(maxp->max_zones) ||
+        !out->WriteU16(maxp->max_t_points) ||
+        !out->WriteU16(maxp->max_storage) ||
+        !out->WriteU16(maxp->max_fdefs) ||
+        !out->WriteU16(maxp->max_idefs) ||
+        !out->WriteU16(maxp->max_stack) ||
+        !out->WriteU16(maxp->max_size_glyf_instructions)) {
+      return OTS_FAILURE();
+    }
+  } else {
+    if (!out->WriteU16(1) ||  // max zones
+        !out->WriteU16(0) ||  // max twilight points
+        !out->WriteU16(0) ||  // max storage
+        !out->WriteU16(0) ||  // max function defs
+        !out->WriteU16(0) ||  // max instruction defs
+        !out->WriteU16(0) ||  // max stack elements
+        !out->WriteU16(0)) {  // max instruction byte count
+      return OTS_FAILURE();
+    }
+  }
+
+  if (!out->WriteU16(maxp->max_c_components) ||
+      !out->WriteU16(maxp->max_c_depth)) {
+    return OTS_FAILURE();
+  }
+
+  return true;
+}
+
+void ots_maxp_free(OpenTypeFile *file) {
+  delete file->maxp;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/maxp.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_MAXP_H_
+#define OTS_MAXP_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeMAXP {
+  uint16_t num_glyphs;
+  bool version_1;
+
+  uint16_t max_points;
+  uint16_t max_contours;
+  uint16_t max_c_points;
+  uint16_t max_c_contours;
+
+  uint16_t max_zones;
+  uint16_t max_t_points;
+  uint16_t max_storage;
+  uint16_t max_fdefs;
+  uint16_t max_idefs;
+  uint16_t max_stack;
+  uint16_t max_size_glyf_instructions;
+
+  uint16_t max_c_components;
+  uint16_t max_c_depth;
+};
+
+}  // namespace ots
+
+#endif  // OTS_MAXP_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/name.cc
@@ -0,0 +1,131 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cstring>
+
+#include "cff.h"
+#include "ots.h"
+
+// name - Naming Table
+// http://www.microsoft.com/opentype/otspec/name.htm
+
+namespace ots {
+
+bool ots_name_parse(OpenTypeFile *, const uint8_t *, size_t) {
+  return true;
+}
+
+bool ots_name_should_serialise(OpenTypeFile *) {
+  return true;
+}
+
+bool ots_name_serialise(OTSStream *out, OpenTypeFile *file) {
+  // NAME is a required table, but we don't want anything to do with it. Thus,
+  // we don't bother parsing it and we just serialise an empty name table.
+
+  const char* kStrings[] = {
+      "Derived font data",  // 0: copyright
+      "OTS derived font",  // 1: the name the user sees
+      "Unspecified",  // 2: face weight
+      "UniqueID",  // 3: unique id
+      "OTS derivied font",  // 4: human readable name
+      "1.000",  // 5: version
+      "False",  // 6: postscript name
+      NULL,  // 7: trademark data
+      "OTS",  // 8: foundary
+      "OTS",  // 9: designer
+  };
+  static const size_t kStringsLen = sizeof(kStrings) / sizeof(kStrings[0]);
+
+  // 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()) {
+    kStrings[6] = file->cff->name.c_str();
+  }
+
+  unsigned num_strings = 0;
+  for (unsigned i = 0; i < kStringsLen; ++i) {
+    if (kStrings[i]) num_strings++;
+  }
+
+  if (!out->WriteU16(0) ||  // version
+      // Magic numbers:
+      //   6:  This entry (U16 * 3 = 6 bytes)
+      //   2:  Mac Roman & Windows Roman = 2 types
+      //   12: Each string entry (U16 * 6 = 12 bytes)
+      !out->WriteU16(num_strings * 2) ||  // count
+      !out->WriteU16(6 + num_strings * 2 * 12)) {  // string data offset
+    return OTS_FAILURE();
+  }
+
+  unsigned current_offset = 0;
+  for (unsigned i = 0; i < kStringsLen; ++i) {
+    if (!kStrings[i]) continue;
+
+    // string length in UTF-8 (ASCII).
+    size_t len = std::strlen(kStrings[i]);
+
+    if (!out->WriteU16(1) ||  // Mac
+        !out->WriteU16(0) ||  // Roman
+        !out->WriteU16(0) ||  // English
+        !out->WriteU16(i) ||
+        !out->WriteU16(len) ||
+        !out->WriteU16(current_offset)) {
+      return OTS_FAILURE();
+    }
+
+    current_offset += len;
+  }
+
+  for (unsigned i = 0; i < kStringsLen; ++i) {
+    if (!kStrings[i]) continue;
+
+    // string length in UTF-16.
+    size_t len = std::strlen(kStrings[i]) * 2;
+
+    if (!out->WriteU16(3) ||  // Windows
+        !out->WriteU16(1) ||  // Unicode BMP (UCS-2)
+        !out->WriteU16(0x0409) ||  // US English
+        !out->WriteU16(i) ||
+        !out->WriteU16(len) ||
+        !out->WriteU16(current_offset)) {
+      return OTS_FAILURE();
+    }
+
+    current_offset += len;
+  }
+
+  // Write strings in Mac Roman compatible with ASCII.
+  // Because all the entries are ASCII, we can just copy.
+  for (unsigned i = 0; i < kStringsLen; ++i) {
+    if (!kStrings[i]) continue;
+
+    const size_t len = std::strlen(kStrings[i]);
+    if (!out->Write(kStrings[i], len)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  // Write strings in UCS-2. Because all the entries are ASCII,
+  // we can just expand each byte to U16.
+  for (unsigned i = 0; i < kStringsLen; ++i) {
+    if (!kStrings[i]) continue;
+
+    const size_t len = std::strlen(kStrings[i]);
+    for (size_t j = 0; j < len; ++j) {
+      uint16_t v = kStrings[i][j];
+      if (!out->WriteU16(v)) {
+        return OTS_FAILURE();
+      }
+    }
+  }
+
+  return true;
+}
+
+void ots_name_free(OpenTypeFile *) {
+}
+
+}  // namespace
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/os2.cc
@@ -0,0 +1,290 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "os2.h"
+
+#include "head.h"
+
+// OS/2 - OS/2 and Windows Metrics
+// http://www.microsoft.com/opentype/otspec/os2.htm
+
+namespace ots {
+
+bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+
+  OpenTypeOS2 *os2 = new OpenTypeOS2;
+  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) ||
+      !table.ReadS16(&os2->subscript_x_offset) ||
+      !table.ReadS16(&os2->subscript_y_offset) ||
+      !table.ReadS16(&os2->superscript_x_size) ||
+      !table.ReadS16(&os2->superscript_y_size) ||
+      !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();
+  }
+
+  if (os2->version > 4) {
+    return OTS_FAILURE();
+  }
+
+  // Some linux fonts (e.g., Kedage-t.ttf and LucidaSansDemiOblique.ttf) have
+  // weird weight/width classes. Overwrite them with FW_NORMAL/1/9.
+  if (os2->weight_class < 100 ||
+      os2->weight_class > 900 ||
+      os2->weight_class % 100) {
+    OTS_WARNING("bad weight: %u", os2->weight_class);
+    os2->weight_class = 400;  // FW_NORMAL
+  }
+  if (os2->width_class < 1) {
+    OTS_WARNING("bad width: %u", os2->width_class);
+    os2->width_class = 1;
+  } else if (os2->width_class > 9) {
+    OTS_WARNING("bad width: %u", os2->width_class);
+    os2->width_class = 9;
+  }
+
+  // lowest 3 bits of fsType are exclusive.
+  if (os2->type & 0x2) {
+    // mask bits 2 & 3.
+    os2->type &= 0xfff3u;
+  } else if (os2->type & 0x4) {
+    // mask bits 1 & 3.
+    os2->type &= 0xfff4u;
+  } else if (os2->type & 0x8) {
+    // mask bits 1 & 2.
+    os2->type &= 0xfff9u;
+  }
+
+  // mask reserved bits. use only 0..3, 8, 9 bits.
+  os2->type &= 0x30f;
+
+  if (os2->subscript_x_size < 0) {
+    OTS_WARNING("bad subscript_x_size: %d", os2->subscript_x_size);
+    os2->subscript_x_size = 0;
+  }
+  if (os2->subscript_y_size < 0) {
+    OTS_WARNING("bad subscript_y_size: %d", os2->subscript_y_size);
+    os2->subscript_y_size = 0;
+  }
+  if (os2->superscript_x_size < 0) {
+    OTS_WARNING("bad superscript_x_size: %d", os2->superscript_x_size);
+    os2->superscript_x_size = 0;
+  }
+  if (os2->superscript_y_size < 0) {
+    OTS_WARNING("bad superscript_y_size: %d", os2->superscript_y_size);
+    os2->superscript_y_size = 0;
+  }
+  if (os2->strikeout_size < 0) {
+    OTS_WARNING("bad strikeout_size: %d", os2->strikeout_size);
+    os2->strikeout_size = 0;
+  }
+
+  for (unsigned i = 0; i < 10; ++i) {
+    if (!table.ReadU8(&os2->panose[i])) {
+      return OTS_FAILURE();
+    }
+  }
+
+  if (!table.ReadU32(&os2->unicode_range_1) ||
+      !table.ReadU32(&os2->unicode_range_2) ||
+      !table.ReadU32(&os2->unicode_range_3) ||
+      !table.ReadU32(&os2->unicode_range_4) ||
+      !table.ReadU32(&os2->vendor_id) ||
+      !table.ReadU16(&os2->selection) ||
+      !table.ReadU16(&os2->first_char_index) ||
+      !table.ReadU16(&os2->last_char_index) ||
+      !table.ReadS16(&os2->typo_ascender) ||
+      !table.ReadS16(&os2->typo_descender) ||
+      !table.ReadS16(&os2->typo_linegap) ||
+      !table.ReadU16(&os2->win_ascent) ||
+      !table.ReadU16(&os2->win_descent)) {
+    return OTS_FAILURE();
+  }
+
+  // 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 (!file->head) {
+    return OTS_FAILURE();
+  }
+  if ((os2->selection & 0x1) &&
+      !(file->head->mac_style & 0x2)) {
+    OTS_WARNING("adjusting Mac style (italic)");
+    file->head->mac_style |= 0x2;
+  }
+  if ((os2->selection & 0x2) &&
+      !(file->head->mac_style & 0x4)) {
+    OTS_WARNING("adjusting Mac style (underscore)");
+    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) &&
+      (file->head->mac_style & 0x3)) {
+    OTS_WARNING("adjusting Mac style (regular)");
+    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();
+  }
+
+  // mask reserved bits. use only 0..9 bits.
+  os2->selection &= 0x3ff;
+
+  if (os2->first_char_index > os2->last_char_index) {
+    return OTS_FAILURE();
+  }
+  if (os2->typo_linegap < 0) {
+    OTS_WARNING("bad linegap: %d", os2->typo_linegap);
+    os2->typo_linegap = 0;
+  }
+
+  if (os2->version < 1) {
+    // http://www.microsoft.com/typography/otspec/os2ver0.htm
+    return true;
+  }
+
+  if (length < offsetof(OpenTypeOS2, code_page_range_2)) {
+    OTS_WARNING("bad version number: %u", os2->version);
+    // Some fonts (e.g., kredit1.ttf and quinquef.ttf) have weird version
+    // numbers. Fix them.
+    os2->version = 0;
+    return true;
+  }
+
+  if (!table.ReadU32(&os2->code_page_range_1) ||
+      !table.ReadU32(&os2->code_page_range_2)) {
+    return OTS_FAILURE();
+  }
+
+  if (os2->version < 2) {
+    // http://www.microsoft.com/typography/otspec/os2ver1.htm
+    return true;
+  }
+
+  if (length < offsetof(OpenTypeOS2, max_context)) {
+    OTS_WARNING("bad version number: %u", os2->version);
+    // some Japanese fonts (e.g., mona.ttf) have weird version number.
+    // fix them.
+    os2->version = 1;
+    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();
+  }
+
+  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;
+  }
+
+  return true;
+}
+
+bool ots_os2_should_serialise(OpenTypeFile *file) {
+  return file->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) ||
+      !out->WriteS16(os2->subscript_x_offset) ||
+      !out->WriteS16(os2->subscript_y_offset) ||
+      !out->WriteS16(os2->superscript_x_size) ||
+      !out->WriteS16(os2->superscript_y_size) ||
+      !out->WriteS16(os2->superscript_x_offset) ||
+      !out->WriteS16(os2->superscript_y_offset) ||
+      !out->WriteS16(os2->strikeout_size) ||
+      !out->WriteS16(os2->strikeout_position) ||
+      !out->WriteS16(os2->family_class)) {
+    return OTS_FAILURE();
+  }
+
+  for (unsigned i = 0; i < 10; ++i) {
+    if (!out->Write(&os2->panose[i], 1)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  if (!out->WriteU32(os2->unicode_range_1) ||
+      !out->WriteU32(os2->unicode_range_2) ||
+      !out->WriteU32(os2->unicode_range_3) ||
+      !out->WriteU32(os2->unicode_range_4) ||
+      !out->WriteU32(os2->vendor_id) ||
+      !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();
+  }
+
+  if (os2->version < 1) {
+    return true;
+  }
+
+  if (!out->WriteU32(os2->code_page_range_1) ||
+      !out->WriteU32(os2->code_page_range_2)) {
+    return OTS_FAILURE();
+  }
+
+  if (os2->version < 2) {
+    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();
+  }
+
+  return true;
+}
+
+void ots_os2_free(OpenTypeFile *file) {
+  delete file->os2;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/os2.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_OS2_H_
+#define OTS_OS2_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeOS2 {
+  uint16_t version;
+  int16_t avg_char_width;
+  uint16_t weight_class;
+  uint16_t width_class;
+  uint16_t type;
+  int16_t subscript_x_size;
+  int16_t subscript_y_size;
+  int16_t subscript_x_offset;
+  int16_t subscript_y_offset;
+  int16_t superscript_x_size;
+  int16_t superscript_y_size;
+  int16_t superscript_x_offset;
+  int16_t superscript_y_offset;
+  int16_t strikeout_size;
+  int16_t strikeout_position;
+  int16_t family_class;
+  uint8_t panose[10];
+  uint32_t unicode_range_1;
+  uint32_t unicode_range_2;
+  uint32_t unicode_range_3;
+  uint32_t unicode_range_4;
+  uint32_t vendor_id;
+  uint16_t selection;
+  uint16_t first_char_index;
+  uint16_t last_char_index;
+  int16_t typo_ascender;
+  int16_t typo_descender;
+  int16_t typo_linegap;
+  uint16_t win_ascent;
+  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;
+};
+
+}  // namespace ots
+
+#endif  // OTS_OS2_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/ots.cc
@@ -0,0 +1,626 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ots.h"
+
+#include <sys/types.h>
+#include <zlib.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <cstring>
+#include <map>
+#include <vector>
+
+// The OpenType Font File
+// http://www.microsoft.com/opentype/otspec/otff.htm
+
+#define F(name, capname) \
+  namespace ots { \
+  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 {
+
+bool g_debug_output = true;
+
+struct OpenTypeTable {
+  uint32_t tag;
+  uint32_t chksum;
+  uint32_t offset;
+  uint32_t length;
+  uint32_t uncompressed_length;
+};
+
+// Round a value up to the nearest multiple of 4. Note that this can overflow
+// and return zero.
+template<typename T> T Round4(T value) {
+  return (value + 3) & ~3;
+}
+
+uint32_t Tag(const char *tag_str) {
+  uint32_t ret;
+  std::memcpy(&ret, tag_str, 4);
+  return ret;
+}
+
+bool CheckTag(uint32_t tag_value) {
+  for (unsigned i = 0; i < 4; ++i) {
+    const uint32_t check = tag_value & 0xff;
+    if (check < 32 || check > 126) {
+      return false;  // non-ASCII character found.
+    }
+    tag_value >>= 8;
+  }
+  return true;
+}
+
+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;
+    }
+  }
+
+  uint8_t* Allocate(size_t length) {
+    uint8_t* p = new uint8_t[length];
+    hunks_.push_back(p);
+    return p;
+  }
+
+ private:
+  std::vector<uint8_t*> hunks_;
+};
+
+const struct {
+  uint32_t 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[] = {
+  { Tag("maxp"), ots::ots_maxp_parse, ots::ots_maxp_serialise,
+    ots::ots_maxp_should_serialise, ots::ots_maxp_free, true },
+  { Tag("head"), ots::ots_head_parse, ots::ots_head_serialise,
+    ots::ots_head_should_serialise, ots::ots_head_free, true },
+  { Tag("OS/2"), ots::ots_os2_parse, ots::ots_os2_serialise,
+    ots::ots_os2_should_serialise, ots::ots_os2_free, true },
+  { Tag("cmap"), ots::ots_cmap_parse, ots::ots_cmap_serialise,
+    ots::ots_cmap_should_serialise, ots::ots_cmap_free, true },
+  { Tag("hhea"), ots::ots_hhea_parse, ots::ots_hhea_serialise,
+    ots::ots_hhea_should_serialise, ots::ots_hhea_free, true },
+  { Tag("hmtx"), ots::ots_hmtx_parse, ots::ots_hmtx_serialise,
+    ots::ots_hmtx_should_serialise, ots::ots_hmtx_free, true },
+  { Tag("name"), ots::ots_name_parse, ots::ots_name_serialise,
+    ots::ots_name_should_serialise, ots::ots_name_free, true },
+  { Tag("post"), ots::ots_post_parse, ots::ots_post_serialise,
+    ots::ots_post_should_serialise, ots::ots_post_free, true },
+  { Tag("loca"), ots::ots_loca_parse, ots::ots_loca_serialise,
+    ots::ots_loca_should_serialise, ots::ots_loca_free, false },
+  { Tag("glyf"), ots::ots_glyf_parse, ots::ots_glyf_serialise,
+    ots::ots_glyf_should_serialise, ots::ots_glyf_free, false },
+  { Tag("CFF "), ots::ots_cff_parse, ots::ots_cff_serialise,
+    ots::ots_cff_should_serialise, ots::ots_cff_free, false },
+  { Tag("VDMX"), ots::ots_vdmx_parse, ots::ots_vdmx_serialise,
+    ots::ots_vdmx_should_serialise, ots::ots_vdmx_free, false },
+  { Tag("hdmx"), ots::ots_hdmx_parse, ots::ots_hdmx_serialise,
+    ots::ots_hdmx_should_serialise, ots::ots_hdmx_free, false },
+  { Tag("gasp"), ots::ots_gasp_parse, ots::ots_gasp_serialise,
+    ots::ots_gasp_should_serialise, ots::ots_gasp_free, false },
+  { Tag("cvt "), ots::ots_cvt_parse, ots::ots_cvt_serialise,
+    ots::ots_cvt_should_serialise, ots::ots_cvt_free, false },
+  { Tag("fpgm"), ots::ots_fpgm_parse, ots::ots_fpgm_serialise,
+    ots::ots_fpgm_should_serialise, ots::ots_fpgm_free, false },
+  { Tag("prep"), ots::ots_prep_parse, ots::ots_prep_serialise,
+    ots::ots_prep_should_serialise, ots::ots_prep_free, false },
+  { Tag("LTSH"), ots::ots_ltsh_parse, ots::ots_ltsh_serialise,
+    ots::ots_ltsh_should_serialise, ots::ots_ltsh_free, false },
+  { Tag("VORG"), ots::ots_vorg_parse, ots::ots_vorg_serialise,
+    ots::ots_vorg_should_serialise, ots::ots_vorg_free, false },
+  { Tag("kern"), ots::ots_kern_parse, ots::ots_kern_serialise,
+    ots::ots_kern_should_serialise, ots::ots_kern_free, false },
+  // TODO(yusukes): Support GDEF, GPOS, GSUB, mort, base, and jstf tables.
+  { 0, NULL, NULL, NULL, NULL, false },
+};
+
+bool IsValidVersionTag(uint32_t tag) {
+  return tag == Tag("\x00\x01\x00\x00") ||
+         // OpenType fonts with CFF data have 'OTTO' tag.
+         tag == Tag("OTTO") ||
+         // Older Mac fonts might have 'true' or 'typ1' tag.
+         tag == Tag("true") ||
+         tag == Tag("typ1");
+}
+
+bool ProcessGeneric(ots::OpenTypeFile *header, ots::OTSStream *output,
+                    const uint8_t *data, size_t length,
+                    const std::vector<OpenTypeTable>& tables,
+                    ots::Buffer& file);
+
+bool ProcessTTF(ots::OpenTypeFile *header,
+                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();
+  }
+
+  if (!file.ReadTag(&header->version)) {
+    return OTS_FAILURE();
+  }
+  if (!IsValidVersionTag(header->version)) {
+      return OTS_FAILURE();
+  }
+
+  if (!file.ReadU16(&header->num_tables) ||
+      !file.ReadU16(&header->search_range) ||
+      !file.ReadU16(&header->entry_selector) ||
+      !file.ReadU16(&header->range_shift)) {
+    return OTS_FAILURE();
+  }
+
+  // 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 (header->num_tables >= 4096 || header->num_tables < 1) {
+    return OTS_FAILURE();
+  }
+
+  unsigned max_pow2 = 0;
+  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 (header->search_range != expected_search_range) {
+    OTS_WARNING("bad search range");
+    header->search_range = expected_search_range;  // Fix the value.
+  }
+
+  // entry_selector is Log2(maximum power of 2 <= numTables)
+  if (header->entry_selector != max_pow2) {
+    return OTS_FAILURE();
+  }
+
+  // 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 > header->search_range by construction of search_range.
+  const uint32_t expected_range_shift
+      = 16 * header->num_tables - header->search_range;
+  if (header->range_shift != expected_range_shift) {
+    OTS_WARNING("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 < header->num_tables; ++i) {
+    OpenTypeTable table;
+    if (!file.ReadTag(&table.tag) ||
+        !file.ReadU32(&table.chksum) ||
+        !file.ReadU32(&table.offset) ||
+        !file.ReadU32(&table.length)) {
+      return OTS_FAILURE();
+    }
+
+    table.uncompressed_length = table.length;
+    tables.push_back(table);
+  }
+
+  return ProcessGeneric(header, output, data, length, tables, file);
+}
+
+bool ProcessWOFF(ots::OpenTypeFile *header,
+                 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();
+  }
+
+  uint32_t woff_tag;
+  if (!file.ReadTag(&woff_tag)) {
+    return OTS_FAILURE();
+  }
+
+  if (woff_tag != Tag("wOFF")) {
+    return OTS_FAILURE();
+  }
+
+  if (!file.ReadTag(&header->version)) {
+    return OTS_FAILURE();
+  }
+  if (!IsValidVersionTag(header->version)) {
+      return OTS_FAILURE();
+  }
+
+  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();
+  }
+
+  if (!file.ReadU16(&header->num_tables)) {
+    return OTS_FAILURE();
+  }
+
+  uint16_t reserved_value;
+  if (!file.ReadU16(&reserved_value) || reserved_value) {
+    return OTS_FAILURE();
+  }
+
+  // We don't care about these fields of the header:
+  //   uint32_t uncompressed_size;
+  //   uint16_t major_version, minor_version
+  //   uint32_t meta_offset, meta_length, meta_length_orig
+  //   uint32_t priv_offset, priv_length
+  if (!file.Skip(6 * 4 + 2 * 2)) {
+    return OTS_FAILURE();
+  }
+
+  // Next up is the list of tables.
+  std::vector<OpenTypeTable> tables;
+
+  for (unsigned i = 0; i < header->num_tables; ++i) {
+    OpenTypeTable table;
+    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();
+    }
+
+    tables.push_back(table);
+  }
+
+  return ProcessGeneric(header, output, data, length, tables, file);
+}
+
+bool ProcessGeneric(ots::OpenTypeFile *header, 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 < 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 = ntohl(tables[i].tag);
+      const uint32_t prev_tag = ntohl(tables[i - 1].tag);
+      if (this_tag <= prev_tag) {
+        return OTS_FAILURE();
+      }
+    }
+
+    // all tag names must be built from printable ASCII characters
+    if (!CheckTag(tables[i].tag)) {
+      return OTS_FAILURE();
+    }
+
+    // tables must be 4-byte aligned
+    if (tables[i].offset & 3) {
+      return OTS_FAILURE();
+    }
+
+    // and must be within the file
+    if (tables[i].offset < data_offset || tables[i].offset >= length) {
+      return OTS_FAILURE();
+    }
+    // disallow all tables with a zero length
+    if (tables[i].length < 1) {
+      // Note: malayalam.ttf has zero length CVT table...
+      return OTS_FAILURE();
+    }
+    // disallow all tables with a length > 1GB
+    if (tables[i].length > 1024 * 1024 * 1024) {
+      return OTS_FAILURE();
+    }
+    // disallow tables where the uncompressed size is < the compressed size.
+    if (tables[i].uncompressed_length < tables[i].length) {
+      return OTS_FAILURE();
+    }
+    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();
+      }
+      if (uncompressed_sum + tables[i].uncompressed_length < uncompressed_sum) {
+        return OTS_FAILURE();
+      }
+
+      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
+    const uint32_t end_byte = Round4(tables[i].offset + tables[i].length);
+    if (!end_byte || end_byte > length) {
+      return OTS_FAILURE();
+    }
+  }
+
+  // All decompressed tables uncompressed must be <= 30MB.
+  if (uncompressed_sum > 30 * 1024 * 1024) {
+    return OTS_FAILURE();
+  }
+
+  std::map<uint32_t, OpenTypeTable> table_map;
+  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 < header->num_tables; ++i) {
+    overlap_checker.push_back(
+        std::make_pair(tables[i].offset, 1 /* start */));
+    overlap_checker.push_back(
+        std::make_pair(tables[i].offset + tables[i].length, 0 /* end */));
+  }
+  std::sort(overlap_checker.begin(), overlap_checker.end());
+  int overlap_count = 0;
+  for (unsigned i = 0; i < overlap_checker.size(); ++i) {
+    overlap_count += (overlap_checker[i].second ? 1 : -1);
+    if (overlap_count > 1) {
+      return OTS_FAILURE();
+    }
+  }
+
+  Arena arena;
+
+  for (unsigned i = 0; ; ++i) {
+    if (table_parsers[i].parse == NULL) break;
+
+    const std::map<uint32_t, OpenTypeTable>::const_iterator it
+        = table_map.find(table_parsers[i].tag);
+
+    if (it == table_map.end()) {
+      if (table_parsers[i].required) {
+        return OTS_FAILURE();
+      }
+      continue;
+    }
+
+    const uint8_t* table_data;
+    size_t table_length;
+
+    if (it->second.uncompressed_length != it->second.length) {
+      // compressed table. Need to uncompress into memory first.
+      table_length = it->second.uncompressed_length;
+      table_data = arena.Allocate(table_length);
+      uLongf dest_len = table_length;
+      int r = uncompress((Bytef*) table_data, &dest_len,
+                         data + it->second.offset, it->second.length);
+      if (r != Z_OK || dest_len != table_length) {
+        return OTS_FAILURE();
+      }
+    } else {
+      // uncompressed table. We can process directly from memory.
+      table_data = data + it->second.offset;
+      table_length = it->second.length;
+    }
+
+    if (!table_parsers[i].parse(header, table_data, table_length)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  if (header->cff) {
+    // font with PostScript glyph
+    if (header->version != Tag("OTTO")) {
+      return OTS_FAILURE();
+    }
+    if (header->glyf || header->loca) {
+      // mixing outline formats is not recommended
+      return OTS_FAILURE();
+    }
+  } else {
+    if (!header->glyf || !header->loca) {
+      // No TrueType glyph found.
+      // Note: bitmap-only fonts are not supported.
+      return OTS_FAILURE();
+    }
+  }
+
+  unsigned 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++;
+    }
+  }
+
+  unsigned max_pow2 = 0;
+  while (1u << (max_pow2 + 1) <= num_output_tables) {
+    max_pow2++;
+  }
+  const uint16_t output_search_range = (1u << max_pow2) << 4;
+
+  output->ResetChecksum();
+  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();
+  }
+  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();
+  }
+
+  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;
+    out.tag = table_parsers[i].tag;
+    out.offset = output->Tell();
+
+    output->ResetChecksum();
+    if (table_parsers[i].tag == Tag("head")) {
+      head_table_offset = out.offset;
+    }
+    if (!table_parsers[i].serialise(output, header)) {
+      return OTS_FAILURE();
+    }
+
+    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();
+    }
+    out.length = end_offset - out.offset;
+
+    // align tables to four bytes
+    if (!output->Pad((4 - (end_offset & 3)) % 4)) {
+      return OTS_FAILURE();
+    }
+    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(), OutputTable::SortByTag);
+  if (!output->Seek(table_record_offset)) {
+    return OTS_FAILURE();
+  }
+
+  output->ResetChecksum();
+  uint32_t tables_chksum = 0;
+  for (unsigned i = 0; i < out_tables.size(); ++i) {
+    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();
+    }
+    tables_chksum += out_tables[i].chksum;
+  }
+  const uint32_t table_record_chksum = output->chksum();
+
+  // http://www.microsoft.com/typography/otspec/otff.htm
+  const uint32_t file_chksum
+      = offset_table_chksum + tables_chksum + table_record_chksum;
+  const uint32_t chksum_magic = static_cast<uint32_t>(0xb1b0afba) - file_chksum;
+
+  // seek into the 'head' table and write in the checksum magic value
+  if (!head_table_offset) {
+    return OTS_FAILURE();  // not reached.
+  }
+  if (!output->Seek(head_table_offset + 8)) {
+    return OTS_FAILURE();
+  }
+  if (!output->WriteU32(chksum_magic)) {
+    return OTS_FAILURE();
+  }
+
+  if (!output->Seek(end_of_file)) {
+    return OTS_FAILURE();
+  }
+
+  return true;
+}
+
+}  // namespace
+
+namespace ots {
+
+void DisableDebugOutput() {
+  g_debug_output = false;
+}
+
+bool Process(OTSStream *output, const uint8_t *data, size_t length) {
+  OpenTypeFile header;
+  if (length < 4) {
+    return OTS_FAILURE();
+  }
+
+  bool result;
+  if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
+    result = ProcessWOFF(&header, output, data, length);
+  } else {
+    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;
+}
+
+#if !defined(_MSC_VER) && defined(OTS_DEBUG)
+bool Failure(const char *f, int l, const char *fn) {
+  if (g_debug_output) {
+    std::fprintf(stderr, "ERROR at %s:%d (%s)\n", f, l, fn);
+    std::fflush(stderr);
+  }
+  return false;
+}
+
+void Warning(const char *f, int l, const char *format, ...) {
+  if (g_debug_output) {
+    std::fprintf(stderr, "WARNING at %s:%d: ", f, l);
+    std::va_list va;
+    va_start(va, format);
+    std::vfprintf(stderr, format, va);
+    va_end(va);
+    std::fprintf(stderr, "\n");
+    std::fflush(stderr);
+  }
+}
+#endif
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/ots.h
@@ -0,0 +1,194 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_H_
+#define OTS_H_
+
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "opentype-sanitiser.h"
+
+namespace ots {
+
+#if defined(_MSC_VER) || !defined(OTS_DEBUG)
+#define OTS_FAILURE() false
+#else
+#define OTS_FAILURE() ots::Failure(__FILE__, __LINE__, __PRETTY_FUNCTION__)
+bool Failure(const char *f, int l, const char *fn);
+#endif
+
+#if defined(_MSC_VER)
+// MSVC supports C99 style variadic macros.
+#define OTS_WARNING(format, ...)
+#else
+// GCC
+#if defined(OTS_DEBUG)
+#define OTS_WARNING(format, args...) \
+    ots::Warning(__FILE__, __LINE__, format, ##args)
+void Warning(const char *f, int l, const char *format, ...)
+     __attribute__((format(printf, 3, 4)));
+#else
+#define OTS_WARNING(format, args...)
+#endif
+#endif
+
+// Define OTS_NO_TRANSCODE_HINTS (i.e., g++ -DOTS_NO_TRANSCODE_HINTS) if you
+// want to omit TrueType hinting instructions and variables in glyf, fpgm, prep,
+// and cvt tables.
+#if defined(OTS_NO_TRANSCODE_HINTS)
+const bool g_transcode_hints = false;
+#else
+const bool g_transcode_hints = true;
+#endif
+
+// -----------------------------------------------------------------------------
+// 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.
+// -----------------------------------------------------------------------------
+class Buffer {
+ public:
+  Buffer(const uint8_t *buffer, size_t len)
+      : buffer_(buffer),
+        length_(len),
+        offset_(0) { }
+
+  bool Skip(size_t n_bytes) {
+    return Read(NULL, n_bytes);
+  }
+
+  bool Read(uint8_t *buffer, size_t n_bytes) {
+    if (n_bytes > 1024 * 1024 * 1024) {
+      return OTS_FAILURE();
+    }
+    if ((offset_ + n_bytes > length_) ||
+        (offset_ > length_ - n_bytes)) {
+      return OTS_FAILURE();
+    }
+    if (buffer) {
+      std::memcpy(buffer, buffer_ + offset_, n_bytes);
+    }
+    offset_ += n_bytes;
+    return true;
+  }
+
+  inline bool ReadU8(uint8_t *value) {
+    if (offset_ + 1 > length_) {
+      return OTS_FAILURE();
+    }
+    *value = buffer_[offset_];
+    ++offset_;
+    return true;
+  }
+
+  bool ReadU16(uint16_t *value) {
+    if (offset_ + 2 > length_) {
+      return OTS_FAILURE();
+    }
+    std::memcpy(value, buffer_ + offset_, sizeof(uint16_t));
+    *value = ntohs(*value);
+    offset_ += 2;
+    return true;
+  }
+
+  bool ReadS16(int16_t *value) {
+    return ReadU16(reinterpret_cast<uint16_t*>(value));
+  }
+
+  bool ReadU32(uint32_t *value) {
+    if (offset_ + 4 > length_) {
+      return OTS_FAILURE();
+    }
+    std::memcpy(value, buffer_ + offset_, sizeof(uint32_t));
+    *value = ntohl(*value);
+    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;
+  }
+
+  const uint8_t *buffer() const { return buffer_; }
+  size_t offset() const { return offset_; }
+  size_t length() const { return length_; }
+
+  void set_offset(size_t newoffset) { offset_ = newoffset; }
+
+ private:
+  const uint8_t * const buffer_;
+  const size_t length_;
+  size_t offset_;
+};
+
+#define FOR_EACH_TABLE_TYPE \
+  F(cff, CFF) \
+  F(cmap, CMAP) \
+  F(cvt, CVT) \
+  F(fpgm, FPGM) \
+  F(gasp, GASP) \
+  F(glyf, GLYF) \
+  F(hdmx, HDMX) \
+  F(head, HEAD) \
+  F(hhea, HHEA) \
+  F(hmtx, HMTX) \
+  F(kern, KERN) \
+  F(loca, LOCA) \
+  F(ltsh, LTSH) \
+  F(maxp, MAXP) \
+  F(name, NAME) \
+  F(os2, OS2) \
+  F(post, POST) \
+  F(prep, PREP) \
+  F(vdmx, VDMX) \
+  F(vorg, VORG)
+
+#define F(name, capname) struct OpenType##capname;
+FOR_EACH_TABLE_TYPE
+#undef F
+
+struct OpenTypeFile {
+  OpenTypeFile() {
+#define F(name, capname) name = NULL;
+    FOR_EACH_TABLE_TYPE
+#undef F
+  }
+
+  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;
+FOR_EACH_TABLE_TYPE
+#undef F
+};
+
+}  // namespace ots
+
+#endif  // OTS_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/post.cc
@@ -0,0 +1,181 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "post.h"
+
+#include "maxp.h"
+
+// post - PostScript
+// http://www.microsoft.com/opentype/otspec/post.htm
+
+namespace ots {
+
+bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+
+  OpenTypePOST *post = new OpenTypePOST;
+  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();
+  }
+
+  if (post->underline_thickness < 0) {
+    post->underline_thickness = 1;
+  }
+
+  if (post->version == 0x00010000) {
+    return true;
+  } else if (post->version == 0x00030000) {
+    return true;
+  } else if (post->version != 0x00020000) {
+    // 0x00025000 is deprecated. We don't accept it.
+    return OTS_FAILURE();
+  }
+
+  // We have a version 2 table with a list of Pascal strings at the end
+
+  // We don't care about the memory usage fields. We'll set all these to zero
+  // when serialising
+  if (!table.Skip(16)) {
+    return OTS_FAILURE();
+  }
+
+  uint16_t num_glyphs = 0;
+  if (!table.ReadU16(&num_glyphs)) {
+    return OTS_FAILURE();
+  }
+
+  if (!file->maxp) {
+    return OTS_FAILURE();
+  }
+
+  if (num_glyphs == 0) {
+    if (file->maxp->num_glyphs > 258) {
+      return OTS_FAILURE();
+    }
+    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 != file->maxp->num_glyphs) {
+    // Note: Fixedsys500c.ttf seems to have inconsistent num_glyphs values.
+    return OTS_FAILURE();
+  }
+
+  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();
+    }
+    if (post->glyph_name_index[i] >= 32768) {
+      // Note: droid_arialuni.ttf fails this test.
+      return OTS_FAILURE();  // reserved area.
+    }
+  }
+
+  // Now we have an array of Pascal strings. We have to check that they are all
+  // valid and read them in.
+  const size_t strings_offset = table.offset();
+  const uint8_t *strings = data + strings_offset;
+  const uint8_t *strings_end = data + length;
+
+  for (;;) {
+    if (strings == strings_end) break;
+    const unsigned string_length = *strings;
+    if (strings + 1 + string_length > strings_end) {
+      return OTS_FAILURE();
+    }
+    if (std::memchr(strings + 1, '\0', string_length)) {
+      return OTS_FAILURE();
+    }
+    post->names.push_back(
+        std::string(reinterpret_cast<const char*>(strings + 1), string_length));
+    strings += 1 + string_length;
+  }
+  const unsigned num_strings = post->names.size();
+
+  // check that all the references are within bounds
+  for (unsigned i = 0; i < num_glyphs; ++i) {
+    unsigned offset = post->glyph_name_index[i];
+    if (offset < 258) {
+      continue;
+    }
+
+    offset -= 258;
+    if (offset >= num_strings) {
+      return OTS_FAILURE();
+    }
+  }
+
+  return true;
+}
+
+bool ots_post_should_serialise(OpenTypeFile *file) {
+  return file->post;
+}
+
+bool ots_post_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypePOST *post = file->post;
+
+  // OpenType with CFF glyphs must have v3 post table.
+  if (file->post && file->cff && file->post->version != 0x00030000) {
+    return OTS_FAILURE();
+  }
+
+  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) ||
+      !out->WriteU32(0) ||
+      !out->WriteU32(0) ||
+      !out->WriteU32(0) ||
+      !out->WriteU32(0)) {
+    return OTS_FAILURE();
+  }
+
+  if (post->version != 0x00020000) {
+    return true;  // v1.0 and v3.0 does not have glyph names.
+  }
+
+  if (!out->WriteU16(post->glyph_name_index.size())) {
+    return OTS_FAILURE();
+  }
+
+  for (unsigned i = 0; i < post->glyph_name_index.size(); ++i) {
+    if (!out->WriteU16(post->glyph_name_index[i])) {
+      return OTS_FAILURE();
+    }
+  }
+
+  // Now we just have to write out the strings in the correct order
+  for (unsigned i = 0; i < post->names.size(); ++i) {
+    const std::string& s = post->names[i];
+    const uint8_t string_length = s.size();
+    if (!out->Write(&string_length, 1)) {
+      return OTS_FAILURE();
+    }
+    // Some ttf fonts (e.g., frank.ttf on Windows Vista) have zero-length name.
+    // We allow them.
+    if (string_length > 0 && !out->Write(s.data(), string_length)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  return true;
+}
+
+void ots_post_free(OpenTypeFile *file) {
+  delete file->post;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/post.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_POST_H_
+#define OTS_POST_H_
+
+#include "ots.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace ots {
+
+struct OpenTypePOST {
+  uint32_t version;
+  uint32_t italic_angle;
+  int16_t underline;
+  int16_t underline_thickness;
+  uint32_t is_fixed_pitch;
+
+  std::vector<uint16_t> glyph_name_index;
+  std::vector<std::string> names;
+};
+
+}  // namespace ots
+
+#endif  // OTS_POST_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/prep.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "prep.h"
+
+// prep - Control Value Program
+// http://www.microsoft.com/opentype/otspec/prep.htm
+
+namespace ots {
+
+bool ots_prep_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+
+  OpenTypePREP *prep = new OpenTypePREP;
+  file->prep = prep;
+
+  if (length >= 128 * 1024u) {
+    return OTS_FAILURE();  // almost all prep tables are less than 9k bytes.
+  }
+
+  if (!table.Skip(length)) {
+    return OTS_FAILURE();
+  }
+
+  prep->data = data;
+  prep->length = length;
+  return true;
+}
+
+bool ots_prep_should_serialise(OpenTypeFile *file) {
+  if (!file->glyf) return false;  // this table is not for CFF fonts.
+  return g_transcode_hints && file->prep;
+}
+
+bool ots_prep_serialise(OTSStream *out, OpenTypeFile *file) {
+  const OpenTypePREP *prep = file->prep;
+
+  if (!out->Write(prep->data, prep->length)) {
+    return OTS_FAILURE();
+  }
+
+  return true;
+}
+
+void ots_prep_free(OpenTypeFile *file) {
+  delete file->prep;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/prep.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_PREP_H_
+#define OTS_PREP_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypePREP {
+  const uint8_t *data;
+  uint32_t length;
+};
+
+}  // namespace ots
+
+#endif  // OTS_PREP_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/vdmx.cc
@@ -0,0 +1,177 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "vdmx.h"
+
+// VDMX - Vertical Device Metrics
+// http://www.microsoft.com/opentype/otspec/vdmx.htm
+
+#define DROP_THIS_TABLE \
+  do { delete file->vdmx; file->vdmx = 0; } while (0)
+
+namespace ots {
+
+bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+  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();
+  }
+
+  if (vdmx->version > 1) {
+    OTS_WARNING("bad version: %u", vdmx->version);
+    DROP_THIS_TABLE;
+    return true;  // continue transcoding
+  }
+
+  vdmx->rat_ranges.reserve(vdmx->num_ratios);
+  for (unsigned i = 0; i < vdmx->num_ratios; ++i) {
+    OpenTypeVDMXRatioRecord rec;
+
+    if (!table.ReadU8(&rec.charset) ||
+        !table.ReadU8(&rec.x_ratio) ||
+        !table.ReadU8(&rec.y_start_ratio) ||
+        !table.ReadU8(&rec.y_end_ratio)) {
+      return OTS_FAILURE();
+    }
+
+    if (rec.charset > 1) {
+      OTS_WARNING("bad charset: %u", rec.charset);
+      DROP_THIS_TABLE;
+      return true;
+    }
+
+    if (rec.y_start_ratio > rec.y_end_ratio) {
+      OTS_WARNING("bad y ratio");
+      DROP_THIS_TABLE;
+      return true;
+    }
+
+    // All values set to zero signal the default grouping to use;
+    // if present, this must be the last Ratio group in the table.
+    if ((i < vdmx->num_ratios - 1u) &&
+        (rec.x_ratio == 0) &&
+        (rec.y_start_ratio == 0) &&
+        (rec.y_end_ratio == 0)) {
+      // workaround for fonts which have 2 or more {0, 0, 0} terminators.
+      OTS_WARNING("superfluous terminator found");
+      DROP_THIS_TABLE;
+      return true;
+    }
+
+    vdmx->rat_ranges.push_back(rec);
+  }
+
+  vdmx->offsets.reserve(vdmx->num_ratios);
+  const size_t current_offset = table.offset();
+  // current_offset is less than (2 bytes * 3) + (4 bytes * USHRT_MAX) = 256k.
+  for (unsigned i = 0; i < vdmx->num_ratios; ++i) {
+    uint16_t offset;
+    if (!table.ReadU16(&offset)) {
+      return OTS_FAILURE();
+    }
+    if (current_offset + offset >= length) {  // thus doesn't overflow.
+      return OTS_FAILURE();
+    }
+
+    vdmx->offsets.push_back(offset);
+  }
+
+  vdmx->groups.reserve(vdmx->num_recs);
+  for (unsigned i = 0; i < vdmx->num_recs; ++i) {
+    OpenTypeVDMXGroup group;
+    if (!table.ReadU16(&group.recs) ||
+        !table.ReadU8(&group.startsz) ||
+        !table.ReadU8(&group.endsz)) {
+      return OTS_FAILURE();
+    }
+    group.entries.reserve(group.recs);
+    for (unsigned j = 0; j < group.recs; ++j) {
+      OpenTypeVDMXVTable vt;
+      if (!table.ReadU16(&vt.y_pel_height) ||
+          !table.ReadS16(&vt.y_max) ||
+          !table.ReadS16(&vt.y_min)) {
+        return OTS_FAILURE();
+      }
+      if (vt.y_max < vt.y_min) {
+        OTS_WARNING("bad y min/max");
+        DROP_THIS_TABLE;
+        return true;
+      }
+
+      // This table must appear in sorted order (sorted by yPelHeight),
+      // but need not be continuous.
+      if ((j != 0) && (group.entries[j - 1].y_pel_height >= vt.y_pel_height)) {
+        OTS_WARNING("the table is not sorted");
+        DROP_THIS_TABLE;
+        return true;
+      }
+
+      group.entries.push_back(vt);
+    }
+    vdmx->groups.push_back(group);
+  }
+
+  return true;
+}
+
+bool ots_vdmx_should_serialise(OpenTypeFile *file) {
+  if (!file->glyf) return false;  // this table is not for CFF fonts.
+  return file->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();
+  }
+
+  for (unsigned i = 0; i < vdmx->rat_ranges.size(); ++i) {
+    const OpenTypeVDMXRatioRecord& rec = vdmx->rat_ranges[i];
+    if (!out->Write(&rec.charset, 1) ||
+        !out->Write(&rec.x_ratio, 1) ||
+        !out->Write(&rec.y_start_ratio, 1) ||
+        !out->Write(&rec.y_end_ratio, 1)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  for (unsigned i = 0; i < vdmx->offsets.size(); ++i) {
+    if (!out->WriteU16(vdmx->offsets[i])) {
+      return OTS_FAILURE();
+    }
+  }
+
+  for (unsigned i = 0; i < vdmx->groups.size(); ++i) {
+    const OpenTypeVDMXGroup& group = vdmx->groups[i];
+    if (!out->WriteU16(group.recs) ||
+        !out->Write(&group.startsz, 1) ||
+        !out->Write(&group.endsz, 1)) {
+      return OTS_FAILURE();
+    }
+    for (unsigned j = 0; j < group.entries.size(); ++j) {
+      const OpenTypeVDMXVTable& vt = group.entries[j];
+      if (!out->WriteU16(vt.y_pel_height) ||
+          !out->WriteS16(vt.y_max) ||
+          !out->WriteS16(vt.y_min)) {
+        return OTS_FAILURE();
+      }
+    }
+  }
+
+  return true;
+}
+
+void ots_vdmx_free(OpenTypeFile *file) {
+  delete file->vdmx;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/vdmx.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_VDMX_H_
+#define OTS_VDMX_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeVDMXRatioRecord {
+  uint8_t charset;
+  uint8_t x_ratio;
+  uint8_t y_start_ratio;
+  uint8_t y_end_ratio;
+};
+
+struct OpenTypeVDMXVTable {
+  uint16_t y_pel_height;
+  int16_t y_max;
+  int16_t y_min;
+};
+
+struct OpenTypeVDMXGroup {
+  uint16_t recs;
+  uint8_t startsz;
+  uint8_t endsz;
+  std::vector<OpenTypeVDMXVTable> entries;
+};
+
+struct OpenTypeVDMX {
+  uint16_t version;
+  uint16_t num_recs;
+  uint16_t num_ratios;
+  std::vector<OpenTypeVDMXRatioRecord> rat_ranges;
+  std::vector<uint16_t> offsets;
+  std::vector<OpenTypeVDMXGroup> groups;
+};
+
+}  // namespace ots
+
+#endif  // OTS_VDMX_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/vorg.cc
@@ -0,0 +1,97 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "vorg.h"
+
+#include <vector>
+
+// VORG - Vertical Origin Table
+// http://www.microsoft.com/opentype/otspec/vorg.htm
+
+#define DROP_THIS_TABLE \
+  do { delete file->vorg; file->vorg = 0; } while (0)
+
+namespace ots {
+
+bool ots_vorg_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+  Buffer table(data, length);
+  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();
+  }
+  if (vorg->major_version != 1) {
+    OTS_WARNING("bad major version: %u", vorg->major_version);
+    DROP_THIS_TABLE;
+    return true;
+  }
+  if (vorg->minor_version != 0) {
+    OTS_WARNING("bad minor version: %u", vorg->minor_version);
+    DROP_THIS_TABLE;
+    return true;
+  }
+
+  // num_recs might be zero (e.g., DFHSMinchoPro5-W3-Demo.otf).
+  if (!num_recs) {
+    return true;
+  }
+
+  uint16_t last_glyph_index = 0;
+  vorg->metrics.reserve(num_recs);
+  for (unsigned i = 0; i < num_recs; ++i) {
+    OpenTypeVORGMetrics rec;
+
+    if (!table.ReadU16(&rec.glyph_index) ||
+        !table.ReadS16(&rec.vert_origin_y)) {
+      return OTS_FAILURE();
+    }
+    if ((i != 0) && (rec.glyph_index <= last_glyph_index)) {
+      OTS_WARNING("the table is not sorted");
+      DROP_THIS_TABLE;
+      return true;
+    }
+    last_glyph_index = rec.glyph_index;
+
+    vorg->metrics.push_back(rec);
+  }
+
+  return true;
+}
+
+bool ots_vorg_should_serialise(OpenTypeFile *file) {
+  if (!file->cff) return false;  // this table is not for fonts with TT glyphs.
+  return file->vorg;
+}
+
+bool ots_vorg_serialise(OTSStream *out, OpenTypeFile *file) {
+  OpenTypeVORG * const vorg = file->vorg;
+
+  if (!out->WriteU16(vorg->major_version) ||
+      !out->WriteU16(vorg->minor_version) ||
+      !out->WriteS16(vorg->default_vert_origin_y) ||
+      !out->WriteU16(vorg->metrics.size())) {
+    return OTS_FAILURE();
+  }
+
+  for (unsigned i = 0; i < vorg->metrics.size(); ++i) {
+    const OpenTypeVORGMetrics& rec = vorg->metrics[i];
+    if (!out->WriteU16(rec.glyph_index) ||
+        !out->WriteS16(rec.vert_origin_y)) {
+      return OTS_FAILURE();
+    }
+  }
+
+  return true;
+}
+
+void ots_vorg_free(OpenTypeFile *file) {
+  delete file->vorg;
+}
+
+}  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/vorg.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_VORG_H_
+#define OTS_VORG_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeVORGMetrics {
+  uint16_t glyph_index;
+  int16_t vert_origin_y;
+};
+
+struct OpenTypeVORG {
+  uint16_t major_version;
+  uint16_t minor_version;
+  int16_t default_vert_origin_y;
+  std::vector<OpenTypeVORGMetrics> metrics;
+};
+
+}  // namespace ots
+
+#endif  // OTS_VORG_H_