Bug 1142952 - Update OTS to latest upstream revision; now at e779d45e7a96d3b97ed3d2b76db7478cb86fdd8b. r=jdaggett
authorJonathan Kew <jkew@mozilla.com>
Thu, 19 Mar 2015 11:11:30 +0000
changeset 234431 eb6141f8f3a342096e162c17381dec1e22426372
parent 234430 46f600c2366bba5e02566ee85df2a9756d5bf335
child 234443 661d70e3289993ed2f6477cd5847ab99d9998177
push id57135
push userjkew@mozilla.com
push dateThu, 19 Mar 2015 11:12:13 +0000
treeherdermozilla-inbound@eb6141f8f3a3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs1142952
milestone39.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 1142952 - Update OTS to latest upstream revision; now at e779d45e7a96d3b97ed3d2b76db7478cb86fdd8b. r=jdaggett
gfx/ots/README.mozilla
gfx/ots/include/opentype-sanitiser.h
gfx/ots/ots-visibility.patch
gfx/ots/src/cmap.cc
gfx/ots/src/cvt.cc
gfx/ots/src/fpgm.cc
gfx/ots/src/os2.cc
gfx/ots/src/ots.cc
gfx/ots/src/ots.h
gfx/ots/src/prep.cc
gfx/ots/src/woff2.cc
gfx/ots/src/woff2.h
gfx/thebes/gfxUserFontSet.cpp
--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,12 +1,11 @@
 This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
 
 Our reference repository is https://github.com/khaledhosny/ots/.
 
-Current revision: 7091a232a10a741591ff25158c98ca3f0c319cf9
+Current revision: e779d45e7a96d3b97ed3d2b76db7478cb86fdd8b
 
 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
@@ -218,37 +218,26 @@ class OTS_API OTSContext {
     virtual ~OTSContext() {}
 
     // Process a given OpenType file and write out a sanitised version
     //   output: a pointer to an object implementing the OTSStream interface. The
     //     sanitisied output will be written to this. In the even of a failure,
     //     partial output may have been written.
     //   input: the OpenType file
     //   length: the size, in bytes, of |input|
-    //   context: optional context that holds various OTS settings like user callbacks
     bool Process(OTSStream *output, const uint8_t *input, size_t length);
 
     // This function will be called when OTS is reporting an error.
     //   level: the severity of the generated message:
     //     0: error messages in case OTS fails to sanitize the font.
     //     1: warning messages about issue OTS fixed in the sanitized font.
     virtual void Message(int level, const char *format, ...) MSGFUNC_FMT_ATTR {}
 
     // This function will be called when OTS needs to decide what to do for a
     // font table.
     //   tag: table tag as an integer in big-endian byte order, independent of
     //   platform endianness
     virtual TableAction GetTableAction(uint32_t tag) { return ots::TABLE_ACTION_DEFAULT; }
 };
 
-// For backward compatibility - remove once Chrome switches over to the new API.
-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();
-
-// Enable WOFF2 support(experimental).
-void OTS_API EnableWOFF2();
-
 }  // namespace ots
 
 #endif  // OPENTYPE_SANITISER_H_
--- a/gfx/ots/ots-visibility.patch
+++ b/gfx/ots/ots-visibility.patch
@@ -51,23 +51,8 @@ diff --git a/gfx/ots/include/opentype-sa
    public:
      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);
