Bug 1098497 - Update OTS to latest upstream (at commit 7091a232a10a741591ff25158c98ca3f0c319cf9) to pick up recent fixes. r=jdaggett
authorJonathan Kew <jkew@mozilla.com>
Mon, 17 Nov 2014 15:24:05 +0000
changeset 216020 47f88e6ae34c7d62f30231ca5637c95360cb491a
parent 216019 7f6a55544bb30db864c232c62108c126448b636c
child 216021 c007f1136acd6644e743b1e5ec483a07d45224ed
child 216068 2d8a4c388808f4175d835e645025355950fc1120
push id51914
push userjkew@mozilla.com
push dateMon, 17 Nov 2014 15:24:23 +0000
treeherdermozilla-inbound@47f88e6ae34c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs1098497
milestone36.0a1
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 1098497 - Update OTS to latest upstream (at commit 7091a232a10a741591ff25158c98ca3f0c319cf9) to pick up recent fixes. r=jdaggett
gfx/ots/README.mozilla
gfx/ots/include/opentype-sanitiser.h
gfx/ots/ots-brotli-path.patch
gfx/ots/ots-visibility.patch
gfx/ots/src/gasp.cc
gfx/ots/src/gdef.cc
gfx/ots/src/gpos.cc
gfx/ots/src/gsub.cc
gfx/ots/src/hdmx.cc
gfx/ots/src/kern.cc
gfx/ots/src/ltsh.cc
gfx/ots/src/math.cc
gfx/ots/src/ots.cc
gfx/ots/src/vdmx.cc
gfx/ots/src/vorg.cc
gfx/ots/src/woff2.cc
gfx/ots/src/woff2.h
gfx/ots/sync.sh
--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,12 +1,12 @@
 This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
 
 Our reference repository is https://github.com/khaledhosny/ots/.
 
-Current revision: c24a839b1c66c4de09e58fabaacb82bf3bd692a4
+Current revision: 7091a232a10a741591ff25158c98ca3f0c319cf9
 
 Upstream files included: LICENSE, src/, include/
 
 Additional files: README.mozilla, src/moz.build
 
 Additional patch: ots-visibility.patch (bug 711079).
 Additional patch: ots-brotli-path.patch (bug 1064737).
