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.0
bugs527276
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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_