- 
- // Force to disable debug output even when the library is compiled with
- // -DOTS_DEBUG.
- void DisableDebugOutput();
- 
- // Enable WOFF2 support(experimental).
--void EnableWOFF2();
-+void OTS_API EnableWOFF2();
- 
- }  // namespace ots
- 
- #endif  // OPENTYPE_SANITISER_H_
--- a/gfx/ots/src/cmap.cc
+++ b/gfx/ots/src/cmap.cc
@@ -679,21 +679,21 @@ bool ots_cmap_parse(OpenTypeFile *file, 
   // check if the table is sorted first by platform ID, then by encoding ID.
   uint32_t last_id = 0;
   for (unsigned i = 0; i < num_tables; ++i) {
     uint32_t current_id
         = (subtable_headers[i].platform << 24)
         + (subtable_headers[i].encoding << 16)
         + subtable_headers[i].language;
     if ((i != 0) && (last_id >= current_id)) {
-      return OTS_FAILURE_MSG("subtable %d with platform ID %d, encoding ID %d, language ID %d "
-                             "following subtable with platform ID %d, encoding ID %d, language ID %d",
-                             i,
-                             (uint8_t)(current_id >> 24), (uint8_t)(current_id >> 16), (uint8_t)(current_id),
-                             (uint8_t)(last_id >> 24), (uint8_t)(last_id >> 16), (uint8_t)(last_id));
+      OTS_WARNING("subtable %d with platform ID %d, encoding ID %d, language ID %d "
+                  "following subtable with platform ID %d, encoding ID %d, language ID %d",
+                  i,
+                  (uint8_t)(current_id >> 24), (uint8_t)(current_id >> 16), (uint8_t)(current_id),
+                  (uint8_t)(last_id >> 24), (uint8_t)(last_id >> 16), (uint8_t)(last_id));
     }
     last_id = current_id;
   }
 
   // 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) {
--- a/gfx/ots/src/cvt.cc
+++ b/gfx/ots/src/cvt.cc
@@ -33,17 +33,17 @@ bool ots_cvt_parse(OpenTypeFile *file, c
   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 file->cvt;
+  return file->cvt != NULL;
 }
 
 bool ots_cvt_serialise(OTSStream *out, OpenTypeFile *file) {
   const OpenTypeCVT *cvt = file->cvt;
 
   if (!out->Write(cvt->data, cvt->length)) {
     return OTS_FAILURE_MSG("Failed to write CVT table");
   }
--- a/gfx/ots/src/fpgm.cc
+++ b/gfx/ots/src/fpgm.cc
@@ -27,17 +27,17 @@ bool ots_fpgm_parse(OpenTypeFile *file, 
 
   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 file->fpgm;
+  return file->fpgm != NULL;
 }
 
 bool ots_fpgm_serialise(OTSStream *out, OpenTypeFile *file) {
   const OpenTypeFPGM *fpgm = file->fpgm;
 
   if (!out->Write(fpgm->data, fpgm->length)) {
     return OTS_FAILURE_MSG("Failed to write fpgm");
   }
--- a/gfx/ots/src/os2.cc
+++ b/gfx/ots/src/os2.cc
@@ -1,14 +1,15 @@
 // 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 <string>
+
 #include "os2.h"
-
 #include "head.h"
 
 // OS/2 - OS/2 and Windows Metrics
 // http://www.microsoft.com/typography/otspec/os2.htm
 
 #define TABLE_NAME "OS/2"
 
 namespace ots {
@@ -30,36 +31,39 @@ bool ots_os2_parse(OpenTypeFile *file, c
       !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_MSG("Failed toi read basic os2 elements");
+    return OTS_FAILURE_MSG("Error reading basic table elements");
   }
 
   if (os2->version > 4) {
-    return OTS_FAILURE_MSG("os2 version too high %d", os2->version);
+    return OTS_FAILURE_MSG("Unsupported table version: %u", os2->version);
   }
 
-  // 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
+  // Follow WPF Font Selection Model's advice.
+  if (1 <= os2->weight_class && os2->weight_class <= 9) {
+    OTS_WARNING("Bad usWeightClass: %u, changing it to: %u", os2->weight_class, os2->weight_class * 100);
+    os2->weight_class *= 100;
   }
+  // Ditto.
+  if (os2->weight_class > 999) {
+    OTS_WARNING("Bad usWeightClass: %u, changing it to: %d", os2->weight_class, 999);
+    os2->weight_class = 999;
+  }
+
   if (os2->width_class < 1) {
-    OTS_WARNING("bad width: %u", os2->width_class);
+    OTS_WARNING("Bad usWidthClass: %u, changing it to: %d", os2->width_class, 1);
     os2->width_class = 1;
   } else if (os2->width_class > 9) {
-    OTS_WARNING("bad width: %u", os2->width_class);
+    OTS_WARNING("Bad usWidthClass: %u, changing it to: %d", os2->width_class, 9);
     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) {
@@ -68,68 +72,72 @@ bool ots_os2_parse(OpenTypeFile *file, c
   } 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;
+#define SET_TO_ZERO(a, b)                                     \
+  if (os2->b < 0) {                                           \
+    OTS_WARNING("Bad " a ": %d, setting it to zero", os2->b); \
+    os2->b = 0;                                               \
   }
 
+  SET_TO_ZERO("ySubscriptXSize", subscript_x_size);
+  SET_TO_ZERO("ySubscriptYSize", subscript_y_size);
+  SET_TO_ZERO("ySuperscriptXSize", superscript_x_size);
+  SET_TO_ZERO("ySuperscriptYSize", superscript_y_size);
+  SET_TO_ZERO("yStrikeoutSize", strikeout_size);
+#undef SET_TO_ZERO
+
+  static std::string panose_strings[10] = {
+    "bFamilyType",
+    "bSerifStyle",
+    "bWeight",
+    "bProportion",
+    "bContrast",
+    "bStrokeVariation",
+    "bArmStyle",
+    "bLetterform",
+    "bMidline",
+    "bXHeight",
+  };
   for (unsigned i = 0; i < 10; ++i) {
     if (!table.ReadU8(&os2->panose[i])) {
-      return OTS_FAILURE_MSG("Failed to read panose in os2 table");
+      return OTS_FAILURE_MSG("Error reading PANOSE %s", panose_strings[i].c_str());
     }
   }
 
   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_MSG("Failed to read more basic os2 fields");
+    return OTS_FAILURE_MSG("Error reading more basic table fields");
   }
 
   // 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_MSG("Head table missing from font as needed by os2 table");
+    return OTS_FAILURE_MSG("Needed head table is missing from the font");
   }
   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)) {
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -9,31 +9,27 @@
 
 #include <algorithm>
 #include <cstdlib>
 #include <cstring>
 #include <limits>
 #include <map>
 #include <vector>
 
-#ifndef OTS_DISABLE_WOFF2
 #include "woff2.h"
-#endif
 
 // The OpenType Font File
 // http://www.microsoft.com/typography/otspec/cmap.htm
 
 namespace {
 
-bool g_debug_output = true;
-bool g_enable_woff2 = false;
-
 // Generate a message with or without a table tag, when 'header' is the OpenTypeFile pointer
 #define OTS_FAILURE_MSG_TAG(msg_,tag_) OTS_FAILURE_MSG_TAG_(header, msg_, tag_)
 #define OTS_FAILURE_MSG_HDR(msg_)      OTS_FAILURE_MSG_(header, msg_)
+#define OTS_WARNING_MSG_HDR(msg_)      OTS_WARNING_MSG_(header, msg_)
 
 
 struct OpenTypeTable {
   uint32_t tag;
   uint32_t chksum;
   uint32_t offset;
   uint32_t length;
   uint32_t uncompressed_length;
@@ -284,44 +280,44 @@ bool ProcessWOFF(ots::OpenTypeFile *head
   uint32_t reported_total_sfnt_size;
   if (!file.ReadU32(&reported_total_sfnt_size)) {
     return OTS_FAILURE_MSG_HDR("error reading total sfnt size");
   }
 
   // We don't care about these fields of the header:
   //   uint16_t major_version, minor_version
   if (!file.Skip(2 * 2)) {
-    return OTS_FAILURE_MSG_HDR("error skipping WOFF header fields");
+    return OTS_FAILURE_MSG_HDR("Failed to read 'majorVersion' or 'minorVersion'");
   }
 
   // Checks metadata block size.
   uint32_t meta_offset;
   uint32_t meta_length;
   uint32_t meta_length_orig;
   if (!file.ReadU32(&meta_offset) ||
       !file.ReadU32(&meta_length) ||
       !file.ReadU32(&meta_length_orig)) {
-    return OTS_FAILURE_MSG_HDR("error reading WOFF header fields");
+    return OTS_FAILURE_MSG_HDR("Failed to read header metadata block fields");
   }
   if (meta_offset) {
     if (meta_offset >= length || length - meta_offset < meta_length) {
-      return OTS_FAILURE_MSG_HDR("invalid metadata block location/size");
+      return OTS_FAILURE_MSG_HDR("Invalid metadata block offset or length");
     }
   }
 
   // Checks private data block size.
   uint32_t priv_offset;
   uint32_t priv_length;
   if (!file.ReadU32(&priv_offset) ||
       !file.ReadU32(&priv_length)) {
-    return OTS_FAILURE_MSG_HDR("error reading WOFF header fields");
+    return OTS_FAILURE_MSG_HDR("Failed to read header private block fields");
   }
   if (priv_offset) {
     if (priv_offset >= length || length - priv_offset < priv_length) {
-      return OTS_FAILURE_MSG_HDR("invalid private block location/size");
+      return OTS_FAILURE_MSG_HDR("Invalid private block offset or length");
     }
   }
 
   // Next up is the list of tables.
   std::vector<OpenTypeTable> tables;
 
   uint32_t first_index = 0;
   uint32_t last_index = 0;
@@ -366,61 +362,59 @@ bool ProcessWOFF(ots::OpenTypeFile *head
   uint64_t block_end = ots::Round4(
       static_cast<uint64_t>(tables[last_index].offset) +
       static_cast<uint64_t>(tables[last_index].length));
   if (block_end > std::numeric_limits<uint32_t>::max()) {
     return OTS_FAILURE_MSG_HDR("invalid table location/size");
   }
   if (meta_offset) {
     if (block_end != meta_offset) {
-      return OTS_FAILURE_MSG_HDR("invalid metadata block location");
+      return OTS_FAILURE_MSG_HDR("Invalid metadata block offset");
     }
     block_end = ots::Round4(static_cast<uint64_t>(meta_offset) +
                             static_cast<uint64_t>(meta_length));
     if (block_end > std::numeric_limits<uint32_t>::max()) {
-      return OTS_FAILURE_MSG_HDR("invalid metadata block size");
+      return OTS_FAILURE_MSG_HDR("Invalid metadata block length");
     }
   }
   if (priv_offset) {
     if (block_end != priv_offset) {
-      return OTS_FAILURE_MSG_HDR("invalid private block location");
+      return OTS_FAILURE_MSG_HDR("Invalid private block offset");
     }
     block_end = ots::Round4(static_cast<uint64_t>(priv_offset) +
                             static_cast<uint64_t>(priv_length));
     if (block_end > std::numeric_limits<uint32_t>::max()) {
-      return OTS_FAILURE_MSG_HDR("invalid private block size");
+      return OTS_FAILURE_MSG_HDR("Invalid private block length");
     }
   }
   if (block_end != ots::Round4(length)) {
-    return OTS_FAILURE_MSG_HDR("file length mismatch (trailing junk?)");
+    return OTS_FAILURE_MSG_HDR("File length mismatch (trailing junk?)");
   }
 
   return ProcessGeneric(header, woff_tag, output, data, length, tables, file);
 }
 
-#ifndef OTS_DISABLE_WOFF2
 bool ProcessWOFF2(ots::OpenTypeFile *header,
                   ots::OTSStream *output, const uint8_t *data, size_t length) {
   size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length);
   if (decompressed_size == 0) {
-    return OTS_FAILURE();
+    return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 is set to 0");
   }
   // decompressed font must be <= 30MB
   if (decompressed_size > 30 * 1024 * 1024) {
-    return OTS_FAILURE();
+    return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 font exceeds 30MB");
   }
 
   std::vector<uint8_t> decompressed_buffer(decompressed_size);
-  if (!ots::ConvertWOFF2ToTTF(header, &decompressed_buffer[0], decompressed_size,
-                              data, length)) {
-    return OTS_FAILURE();
+  if (!ots::ConvertWOFF2ToSFNT(header, &decompressed_buffer[0], decompressed_size,
+                               data, length)) {
+    return OTS_FAILURE_MSG_HDR("Failed to convert WOFF 2.0 font to SFNT");
   }
   return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size);
 }
-#endif
 
 ots::TableAction GetTableAction(ots::OpenTypeFile *header, uint32_t tag) {
   ots::TableAction action = ots::TABLE_ACTION_DEFAULT;
 
   action = header->context->GetTableAction(htonl(tag));
 
   if (action == ots::TABLE_ACTION_DEFAULT) {
     action = ots::TABLE_ACTION_DROP;
@@ -474,17 +468,17 @@ bool ProcessGeneric(ots::OpenTypeFile *h
 
   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_MSG_HDR("table directory not correctly ordered");
+        OTS_WARNING_MSG_HDR("Table directory is not correctly ordered");
       }
     }
 
     // all tag names must be built from printable ASCII characters
     if (!CheckTag(tables[i].tag)) {
       return OTS_FAILURE_MSG_TAG("invalid table tag", &tables[i].tag);
     }
 
@@ -601,18 +595,24 @@ bool ProcessGeneric(ots::OpenTypeFile *h
     }
     if (header->glyf || header->loca) {
       // mixing outline formats is not recommended
       return OTS_FAILURE_MSG_HDR("font contains both PS and TT glyphs");
     }
   } else {
     if (!header->glyf || !header->loca) {
       // No TrueType glyph found.
-      // Note: bitmap-only fonts are not supported.
-      return OTS_FAILURE_MSG_HDR("neither PS nor TT glyphs present");
+#define PASSTHRU_TABLE(TAG) (table_map.find(Tag(TAG)) != table_map.end() && \
+                             GetTableAction(header, Tag(TAG)) == ots::TABLE_ACTION_PASSTHRU)
+      // We don't sanitise bitmap table, but don't reject bitmap-only fonts if
+      // we keep the tables.
+      if (!PASSTHRU_TABLE("CBDT") || !PASSTHRU_TABLE("CBLC")) {
+        return OTS_FAILURE_MSG_HDR("no supported glyph shapes table(s) present");
+      }
+#undef PASSTHRU_TABLE
     }
   }
 
   uint16_t num_output_tables = 0;
   for (unsigned i = 0; ; ++i) {
     if (table_parsers[i].parse == NULL) {
       break;
     }
@@ -787,64 +787,36 @@ 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");
 }
 
-void DisableDebugOutput() {
-  g_debug_output = false;
-}
-
-void EnableWOFF2() {
-  g_enable_woff2 = true;
-}
-
 bool OTSContext::Process(OTSStream *output,
                          const uint8_t *data,
                          size_t length) {
   OpenTypeFile header;
 
   header.context = this;
 
   if (length < 4) {
     return OTS_FAILURE_MSG_(&header, "file less than 4 bytes");
   }
 
   bool result;
   if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
     result = ProcessWOFF(&header, output, data, length);
-#ifndef OTS_DISABLE_WOFF2
-  } else if (g_enable_woff2 &&
-             data[0] == 'w' && data[1] == 'O' && data[2] == 'F' &&
-             data[3] == '2') {
+  } else if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == '2') {
     result = ProcessWOFF2(&header, output, data, length);
-#endif
   } 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;
 }
 
-// For backward compatibility
-bool Process(OTSStream *output, const uint8_t *data, size_t length) {
-  static OTSContext context;
-  return context.Process(output, data, length);
-}
-
-#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;
-}
-#endif
-
 }  // namespace ots