--- a/gfx/ots/include/opentype-sanitiser.h
+++ b/gfx/ots/include/opentype-sanitiser.h
@@ -210,17 +210,17 @@ enum TableAction {
   TABLE_ACTION_SANITIZE, // Sanitize the table, potentially droping it
   TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
   TABLE_ACTION_DROP      // Drop the table
 };
 
 class OTS_API OTSContext {
   public:
     OTSContext() {}
-    ~OTSContext() {}
+    virtual ~OTSContext() {}
 
     // Process a given OpenType file and write out a sanitised version
     //   output: a pointer to an object implementing the OTSStream interface. The
     //     sanitisied output will be written to this. In the even of a failure,
     //     partial output may have been written.
     //   input: the OpenType file
     //   length: the size, in bytes, of |input|
     //   context: optional context that holds various OTS settings like user callbacks
deleted file mode 100644
--- a/gfx/ots/ots-brotli-path.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-diff --git a/gfx/ots/src/woff2.cc b/gfx/ots/src/woff2.cc
---- a/gfx/ots/src/woff2.cc
-+++ b/gfx/ots/src/woff2.cc
-@@ -6,17 +6,17 @@
- // Condensed file format.
- 
- #include <cassert>
- #include <cstdlib>
- #include <vector>
- 
- #include <zlib.h>
- 
--#include "third_party/brotli/src/brotli/dec/decode.h"
-+#include "decode.h"
- 
- #include "opentype-sanitiser.h"
- #include "ots-memory-stream.h"
- #include "ots.h"
- #include "woff2.h"
- 
- namespace {
- 
--- a/gfx/ots/ots-visibility.patch
+++ b/gfx/ots/ots-visibility.patch
@@ -45,17 +45,17 @@ diff --git a/gfx/ots/include/opentype-sa
    TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
    TABLE_ACTION_DROP      // Drop the table
  };
  
 -class OTSContext {
 +class OTS_API OTSContext {
    public:
      OTSContext() {}
-     ~OTSContext() {}
+     virtual ~OTSContext() {}
  
      // Process a given OpenType file and write out a sanitised version
      //   output: a pointer to an object implementing the OTSStream interface. The
      //     sanitisied output will be written to this. In the even of a failure,
      //     partial output may have been written.
 @@ -222,13 +242,13 @@ class OTSContext {
  // For backward compatibility - remove once Chrome switches over to the new API.
  bool Process(OTSStream *output, const uint8_t *input, size_t length);
--- a/gfx/ots/src/gasp.cc
+++ b/gfx/ots/src/gasp.cc
@@ -6,20 +6,20 @@
 
 // gasp - Grid-fitting And Scan-conversion Procedure
 // http://www.microsoft.com/typography/otspec/gasp.htm
 
 #define TABLE_NAME "gasp"
 
 #define DROP_THIS_TABLE(...) \
   do { \
+    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
+    OTS_FAILURE_MSG("Table discarded"); \
     delete file->gasp; \
     file->gasp = 0; \
-    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
-    OTS_FAILURE_MSG("Table discarded"); \
   } 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;
--- a/gfx/ots/src/gdef.cc
+++ b/gfx/ots/src/gdef.cc
@@ -226,19 +226,19 @@ bool ParseMarkGlyphSetsDefTable(ots::Ope
   file->gdef->num_mark_glyph_sets = mark_set_count;
   return true;
 }
 
 }  // namespace
 
 #define DROP_THIS_TABLE(msg_) \
   do { \
+    OTS_FAILURE_MSG(msg_ ", table discarded"); \
     file->gdef->data = 0; \
     file->gdef->length = 0; \
-    OTS_FAILURE_MSG(msg_ ", table discarded"); \
   } while (0)
 
 namespace ots {
 
 bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   // Grab the number of glyphs in the file from the maxp table to check
   // GlyphIDs in GDEF table.
   if (!file->maxp) {
--- a/gfx/ots/src/gpos.cc
+++ b/gfx/ots/src/gpos.cc
@@ -672,19 +672,19 @@ bool ParseExtensionPositioning(const ots
   return ots::ParseExtensionSubtable(file, data, length,
                                      &kGposLookupSubtableParser);
 }
 
 }  // namespace
 
 #define DROP_THIS_TABLE(msg_) \
   do { \
+    OTS_FAILURE_MSG(msg_ ", table discarded"); \
     file->gpos->data = 0; \
     file->gpos->length = 0; \
-    OTS_FAILURE_MSG(msg_ ", table discarded"); \
   } while (0)
 
 namespace ots {
 
 // As far as I checked, following fonts contain invalid GPOS table and
 // OTS will drop their GPOS table.
 //
 // # invalid delta format in device table
--- a/gfx/ots/src/gsub.cc
+++ b/gfx/ots/src/gsub.cc
@@ -525,19 +525,19 @@ bool ParseReverseChainingContextSingleSu
 
   return true;
 }
 
 }  // namespace
 
 #define DROP_THIS_TABLE(msg_) \
   do { \
+    OTS_FAILURE_MSG(msg_ ", table discarded"); \
     file->gsub->data = 0; \
     file->gsub->length = 0; \
-    OTS_FAILURE_MSG(msg_ ", table discarded"); \
   } while (0)
 
 namespace ots {
 
 // As far as I checked, following fonts contain invalid values in GSUB table.
 // OTS will drop their GSUB table.
 //
 // # too large substitute (value is 0xFFFF)
--- a/gfx/ots/src/hdmx.cc
+++ b/gfx/ots/src/hdmx.cc
@@ -8,20 +8,20 @@
 
 // hdmx - Horizontal Device Metrics
 // http://www.microsoft.com/typography/otspec/hdmx.htm
 
 #define TABLE_NAME "hdmx"
 
 #define DROP_THIS_TABLE(...) \
   do { \
+    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
+    OTS_FAILURE_MSG("Table discarded"); \
     delete file->hdmx; \
     file->hdmx = 0; \
-    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
-    OTS_FAILURE_MSG("Table discarded"); \
   } 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;
--- a/gfx/ots/src/kern.cc
+++ b/gfx/ots/src/kern.cc
@@ -6,19 +6,19 @@
 
 // kern - Kerning
 // http://www.microsoft.com/typography/otspec/kern.htm
 
 #define TABLE_NAME "kern"
 
 #define DROP_THIS_TABLE(msg_) \
   do { \
+    OTS_FAILURE_MSG(msg_ ", table discarded"); \
     delete file->kern; \
     file->kern = 0; \
-    OTS_FAILURE_MSG(msg_ ", table discarded"); \
   } 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;
--- a/gfx/ots/src/ltsh.cc
+++ b/gfx/ots/src/ltsh.cc
@@ -8,20 +8,20 @@
 
 // LTSH - Linear Threshold
 // http://www.microsoft.com/typography/otspec/ltsh.htm
 
 #define TABLE_NAME "LTSH"
 
 #define DROP_THIS_TABLE(...) \
   do { \
+    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
+    OTS_FAILURE_MSG("Table discarded"); \
     delete file->ltsh; \
     file->ltsh = 0; \
-    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
-    OTS_FAILURE_MSG("Table discarded"); \
   } while (0)
 
 namespace ots {
 
 bool ots_ltsh_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   Buffer table(data, length);
 
   if (!file->maxp) {
--- a/gfx/ots/src/math.cc
+++ b/gfx/ots/src/math.cc
@@ -513,19 +513,19 @@ bool ParseMathVariantsTable(const ots::O
 
   return true;
 }
 
 }  // namespace
 
 #define DROP_THIS_TABLE(msg_) \
   do { \
+    OTS_FAILURE_MSG(msg_ ", table discarded"); \
     file->math->data = 0; \
     file->math->length = 0; \
-    OTS_FAILURE_MSG(msg_ ", table discarded"); \
   } while (0)
 
 namespace ots {
 
 bool ots_math_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   // Grab the number of glyphs in the file from the maxp table to check
   // GlyphIDs in MATH table.
   if (!file->maxp) {
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -404,17 +404,17 @@ bool ProcessWOFF2(ots::OpenTypeFile *hea
     return OTS_FAILURE();
   }
   // decompressed font must be <= 30MB
   if (decompressed_size > 30 * 1024 * 1024) {
     return OTS_FAILURE();
   }
 
   std::vector<uint8_t> decompressed_buffer(decompressed_size);
-  if (!ots::ConvertWOFF2ToTTF(&decompressed_buffer[0], decompressed_size,
+  if (!ots::ConvertWOFF2ToTTF(header, &decompressed_buffer[0], decompressed_size,
                               data, length)) {
     return OTS_FAILURE();
   }
   return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size);
 }
 #endif
 
 ots::TableAction GetTableAction(ots::OpenTypeFile *header, uint32_t tag) {
--- a/gfx/ots/src/vdmx.cc
+++ b/gfx/ots/src/vdmx.cc
@@ -6,20 +6,20 @@
 
 // VDMX - Vertical Device Metrics
 // http://www.microsoft.com/typography/otspec/vdmx.htm
 
 #define TABLE_NAME "VDMX"
 
 #define DROP_THIS_TABLE(...) \
   do { \
+    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
+    OTS_FAILURE_MSG("Table discarded"); \
     delete file->vdmx; \
     file->vdmx = 0; \
-    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
-    OTS_FAILURE_MSG("Table discarded"); \
   } 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;
--- a/gfx/ots/src/vorg.cc
+++ b/gfx/ots/src/vorg.cc
@@ -8,20 +8,20 @@
 
 // VORG - Vertical Origin Table
 // http://www.microsoft.com/typography/otspec/vorg.htm
 
 #define TABLE_NAME "VORG"
 
 #define DROP_THIS_TABLE(...) \
   do { \
+    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
+    OTS_FAILURE_MSG("Table discarded"); \
     delete file->vorg; \
     file->vorg = 0; \
-    OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
-    OTS_FAILURE_MSG("Table discarded"); \
   } 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;
--- a/gfx/ots/src/woff2.cc
+++ b/gfx/ots/src/woff2.cc
@@ -4,25 +4,25 @@
 
 // This is the implementation of decompression of the proposed WOFF Ultra
 // Condensed file format.
 
 #include <cassert>
 #include <cstdlib>
 #include <vector>
 
-#include <zlib.h>
-
 #include "decode.h"
 
 #include "opentype-sanitiser.h"
 #include "ots-memory-stream.h"
 #include "ots.h"
 #include "woff2.h"
 
+#define TABLE_NAME "WOFF2"
+
 namespace {
 
 // simple glyph flags
 const uint8_t kGlyfOnCurve = 1 << 0;
 const uint8_t kGlyfXShort = 1 << 1;
 const uint8_t kGlyfYShort = 1 << 2;
 const uint8_t kGlyfRepeat = 1 << 3;
 const uint8_t kGlyfThisXIsSame = 1 << 4;
@@ -41,25 +41,18 @@ const size_t kSfntEntrySize = 16;
 const size_t kCheckSumAdjustmentOffset = 8;
 
 const size_t kEndPtsOfContoursOffset = 10;
 const size_t kCompositeGlyphBegin = 10;
 
 // Note that the byte order is big-endian, not the same as ots.cc
 #define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d)
 
-const unsigned int kWoff2FlagsContinueStream = 1 << 4;
 const unsigned int kWoff2FlagsTransform = 1 << 5;
 
-// Compression type values common to both short and long formats
-const uint32_t kCompressionTypeMask = 0xf;
-const uint32_t kCompressionTypeNone = 0;
-const uint32_t kCompressionTypeGzip = 1;
-const uint32_t kCompressionTypeBrotli = 2;
-
 const uint32_t kKnownTags[] = {
   TAG('c', 'm', 'a', 'p'),  // 0
   TAG('h', 'e', 'a', 'd'),  // 1
   TAG('h', 'h', 'e', 'a'),  // 2
   TAG('h', 'm', 't', 'x'),  // 3
   TAG('m', 'a', 'x', 'p'),  // 4
   TAG('n', 'a', 'm', 'e'),  // 5
   TAG('O', 'S', '/', '2'),  // 6
@@ -125,29 +118,25 @@ struct Point {
   int16_t x;
   int16_t y;
   bool on_curve;
 };
 
 struct Table {
   uint32_t tag;
   uint32_t flags;
-  uint32_t src_offset;
-  uint32_t src_length;
 
   uint32_t transform_length;
 
   uint32_t dst_offset;
   uint32_t dst_length;
 
   Table()
       : tag(0),
         flags(0),
-        src_offset(0),
-        src_length(0),
         transform_length(0),
         dst_offset(0),
         dst_length(0) {}
 };
 
 // Based on section 6.1.1 of MicroType Express draft spec
 bool Read255UShort(ots::Buffer* buf, uint16_t* value) {
   static const uint8_t kWordCode = 253;
@@ -770,81 +759,67 @@ bool FixChecksums(const std::vector<Tabl
   file_checksum += ComputeChecksum(dst,
       kSfntHeaderSize + kSfntEntrySize * n_tables);
   uint32_t checksum_adjustment = 0xb1b0afba - file_checksum;
   StoreU32(dst, adjustment_offset, checksum_adjustment);
   return true;
 }
 
 bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
-    const uint8_t* src_buf, size_t src_size, uint32_t compression_type) {
-  if (compression_type == kCompressionTypeGzip) {
-    uLongf uncompressed_length = dst_size;
-    int r = uncompress(reinterpret_cast<Bytef *>(dst_buf), &uncompressed_length,
-        src_buf, src_size);
-    if (r != Z_OK || uncompressed_length != dst_size) {
-      return OTS_FAILURE();
-    }
-    return true;
-  } else if (compression_type == kCompressionTypeBrotli) {
-    size_t uncompressed_size = dst_size;
-    int ok = BrotliDecompressBuffer(src_size, src_buf,
-                                    &uncompressed_size, dst_buf);
-    if (!ok || uncompressed_size != dst_size) {
-      return OTS_FAILURE();
-    }
-    return true;
+    const uint8_t* src_buf, size_t src_size) {
+  size_t uncompressed_size = dst_size;
+  int ok = BrotliDecompressBuffer(src_size, src_buf,
+                                  &uncompressed_size, dst_buf);
+  if (!ok || uncompressed_size != dst_size) {
+    return OTS_FAILURE();
   }
-  // Unknown compression type
-  return OTS_FAILURE();
+  return true;
 }
 
-bool ReadShortDirectory(ots::Buffer* file, std::vector<Table>* tables,
+bool ReadShortDirectory(ots::OpenTypeFile* file,
+    ots::Buffer* buffer, std::vector<Table>* tables,
     size_t num_tables) {
   for (size_t i = 0; i < num_tables; ++i) {
     Table* table = &tables->at(i);
     uint8_t flag_byte;
-    if (!file->ReadU8(&flag_byte)) {
-      return OTS_FAILURE();
+    if (!buffer->ReadU8(&flag_byte)) {
+      return OTS_FAILURE_MSG("Failed to read the flags of table directory entry %d", i);
     }
     uint32_t tag;
     if ((flag_byte & 0x3f) == 0x3f) {
-      if (!file->ReadU32(&tag)) {
-        return OTS_FAILURE();
+      if (!buffer->ReadU32(&tag)) {
+        return OTS_FAILURE_MSG("Failed to read the tag of table directory entry %d", i);
       }
     } else {
       tag = kKnownTags[flag_byte & 0x3f];
     }
     // Bits 6 and 7 are reserved and must be 0.
     if ((flag_byte & 0xc0) != 0) {
-      return OTS_FAILURE();
+      return OTS_FAILURE_MSG("Bits 6 and 7 are not 0 for table directory entry %d", i);
     }
-    uint32_t flags = kCompressionTypeBrotli;
-    if (i > 0) {
-      flags |= kWoff2FlagsContinueStream;
-    }
+    uint32_t flags = 0;
     // Always transform the glyf and loca tables
     if (tag == TAG('g', 'l', 'y', 'f') ||
         tag == TAG('l', 'o', 'c', 'a')) {
       flags |= kWoff2FlagsTransform;
     }
     uint32_t dst_length;
-    if (!ReadBase128(file, &dst_length)) {
-      return OTS_FAILURE();
+    if (!ReadBase128(buffer, &dst_length)) {
+      return OTS_FAILURE_MSG("Failed to read \"origLength\" for table %4.4s", (char*)&tag);
     }
     uint32_t transform_length = dst_length;
     if ((flags & kWoff2FlagsTransform) != 0) {
-      if (!ReadBase128(file, &transform_length)) {
-        return OTS_FAILURE();
+      if (!ReadBase128(buffer, &transform_length)) {
+        return OTS_FAILURE_MSG("Failed to read \"transformLength\" for table %4.4s", (char*)&tag);
       }
     }
     // Disallow huge numbers (> 1GB) for sanity.
     if (transform_length > 1024 * 1024 * 1024 ||
         dst_length > 1024 * 1024 * 1024) {
-      return OTS_FAILURE();
+      return OTS_FAILURE_MSG("\"origLength\" or \"transformLength\" > 1GB");
     }
     table->tag = tag;
     table->flags = flags;
     table->transform_length = transform_length;
     table->dst_length = dst_length;
   }
   return true;
 }
@@ -859,92 +834,82 @@ size_t ComputeWOFF2FinalSize(const uint8
 
   if (!file.Skip(16) ||
       !file.ReadU32(&total_length)) {
     return 0;
   }
   return total_length;
 }
 
-bool ConvertWOFF2ToTTF(uint8_t* result, size_t result_length,
+bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
+                       uint8_t* result, size_t result_length,
                        const uint8_t* data, size_t length) {
   static const uint32_t kWoff2Signature = 0x774f4632;  // "wOF2"
-  ots::Buffer file(data, length);
+  ots::Buffer buffer(data, length);
 
   uint32_t signature;
   uint32_t flavor = 0;
-  if (!file.ReadU32(&signature) || signature != kWoff2Signature ||
-      !file.ReadU32(&flavor)) {
-    return OTS_FAILURE();
+  if (!buffer.ReadU32(&signature) || signature != kWoff2Signature ||
+      !buffer.ReadU32(&flavor)) {
+    return OTS_FAILURE_MSG("Failed to read \"signature\" or \"flavor\", or not WOFF2 signature");
   }
 
   if (!IsValidVersionTag(ntohl(flavor))) {
-    return OTS_FAILURE();
+    return OTS_FAILURE_MSG("Invalid \"flavor\"");
   }
 
   uint32_t reported_length;
-  if (!file.ReadU32(&reported_length) || length != reported_length) {
-    return OTS_FAILURE();
+  if (!buffer.ReadU32(&reported_length) || length != reported_length) {
+    return OTS_FAILURE_MSG("Failed to read \"length\" or it does not match the actual file size");
   }
   uint16_t num_tables;
-  if (!file.ReadU16(&num_tables) || !num_tables) {
-    return OTS_FAILURE();
+  if (!buffer.ReadU16(&num_tables) || !num_tables) {
+    return OTS_FAILURE_MSG("Failed to read \"numTables\"");
   }
   // We don't care about these fields of the header:
   //   uint16_t reserved
   //   uint32_t total_sfnt_size
-  if (!file.Skip(6)) {
-    return OTS_FAILURE();
+  if (!buffer.Skip(6)) {
+    return OTS_FAILURE_MSG("Failed to read \"reserve\" or \"totalSfntSize\"");
   }
   uint32_t compressed_length;
-  if (!file.ReadU32(&compressed_length)) {
+  if (!buffer.ReadU32(&compressed_length)) {
+    return OTS_FAILURE_MSG("Failed to read \"totalCompressedSize\"");
+  }
+  if (compressed_length > std::numeric_limits<uint32_t>::max()) {
     return OTS_FAILURE();
   }
+
   // We don't care about these fields of the header:
   //   uint16_t major_version, minor_version
   //   uint32_t meta_offset, meta_length, meta_orig_length
   //   uint32_t priv_offset, priv_length
-  if (!file.Skip(24)) {
+  if (!buffer.Skip(24)) {
     return OTS_FAILURE();
   }
   std::vector<Table> tables(num_tables);
-  if (!ReadShortDirectory(&file, &tables, num_tables)) {
+  if (!ReadShortDirectory(file, &buffer, &tables, num_tables)) {
+    return OTS_FAILURE_MSG("Failed to read table directory");
+  }
+  uint64_t compressed_offset = buffer.offset();
+  if (compressed_offset > std::numeric_limits<uint32_t>::max()) {
     return OTS_FAILURE();
   }
-  uint64_t src_offset = file.offset();
   uint64_t dst_offset = kSfntHeaderSize +
       kSfntEntrySize * static_cast<uint64_t>(num_tables);
-  uint64_t uncompressed_sum = 0;
   for (uint16_t i = 0; i < num_tables; ++i) {
     Table* table = &tables.at(i);
-    table->src_offset = static_cast<uint32_t>(src_offset);
-    table->src_length = (i == 0 ? compressed_length : 0);
-    src_offset += table->src_length;
-    if (src_offset > std::numeric_limits<uint32_t>::max()) {
-      return OTS_FAILURE();
-    }
-    src_offset = ots::Round4(src_offset);
     table->dst_offset = static_cast<uint32_t>(dst_offset);
     dst_offset += table->dst_length;
     if (dst_offset > std::numeric_limits<uint32_t>::max()) {
       return OTS_FAILURE();
     }
     dst_offset = ots::Round4(dst_offset);
-    if ((table->flags & kCompressionTypeMask) != kCompressionTypeNone) {
-      uncompressed_sum += table->src_length;
-      if (uncompressed_sum > std::numeric_limits<uint32_t>::max()) {
-        return OTS_FAILURE();
-      }
-    }
   }
-  // Enforce same 30M limit on uncompressed tables as OTS
-  if (uncompressed_sum > 30 * 1024 * 1024) {
-    return OTS_FAILURE();
-  }
-  if (src_offset > length || dst_offset > result_length) {
+  if (ots::Round4(compressed_offset + compressed_length) > length || dst_offset > result_length) {
     return OTS_FAILURE();
   }
 
   const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables;
   if (sfnt_header_and_table_directory_size > result_length) {
     return OTS_FAILURE();
   }
 
@@ -963,60 +928,42 @@ bool ConvertWOFF2ToTTF(uint8_t* result, 
   for (uint16_t i = 0; i < num_tables; ++i) {
     const Table* table = &tables.at(i);
     offset = StoreU32(result, offset, table->tag);
     offset = StoreU32(result, offset, 0);  // checksum, to fill in later
     offset = StoreU32(result, offset, table->dst_offset);
     offset = StoreU32(result, offset, table->dst_length);
   }
   std::vector<uint8_t> uncompressed_buf;
-  bool continue_valid = false;
   const uint8_t* transform_buf = NULL;
+  uint64_t total_size = 0;
+
+  for (uint16_t i = 0; i < num_tables; ++i) {
+    total_size += tables.at(i).transform_length;
+    if (total_size > std::numeric_limits<uint32_t>::max()) {
+      return OTS_FAILURE();
+    }
+  }
+  // Enforce same 30M limit on uncompressed tables as OTS
+  if (total_size > 30 * 1024 * 1024) {
+    return OTS_FAILURE();
+  }
+  const size_t total_size_size_t = static_cast<size_t>(total_size);
+  uncompressed_buf.resize(total_size_size_t);
+  const uint8_t* src_buf = data + compressed_offset;
+  if (!Woff2Uncompress(&uncompressed_buf[0], total_size_size_t,
+      src_buf, compressed_length)) {
+    return OTS_FAILURE();
+  }
+  transform_buf = &uncompressed_buf[0];
+
   for (uint16_t i = 0; i < num_tables; ++i) {
     const Table* table = &tables.at(i);
     uint32_t flags = table->flags;
-    const uint8_t* src_buf = data + table->src_offset;
-    uint32_t compression_type = flags & kCompressionTypeMask;
     size_t transform_length = table->transform_length;
-    if ((flags & kWoff2FlagsContinueStream) != 0) {
-      if (!continue_valid) {
-        return OTS_FAILURE();
-      }
-    } else if (compression_type == kCompressionTypeNone) {
-      if (transform_length != table->src_length) {
-        return OTS_FAILURE();
-      }
-      transform_buf = src_buf;
-      continue_valid = false;
-    } else if ((flags & kWoff2FlagsContinueStream) == 0) {
-      uint64_t total_size = transform_length;
-      for (uint16_t j = i + 1; j < num_tables; ++j) {
-        if ((tables.at(j).flags & kWoff2FlagsContinueStream) == 0) {
-          break;
-        }
-        total_size += tables.at(j).transform_length;
-        if (total_size > std::numeric_limits<uint32_t>::max()) {
-          return OTS_FAILURE();
-        }
-      }
-      // Enforce same 30M limit on uncompressed tables as OTS
-      if (total_size > 30 * 1024 * 1024) {
-        return OTS_FAILURE();
-      }
-      const size_t total_size_size_t = static_cast<size_t>(total_size);
-      uncompressed_buf.resize(total_size_size_t);
-      if (!Woff2Uncompress(&uncompressed_buf[0], total_size_size_t,
-          src_buf, compressed_length, compression_type)) {
-        return OTS_FAILURE();
-      }
-      transform_buf = &uncompressed_buf[0];
-      continue_valid = true;
-    } else {
-      return OTS_FAILURE();
-    }
 
     if ((flags & kWoff2FlagsTransform) == 0) {
       if (transform_length != table->dst_length) {
         return OTS_FAILURE();
       }
       if (static_cast<uint64_t>(table->dst_offset) + transform_length >
           result_length) {
         return OTS_FAILURE();
@@ -1024,20 +971,21 @@ bool ConvertWOFF2ToTTF(uint8_t* result, 
       std::memcpy(result + table->dst_offset, transform_buf,
           transform_length);
     } else {
       if (!ReconstructTransformed(tables, table->tag,
             transform_buf, transform_length, result, result_length)) {
         return OTS_FAILURE();
       }
     }
-    if (continue_valid) {
-      transform_buf += transform_length;
-      if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) {
-        return OTS_FAILURE();
-      }
+
+    transform_buf += transform_length;
+    if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) {
+      return OTS_FAILURE();
     }
   }
 
   return FixChecksums(tables, result);
 }
 
 }  // namespace ots
+
+#undef TABLE_NAME
--- a/gfx/ots/src/woff2.h
+++ b/gfx/ots/src/woff2.h
@@ -8,13 +8,13 @@
 namespace ots {
 
 // Compute the size of the final uncompressed font, or 0 on error.
 size_t ComputeWOFF2FinalSize(const uint8_t *data, size_t length);
 
 // Decompresses the font into the target buffer. The result_length should
 // be the same as determined by ComputeFinalSize(). Returns true on successful
 // decompression.
-bool ConvertWOFF2ToTTF(uint8_t *result, size_t result_length,
+bool ConvertWOFF2ToTTF(OpenTypeFile *file, uint8_t *result, size_t result_length,
                        const uint8_t *data, size_t length);
 }
 
 #endif  // OTS_WOFF2_H_
--- a/gfx/ots/sync.sh
+++ b/gfx/ots/sync.sh
@@ -21,11 +21,8 @@ rm -rf include/
 cp -r $1/include .
 
 echo "Updating README.mozilla..."
 REVISION=`cd $1; git log | head -1 | sed "s/commit //"`
 sed -e "s/\(Current revision: \).*/\1$REVISION/" -i "" README.mozilla
 
 echo "Applying ots-visibility.patch..."
 patch -p3 < ots-visibility.patch
-
-echo "Applying ots-brotli-path.patch..."
-patch -p3 < ots-brotli-path.patch