Bug 1057488 - Part 4: Update OTS to 5c25bdac8f02080f49fa416ea997ed77e3be0d30. r=jfkthame
authorFrédéric Wang <fred.wang@free.fr>
Sun, 24 Aug 2014 09:52:00 -0400
changeset 223056 2bf8a805206e2bf6bf413fbce20c5d134a285bfa
parent 223055 96312bdb2fb49b5ff951b863944c8b6ba8840bde
child 223057 822c7f85492071623888d03a36a987421ba51a32
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1057488
milestone34.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 1057488 - Part 4: Update OTS to 5c25bdac8f02080f49fa416ea997ed77e3be0d30. r=jfkthame
gfx/ots/README.mozilla
gfx/ots/src/cff_type2_charstring.cc
gfx/ots/src/cmap.cc
gfx/ots/src/cvt.cc
gfx/ots/src/fpgm.cc
gfx/ots/src/gasp.cc
gfx/ots/src/glyf.cc
gfx/ots/src/hdmx.cc
gfx/ots/src/kern.cc
gfx/ots/src/layout.cc
gfx/ots/src/ltsh.cc
gfx/ots/src/math.cc
gfx/ots/src/maxp.cc
gfx/ots/src/ots.cc
gfx/ots/src/ots.h
gfx/ots/src/prep.cc
gfx/ots/src/vdmx.cc
gfx/ots/src/vorg.cc
--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,11 +1,11 @@
 This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
 
 Our reference repository is https://github.com/khaledhosny/ots/.
 
-Current revision: 97d043dd8977751835ca8d33d773ae8416e456d5
+Current revision: 5c25bdac8f02080f49fa416ea997ed77e3be0d30
 
 Upstream files included: LICENSE, src/, include/
 
 Additional files: README.mozilla, src/moz.build
 
 Additional patch: ots-visibility.patch (bug 711079).
--- a/gfx/ots/src/cff_type2_charstring.cc
+++ b/gfx/ots/src/cff_type2_charstring.cc
@@ -703,17 +703,17 @@ bool ExecuteType2CharStringOperator(int3
     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);
+  //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.
--- a/gfx/ots/src/cmap.cc
+++ b/gfx/ots/src/cmap.cc
@@ -743,42 +743,43 @@ bool ots_cmap_parse(OpenTypeFile *file, 
   }
   const uint16_t num_glyphs = file->maxp->num_glyphs;
 
   // We only support a subset of the possible character map tables. Microsoft
   // 'strongly recommends' that everyone supports the Unicode BMP table with
   // the UCS-4 table for non-BMP glyphs. We'll pass the following subtables:
   //   Platform ID   Encoding ID  Format
   //   0             0            4       (Unicode Default)
+  //   0             1            4       (Unicode 1.1)
   //   0             3            4       (Unicode BMP)
   //   0             3            12      (Unicode UCS-4)
   //   0             5            14      (Unicode Variation Sequences)
   //   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-0-4 and 0-1-4 tables are (usually) written as a 3-1-4 table. If 3-1-4 table
+  //    also exists, the 0-0-4 or 0-1-4 tables are ignored.
   //  * Unlike 0-0-4 table, 0-3-4 table is written as a 0-3-4 table.
   //    Some fonts which include 0-5-14 table seems to be required 0-3-4
   //    table. The 0-3-4 table will be wriiten even if 3-1-4 table also exists.
   //  * 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) &&
+      if ((subtable_headers[i].encoding == 0 || subtable_headers[i].encoding == 1) &&
           (subtable_headers[i].format == 4)) {
-        // parse and output the 0-0-4 table as 3-1-4 table. Sometimes the 0-0-4
+        // parse and output the 0-0-4 and 0-1-4 tables as 3-1-4 table. Sometimes the 0-0-4
         // table actually points to MS symbol data and thus should be parsed as
         // 3-0-4 table (e.g., marqueem.ttf and quixotic.ttf). This error will be
         // recovered in ots_cmap_serialise().
         if (!ParseFormat4(file, 3, 1, data + subtable_headers[i].offset,
                       subtable_headers[i].length, num_glyphs)) {
           return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
         }
       } else if ((subtable_headers[i].encoding == 3) &&
@@ -872,17 +873,17 @@ bool ots_cmap_serialise(OTSStream *out, 
                                  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 && !have_034 && !have_31012 && !have_31013) {
-    return OTS_FAILURE();
+    return OTS_FAILURE_MSG("no supported subtables were found");
   }
 
   if (!out->WriteU16(0) ||
       !out->WriteU16(num_subtables)) {
     return OTS_FAILURE();
   }
 
   const off_t record_offset = out->Tell();
--- 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 g_transcode_hints && file->cvt;
+  return 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_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 g_transcode_hints && file->fpgm;
+  return 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_MSG("Failed to write fpgm");
   }