--- a/gfx/ots/src/ots.h
+++ b/gfx/ots/src/ots.h
@@ -17,28 +17,32 @@
 
 // arraysize borrowed from base/basictypes.h
 template <typename T, size_t N>
 char (&ArraySizeHelper(T (&array)[N]))[N];
 #define arraysize(array) (sizeof(ArraySizeHelper(array)))
 
 namespace ots {
 
-#if defined(_MSC_VER) || !defined(OTS_DEBUG)
+#if !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);
+#define OTS_FAILURE() \
+  (\
+    std::fprintf(stderr, "ERROR at %s:%d (%s)\n", \
+                 __FILE__, __LINE__, __FUNCTION__) \
+    && false\
+  )
 #endif
 
 // All OTS_FAILURE_* macros ultimately evaluate to 'false', just like the original
 // message-less OTS_FAILURE(), so that the current parser will return 'false' as
 // its result (indicating a failure).
 
-#if defined(_MSC_VER) || !defined(OTS_DEBUG)
+#if !defined(OTS_DEBUG)
 #define OTS_MESSAGE_(level,otf_,...) \
   (otf_)->context->Message(level,__VA_ARGS__)
 #else
 #define OTS_MESSAGE_(level,otf_,...) \
   OTS_FAILURE(), \
   (otf_)->context->Message(level,__VA_ARGS__)
 #endif
 
--- a/gfx/ots/src/prep.cc
+++ b/gfx/ots/src/prep.cc
@@ -27,17 +27,17 @@ bool ots_prep_parse(OpenTypeFile *file, 
 
   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 file->prep;
+  return file->prep != NULL;
 }
 
 bool ots_prep_serialise(OTSStream *out, OpenTypeFile *file) {
   const OpenTypePREP *prep = file->prep;
 
   if (!out->Write(prep->data, prep->length)) {
     return OTS_FAILURE_MSG("Failed to write table length");
   }
--- a/gfx/ots/src/woff2.cc
+++ b/gfx/ots/src/woff2.cc
@@ -40,16 +40,17 @@ const size_t kSfntHeaderSize = 12;
 const size_t kSfntEntrySize = 16;
 const size_t kCheckSumAdjustmentOffset = 8;
 
 const size_t kEndPtsOfContoursOffset = 10;
 const size_t kCompositeGlyphBegin = 10;
 
 // Note that the byte order is big-endian, not the same as ots.cc
 #define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d)
+#define CHR(t)           (t >> 24),  (t >> 16),  (t >> 8), (t >> 0)
 
 const unsigned int kWoff2FlagsTransform = 1 << 5;
 
 const uint32_t kKnownTags[] = {
   TAG('c', 'm', 'a', 'p'),  // 0
   TAG('h', 'e', 'a', 'd'),  // 1
   TAG('h', 'h', 'e', 'a'),  // 2
   TAG('h', 'm', 't', 'x'),  // 3
@@ -130,16 +131,20 @@ struct Table {
   uint32_t dst_length;
 
   Table()
       : tag(0),
         flags(0),
         transform_length(0),
         dst_offset(0),
         dst_length(0) {}
+
+  bool operator<(const Table& other) const {
+    return tag < other.tag;
+  }
 };
 
 // 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;
   static const uint8_t kOneMoreByteCode2 = 254;
   static const uint8_t kOneMoreByteCode1 = 255;
   static const uint8_t kLowestUCode = 253;
@@ -177,17 +182,17 @@ bool Read255UShort(ots::Buffer* buf, uin
 bool ReadBase128(ots::Buffer* buf, uint32_t* value) {
   uint32_t result = 0;
   for (size_t i = 0; i < 5; ++i) {
     uint8_t code = 0;
     if (!buf->ReadU8(&code)) {
       return OTS_FAILURE();
     }
     // If any of the top seven bits are set then we're about to overflow.
-    if (result & 0xe0000000U) {
+    if (result & 0xfe000000U) {
       return OTS_FAILURE();
     }
     result = (result << 7) | (code & 0x7f);
     if ((code & 0x80) == 0) {
       *value = result;
       return true;
     }
   }
@@ -504,45 +509,48 @@ bool StoreLoca(const std::vector<uint32_
     } else {
       offset = StoreU16(dst, offset, static_cast<uint16_t>(value >> 1));
     }
   }
   return true;
 }
 
 // Reconstruct entire glyf table based on transformed original
-bool ReconstructGlyf(const uint8_t* data, size_t data_size,
+bool ReconstructGlyf(ots::OpenTypeFile* file,
+    const uint8_t* data, size_t data_size,
     uint8_t* dst, size_t dst_size,
     uint8_t* loca_buf, size_t loca_size) {
   static const int kNumSubStreams = 7;
-  ots::Buffer file(data, data_size);
+  ots::Buffer buffer(data, data_size);
   uint32_t version;
   std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
 
-  if (!file.ReadU32(&version)) {
-    return OTS_FAILURE();
+  if (!buffer.ReadU32(&version)) {
+    return OTS_FAILURE_MSG("Failed to read 'version' of transformed 'glyf' table");
   }
   uint16_t num_glyphs;
+  if (!buffer.ReadU16(&num_glyphs)) {
+    return OTS_FAILURE_MSG("Failed to read 'numGlyphs' from transformed 'glyf' table");
+  }
   uint16_t index_format;
-  if (!file.ReadU16(&num_glyphs) ||
-      !file.ReadU16(&index_format)) {
-    return OTS_FAILURE();
+  if (!buffer.ReadU16(&index_format)) {
+    return OTS_FAILURE_MSG("Failed to read 'indexFormat' from transformed 'glyf' table");
   }
   unsigned int offset = (2 + kNumSubStreams) * 4;
   if (offset > data_size) {
-    return OTS_FAILURE();
+    return OTS_FAILURE_MSG("Size of transformed 'glyf' table is too small to fit its data");
   }
   // Invariant from here on: data_size >= offset
   for (int i = 0; i < kNumSubStreams; ++i) {
     uint32_t substream_size;
-    if (!file.ReadU32(&substream_size)) {
-      return OTS_FAILURE();
+    if (!buffer.ReadU32(&substream_size)) {
+      return OTS_FAILURE_MSG("Failed to read substream size %d of transformed 'glyf' table", i);
     }
     if (substream_size > data_size - offset) {
-      return OTS_FAILURE();
+      return OTS_FAILURE_MSG("Size of substream %d of transformed 'glyf' table does not fit in table size");
     }
     substreams.at(i) = std::make_pair(data + offset, substream_size);
     offset += substream_size;
   }
   ots::Buffer n_contour_stream(substreams.at(0).first, substreams.at(0).second);
   ots::Buffer n_points_stream(substreams.at(1).first, substreams.at(1).second);
   ots::Buffer flag_stream(substreams.at(2).first, substreams.at(2).second);
   ots::Buffer glyph_stream(substreams.at(3).first, substreams.at(3).second);
@@ -555,56 +563,56 @@ bool ReconstructGlyf(const uint8_t* data
   loca_values.reserve(num_glyphs + 1);
   std::vector<uint16_t> n_points_vec;
   std::vector<Point> points;
   uint32_t loca_offset = 0;
   for (unsigned int i = 0; i < num_glyphs; ++i) {
     size_t glyph_size = 0;
     uint16_t n_contours = 0;
     if (!n_contour_stream.ReadU16(&n_contours)) {
-      return OTS_FAILURE();
+      return OTS_FAILURE_MSG("Filed to read 'numberOfContours' of glyph %d from transformed 'glyf' table", i);
     }
     uint8_t* glyf_dst = dst + loca_offset;
     size_t glyf_dst_size = dst_size - loca_offset;
     if (n_contours == 0xffff) {
       // composite glyph
       bool have_instructions = false;
       uint16_t instruction_size = 0;
       if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size,
             &glyph_size, &have_instructions)) {
-        return OTS_FAILURE();
+        return OTS_FAILURE_MSG("Filed to process composite glyph %d from transformed 'glyf' table", i);
       }
       if (have_instructions) {
         if (!Read255UShort(&glyph_stream, &instruction_size)) {
-          return OTS_FAILURE();
+          return OTS_FAILURE_MSG("Failed to read 'instructionLength' of glyph %d from transformed 'glyf' table", i);
         }
         // No integer overflow here (instruction_size < 2^16).
         if (instruction_size + 2U > glyf_dst_size - glyph_size) {
-          return OTS_FAILURE();
+          return OTS_FAILURE_MSG("'instructionLength' of glyph %d from transformed 'glyf' table does not fit in the destination glyph size", i);
         }
         StoreU16(glyf_dst, glyph_size, instruction_size);
         if (!instruction_stream.Read(glyf_dst + glyph_size + 2,
               instruction_size)) {
-          return OTS_FAILURE();
+          return OTS_FAILURE_MSG("Filed to read instructions of glyph %d from transformed 'glyf' table", i);
         }
         glyph_size += instruction_size + 2;
       }
     } else if (n_contours > 0) {
       // simple glyph
       n_points_vec.clear();
       points.clear();
       uint32_t total_n_points = 0;
       uint16_t n_points_contour;
       for (uint32_t j = 0; j < n_contours; ++j) {
         if (!Read255UShort(&n_points_stream, &n_points_contour)) {
-          return OTS_FAILURE();
+          return OTS_FAILURE_MSG("Filed to read number of points of contour %d of glyph %d from transformed 'glyf' table", j, i);
         }
         n_points_vec.push_back(n_points_contour);
         if (total_n_points + n_points_contour < total_n_points) {
-          return OTS_FAILURE();
+          return OTS_FAILURE_MSG("Negative number of points of contour %d of glyph %d from transformed 'glyf' table", j, i);
         }
         total_n_points += n_points_contour;
       }
       uint32_t flag_size = total_n_points;
       if (flag_size > flag_stream.length() - flag_stream.offset()) {
         return OTS_FAILURE();
       }
       const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset();
@@ -649,17 +657,17 @@ bool ReconstructGlyf(const uint8_t* data
       }
       uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size;
       StoreU16(instruction_dst, 0, instruction_size);
       if (!instruction_stream.Read(instruction_dst + 2, instruction_size)) {
         return OTS_FAILURE();
       }
       if (!StorePoints(points, n_contours, instruction_size,
             glyf_dst, glyf_dst_size, &glyph_size)) {
-        return OTS_FAILURE();
+        return OTS_FAILURE_MSG("Failed to store points of glyph %d from the transformed 'glyf' table", i);
       }
     } else {
       glyph_size = 0;
     }
     loca_values.push_back(loca_offset);
     if (glyph_size + 3 < glyph_size) {
       return OTS_FAILURE();
     }
@@ -670,17 +678,17 @@ bool ReconstructGlyf(const uint8_t* data
       return OTS_FAILURE();
     }
     loca_offset += glyph_size;
   }
   loca_values.push_back(loca_offset);
   assert(loca_values.size() == static_cast<size_t>(num_glyphs + 1));
   if (!ProcessBboxStream(&bbox_stream, num_glyphs, loca_values,
           dst, dst_size)) {
-    return OTS_FAILURE();
+    return OTS_FAILURE_MSG("Filed to process 'bboxStream' from the transformed 'glyf' table");
   }
   return StoreLoca(loca_values, index_format, loca_buf, loca_size);
 }
 
 // This is linear search, but could be changed to binary because we
 // do have a guarantee that the tables are sorted by tag. But the total
 // cpu time is expected to be very small in any case.
 const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) {
@@ -688,34 +696,35 @@ const Table* FindTable(const std::vector
   for (size_t i = 0; i < n_tables; ++i) {
     if (tables.at(i).tag == tag) {
       return &tables.at(i);
     }
   }
   return NULL;
 }
 
-bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag,
+bool ReconstructTransformed(ots::OpenTypeFile* file,
+    const std::vector<Table>& tables, uint32_t tag,
     const uint8_t* transformed_buf, size_t transformed_size,
     uint8_t* dst, size_t dst_length) {
   if (tag == TAG('g', 'l', 'y', 'f')) {
     const Table* glyf_table = FindTable(tables, tag);
     const Table* loca_table = FindTable(tables, TAG('l', 'o', 'c', 'a'));
     if (glyf_table == NULL || loca_table == NULL) {
       return OTS_FAILURE();
     }
     if (static_cast<uint64_t>(glyf_table->dst_offset) + glyf_table->dst_length >
         dst_length) {
       return OTS_FAILURE();
     }
     if (static_cast<uint64_t>(loca_table->dst_offset) + loca_table->dst_length >
         dst_length) {
       return OTS_FAILURE();
     }
-    return ReconstructGlyf(transformed_buf, transformed_size,
+    return ReconstructGlyf(file, transformed_buf, transformed_size,
         dst + glyf_table->dst_offset, glyf_table->dst_length,
         dst + loca_table->dst_offset, loca_table->dst_length);
   } else if (tag == TAG('l', 'o', 'c', 'a')) {
     // processing was already done by glyf table, but validate
     if (!FindTable(tables, TAG('g', 'l', 'y', 'f'))) {
       return OTS_FAILURE();
     }
   } else {
@@ -769,17 +778,17 @@ bool Woff2Uncompress(uint8_t* dst_buf, s
   int ok = BrotliDecompressBuffer(src_size, src_buf,
                                   &uncompressed_size, dst_buf);
   if (!ok || uncompressed_size != dst_size) {
     return OTS_FAILURE();
   }
   return true;
 }
 
-bool ReadShortDirectory(ots::OpenTypeFile* file,
+bool ReadTableDirectory(ots::OpenTypeFile* file,
     ots::Buffer* buffer, std::vector<Table>* tables,
     size_t num_tables) {
   for (size_t i = 0; i < num_tables; ++i) {
     Table* table = &tables->at(i);
     uint8_t flag_byte;
     if (!buffer->ReadU8(&flag_byte)) {
       return OTS_FAILURE_MSG("Failed to read the flags of table directory entry %d", i);
     }
@@ -798,28 +807,28 @@ bool ReadShortDirectory(ots::OpenTypeFil
     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(buffer, &dst_length)) {
-      return OTS_FAILURE_MSG("Failed to read \"origLength\" for table %4.4s", (char*)&tag);
+      return OTS_FAILURE_MSG("Failed to read 'origLength' for table '%c%c%c%c'", CHR(tag));
     }
     uint32_t transform_length = dst_length;
     if ((flags & kWoff2FlagsTransform) != 0) {
       if (!ReadBase128(buffer, &transform_length)) {
-        return OTS_FAILURE_MSG("Failed to read \"transformLength\" for table %4.4s", (char*)&tag);
+        return OTS_FAILURE_MSG("Failed to read 'transformLength' for table '%c%c%c%c'", CHR(tag));
       }
     }
     // Disallow huge numbers (> 1GB) for sanity.
     if (transform_length > 1024 * 1024 * 1024 ||
         dst_length > 1024 * 1024 * 1024) {
-      return OTS_FAILURE_MSG("\"origLength\" or \"transformLength\" > 1GB");
+      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;
 }
@@ -834,64 +843,96 @@ size_t ComputeWOFF2FinalSize(const uint8
 
   if (!file.Skip(16) ||
       !file.ReadU32(&total_length)) {
     return 0;
   }
   return total_length;
 }
 
-bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
-                       uint8_t* result, size_t result_length,
-                       const uint8_t* data, size_t length) {
+bool ConvertWOFF2ToSFNT(ots::OpenTypeFile* file,
+                        uint8_t* result, size_t result_length,
+                        const uint8_t* data, size_t length) {
   static const uint32_t kWoff2Signature = 0x774f4632;  // "wOF2"
   ots::Buffer buffer(data, length);
 
   uint32_t signature;
   uint32_t flavor = 0;
   if (!buffer.ReadU32(&signature) || signature != kWoff2Signature ||
       !buffer.ReadU32(&flavor)) {
-    return OTS_FAILURE_MSG("Failed to read \"signature\" or \"flavor\", or not WOFF2 signature");
+    return OTS_FAILURE_MSG("Failed to read 'signature' or 'flavor', or not WOFF2 signature");
   }
 
   if (!IsValidVersionTag(ntohl(flavor))) {
-    return OTS_FAILURE_MSG("Invalid \"flavor\"");
+    return OTS_FAILURE_MSG("Invalid 'flavor'");
   }
 
   uint32_t reported_length;
   if (!buffer.ReadU32(&reported_length) || length != reported_length) {
-    return OTS_FAILURE_MSG("Failed to read \"length\" or it does not match the actual file size");
+    return OTS_FAILURE_MSG("Failed to read 'length' or it does not match the actual file size");
   }
   uint16_t num_tables;
   if (!buffer.ReadU16(&num_tables) || !num_tables) {
-    return OTS_FAILURE_MSG("Failed to read \"numTables\"");
+    return OTS_FAILURE_MSG("Failed to read 'numTables'");
   }
+
+  uint16_t reserved_value;
+  if (!buffer.ReadU16(&reserved_value)) {
+    return OTS_FAILURE_MSG("Failed to read 'reserved' field");
+  }
+
   // We don't care about these fields of the header:
-  //   uint16_t reserved
-  //   uint32_t total_sfnt_size
-  if (!buffer.Skip(6)) {
-    return OTS_FAILURE_MSG("Failed to read \"reserve\" or \"totalSfntSize\"");
+  //   uint32_t total_sfnt_size, the caller already passes it as result_length
+  if (!buffer.Skip(4)) {
+    return OTS_FAILURE_MSG("Failed to read 'totalSfntSize'");
   }
   uint32_t compressed_length;
   if (!buffer.ReadU32(&compressed_length)) {
-    return OTS_FAILURE_MSG("Failed to read \"totalCompressedSize\"");
+    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 (!buffer.Skip(24)) {
-    return OTS_FAILURE();
+  if (!buffer.Skip(2 * 2)) {
+    return OTS_FAILURE_MSG("Failed to read 'majorVersion' or 'minorVersion'");
+  }
+
+  // Checks metadata block size.
+  uint32_t meta_offset;
+  uint32_t meta_length;
+  uint32_t meta_length_orig;
+  if (!buffer.ReadU32(&meta_offset) ||
+      !buffer.ReadU32(&meta_length) ||
+      !buffer.ReadU32(&meta_length_orig)) {
+    return OTS_FAILURE_MSG("Failed to read header metadata block fields");
   }
+  if (meta_offset) {
+    if (meta_offset >= length || length - meta_offset < meta_length) {
+      return OTS_FAILURE_MSG("Invalid metadata block offset or length");
+    }
+  }
+
+  // Checks private data block size.
+  uint32_t priv_offset;
+  uint32_t priv_length;
+  if (!buffer.ReadU32(&priv_offset) ||
+      !buffer.ReadU32(&priv_length)) {
+    return OTS_FAILURE_MSG("Failed to read header private block fields");
+  }
+  if (priv_offset) {
+    if (priv_offset >= length || length - priv_offset < priv_length) {
+      return OTS_FAILURE_MSG("Invalid private block offset or length");
+    }
+  }
+
   std::vector<Table> tables(num_tables);
-  if (!ReadShortDirectory(file, &buffer, &tables, num_tables)) {
+  if (!ReadTableDirectory(file, &buffer, &tables, num_tables)) {
     return OTS_FAILURE_MSG("Failed to read table directory");
   }
   uint64_t compressed_offset = buffer.offset();
   if (compressed_offset > std::numeric_limits<uint32_t>::max()) {
     return OTS_FAILURE();
   }
   uint64_t dst_offset = kSfntHeaderSize +
       kSfntEntrySize * static_cast<uint64_t>(num_tables);
@@ -899,39 +940,72 @@ bool ConvertWOFF2ToTTF(ots::OpenTypeFile
     Table* table = &tables.at(i);
     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 (ots::Round4(compressed_offset + compressed_length) > length || dst_offset > result_length) {
-    return OTS_FAILURE();
+
+  uint64_t block_end = ots::Round4(compressed_offset + compressed_length);
+  if (block_end > length || dst_offset != result_length) {
+    return OTS_FAILURE_MSG("Uncompressed sfnt size mismatch");
   }
 
   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();
   }
 
+  if (meta_offset) {
+    if (block_end != meta_offset) {
+      return OTS_FAILURE_MSG("Invalid metadata block offset");
+    }
+    block_end = ots::Round4(static_cast<uint64_t>(meta_offset) +
+                            static_cast<uint64_t>(meta_length));
+    if (block_end > std::numeric_limits<uint32_t>::max()) {
+      return OTS_FAILURE_MSG("Invalid metadata block length");
+    }
+  }
+
+  if (priv_offset) {
+    if (block_end != priv_offset) {
+      return OTS_FAILURE_MSG("Invalid private block offset");
+    }
+    block_end = ots::Round4(static_cast<uint64_t>(priv_offset) +
+                            static_cast<uint64_t>(priv_length));
+    if (block_end > std::numeric_limits<uint32_t>::max()) {
+      return OTS_FAILURE_MSG("Invalid private block length");
+    }
+  }
+
+  if (block_end != ots::Round4(length)) {
+    return OTS_FAILURE_MSG("File length mismatch (trailing junk?)");
+  }
+
   // Start building the font
   size_t offset = 0;
   offset = StoreU32(result, offset, flavor);
   offset = StoreU16(result, offset, num_tables);
   uint8_t max_pow2 = 0;
   while (1u << (max_pow2 + 1) <= num_tables) {
     max_pow2++;
   }
   const uint16_t output_search_range = (1u << max_pow2) << 4;
   offset = StoreU16(result, offset, output_search_range);
   offset = StoreU16(result, offset, max_pow2);
   offset = StoreU16(result, offset, (num_tables << 4) - output_search_range);
+
+  // sort tags in the table directory in ascending alphabetical order
+  std::vector<Table> sorted_tables(tables);
+  std::sort(sorted_tables.begin(), sorted_tables.end());
+
   for (uint16_t i = 0; i < num_tables; ++i) {
-    const Table* table = &tables.at(i);
+    const Table* table = &sorted_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;
   const uint8_t* transform_buf = NULL;
   uint64_t total_size = 0;
@@ -946,17 +1020,17 @@ bool ConvertWOFF2ToTTF(ots::OpenTypeFile
   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();
+    return OTS_FAILURE_MSG("Failed to uncompress font data");
   }
   transform_buf = &uncompressed_buf[0];
 
   for (uint16_t i = 0; i < num_tables; ++i) {
     const Table* table = &tables.at(i);
     uint32_t flags = table->flags;
     size_t transform_length = table->transform_length;
 
@@ -966,26 +1040,26 @@ bool ConvertWOFF2ToTTF(ots::OpenTypeFile
       }
       if (static_cast<uint64_t>(table->dst_offset) + transform_length >
           result_length) {
         return OTS_FAILURE();
       }
       std::memcpy(result + table->dst_offset, transform_buf,
           transform_length);
     } else {
-      if (!ReconstructTransformed(tables, table->tag,
+      if (!ReconstructTransformed(file, tables, table->tag,
             transform_buf, transform_length, result, result_length)) {
-        return OTS_FAILURE();
+        return OTS_FAILURE_MSG("Failed to reconstruct '%c%c%c%c' table", CHR(table->tag));
       }
     }
 
     transform_buf += transform_length;
     if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) {
       return OTS_FAILURE();
     }
   }
 
-  return FixChecksums(tables, result);
+  return FixChecksums(sorted_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(OpenTypeFile *file, uint8_t *result, size_t result_length,
-                       const uint8_t *data, size_t length);
+bool ConvertWOFF2ToSFNT(OpenTypeFile *file, uint8_t *result, size_t result_length,
+                        const uint8_t *data, size_t length);
 }
 
 #endif  // OTS_WOFF2_H_
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -735,21 +735,16 @@ gfxUserFontEntry::FontDataDownloadComple
 gfxUserFontSet::gfxUserFontSet()
     : mFontFamilies(4), mLocalRulesUsed(false)
 {
     IncrementGeneration(true);
     gfxPlatformFontList* fp = gfxPlatformFontList::PlatformFontList();
     if (fp) {
         fp->AddUserFontSet(this);
     }
-
-    // This is a one-time global switch for OTS. However, as long as we use
-    // a preference to control the availability of WOFF2 support, we will
-    // not actually pass any WOFF2 data to OTS unless the pref is on.
-    ots::EnableWOFF2();
 }
 
 gfxUserFontSet::~gfxUserFontSet()
 {
     gfxPlatformFontList* fp = gfxPlatformFontList::PlatformFontList();
     if (fp) {
         fp->RemoveUserFontSet(this);
     }