Bug 1074223 - Update OTS to pick up fixes for upstream issues 35, 37. Current rev: c24a839b1c66c4de09e58fabaacb82bf3bd692a4. r=jdaggett, a=lmandel
authorJonathan Kew <jkew@mozilla.com>
Thu, 09 Oct 2014 08:43:30 +0100
changeset 225714 6524ec11ce53
parent 225713 a7b8a4567262
child 225715 98fc091c4706
push id3988
push userryanvm@gmail.com
push date2014-10-17 01:37 +0000
treeherdermozilla-beta@c3fa7201e034 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett, lmandel
bugs1074223
milestone34.0
Bug 1074223 - Update OTS to pick up fixes for upstream issues 35, 37. Current rev: c24a839b1c66c4de09e58fabaacb82bf3bd692a4. r=jdaggett, a=lmandel
gfx/ots/README.mozilla
gfx/ots/include/opentype-sanitiser.h
gfx/ots/ots-brotli-path.patch
gfx/ots/ots-visibility.patch
gfx/ots/src/cff.cc
gfx/ots/src/cff_type2_charstring.cc
gfx/ots/src/cff_type2_charstring.h
gfx/ots/src/cmap.cc
gfx/ots/src/gasp.cc
gfx/ots/src/hdmx.cc
gfx/ots/src/kern.cc
gfx/ots/src/loca.cc
gfx/ots/src/ltsh.cc
gfx/ots/src/metrics.cc
gfx/ots/src/name.cc
gfx/ots/src/ots.cc
gfx/ots/src/ots.h
gfx/ots/src/post.cc
gfx/ots/src/vorg.cc
gfx/ots/src/woff2.cc
gfx/ots/sync.sh
gfx/thebes/gfxUserFontSet.cpp
--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,11 +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: 5c25bdac8f02080f49fa416ea997ed77e3be0d30
+Current revision: c24a839b1c66c4de09e58fabaacb82bf3bd692a4
 
 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
@@ -222,25 +222,31 @@ class OTS_API OTSContext {
     //     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.
-    virtual void Message(const char *format, ...) MSGFUNC_FMT_ATTR {}
+    //   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 EnableWOFF2();
 
 }  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/ots-brotli-path.patch
@@ -0,0 +1,22 @@
+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
@@ -32,17 +32,17 @@ diff --git a/gfx/ots/include/opentype-sa
  #if defined(_WIN32)
  #include <stdlib.h>
  typedef signed char int8_t;
  typedef unsigned char uint8_t;
  typedef short int16_t;
  typedef unsigned short uint16_t;
  typedef int int32_t;
  typedef unsigned int uint32_t;