--- a/gfx/ots/src/gasp.cc
+++ b/gfx/ots/src/gasp.cc
@@ -4,20 +4,21 @@
 
 #include "gasp.h"
 
 // gasp - Grid-fitting And Scan-conversion Procedure
 // http://www.microsoft.com/typography/otspec/gasp.htm
 
 #define TABLE_NAME "gasp"
 
-#define DROP_THIS_TABLE \
+#define DROP_THIS_TABLE(...) \
   do { \
     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);
 
@@ -27,47 +28,43 @@ bool ots_gasp_parse(OpenTypeFile *file, 
   uint16_t num_ranges = 0;
   if (!table.ReadU16(&gasp->version) ||
       !table.ReadU16(&num_ranges)) {
     return OTS_FAILURE_MSG("Failed to read table header");
   }
 
   if (gasp->version > 1) {
     // Lots of Linux fonts have bad version numbers...
-    OTS_WARNING("bad version: %u", gasp->version);
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("bad version: %u", gasp->version);
     return true;
   }
 
   if (num_ranges == 0) {
-    OTS_WARNING("num_ranges is zero");
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("num_ranges is zero");
     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_MSG("Failed to read subrange %d", i);
     }
     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;
+      DROP_THIS_TABLE("ranges are not sorted");
       return true;
     }
     if ((i == num_ranges - 1u) &&  // never underflow.
         (max_ppem != 0xffffu)) {
-      OTS_WARNING("The last record should be 0xFFFF as a sentinel value "
+      DROP_THIS_TABLE("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;
     }
--- a/gfx/ots/src/glyf.cc
+++ b/gfx/ots/src/glyf.cc
@@ -107,29 +107,19 @@ bool ParseSimpleGlyph(ots::OpenTypeFile 
     return OTS_FAILURE_MSG("Bytecode length too high %d", bytecode_length);
   }
 
   const uint32_t gly_header_length = 10 + num_contours * 2 + 2;
   if (gly_length < (gly_header_length + bytecode_length)) {
     return OTS_FAILURE_MSG("Glyph header length too high %d", gly_header_length);
   }
 
-  if (ots::g_transcode_hints) {
-    glyf->iov.push_back(std::make_pair(
-        data + gly_offset,
-        static_cast<size_t>(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,
-        static_cast<size_t>(gly_header_length - 2)));
-    glyf->iov.push_back(std::make_pair((const uint8_t*) "\x00\x00",
-                                       static_cast<size_t>(2)));
-  }
+  glyf->iov.push_back(std::make_pair(
+      data + gly_offset,
+      static_cast<size_t>(gly_header_length + bytecode_length)));
 
   if (!table->Skip(bytecode_length)) {
     return OTS_FAILURE_MSG("Can't skip bytecode of length %d", bytecode_length);
   }
 
   uint32_t flags_count_physical = 0;  // on memory
   uint32_t xy_coordinates_length = 0;
   for (uint32_t flags_count_logical = 0;
@@ -158,20 +148,17 @@ bool ParseSimpleGlyph(ots::OpenTypeFile 
     return OTS_FAILURE_MSG("Invalid glyph length %d", gly_length);
   }
 
   glyf->iov.push_back(std::make_pair(
       data + gly_offset + gly_header_length + bytecode_length,
       static_cast<size_t>(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;
-  }
+      = gly_header_length + flags_count_physical + xy_coordinates_length + bytecode_length;
 
   return true;
 }
 
 }  // namespace
 
 namespace ots {
 
--- a/gfx/ots/src/hdmx.cc
+++ b/gfx/ots/src/hdmx.cc
@@ -6,62 +6,59 @@
 #include "head.h"
 #include "maxp.h"
 
 // hdmx - Horizontal Device Metrics
 // http://www.microsoft.com/typography/otspec/hdmx.htm
 
 #define TABLE_NAME "hdmx"
 
-#define DROP_THIS_TABLE \
+#define DROP_THIS_TABLE(...) \
   do { \
     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;
 
   if (!file->head || !file->maxp) {
     return OTS_FAILURE_MSG("Missing maxp or head tables in font, needed by hdmx");
   }
 
   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;
+    DROP_THIS_TABLE("the table should not be present when bit 2 and 4 of the "
+                    "head->flags are not set");
     return true;
   }
 
   int16_t num_recs;
   if (!table.ReadU16(&hdmx->version) ||
       !table.ReadS16(&num_recs) ||
       !table.ReadS32(&hdmx->size_device_record)) {
     return OTS_FAILURE_MSG("Failed to read hdmx header");
   }
   if (hdmx->version != 0) {
-    OTS_WARNING("bad version: %u", hdmx->version);
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("bad version: %u", hdmx->version);
     return true;
   }
   if (num_recs <= 0) {
-    OTS_WARNING("bad num_recs: %d", num_recs);
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("bad num_recs: %d", num_recs);
     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;
+    DROP_THIS_TABLE("bad hdmx->size_device_record: %d", hdmx->size_device_record);
     return true;
   }
 
   hdmx->pad_len = hdmx->size_device_record - actual_size_device_record;
   if (hdmx->pad_len > 3) {
     return OTS_FAILURE_MSG("Bad padding %d", hdmx->pad_len);
   }
 
@@ -71,18 +68,17 @@ bool ots_hdmx_parse(OpenTypeFile *file, 
     OpenTypeHDMXDeviceRecord rec;
 
     if (!table.ReadU8(&rec.pixel_size) ||
         !table.ReadU8(&rec.max_width)) {
       return OTS_FAILURE_MSG("Failed to read hdmx record %d", i);
     }
     if ((i != 0) &&
         (rec.pixel_size <= last_pixel_size)) {
-      OTS_WARNING("records are not sorted");
-      DROP_THIS_TABLE;
+      DROP_THIS_TABLE("records are not sorted");
       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)) {
--- a/gfx/ots/src/kern.cc
+++ b/gfx/ots/src/kern.cc
@@ -4,21 +4,21 @@
 
 #include "kern.h"
 
 // kern - Kerning
 // http://www.microsoft.com/typography/otspec/kern.htm
 
 #define TABLE_NAME "kern"
 
-#define DROP_THIS_TABLE \
+#define DROP_THIS_TABLE(msg_) \
   do { \
     delete file->kern; \
     file->kern = 0; \
-    OTS_FAILURE_MSG("Table discarded"); \
+    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;
@@ -26,23 +26,22 @@ bool ots_kern_parse(OpenTypeFile *file, 
 
   uint16_t num_tables = 0;
   if (!table.ReadU16(&kern->version) ||
       !table.ReadU16(&num_tables)) {
     return OTS_FAILURE_MSG("Failed to read kern header");
   }
 
   if (kern->version > 0) {
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("bad table version");
     return true;
   }
 
   if (num_tables == 0) {
-    OTS_WARNING("num_tables is zero");
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("num_tables is zero");
     return true;
   }
 
   kern->subtables.reserve(num_tables);
   for (unsigned i = 0; i < num_tables; ++i) {
     OpenTypeKERNFormat0 subtable;
     uint16_t sub_length = 0;
 
@@ -66,18 +65,17 @@ bool ots_kern_parse(OpenTypeFile *file, 
     }
 
     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;
+      DROP_THIS_TABLE("Reserved fields should zero-filled.");
       return true;
     }
     const uint32_t format = (subtable.coverage & 0xFF00) >> 8;
     if (format != 0) {
       OTS_WARNING("Format %d is not supported.", format);
       continue;
     }
 
@@ -86,28 +84,26 @@ bool ots_kern_parse(OpenTypeFile *file, 
     if (!table.ReadU16(&num_pairs) ||
         !table.ReadU16(&subtable.search_range) ||
         !table.ReadU16(&subtable.entry_selector) ||
         !table.ReadU16(&subtable.range_shift)) {
       return OTS_FAILURE_MSG("Failed to read kern subtable %d format 0 fields", i);
     }
 
     if (!num_pairs) {
-      OTS_WARNING("Zero length subtable is found.");
-      DROP_THIS_TABLE;
+      DROP_THIS_TABLE("Zero length subtable is found.");
       return true;
     }
 
     // Sanity checks for search_range, entry_selector, and range_shift. See the
     // comment in ots.cc for details.
     const size_t kFormat0PairSize = 6;  // left, right, and value. 2 bytes each.
     if (num_pairs > (65536 / kFormat0PairSize)) {
       // Some fonts (e.g. calibri.ttf, pykes_peak_zero.ttf) have pairs >= 10923.
-      OTS_WARNING("Too large subtable.");
-      DROP_THIS_TABLE;
+      DROP_THIS_TABLE("Too large subtable.");
       return true;
     }
     unsigned max_pow2 = 0;
     while (1u << (max_pow2 + 1) <= num_pairs) {
       ++max_pow2;
     }
     const uint16_t expected_search_range = (1u << max_pow2) * kFormat0PairSize;
     if (subtable.search_range != expected_search_range) {
@@ -132,32 +128,30 @@ bool ots_kern_parse(OpenTypeFile *file, 
       if (!table.ReadU16(&kerning_pair.left) ||
           !table.ReadU16(&kerning_pair.right) ||
           !table.ReadS16(&kerning_pair.value)) {
         return OTS_FAILURE_MSG("Failed to read subtable %d kerning pair %d", i, j);
       }
       const uint32_t current_pair
           = (kerning_pair.left << 16) + kerning_pair.right;
       if (j != 0 && current_pair <= last_pair) {
-        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;
+        DROP_THIS_TABLE("Kerning pairs are not sorted.");
         return true;
       }
       last_pair = current_pair;
       subtable.pairs.push_back(kerning_pair);
     }
 
     kern->subtables.push_back(subtable);
   }
 
   if (!kern->subtables.size()) {
-    OTS_WARNING("All subtables are removed.");
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("All subtables are removed.");
     return true;
   }
 
   return true;
 }
 
 bool ots_kern_should_serialise(OpenTypeFile *file) {
   if (!file->glyf) return false;  // this table is not for CFF fonts.
--- a/gfx/ots/src/layout.cc
+++ b/gfx/ots/src/layout.cc
@@ -265,34 +265,32 @@ bool ParseClassDefFormat1(const ots::Ope
     return OTS_FAILURE_MSG("Failed to skip class definition header");
   }
 
   uint16_t start_glyph = 0;
   if (!subtable.ReadU16(&start_glyph)) {
     return OTS_FAILURE_MSG("Failed to read starting glyph of class definition");
   }
   if (start_glyph > num_glyphs) {
-    OTS_WARNING("bad start glyph ID: %u", start_glyph);
     return OTS_FAILURE_MSG("Bad starting glyph %d in class definition", start_glyph);
   }
 
   uint16_t glyph_count = 0;
   if (!subtable.ReadU16(&glyph_count)) {
     return OTS_FAILURE_MSG("Failed to read glyph count in class definition");
   }
   if (glyph_count > num_glyphs) {
     return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count);
   }
   for (unsigned i = 0; i < glyph_count; ++i) {
     uint16_t class_value = 0;
     if (!subtable.ReadU16(&class_value)) {
       return OTS_FAILURE_MSG("Failed to read class value for glyph %d in class definition", i);
     }
     if (class_value > num_classes) {
-      OTS_WARNING("bad class value: %u", class_value);
       return OTS_FAILURE_MSG("Bad class value %d for glyph %d in class definition", class_value, i);
     }
   }
 
   return true;
 }
 
 bool ParseClassDefFormat2(const ots::OpenTypeFile *file,
--- a/gfx/ots/src/ltsh.cc
+++ b/gfx/ots/src/ltsh.cc
@@ -6,20 +6,21 @@
 
 #include "maxp.h"
 
 // LTSH - Linear Threshold
 // http://www.microsoft.com/typography/otspec/ltsh.htm
 
 #define TABLE_NAME "LTSH"
 
-#define DROP_THIS_TABLE \
+#define DROP_THIS_TABLE(...) \
   do { \
     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);
 
@@ -32,24 +33,22 @@ bool ots_ltsh_parse(OpenTypeFile *file, 
 
   uint16_t num_glyphs = 0;
   if (!table.ReadU16(&ltsh->version) ||
       !table.ReadU16(&num_glyphs)) {
     return OTS_FAILURE_MSG("Failed to read ltsh header");
   }
 
   if (ltsh->version != 0) {
-    OTS_WARNING("bad version: %u", ltsh->version);
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("bad version: %u", ltsh->version);
     return true;
   }
 
   if (num_glyphs != file->maxp->num_glyphs) {
-    OTS_WARNING("bad num_glyphs: %u", num_glyphs);
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("bad num_glyphs: %u", num_glyphs);
     return true;
   }
 
   ltsh->ypels.reserve(num_glyphs);
   for (unsigned i = 0; i < num_glyphs; ++i) {
     uint8_t pel = 0;
     if (!table.ReadU8(&pel)) {
       return OTS_FAILURE_MSG("Failed to read pixels for glyph %d", i);
--- a/gfx/ots/src/math.cc
+++ b/gfx/ots/src/math.cc
@@ -379,22 +379,20 @@ bool ParseGlyphAssemblyTable(const ots::
     uint16_t glyph = 0;
     uint16_t part_flags = 0;
     if (!subtable.ReadU16(&glyph) ||
         !subtable.Skip(2 * 3) ||
         !subtable.ReadU16(&part_flags)) {
       return OTS_FAILURE();
     }
     if (glyph >= num_glyphs) {
-      OTS_WARNING("bad glyph ID: %u", glyph);
-      return OTS_FAILURE();
+      return OTS_FAILURE_MSG("bad glyph ID: %u", glyph);
     }
     if (part_flags & ~0x00000001) {
-      OTS_WARNING("unknown part flag: %u", part_flags);
-      return OTS_FAILURE();
+      return OTS_FAILURE_MSG("unknown part flag: %u", part_flags);
     }
   }
 
   return true;
 }
 
 bool ParseMathGlyphConstructionTable(const ots::OpenTypeFile *file,
                                      const uint8_t *data,
@@ -430,18 +428,17 @@ bool ParseMathGlyphConstructionTable(con
   // Check the sequence of MathGlyphVariantRecord.
   for (unsigned i = 0; i < variant_count; ++i) {
     uint16_t glyph = 0;
     if (!subtable.ReadU16(&glyph) ||
         !subtable.Skip(2)) {
       return OTS_FAILURE();
     }
     if (glyph >= num_glyphs) {
-      OTS_WARNING("bad glyph ID: %u", glyph);
-      return OTS_FAILURE();
+      return OTS_FAILURE_MSG("bad glyph ID: %u", glyph);
     }
   }
 
   return true;
 }
 
 bool ParseMathGlyphConstructionSequence(const ots::OpenTypeFile *file,
                                         ots::Buffer* subtable,
@@ -514,18 +511,22 @@ bool ParseMathVariantsTable(const ots::O
     return OTS_FAILURE();
   }
 
   return true;
 }
 
 }  // namespace
 
-#define DROP_THIS_TABLE \
-  do { file->math->data = 0; file->math->length = 0; } while (0)
+#define DROP_THIS_TABLE(msg_) \
+  do { \
+    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) {
     return OTS_FAILURE();
@@ -537,18 +538,17 @@ bool ots_math_parse(OpenTypeFile *file, 
   OpenTypeMATH* math = new OpenTypeMATH;
   file->math = math;
 
   uint32_t version = 0;
   if (!table.ReadU32(&version)) {
     return OTS_FAILURE();
   }
   if (version != 0x00010000) {
-    OTS_WARNING("bad MATH version");
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("bad MATH version");
     return true;
   }
 
   uint16_t offset_math_constants = 0;
   uint16_t offset_math_glyph_info = 0;
   uint16_t offset_math_variants = 0;
   if (!table.ReadU16(&offset_math_constants) ||
       !table.ReadU16(&offset_math_glyph_info) ||
@@ -557,34 +557,33 @@ bool ots_math_parse(OpenTypeFile *file, 
   }
 
   if (offset_math_constants >= length ||
       offset_math_constants < kMathHeaderSize ||
       offset_math_glyph_info >= length ||
       offset_math_glyph_info < kMathHeaderSize ||
       offset_math_variants >= length ||
       offset_math_variants < kMathHeaderSize) {
-    OTS_WARNING("bad offset in MATH header");
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("bad offset in MATH header");
     return true;
   }
 
   if (!ParseMathConstantsTable(file, data + offset_math_constants,
                                length - offset_math_constants)) {
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("failed to parse MathConstants table");
     return true;
   }
   if (!ParseMathGlyphInfoTable(file, data + offset_math_glyph_info,
                                length - offset_math_glyph_info, num_glyphs)) {
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("failed to parse MathGlyphInfo table");
     return true;
   }
   if (!ParseMathVariantsTable(file, data + offset_math_variants,
                               length - offset_math_variants, num_glyphs)) {
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("failed to parse MathVariants table");
     return true;
   }
 
   math->data = data;
   math->length = length;
   return true;
 }
 
--- a/gfx/ots/src/maxp.cc
+++ b/gfx/ots/src/maxp.cc
@@ -88,36 +88,24 @@ bool ots_maxp_serialise(OTSStream *out, 
 
   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_MSG("Failed to write maxp");
   }
 
-  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_MSG("Failed to write more maxp");
-    }
-  } 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_MSG("Failed to write more maxp");
-    }
+  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_MSG("Failed to write more maxp");
   }
 
   if (!out->WriteU16(maxp->max_c_components) ||
       !out->WriteU16(maxp->max_c_depth)) {
     return OTS_FAILURE_MSG("Failed to write yet more maxp");
   }
 
   return true;
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -194,32 +194,32 @@ bool ProcessTTF(ots::OpenTypeFile *heade
   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");
+    OTS_FAILURE_MSG_HDR("bad search range");
     header->search_range = expected_search_range;  // Fix the value.
   }
 
   // entry_selector is Log2(maximum power of 2 <= numTables)
   if (header->entry_selector != max_pow2) {
     return OTS_FAILURE_MSG_HDR("incorrect entrySelector for table directory");
   }
 
   // range_shift is NumTables x 16-searchRange. We know that 16*num_tables
   // doesn't over flow because we range checked it above. Also, we know that
   // it's > 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");
+    OTS_FAILURE_MSG_HDR("bad range shift");
     header->range_shift = expected_range_shift;  // the same as above.
   }
 
   // Next up is the list of tables.
   std::vector<OpenTypeTable> tables;
 
   for (unsigned i = 0; i < header->num_tables; ++i) {
     OpenTypeTable table;
@@ -834,23 +834,11 @@ bool OTSContext::Process(OTSStream *outp
 #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
--- a/gfx/ots/src/ots.h
+++ b/gfx/ots/src/ots.h
@@ -24,58 +24,43 @@ 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
-
 // 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 a message_func pointer has been provided, this will be called before returning
-// the 'false' status.
+
+#if defined(_MSC_VER) || !defined(OTS_DEBUG)
+#define OTS_MESSAGE_(otf_,...) \
+  (otf_)->context->Message(__VA_ARGS__)
+#else
+#define OTS_MESSAGE_(otf_,...) \
+  OTS_FAILURE(), \
+  (otf_)->context->Message(__VA_ARGS__)
+#endif
 
 // Generate a simple message
 #define OTS_FAILURE_MSG_(otf_,...) \
-  ((otf_)->context->Message(__VA_ARGS__), false)
+  (OTS_MESSAGE_(otf_,__VA_ARGS__), false)
 
 // Generate a message with an associated table tag
 #define OTS_FAILURE_MSG_TAG_(otf_,msg_,tag_) \
-  ((otf_)->context->Message("%4.4s: %s", tag_, msg_), false)
+  (OTS_MESSAGE_(otf_,"%4.4s: %s", tag_, msg_), false)
 
 // Convenience macro for use in files that only handle a single table tag,
 // defined as TABLE_NAME at the top of the file; the 'file' variable is
 // expected to be the current OpenTypeFile pointer.
 #define OTS_FAILURE_MSG(...) OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__)
 
-// 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
+#define OTS_WARNING OTS_FAILURE_MSG
 
 // -----------------------------------------------------------------------------
 // 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.
 // -----------------------------------------------------------------------------
--- 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 g_transcode_hints && file->prep;
+  return 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_MSG("Failed to write table length");
   }
--- a/gfx/ots/src/vdmx.cc
+++ b/gfx/ots/src/vdmx.cc
@@ -4,20 +4,21 @@
 
 #include "vdmx.h"
 
 // VDMX - Vertical Device Metrics
 // http://www.microsoft.com/typography/otspec/vdmx.htm
 
 #define TABLE_NAME "VDMX"
 
-#define DROP_THIS_TABLE \
+#define DROP_THIS_TABLE(...) \
   do { \
     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;
@@ -25,53 +26,49 @@ bool ots_vdmx_parse(OpenTypeFile *file, 
 
   if (!table.ReadU16(&vdmx->version) ||
       !table.ReadU16(&vdmx->num_recs) ||
       !table.ReadU16(&vdmx->num_ratios)) {
     return OTS_FAILURE_MSG("Failed to read table header");
   }
 
   if (vdmx->version > 1) {
-    OTS_WARNING("bad version: %u", vdmx->version);
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("bad version: %u", vdmx->version);
     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_MSG("Failed to read ratio header %d", i);
     }
 
     if (rec.charset > 1) {
-      OTS_WARNING("bad charset: %u", rec.charset);
-      DROP_THIS_TABLE;
+      DROP_THIS_TABLE("bad charset: %u", rec.charset);
       return true;
     }
 
     if (rec.y_start_ratio > rec.y_end_ratio) {
-      OTS_WARNING("bad y ratio");
-      DROP_THIS_TABLE;
+      DROP_THIS_TABLE("bad y ratio");
       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;
+      DROP_THIS_TABLE("superfluous terminator found");
       return true;
     }
 
     vdmx->rat_ranges.push_back(rec);
   }
 
   vdmx->offsets.reserve(vdmx->num_ratios);
   const size_t current_offset = table.offset();
@@ -100,26 +97,24 @@ bool ots_vdmx_parse(OpenTypeFile *file, 
     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_MSG("Failed to read reacord %d group %d", i, j);
       }
       if (vt.y_max < vt.y_min) {
-        OTS_WARNING("bad y min/max");
-        DROP_THIS_TABLE;
+        DROP_THIS_TABLE("bad y min/max");
         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;
+        DROP_THIS_TABLE("the table is not sorted");
         return true;
       }
 
       group.entries.push_back(vt);
     }
     vdmx->groups.push_back(group);
   }
 
--- a/gfx/ots/src/vorg.cc
+++ b/gfx/ots/src/vorg.cc
@@ -6,20 +6,21 @@
 
 #include <vector>
 
 // VORG - Vertical Origin Table
 // http://www.microsoft.com/typography/otspec/vorg.htm
 
 #define TABLE_NAME "VORG"
 
-#define DROP_THIS_TABLE \
+#define DROP_THIS_TABLE(...) \
   do { \
     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;
@@ -28,23 +29,21 @@ bool ots_vorg_parse(OpenTypeFile *file, 
   uint16_t num_recs;
   if (!table.ReadU16(&vorg->major_version) ||
       !table.ReadU16(&vorg->minor_version) ||
       !table.ReadS16(&vorg->default_vert_origin_y) ||
       !table.ReadU16(&num_recs)) {
     return OTS_FAILURE_MSG("Failed to read header");
   }
   if (vorg->major_version != 1) {
-    OTS_WARNING("bad major version: %u", vorg->major_version);
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("bad major version: %u", vorg->major_version);
     return true;
   }
   if (vorg->minor_version != 0) {
-    OTS_WARNING("bad minor version: %u", vorg->minor_version);
-    DROP_THIS_TABLE;
+    DROP_THIS_TABLE("bad minor version: %u", vorg->minor_version);
     return true;
   }
 
   // num_recs might be zero (e.g., DFHSMinchoPro5-W3-Demo.otf).
   if (!num_recs) {
     return true;
   }
 
@@ -53,18 +52,17 @@ bool ots_vorg_parse(OpenTypeFile *file, 
   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_MSG("Failed to read record %d", i);
     }
     if ((i != 0) && (rec.glyph_index <= last_glyph_index)) {
-      OTS_WARNING("the table is not sorted");
-      DROP_THIS_TABLE;
+      DROP_THIS_TABLE("the table is not sorted");
       return true;
     }
     last_glyph_index = rec.glyph_index;
 
     vorg->metrics.push_back(rec);
   }
 
   return true;