-@@ -187,17 +187,17 @@ class OTSStream {
+@@ -187,17 +207,17 @@ class OTSStream {
  
  enum TableAction {
    TABLE_ACTION_DEFAULT,  // Use OTS's default action for that table
    TABLE_ACTION_SANITIZE, // Sanitize the table, potentially droping it
    TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
    TABLE_ACTION_DROP      // Drop the table
  };
  
@@ -51,8 +51,23 @@ diff --git a/gfx/ots/include/opentype-sa
    public:
      OTSContext() {}
      ~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/cff.cc
+++ b/gfx/ots/src/cff.cc
@@ -457,31 +457,31 @@ bool ParsePrivateDictData(
     }
     operands.clear();
   }
 
   return true;
 }
 
 bool ParseDictData(const uint8_t *data, size_t table_length,
-                   const ots::CFFIndex &index, size_t glyphs,
+                   const ots::CFFIndex &index, uint16_t glyphs,
                    size_t sid_max, DICT_DATA_TYPE type,
                    ots::OpenTypeCFF *out_cff) {
   for (unsigned i = 1; i < index.offsets.size(); ++i) {
     if (type == DICT_DATA_TOPLEVEL) {
       out_cff->char_strings_array.push_back(new ots::CFFIndex);
     }
     size_t dict_length = index.offsets[i] - index.offsets[i - 1];
     ots::Buffer table(data + index.offsets[i - 1], dict_length);
 
     std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > operands;
 
     FONT_FORMAT font_format = FORMAT_UNKNOWN;
     bool have_ros = false;
-    size_t charstring_glyphs = 0;
+    uint16_t charstring_glyphs = 0;
     size_t charset_offset = 0;
 
     while (table.offset() < dict_length) {
       if (!ParseDictDataReadNext(&table, &operands)) {
         return OTS_FAILURE();
       }
       if (operands.empty()) {
         return OTS_FAILURE();
@@ -695,17 +695,17 @@ bool ParseDictData(const uint8_t *data, 
           // parse FDSelect data structure
           ots::Buffer cff_table(data, table_length);
           cff_table.set_offset(operands.back().first);
           uint8_t format = 0;
           if (!cff_table.ReadU8(&format)) {
             return OTS_FAILURE();
           }
           if (format == 0) {
-            for (size_t j = 0; j < glyphs; ++j) {
+            for (uint16_t j = 0; j < glyphs; ++j) {
               uint8_t fd_index = 0;
               if (!cff_table.ReadU8(&fd_index)) {
                 return OTS_FAILURE();
               }
               (out_cff->fd_select)[j] = fd_index;
             }
           } else if (format == 3) {
             uint16_t n_ranges = 0;
@@ -839,17 +839,17 @@ bool ParseDictData(const uint8_t *data, 
       ots::Buffer cff_table(data, table_length);
       cff_table.set_offset(charset_offset);
       uint8_t format = 0;
       if (!cff_table.ReadU8(&format)) {
         return OTS_FAILURE();
       }
       switch (format) {
         case 0:
-          for (unsigned j = 1 /* .notdef is omitted */; j < glyphs; ++j) {
+          for (uint16_t j = 1 /* .notdef is omitted */; j < glyphs; ++j) {
             uint16_t sid = 0;
             if (!cff_table.ReadU16(&sid)) {
               return OTS_FAILURE();
             }
             if (!have_ros && (sid > sid_max)) {
               return OTS_FAILURE();
             }
             // TODO(yusukes): check CIDs when have_ros is true.
@@ -962,17 +962,17 @@ bool ots_cff_parse(OpenTypeFile *file, c
   CFFIndex string_index;
   if (!ParseIndex(&table, &string_index)) {
     return OTS_FAILURE();
   }
   if (string_index.count >= 65000 - kNStdString) {
     return OTS_FAILURE();
   }
 
-  const size_t num_glyphs = file->maxp->num_glyphs;
+  const uint16_t num_glyphs = file->maxp->num_glyphs;
   const size_t sid_max = string_index.count + kNStdString;
   // string_index.count == 0 is allowed.
 
   // parse "9. Top DICT Data"
   if (!ParseDictData(data, length, top_dict_index,
                      num_glyphs, sid_max,
                      DICT_DATA_TOPLEVEL, file->cff)) {
     return OTS_FAILURE();
@@ -991,17 +991,18 @@ bool ots_cff_parse(OpenTypeFile *file, c
   for (iter = file->cff->fd_select.begin(); iter != end; ++iter) {
     if (iter->second >= file->cff->font_dict_length) {
       return OTS_FAILURE();
     }
   }
 
   // Check if all charstrings (font hinting code for each glyph) are valid.
   for (size_t i = 0; i < file->cff->char_strings_array.size(); ++i) {
-    if (!ValidateType2CharStringIndex(*(file->cff->char_strings_array.at(i)),
+    if (!ValidateType2CharStringIndex(file,
+                                      *(file->cff->char_strings_array.at(i)),
                                       global_subrs_index,
                                       file->cff->fd_select,
                                       file->cff->local_subrs_per_font,
                                       file->cff->local_subrs,
                                       &table)) {
       return OTS_FAILURE_MSG("Failed validating charstring set %d", (int) i);
     }
   }
--- a/gfx/ots/src/cff_type2_charstring.cc
+++ b/gfx/ots/src/cff_type2_charstring.cc
@@ -9,31 +9,34 @@
 
 #include <climits>
 #include <cstdio>
 #include <cstring>
 #include <stack>
 #include <string>
 #include <utility>
 
+#define TABLE_NAME "CFF"
+
 namespace {
 
 // Type 2 Charstring Implementation Limits. See Appendix. B in Adobe Technical
 // Note #5177.
 const int32_t kMaxSubrsCount = 65536;
 const size_t kMaxCharStringLength = 65535;
 const size_t kMaxArgumentStack = 48;
 const size_t kMaxNumberOfStemHints = 96;
 const size_t kMaxSubrNesting = 10;
 
 // |dummy_result| should be a huge positive integer so callsubr and callgsubr
 // will fail with the dummy value.
 const int32_t dummy_result = INT_MAX;
 
-bool ExecuteType2CharString(size_t call_depth,
+bool ExecuteType2CharString(ots::OpenTypeFile *file,
+                            size_t call_depth,
                             const ots::CFFIndex& global_subrs_index,
                             const ots::CFFIndex& local_subrs_index,
                             ots::Buffer *cff_table,
                             ots::Buffer *char_string,
                             std::stack<int32_t> *argument_stack,
                             bool *out_found_endchar,
                             bool *out_found_width,
                             size_t *in_out_num_stems);
@@ -217,17 +220,18 @@ bool ReadNextNumberFromType2CharString(o
 
   return true;
 }
 
 // Executes |op| and updates |argument_stack|. Returns true if the execution
 // succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively
 // calls ExecuteType2CharString() function. The arguments other than |op| and
 // |argument_stack| are passed for that reason.
-bool ExecuteType2CharStringOperator(int32_t op,
+bool ExecuteType2CharStringOperator(ots::OpenTypeFile *file,
+                                    int32_t op,
                                     size_t call_depth,
                                     const ots::CFFIndex& global_subrs_index,
                                     const ots::CFFIndex& local_subrs_index,
                                     ots::Buffer *cff_table,
                                     ots::Buffer *char_string,
                                     std::stack<int32_t> *argument_stack,
                                     bool *out_found_endchar,
                                     bool *in_out_found_width,
@@ -281,17 +285,18 @@ bool ExecuteType2CharStringOperator(int3
     }
     const size_t offset = subrs_index.offsets[subr_number];
     cff_table->set_offset(offset);
     if (!cff_table->Skip(length)) {
       return OTS_FAILURE();
     }
     ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length);
 
-    return ExecuteType2CharString(call_depth + 1,
+    return ExecuteType2CharString(file,
+                                  call_depth + 1,
                                   global_subrs_index,
                                   local_subrs_index,
                                   cff_table,
                                   &char_string_to_jump,
                                   argument_stack,
                                   out_found_endchar,
                                   in_out_found_width,
                                   in_out_num_stems);
@@ -703,34 +708,34 @@ 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);
-  return OTS_FAILURE();
+  return OTS_FAILURE_MSG("Undefined operator: %d (0x%x)", op, op);
 }
 
 // Executes |char_string| and updates |argument_stack|.
 //
 // call_depth: The current call depth. Initial value is zero.
 // global_subrs_index: Global subroutines.
 // local_subrs_index: Local subroutines for the current glyph.
 // cff_table: A whole CFF table which contains all global and local subroutines.
 // char_string: A charstring we'll execute. |char_string| can be a main routine
 //              in CharString INDEX, or a subroutine in GlobalSubr/LocalSubr.
 // argument_stack: The stack which an operator in |char_string| operates.
 // out_found_endchar: true is set if |char_string| contains 'endchar'.
 // in_out_found_width: true is set if |char_string| contains 'width' byte (which
 //                     is 0 or 1 byte.)
 // in_out_num_stems: total number of hstems and vstems processed so far.
-bool ExecuteType2CharString(size_t call_depth,
+bool ExecuteType2CharString(ots::OpenTypeFile *file,
+                            size_t call_depth,
                             const ots::CFFIndex& global_subrs_index,
                             const ots::CFFIndex& local_subrs_index,
                             ots::Buffer *cff_table,
                             ots::Buffer *char_string,
                             std::stack<int32_t> *argument_stack,
                             bool *out_found_endchar,
                             bool *in_out_found_width,
                             size_t *in_out_num_stems) {
@@ -769,17 +774,18 @@ bool ExecuteType2CharString(size_t call_
       argument_stack->push(operator_or_operand);
       if (argument_stack->size() > kMaxArgumentStack) {
         return OTS_FAILURE();
       }
       continue;
     }
 
     // An operator is found. Execute it.
-    if (!ExecuteType2CharStringOperator(operator_or_operand,
+    if (!ExecuteType2CharStringOperator(file,
+                                        operator_or_operand,
                                         call_depth,
                                         global_subrs_index,
                                         local_subrs_index,
                                         cff_table,
                                         char_string,
                                         argument_stack,
                                         out_found_endchar,
                                         in_out_found_width,
@@ -834,44 +840,47 @@ bool SelectLocalSubr(const std::map<uint
   return true;
 }
 
 }  // namespace
 
 namespace ots {
 
 bool ValidateType2CharStringIndex(
+    ots::OpenTypeFile *file,
     const CFFIndex& char_strings_index,
     const CFFIndex& global_subrs_index,
     const std::map<uint16_t, uint8_t> &fd_select,
     const std::vector<CFFIndex *> &local_subrs_per_font,
     const CFFIndex *local_subrs,
     Buffer* cff_table) {
-  if (char_strings_index.offsets.size() == 0) {
+  const uint16_t num_offsets =
+      static_cast<uint16_t>(char_strings_index.offsets.size());
+  if (num_offsets != char_strings_index.offsets.size() || num_offsets == 0) {
     return OTS_FAILURE();  // no charstring.
   }
 
   // For each glyph, validate the corresponding charstring.
-  for (unsigned i = 1; i < char_strings_index.offsets.size(); ++i) {
+  for (uint16_t i = 1; i < num_offsets; ++i) {
     // Prepare a Buffer object, |char_string|, which contains the charstring
     // for the |i|-th glyph.
     const size_t length =
       char_strings_index.offsets[i] - char_strings_index.offsets[i - 1];
     if (length > kMaxCharStringLength) {
       return OTS_FAILURE();
     }
     const size_t offset = char_strings_index.offsets[i - 1];
     cff_table->set_offset(offset);
     if (!cff_table->Skip(length)) {
       return OTS_FAILURE();
     }
     Buffer char_string(cff_table->buffer() + offset, length);
 
     // Get a local subrs for the glyph.
-    const unsigned glyph_index = i - 1;  // index in the map is 0-origin.
+    const uint16_t glyph_index = i - 1;  // index in the map is 0-origin.
     const CFFIndex *local_subrs_to_use = NULL;
     if (!SelectLocalSubr(fd_select,
                          local_subrs_per_font,
                          local_subrs,
                          glyph_index,
                          &local_subrs_to_use)) {
       return OTS_FAILURE();
     }
@@ -881,22 +890,25 @@ bool ValidateType2CharStringIndex(
       local_subrs_to_use = &default_empty_subrs;
     }
 
     // Check a charstring for the |i|-th glyph.
     std::stack<int32_t> argument_stack;
     bool found_endchar = false;
     bool found_width = false;
     size_t num_stems = 0;
-    if (!ExecuteType2CharString(0 /* initial call_depth is zero */,
+    if (!ExecuteType2CharString(file,
+                                0 /* initial call_depth is zero */,
                                 global_subrs_index, *local_subrs_to_use,
                                 cff_table, &char_string, &argument_stack,
                                 &found_endchar, &found_width, &num_stems)) {
       return OTS_FAILURE();
     }
     if (!found_endchar) {
       return OTS_FAILURE();
     }
   }
   return true;
 }
 
 }  // namespace ots
+
+#undef TABLE_NAME
--- a/gfx/ots/src/cff_type2_charstring.h
+++ b/gfx/ots/src/cff_type2_charstring.h
@@ -30,16 +30,17 @@ namespace ots {
 //                      in |char_strings_index|.
 //  fd_select: A map from glyph # to font #.
 //  local_subrs_per_font: A list of Local Subrs associated with FDArrays. Can be
 //                        empty.
 //  local_subrs: A Local Subrs associated with Top DICT. Can be NULL.
 //  cff_table: A buffer which contains actual byte code of charstring, global
 //             subroutines and local subroutines.
 bool ValidateType2CharStringIndex(
+    OpenTypeFile *file,
     const CFFIndex &char_strings_index,
     const CFFIndex &global_subrs_index,
     const std::map<uint16_t, uint8_t> &fd_select,
     const std::vector<CFFIndex *> &local_subrs_per_font,
     const CFFIndex *local_subrs,
     Buffer *cff_table);
 
 // The list of Operators. See Appendix. A in Adobe Technical Note #5177.
--- a/gfx/ots/src/cmap.cc
+++ b/gfx/ots/src/cmap.cc
@@ -213,17 +213,17 @@ bool ParseFormat4(ots::OpenTypeFile *fil
                            ranges[segcount - 1].start_range, ranges[segcount - 1].end_range);
   }
 
   // A format 4 CMAP subtable is complex. To be safe we simulate a lookup of
   // each code-point defined in the table and make sure that they are all valid
   // glyphs and that we don't access anything out-of-bounds.
   for (unsigned i = 0; i < segcount; ++i) {
     for (unsigned cp = ranges[i].start_range; cp <= ranges[i].end_range; ++cp) {
-      const uint16_t code_point = cp;
+      const uint16_t code_point = static_cast<uint16_t>(cp);
       if (ranges[i].id_range_offset == 0) {
         // this is explictly allowed to overflow in the spec
         const uint16_t glyph = code_point + ranges[i].id_delta;
         if (glyph >= num_glyphs) {
           return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1);
         }
       } else {
         const uint16_t range_delta = code_point - ranges[i].start_range;
@@ -861,23 +861,23 @@ bool ots_cmap_serialise(OTSStream *out, 
   const bool have_0514 = file->cmap->subtable_0_5_14.size() != 0;
   const bool have_100 = file->cmap->subtable_1_0_0.size() != 0;
   const bool have_304 = file->cmap->subtable_3_0_4_data != NULL;
   // MS Symbol and MS Unicode tables should not co-exist.
   // See the comment above in 0-0-4 parser.
   const bool have_314 = (!have_304) && file->cmap->subtable_3_1_4_data;
   const bool have_31012 = file->cmap->subtable_3_10_12.size() != 0;
   const bool have_31013 = file->cmap->subtable_3_10_13.size() != 0;
-  const unsigned num_subtables = static_cast<unsigned>(have_034) +
-                                 static_cast<unsigned>(have_0514) +
-                                 static_cast<unsigned>(have_100) +
-                                 static_cast<unsigned>(have_304) +
-                                 static_cast<unsigned>(have_314) +
-                                 static_cast<unsigned>(have_31012) +
-                                 static_cast<unsigned>(have_31013);
+  const uint16_t num_subtables = static_cast<uint16_t>(have_034) +
+                                 static_cast<uint16_t>(have_0514) +
+                                 static_cast<uint16_t>(have_100) +
+                                 static_cast<uint16_t>(have_304) +
+                                 static_cast<uint16_t>(have_314) +
+                                 static_cast<uint16_t>(have_31012) +
+                                 static_cast<uint16_t>(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_MSG("no supported subtables were found");
   }
 
@@ -1001,18 +1001,18 @@ bool ots_cmap_serialise(OTSStream *out, 
   }
 
   const off_t offset_31013 = out->Tell();
   if (have_31013) {
     std::vector<OpenTypeCMAPSubtableRange> &groups
         = file->cmap->subtable_3_10_13;
     const unsigned num_groups = groups.size();
     if (!out->WriteU16(13) ||
-        !out->WriteU32(0) ||
-        !out->WriteU32(num_groups * 12 + 14) ||
+        !out->WriteU16(0) ||
+        !out->WriteU32(num_groups * 12 + 16) ||
         !out->WriteU32(0) ||
         !out->WriteU32(num_groups)) {
       return OTS_FAILURE();
     }
 
     for (unsigned i = 0; i < num_groups; ++i) {
       if (!out->WriteU32(groups[i].start_range) ||
           !out->WriteU32(groups[i].end_range) ||
--- a/gfx/ots/src/gasp.cc
+++ b/gfx/ots/src/gasp.cc
@@ -82,22 +82,24 @@ bool ots_gasp_parse(OpenTypeFile *file, 
 
 bool ots_gasp_should_serialise(OpenTypeFile *file) {
   return file->gasp != NULL;
 }
 
 bool ots_gasp_serialise(OTSStream *out, OpenTypeFile *file) {
   const OpenTypeGASP *gasp = file->gasp;
 
-  if (!out->WriteU16(gasp->version) ||
-      !out->WriteU16(gasp->gasp_ranges.size())) {
+  const uint16_t num_ranges = static_cast<uint16_t>(gasp->gasp_ranges.size());
+  if (num_ranges != gasp->gasp_ranges.size() ||
+      !out->WriteU16(gasp->version) ||
+      !out->WriteU16(num_ranges)) {
     return OTS_FAILURE_MSG("failed to write gasp header");
   }
 
-  for (unsigned i = 0; i < gasp->gasp_ranges.size(); ++i) {
+  for (uint16_t i = 0; i < num_ranges; ++i) {
     if (!out->WriteU16(gasp->gasp_ranges[i].first) ||
         !out->WriteU16(gasp->gasp_ranges[i].second)) {
       return OTS_FAILURE_MSG("Failed to write gasp subtable %d", i);
     }
   }
 
   return true;
 }
--- a/gfx/ots/src/hdmx.cc
+++ b/gfx/ots/src/hdmx.cc
@@ -102,23 +102,26 @@ bool ots_hdmx_should_serialise(OpenTypeF
   if (!file->hdmx) return false;
   if (!file->glyf) return false;  // this table is not for CFF fonts.
   return true;
 }
 
 bool ots_hdmx_serialise(OTSStream *out, OpenTypeFile *file) {
   OpenTypeHDMX * const hdmx = file->hdmx;
 
-  if (!out->WriteU16(hdmx->version) ||
-      !out->WriteS16(hdmx->records.size()) ||
+  const int16_t num_recs = static_cast<int16_t>(hdmx->records.size());
+  if (hdmx->records.size() >
+          static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
+      !out->WriteU16(hdmx->version) ||
+      !out->WriteS16(num_recs) ||
       !out->WriteS32(hdmx->size_device_record)) {
     return OTS_FAILURE_MSG("Failed to write hdmx header");
   }
 
-  for (unsigned i = 0; i < hdmx->records.size(); ++i) {
+  for (int16_t i = 0; i < num_recs; ++i) {
     const OpenTypeHDMXDeviceRecord& rec = hdmx->records[i];
     if (!out->Write(&rec.pixel_size, 1) ||
         !out->Write(&rec.max_width, 1) ||
         !out->Write(&rec.widths[0], rec.widths.size())) {
       return OTS_FAILURE_MSG("Failed to write hdmx record %d", i);
     }
     if ((hdmx->pad_len > 0) &&
         !out->Write((const uint8_t *)"\x00\x00\x00", hdmx->pad_len)) {
--- a/gfx/ots/src/kern.cc
+++ b/gfx/ots/src/kern.cc
@@ -108,18 +108,18 @@ bool ots_kern_parse(OpenTypeFile *file, 
     const uint16_t expected_search_range = (1u << max_pow2) * kFormat0PairSize;
     if (subtable.search_range != expected_search_range) {
       OTS_WARNING("bad search range");
       subtable.search_range = expected_search_range;
     }
     if (subtable.entry_selector != max_pow2) {
       return OTS_FAILURE_MSG("Bad subtable %d entry selector %d", i, subtable.entry_selector);
     }
-    const uint32_t expected_range_shift
-        = kFormat0PairSize * num_pairs - subtable.search_range;
+    const uint16_t expected_range_shift =
+        kFormat0PairSize * num_pairs - subtable.search_range;
     if (subtable.range_shift != expected_range_shift) {
       OTS_WARNING("bad range shift");
       subtable.range_shift = expected_range_shift;
     }
 
     // Read kerning pairs.
     subtable.pairs.reserve(num_pairs);
     uint32_t last_pair = 0;
@@ -156,27 +156,31 @@ bool ots_kern_parse(OpenTypeFile *file, 
 bool ots_kern_should_serialise(OpenTypeFile *file) {
   if (!file->glyf) return false;  // this table is not for CFF fonts.
   return file->kern != NULL;
 }
 
 bool ots_kern_serialise(OTSStream *out, OpenTypeFile *file) {
   const OpenTypeKERN *kern = file->kern;
 
-  if (!out->WriteU16(kern->version) ||
-      !out->WriteU16(kern->subtables.size())) {
+  const uint16_t num_subtables = static_cast<uint16_t>(kern->subtables.size());
+  if (num_subtables != kern->subtables.size() ||
+      !out->WriteU16(kern->version) ||
+      !out->WriteU16(num_subtables)) {
     return OTS_FAILURE_MSG("Can't write kern table header");
   }
 
-  for (unsigned i = 0; i < kern->subtables.size(); ++i) {
-    const uint16_t length = 14 + (6 * kern->subtables[i].pairs.size());
-    if (!out->WriteU16(kern->subtables[i].version) ||
-        !out->WriteU16(length) ||
+  for (uint16_t i = 0; i < num_subtables; ++i) {
+    const size_t length = 14 + (6 * kern->subtables[i].pairs.size());
+    if (length > std::numeric_limits<uint16_t>::max() ||
+        !out->WriteU16(kern->subtables[i].version) ||
+        !out->WriteU16(static_cast<uint16_t>(length)) ||
         !out->WriteU16(kern->subtables[i].coverage) ||
-        !out->WriteU16(kern->subtables[i].pairs.size()) ||
+        !out->WriteU16(
+            static_cast<uint16_t>(kern->subtables[i].pairs.size())) ||
         !out->WriteU16(kern->subtables[i].search_range) ||
         !out->WriteU16(kern->subtables[i].entry_selector) ||
         !out->WriteU16(kern->subtables[i].range_shift)) {
       return OTS_FAILURE_MSG("Failed to write kern subtable %d", i);
     }
     for (unsigned j = 0; j < kern->subtables[i].pairs.size(); ++j) {
       if (!out->WriteU16(kern->subtables[i].pairs[j].left) ||
           !out->WriteU16(kern->subtables[i].pairs[j].right) ||
--- a/gfx/ots/src/loca.cc
+++ b/gfx/ots/src/loca.cc
@@ -73,17 +73,19 @@ bool ots_loca_serialise(OTSStream *out, 
   const OpenTypeHEAD *head = file->head;
 
   if (!head) {
     return OTS_FAILURE_MSG("Missing head table in font needed by loca");
   }
 
   if (head->index_to_loc_format == 0) {
     for (unsigned i = 0; i < loca->offsets.size(); ++i) {
-      if (!out->WriteU16(loca->offsets[i] >> 1)) {
+      const uint16_t offset = static_cast<uint16_t>(loca->offsets[i] >> 1);
+      if ((offset != (loca->offsets[i] >> 1)) ||
+          !out->WriteU16(offset)) {
         return OTS_FAILURE_MSG("Failed to write glyph offset for glyph %d", i);
       }
     }
   } else {
     for (unsigned i = 0; i < loca->offsets.size(); ++i) {
       if (!out->WriteU32(loca->offsets[i])) {
         return OTS_FAILURE_MSG("Failed to write glyph offset for glyph %d", i);
       }
--- a/gfx/ots/src/ltsh.cc
+++ b/gfx/ots/src/ltsh.cc
@@ -62,21 +62,23 @@ bool ots_ltsh_parse(OpenTypeFile *file, 
 bool ots_ltsh_should_serialise(OpenTypeFile *file) {
   if (!file->glyf) return false;  // this table is not for CFF fonts.
   return file->ltsh != NULL;
 }
 
 bool ots_ltsh_serialise(OTSStream *out, OpenTypeFile *file) {
   const OpenTypeLTSH *ltsh = file->ltsh;
 
-  if (!out->WriteU16(ltsh->version) ||
-      !out->WriteU16(ltsh->ypels.size())) {
+  const uint16_t num_ypels = static_cast<uint16_t>(ltsh->ypels.size());
+  if (num_ypels != ltsh->ypels.size() ||
+      !out->WriteU16(ltsh->version) ||
+      !out->WriteU16(num_ypels)) {
     return OTS_FAILURE_MSG("Failed to write pels size");
   }
-  for (unsigned i = 0; i < ltsh->ypels.size(); ++i) {
+  for (uint16_t i = 0; i < num_ypels; ++i) {
     if (!out->Write(&(ltsh->ypels[i]), 1)) {
       return OTS_FAILURE_MSG("Failed to write pixel size for glyph %d", i);
     }
   }
 
   return true;
 }
 
--- a/gfx/ots/src/metrics.cc
+++ b/gfx/ots/src/metrics.cc
@@ -121,46 +121,52 @@ bool ParseMetricsTable(const ots::OpenTy
   metrics->entries.reserve(num_metrics);
   for (unsigned i = 0; i < num_metrics; ++i) {
     uint16_t adv = 0;
     int16_t sb = 0;
     if (!table->ReadU16(&adv) || !table->ReadS16(&sb)) {
       return OTS_FAILURE_MSG("Failed to read metric %d", i);
     }
 
+    // This check is bogus, see https://github.com/khaledhosny/ots/issues/36
+#if 0
     // Since so many fonts don't have proper value on |adv| and |sb|,
     // we should not call ots_failure() here. For example, about 20% of fonts
     // in http://www.princexml.com/fonts/ (200+ fonts) fails these tests.
     if (adv > header->adv_width_max) {
       OTS_WARNING("bad adv: %u > %u", adv, header->adv_width_max);
       adv = header->adv_width_max;
     }
 
     if (sb < header->min_sb1) {
       OTS_WARNING("bad sb: %d < %d", sb, header->min_sb1);
       sb = header->min_sb1;
     }
+#endif
 
     metrics->entries.push_back(std::make_pair(adv, sb));
   }
 
   metrics->sbs.reserve(num_sbs);
   for (unsigned i = 0; i < num_sbs; ++i) {
     int16_t sb;
     if (!table->ReadS16(&sb)) {
       // Some Japanese fonts (e.g., mona.ttf) fail this test.
       return OTS_FAILURE_MSG("Failed to read side bearing %d", i + num_metrics);
     }
 
+    // This check is bogus, see https://github.com/khaledhosny/ots/issues/36
+#if 0
     if (sb < header->min_sb1) {
       // The same as above. Three fonts in http://www.fontsquirrel.com/fontface
       // (e.g., Notice2Std.otf) have weird lsb values.
       OTS_WARNING("bad lsb: %d < %d", sb, header->min_sb1);
       sb = header->min_sb1;
     }
+#endif
 
     metrics->sbs.push_back(sb);
   }
 
   return true;
 }
 
 bool SerialiseMetricsTable(const ots::OpenTypeFile *file,
--- a/gfx/ots/src/name.cc
+++ b/gfx/ots/src/name.cc
@@ -195,17 +195,17 @@ bool ots_name_parse(OpenTypeFile* file, 
   // check existence of required name strings (synthesize if necessary)
   //  [0 - copyright - skip]
   //   1 - family
   //   2 - subfamily
   //  [3 - unique ID - skip]
   //   4 - full name
   //   5 - version
   //   6 - postscript name
-  static const unsigned kStdNameCount = 7;
+  static const uint16_t kStdNameCount = 7;
   static const char* kStdNames[kStdNameCount] = {
     NULL,
     "OTS derived font",
     "Unspecified",
     NULL,
     "OTS derived font",
     "1.000",
     "OTS-derived-font"
@@ -232,17 +232,17 @@ bool ots_name_parse(OpenTypeFile* file, 
       continue;
     }
     if (name_iter->platform_id == 3) {
       win_name[id] = true;
       continue;
     }
   }
 
-  for (unsigned i = 0; i < kStdNameCount; ++i) {
+  for (uint16_t i = 0; i < kStdNameCount; ++i) {
     if (kStdNames[i] == NULL) {
       continue;
     }
     if (!mac_name[i]) {
       NameRecord rec(1 /* platform_id */, 0 /* encoding_id */,
                      0 /* language_id */ , i /* name_id */);
       rec.text.assign(kStdNames[i]);
       name->names.push_back(rec);
@@ -266,59 +266,63 @@ bool ots_name_parse(OpenTypeFile* file, 
 
 bool ots_name_should_serialise(OpenTypeFile* file) {
   return file->name != NULL;
 }
 
 bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
   const OpenTypeNAME* name = file->name;
 
-  uint16_t name_count = name->names.size();
-  uint16_t lang_tag_count = name->lang_tags.size();
+  uint16_t name_count = static_cast<uint16_t>(name->names.size());
+  uint16_t lang_tag_count = static_cast<uint16_t>(name->lang_tags.size());
   uint16_t format = 0;
   size_t string_offset = 6 + name_count * 12;
 
   if (name->lang_tags.size() > 0) {
     // lang tags require a format-1 name table
     format = 1;
     string_offset += 2 + lang_tag_count * 4;
   }
   if (string_offset > 0xffff) {
     return OTS_FAILURE_MSG("Bad string offset %ld", string_offset);
   }
   if (!out->WriteU16(format) ||
       !out->WriteU16(name_count) ||
-      !out->WriteU16(string_offset)) {
+      !out->WriteU16(static_cast<uint16_t>(string_offset))) {
     return OTS_FAILURE_MSG("Failed to write name header");
   }
 
   std::string string_data;
   for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin();
        name_iter != name->names.end(); name_iter++) {
     const NameRecord& rec = *name_iter;
-    if (!out->WriteU16(rec.platform_id) ||
+    if (string_data.size() + rec.text.size() >
+            std::numeric_limits<uint16_t>::max() ||
+        !out->WriteU16(rec.platform_id) ||
         !out->WriteU16(rec.encoding_id) ||
         !out->WriteU16(rec.language_id) ||
         !out->WriteU16(rec.name_id) ||
-        !out->WriteU16(rec.text.size()) ||
-        !out->WriteU16(string_data.size()) ) {
+        !out->WriteU16(static_cast<uint16_t>(rec.text.size())) ||
+        !out->WriteU16(static_cast<uint16_t>(string_data.size())) ) {
       return OTS_FAILURE_MSG("Faile to write name entry");
     }
     string_data.append(rec.text);
   }
 
   if (format == 1) {
     if (!out->WriteU16(lang_tag_count)) {
       return OTS_FAILURE_MSG("Faile to write language tag count");
     }
     for (std::vector<std::string>::const_iterator tag_iter =
              name->lang_tags.begin();
          tag_iter != name->lang_tags.end(); tag_iter++) {
-      if (!out->WriteU16(tag_iter->size()) ||
-          !out->WriteU16(string_data.size())) {
+      if (string_data.size() + tag_iter->size() >
+              std::numeric_limits<uint16_t>::max() ||
+          !out->WriteU16(static_cast<uint16_t>(tag_iter->size())) ||
+          !out->WriteU16(static_cast<uint16_t>(string_data.size()))) {
         return OTS_FAILURE_MSG("Failed to write string");
       }
       string_data.append(*tag_iter);
     }
   }
 
   if (!out->Write(string_data.data(), string_data.size())) {
     return OTS_FAILURE_MSG("Faile to write string data");
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -206,18 +206,18 @@ bool ProcessTTF(ots::OpenTypeFile *heade
   // 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;
+  const uint16_t expected_range_shift =
+      16 * header->num_tables - header->search_range;
   if (header->range_shift != expected_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;
 
@@ -606,17 +606,17 @@ bool ProcessGeneric(ots::OpenTypeFile *h
   } 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");
     }
   }
 
-  unsigned num_output_tables = 0;
+  uint16_t num_output_tables = 0;
   for (unsigned i = 0; ; ++i) {
     if (table_parsers[i].parse == NULL) {
       break;
     }
 
     if (table_parsers[i].should_serialise(header)) {
       num_output_tables++;
     }
@@ -625,17 +625,17 @@ bool ProcessGeneric(ots::OpenTypeFile *h
   for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
        it != table_map.end(); ++it) {
     ots::TableAction action = GetTableAction(header, it->first);
     if (action == ots::TABLE_ACTION_PASSTHRU) {
       num_output_tables++;
     }
   }
 
-  unsigned max_pow2 = 0;
+  uint16_t max_pow2 = 0;
   while (1u << (max_pow2 + 1) <= num_output_tables) {
     max_pow2++;
   }
   const uint16_t output_search_range = (1u << max_pow2) << 4;
 
   // most of the errors here are highly unlikely - they'd only occur if the
   // output stream returns a failure, e.g. lack of space to write
   output->ResetChecksum();
@@ -826,16 +826,22 @@ bool OTSContext::Process(OTSStream *outp
 
   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;
 }
--- a/gfx/ots/src/ots.h
+++ b/gfx/ots/src/ots.h
@@ -29,38 +29,41 @@ namespace ots {
 bool Failure(const char *f, int l, const char *fn);
 #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)
-#define OTS_MESSAGE_(otf_,...) \
-  (otf_)->context->Message(__VA_ARGS__)
+#define OTS_MESSAGE_(level,otf_,...) \
+  (otf_)->context->Message(level,__VA_ARGS__)
 #else
-#define OTS_MESSAGE_(otf_,...) \
+#define OTS_MESSAGE_(level,otf_,...) \
   OTS_FAILURE(), \
-  (otf_)->context->Message(__VA_ARGS__)
+  (otf_)->context->Message(level,__VA_ARGS__)
 #endif
 
 // Generate a simple message
 #define OTS_FAILURE_MSG_(otf_,...) \
-  (OTS_MESSAGE_(otf_,__VA_ARGS__), false)
+  (OTS_MESSAGE_(0,otf_,__VA_ARGS__), false)
+
+#define OTS_WARNING_MSG_(otf_,...) \
+  OTS_MESSAGE_(1,otf_,__VA_ARGS__)
 
 // Generate a message with an associated table tag
 #define OTS_FAILURE_MSG_TAG_(otf_,msg_,tag_) \
-  (OTS_MESSAGE_(otf_,"%4.4s: %s", tag_, msg_), false)
+  (OTS_MESSAGE_(0,otf_,"%4.4s: %s", tag_, msg_), false)
 
-// Convenience macro for use in files that only handle a single table tag,
+// Convenience macros 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_WARNING OTS_FAILURE_MSG
+#define OTS_WARNING(...) OTS_WARNING_MSG_(file, TABLE_NAME ": " __VA_ARGS__)
 
 // -----------------------------------------------------------------------------
 // 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/post.cc
+++ b/gfx/ots/src/post.cc
@@ -143,31 +143,35 @@ bool ots_post_serialise(OTSStream *out, 
       !out->WriteU32(0)) {
     return OTS_FAILURE_MSG("Failed to write post header");
   }
 
   if (post->version != 0x00020000) {
     return true;  // v1.0 and v3.0 does not have glyph names.
   }
 
-  if (!out->WriteU16(post->glyph_name_index.size())) {
+  const uint16_t num_indexes =
+      static_cast<uint16_t>(post->glyph_name_index.size());
+  if (num_indexes != post->glyph_name_index.size() ||
+      !out->WriteU16(num_indexes)) {
     return OTS_FAILURE_MSG("Failed to write number of indices");
   }
 
-  for (unsigned i = 0; i < post->glyph_name_index.size(); ++i) {
+  for (uint16_t i = 0; i < num_indexes; ++i) {
     if (!out->WriteU16(post->glyph_name_index[i])) {
       return OTS_FAILURE_MSG("Failed to write name index %d", i);
     }
   }
 
   // Now we just have to write out the strings in the correct order
   for (unsigned i = 0; i < post->names.size(); ++i) {
     const std::string& s = post->names[i];
-    const uint8_t string_length = s.size();
-    if (!out->Write(&string_length, 1)) {
+    const uint8_t string_length = static_cast<uint8_t>(s.size());
+    if (string_length != s.size() ||
+        !out->Write(&string_length, 1)) {
       return OTS_FAILURE_MSG("Failed to write string %d", i);
     }
     // Some ttf fonts (e.g., frank.ttf on Windows Vista) have zero-length name.
     // We allow them.
     if (string_length > 0 && !out->Write(s.data(), string_length)) {
       return OTS_FAILURE_MSG("Failed to write string length for string %d", i);
     }
   }
--- a/gfx/ots/src/vorg.cc
+++ b/gfx/ots/src/vorg.cc
@@ -70,25 +70,27 @@ bool ots_vorg_parse(OpenTypeFile *file, 
 
 bool ots_vorg_should_serialise(OpenTypeFile *file) {
   if (!file->cff) return false;  // this table is not for fonts with TT glyphs.
   return file->vorg != NULL;
 }
 
 bool ots_vorg_serialise(OTSStream *out, OpenTypeFile *file) {
   OpenTypeVORG * const vorg = file->vorg;
-
-  if (!out->WriteU16(vorg->major_version) ||
+  
+  const uint16_t num_metrics = static_cast<uint16_t>(vorg->metrics.size());
+  if (num_metrics != vorg->metrics.size() ||
+      !out->WriteU16(vorg->major_version) ||
       !out->WriteU16(vorg->minor_version) ||
       !out->WriteS16(vorg->default_vert_origin_y) ||
-      !out->WriteU16(vorg->metrics.size())) {
+      !out->WriteU16(num_metrics)) {
     return OTS_FAILURE_MSG("Failed to write table header");
   }
 
-  for (unsigned i = 0; i < vorg->metrics.size(); ++i) {
+  for (uint16_t i = 0; i < num_metrics; ++i) {
     const OpenTypeVORGMetrics& rec = vorg->metrics[i];
     if (!out->WriteU16(rec.glyph_index) ||
         !out->WriteS16(rec.vert_origin_y)) {
       return OTS_FAILURE_MSG("Failed to write record %d", i);
     }
   }
 
   return true;
--- a/gfx/ots/src/woff2.cc
+++ b/gfx/ots/src/woff2.cc
@@ -16,22 +16,22 @@
 #include "opentype-sanitiser.h"
 #include "ots-memory-stream.h"
 #include "ots.h"
 #include "woff2.h"
 
 namespace {
 
 // simple glyph flags
-const int kGlyfOnCurve = 1 << 0;
-const int kGlyfXShort = 1 << 1;
-const int kGlyfYShort = 1 << 2;
-const int kGlyfRepeat = 1 << 3;
-const int kGlyfThisXIsSame = 1 << 4;
-const int kGlyfThisYIsSame = 1 << 5;
+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;
+const uint8_t kGlyfThisYIsSame = 1 << 5;
 
 // composite glyph flags
 const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
 const int FLAG_WE_HAVE_A_SCALE = 1 << 3;
 const int FLAG_MORE_COMPONENTS = 1 << 5;
 const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
 const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
@@ -117,18 +117,18 @@ const uint32_t kKnownTags[] = {
   TAG('S', 'i', 'l', 'f'),  // 58
   TAG('G', 'l', 'a', 't'),  // 59
   TAG('G', 'l', 'o', 'c'),  // 60
   TAG('F', 'e', 'a', 't'),  // 61
   TAG('S', 'i', 'l', 'l'),  // 62
 };
 
 struct Point {
-  int x;
-  int y;
+  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;
@@ -144,21 +144,21 @@ struct Table {
         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, unsigned int* value) {
-  static const int kWordCode = 253;
-  static const int kOneMoreByteCode2 = 254;
-  static const int kOneMoreByteCode1 = 255;
-  static const int kLowestUCode = 253;
+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;
   uint8_t code = 0;
   if (!buf->ReadU8(&code)) {
     return OTS_FAILURE();
   }
   if (code == kWordCode) {
     uint16_t result = 0;
     if (!buf->ReadU16(&result)) {
       return OTS_FAILURE();
@@ -206,25 +206,25 @@ bool ReadBase128(ots::Buffer* buf, uint3
   return OTS_FAILURE();
 }
 
 // Caller must ensure that buffer overrun won't happen.
 // TODO(ksakamaoto): Consider creating 'writer' version of the Buffer class
 // and use it across the code.
 size_t StoreU32(uint8_t* dst, size_t offset, uint32_t x) {
   dst[offset] = x >> 24;
-  dst[offset + 1] = x >> 16;
-  dst[offset + 2] = x >> 8;
-  dst[offset + 3] = x;
+  dst[offset + 1] = (x >> 16) & 0xff;
+  dst[offset + 2] = (x >> 8) & 0xff;
+  dst[offset + 3] = x & 0xff;
   return offset + 4;
 }
 
-size_t Store16(uint8_t* dst, size_t offset, int x) {
+size_t StoreU16(uint8_t* dst, size_t offset, uint16_t x) {
   dst[offset] = x >> 8;
-  dst[offset + 1] = x;
+  dst[offset + 1] = x & 0xff;
   return offset + 2;
 }
 
 int WithSign(int flag, int baseval) {
   assert(0 <= baseval && baseval < 65536);
   return (flag & 1) ? baseval : -baseval;
 }
 
@@ -285,43 +285,43 @@ bool TripletDecode(const uint8_t* flags_
           (in[triplet_index + 2] << 8) + in[triplet_index + 3]);
     }
     triplet_index += n_data_bytes;
     // Possible overflow but coordinate values are not security sensitive
     x += dx;
     y += dy;
     result->push_back(Point());
     Point& back = result->back();
-    back.x = x;
-    back.y = y;
+    back.x = static_cast<int16_t>(x);
+    back.y = static_cast<int16_t>(y);
     back.on_curve = on_curve;
   }
   *in_bytes_consumed = triplet_index;
   return true;
 }
 
 // This function stores just the point data. On entry, dst points to the
 // beginning of a simple glyph. Returns true on success.
 bool StorePoints(const std::vector<Point>& points,
     unsigned int n_contours, unsigned int instruction_length,
     uint8_t* dst, size_t dst_size, size_t* glyph_size) {
   // I believe that n_contours < 65536, in which case this is safe. However, a
   // comment and/or an assert would be good.
   unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 +
     instruction_length;
-  int last_flag = -1;
-  int repeat_count = 0;
+  uint8_t last_flag = 0xff;
+  uint8_t repeat_count = 0;
   int last_x = 0;
   int last_y = 0;
   unsigned int x_bytes = 0;
   unsigned int y_bytes = 0;
 
   for (size_t i = 0; i < points.size(); ++i) {
     const Point& point = points.at(i);
-    int flag = point.on_curve ? kGlyfOnCurve : 0;
+    uint8_t flag = point.on_curve ? kGlyfOnCurve : 0;
     int dx = point.x - last_x;
     int dy = point.y - last_y;
     if (dx == 0) {
       flag |= kGlyfThisXIsSame;
     } else if (dx > -256 && dx < 256) {
       flag |= kGlyfXShort | (dx > 0 ? kGlyfThisXIsSame : 0);
       x_bytes += 1;
     } else {
@@ -374,57 +374,57 @@ bool StorePoints(const std::vector<Point
   int y_offset = flag_offset + x_bytes;
   last_x = 0;
   last_y = 0;
   for (size_t i = 0; i < points.size(); ++i) {
     int dx = points.at(i).x - last_x;
     if (dx == 0) {
       // pass
     } else if (dx > -256 && dx < 256) {
-      dst[x_offset++] = std::abs(dx);
+      dst[x_offset++] = static_cast<uint8_t>(std::abs(dx));
     } else {
       // will always fit for valid input, but overflow is harmless
-      x_offset = Store16(dst, x_offset, dx);
+      x_offset = StoreU16(dst, x_offset, static_cast<uint16_t>(dx));
     }
     last_x += dx;
     int dy = points.at(i).y - last_y;
     if (dy == 0) {
       // pass
     } else if (dy > -256 && dy < 256) {
-      dst[y_offset++] = std::abs(dy);
+      dst[y_offset++] = static_cast<uint8_t>(std::abs(dy));
     } else {
-      y_offset = Store16(dst, y_offset, dy);
+      y_offset = StoreU16(dst, y_offset, static_cast<uint16_t>(dy));
     }
     last_y += dy;
   }
   *glyph_size = y_offset;
   return true;
 }
 
 // Compute the bounding box of the coordinates, and store into a glyf buffer.
 // A precondition is that there are at least 10 bytes available.
 void ComputeBbox(const std::vector<Point>& points, uint8_t* dst) {
-  int x_min = 0;
-  int y_min = 0;
-  int x_max = 0;
-  int y_max = 0;
+  int16_t x_min = 0;
+  int16_t y_min = 0;
+  int16_t x_max = 0;
+  int16_t y_max = 0;
 
   for (size_t i = 0; i < points.size(); ++i) {
-    int x = points.at(i).x;
-    int y = points.at(i).y;
+    int16_t x = points.at(i).x;
+    int16_t y = points.at(i).y;
     if (i == 0 || x < x_min) x_min = x;
     if (i == 0 || x > x_max) x_max = x;
     if (i == 0 || y < y_min) y_min = y;
     if (i == 0 || y > y_max) y_max = y;
   }
   size_t offset = 2;
-  offset = Store16(dst, offset, x_min);
-  offset = Store16(dst, offset, y_min);
-  offset = Store16(dst, offset, x_max);
-  offset = Store16(dst, offset, y_max);
+  offset = StoreU16(dst, offset, x_min);
+  offset = StoreU16(dst, offset, y_min);
+  offset = StoreU16(dst, offset, x_max);
+  offset = StoreU16(dst, offset, y_max);
 }
 
 // Process entire bbox stream. This is done as a separate pass to allow for
 // composite bbox computations (an optional more aggressive transform).
 bool ProcessBboxStream(ots::Buffer* bbox_stream, unsigned int n_glyphs,
     const std::vector<uint32_t>& loca_values, uint8_t* glyf_buf,
     size_t glyf_buf_length) {
   const uint8_t* buf = bbox_stream->buffer();
@@ -481,17 +481,17 @@ bool ProcessComposite(ots::Buffer* compo
     if (!composite_stream->Skip(arg_size)) {
       return OTS_FAILURE();
     }
   }
   size_t composite_glyph_size = composite_stream->offset() - start_offset;
   if (composite_glyph_size + kCompositeGlyphBegin > dst_size) {
     return OTS_FAILURE();
   }
-  Store16(dst, 0, 0xffff);  // nContours = -1 for composite glyph
+  StoreU16(dst, 0, 0xffff);  // nContours = -1 for composite glyph
   std::memcpy(dst + kCompositeGlyphBegin,
       composite_stream->buffer() + start_offset,
       composite_glyph_size);
   *glyph_size = kCompositeGlyphBegin + composite_glyph_size;
   *have_instructions = we_have_instructions;
   return true;
 }
 
@@ -508,17 +508,17 @@ bool StoreLoca(const std::vector<uint32_
     return OTS_FAILURE();
   }
   size_t offset = 0;
   for (size_t i = 0; i < loca_values.size(); ++i) {
     uint32_t value = loca_values.at(i);
     if (index_format) {
       offset = StoreU32(dst, offset, value);
     } else {
-      offset = Store16(dst, offset, value >> 1);
+      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,
     uint8_t* dst, size_t dst_size,
@@ -559,67 +559,67 @@ bool ReconstructGlyf(const uint8_t* data
   ots::Buffer glyph_stream(substreams.at(3).first, substreams.at(3).second);
   ots::Buffer composite_stream(substreams.at(4).first, substreams.at(4).second);
   ots::Buffer bbox_stream(substreams.at(5).first, substreams.at(5).second);
   ots::Buffer instruction_stream(substreams.at(6).first,
                                  substreams.at(6).second);
 
   std::vector<uint32_t> loca_values;
   loca_values.reserve(num_glyphs + 1);
-  std::vector<unsigned int> n_points_vec;
+  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();
     }
     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;
-      unsigned int instruction_size = 0;
+      uint16_t instruction_size = 0;
       if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size,
             &glyph_size, &have_instructions)) {
         return OTS_FAILURE();
       }
       if (have_instructions) {
         if (!Read255UShort(&glyph_stream, &instruction_size)) {
           return OTS_FAILURE();
         }
         // No integer overflow here (instruction_size < 2^16).
-        if (instruction_size + 2 > glyf_dst_size - glyph_size) {
+        if (instruction_size + 2U > glyf_dst_size - glyph_size) {
           return OTS_FAILURE();
         }
-        Store16(glyf_dst, glyph_size, instruction_size);
+        StoreU16(glyf_dst, glyph_size, instruction_size);
         if (!instruction_stream.Read(glyf_dst + glyph_size + 2,
               instruction_size)) {
           return OTS_FAILURE();
         }
         glyph_size += instruction_size + 2;
       }
     } else if (n_contours > 0) {
       // simple glyph
       n_points_vec.clear();
       points.clear();
-      unsigned int total_n_points = 0;
-      unsigned int n_points_contour;
-      for (unsigned int j = 0; j < n_contours; ++j) {
+      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();
         }
         n_points_vec.push_back(n_points_contour);
         if (total_n_points + n_points_contour < total_n_points) {
           return OTS_FAILURE();
         }
         total_n_points += n_points_contour;
       }
-      unsigned int flag_size = total_n_points;
+      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();
       const uint8_t* triplet_buf = glyph_stream.buffer() +
         glyph_stream.offset();
       size_t triplet_size = glyph_stream.length() - glyph_stream.offset();
       size_t triplet_bytes_consumed = 0;
@@ -627,44 +627,44 @@ bool ReconstructGlyf(const uint8_t* data
             &points, &triplet_bytes_consumed)) {
         return OTS_FAILURE();
       }
       const uint32_t header_and_endpts_contours_size =
           kEndPtsOfContoursOffset + 2 * n_contours;
       if (glyf_dst_size < header_and_endpts_contours_size) {
         return OTS_FAILURE();
       }
-      Store16(glyf_dst, 0, n_contours);
+      StoreU16(glyf_dst, 0, n_contours);
       ComputeBbox(points, glyf_dst);
       size_t endpts_offset = kEndPtsOfContoursOffset;
       int end_point = -1;
       for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) {
         end_point += n_points_vec.at(contour_ix);
         if (end_point >= 65536) {
           return OTS_FAILURE();
         }
-        endpts_offset = Store16(glyf_dst, endpts_offset, end_point);
+        endpts_offset = StoreU16(glyf_dst, endpts_offset, static_cast<uint16_t>(end_point));
       }
       if (!flag_stream.Skip(flag_size)) {
         return OTS_FAILURE();
       }
       if (!glyph_stream.Skip(triplet_bytes_consumed)) {
         return OTS_FAILURE();
       }
-      unsigned int instruction_size;
+      uint16_t instruction_size;
       if (!Read255UShort(&glyph_stream, &instruction_size)) {
         return OTS_FAILURE();
       }
       // No integer overflow here (instruction_size < 2^16).
       if (glyf_dst_size - header_and_endpts_contours_size <
-          instruction_size + 2) {
+          instruction_size + 2U) {
         return OTS_FAILURE();
       }
       uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size;
-      Store16(instruction_dst, 0, instruction_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();
       }
     } else {
@@ -910,24 +910,24 @@ bool ConvertWOFF2ToTTF(uint8_t* result, 
     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 = src_offset;
+    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 = dst_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()) {
@@ -946,25 +946,25 @@ bool ConvertWOFF2ToTTF(uint8_t* result, 
   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();
   }
 
   // Start building the font
   size_t offset = 0;
   offset = StoreU32(result, offset, flavor);
-  offset = Store16(result, offset, num_tables);
-  unsigned max_pow2 = 0;
+  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 = Store16(result, offset, output_search_range);
-  offset = Store16(result, offset, max_pow2);
-  offset = Store16(result, offset, (num_tables << 4) - output_search_range);
+  offset = StoreU16(result, offset, output_search_range);
+  offset = StoreU16(result, offset, max_pow2);
+  offset = StoreU16(result, offset, (num_tables << 4) - output_search_range);
   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;
@@ -996,18 +996,19 @@ bool ConvertWOFF2ToTTF(uint8_t* result, 
         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();
       }
-      uncompressed_buf.resize(total_size);
-      if (!Woff2Uncompress(&uncompressed_buf[0], total_size,
+      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();
     }
--- a/gfx/ots/sync.sh
+++ b/gfx/ots/sync.sh
@@ -7,22 +7,25 @@ if [ $# = 0 ] ; then
     exit 1
 fi
 
 echo "Updating LICENSE..."
 cp $1/LICENSE .
 
 echo "Updating src..."
 cd src
-ls --ignore moz.build | xargs rm -rf
+ls | fgrep -v moz.build | xargs rm -rf
 cp -r $1/src/* .
 cd ..
 
 echo "Updating include..."
 rm -rf include/
 cp -r $1/include .
 
 echo "Updating README.mozilla..."
 REVISION=`cd $1; git log | head -1 | sed "s/commit //"`
-sed "s/\(Current revision: \).*/\1$REVISION/" -i README.mozilla
+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
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -187,17 +187,18 @@ public:
             aTag == TRUETYPE_TAG('S', 'V', 'G', ' ') ||
             aTag == TRUETYPE_TAG('C', 'O', 'L', 'R') ||
             aTag == TRUETYPE_TAG('C', 'P', 'A', 'L')) {
             return ots::TABLE_ACTION_PASSTHRU;
         }
         return ots::TABLE_ACTION_DEFAULT;
     }
 
-    virtual void Message(const char *format, ...) MSGFUNC_FMT_ATTR MOZ_OVERRIDE {
+    virtual void Message(int level, const char* format,
+                         ...) MSGFUNC_FMT_ATTR MOZ_OVERRIDE {
         va_list va;
         va_start(va, format);
 
         // buf should be more than adequate for any message OTS generates,
         // so we don't worry about checking the result of vsnprintf()
         char buf[512];
         (void)vsnprintf(buf, sizeof(buf), format, va);