Bug 1384862 - Update WOFF2 code to latest upstream. r=sylvestre
authorJonathan Kew <jkew@mozilla.com>
Thu, 27 Jul 2017 10:33:47 +0200
changeset 373585 0dc9284b03d41e8ed9096915fd95e18c8b99951c
parent 373584 125b73295e1e6ada26a50ce8882fc27847ff2eb5
child 373586 3eb6f350efc46346b7b2df48c820057d2eb8f6b9
push id32305
push userryanvm@gmail.com
push dateWed, 09 Aug 2017 22:43:53 +0000
treeherdermozilla-central@411fe4772f31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssylvestre
bugs1384862
milestone57.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 1384862 - Update WOFF2 code to latest upstream. r=sylvestre
modules/woff2/README.mozilla
modules/woff2/brotli-0.6.0-api-change.patch
modules/woff2/redefine-unique_ptr.patch
modules/woff2/src/buffer.h
modules/woff2/src/convert_woff2ttf_fuzzer.cc
modules/woff2/src/convert_woff2ttf_fuzzer_new_entry.cc
modules/woff2/src/font.cc
modules/woff2/src/glyph.cc
modules/woff2/src/normalize.cc
modules/woff2/src/port.h
modules/woff2/src/store_bytes.h
modules/woff2/src/variable_length.cc
modules/woff2/src/woff2_common.cc
modules/woff2/src/woff2_dec.cc
modules/woff2/src/woff2_enc.cc
--- a/modules/woff2/README.mozilla
+++ b/modules/woff2/README.mozilla
@@ -6,17 +6,13 @@ Upstream code can be viewed at
 
 and cloned by
   git clone https://github.com/google/woff2
 
 The in-tree copy is updated by running
   sh update.sh
 from within the modules/woff2 directory.
 
-Current version: [commit 63b8fb6d0d797f04e77ee825fd8fcf7ea6205aac].
+Current version: [commit e580ebc30a54becf69a75f6e6d6008536ae0c0b4].
 
 redefine-unique_ptr.patch redefines the class std::unique_ptr to workaround a
 build issue with missing C++11 features.
 See https://bugzilla.mozilla.org/show_bug.cgi?id=1227058
-
-brotli-0.6.0-api-change.patch adjusts the WOFF2 code to match Brotli API
-changes in the 0.6.0 release. (Will be superseded by next WOFF2 update.)
-See https://bugzilla.mozilla.org/show_bug.cgi?id=1340910
deleted file mode 100644
--- a/modules/woff2/brotli-0.6.0-api-change.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-diff --git a/modules/woff2/src/woff2_dec.cc b/modules/woff2/src/woff2_dec.cc
---- a/modules/woff2/src/woff2_dec.cc
-+++ b/modules/woff2/src/woff2_dec.cc
-@@ -31,17 +31,17 @@
- namespace std
- {
-   using mozilla::DefaultDelete;
-   using mozilla::UniquePtr;
-   #define default_delete DefaultDelete
-   #define unique_ptr UniquePtr
- }
- 
--#include "./decode.h"
-+#include "brotli/decode.h"
- #include "./buffer.h"
- #include "./port.h"
- #include "./round.h"
- #include "./store_bytes.h"
- #include "./table_tags.h"
- #include "./variable_length.h"
- #include "./woff2_common.h"
- 
-@@ -746,18 +746,18 @@ bool ReconstructTransformedHmtx(const ui
-   }
- 
-   return true;
- }
- 
- bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
-   const uint8_t* src_buf, size_t src_size) {
-   size_t uncompressed_size = dst_size;
--  int ok = BrotliDecompressBuffer(src_size, src_buf,
--                                  &uncompressed_size, dst_buf);
-+  int ok = BrotliDecoderDecompress(src_size, src_buf,
-+                                   &uncompressed_size, dst_buf);
-   if (PREDICT_FALSE(!ok || uncompressed_size != dst_size)) {
-     return FONT_COMPRESSION_FAILURE();
-   }
-   return true;
- }
- 
- bool ReadTableDirectory(Buffer* file, std::vector<Table>* tables,
-     size_t num_tables) {
--- a/modules/woff2/redefine-unique_ptr.patch
+++ b/modules/woff2/redefine-unique_ptr.patch
@@ -14,16 +14,16 @@ diff --git a/modules/woff2/src/woff2_dec
 +namespace std
 +{
 +  using mozilla::DefaultDelete;
 +  using mozilla::UniquePtr;
 +  #define default_delete DefaultDelete
 +  #define unique_ptr UniquePtr
 +}
 +
- #include "./decode.h"
+ #include "./brotli/decode.h"
  #include "./buffer.h"
  #include "./port.h"
  #include "./round.h"
  #include "./store_bytes.h"
  #include "./table_tags.h"
  #include "./variable_length.h"
  #include "./woff2_common.h"
--- a/modules/woff2/src/buffer.h
+++ b/modules/woff2/src/buffer.h
@@ -60,35 +60,35 @@ inline bool Failure(const char *f, int l
 // Buffer helper class
 //
 // This class perform some trival buffer operations while checking for
 // out-of-bounds errors. As a family they return false if anything is amiss,
 // updating the current offset otherwise.
 // -----------------------------------------------------------------------------
 class Buffer {
  public:
-  Buffer(const uint8_t *buffer, size_t len)
-      : buffer_(buffer),
+  Buffer(const uint8_t *data, size_t len)
+      : buffer_(data),
         length_(len),
         offset_(0) { }
 
   bool Skip(size_t n_bytes) {
     return Read(NULL, n_bytes);
   }
 
-  bool Read(uint8_t *buffer, size_t n_bytes) {
+  bool Read(uint8_t *data, size_t n_bytes) {
     if (n_bytes > 1024 * 1024 * 1024) {
       return FONT_COMPRESSION_FAILURE();
     }
     if ((offset_ + n_bytes > length_) ||
         (offset_ > length_ - n_bytes)) {
       return FONT_COMPRESSION_FAILURE();
     }
-    if (buffer) {
-      std::memcpy(buffer, buffer_ + offset_, n_bytes);
+    if (data) {
+      std::memcpy(data, buffer_ + offset_, n_bytes);
     }
     offset_ += n_bytes;
     return true;
   }
 
   inline bool ReadU8(uint8_t *value) {
     if (offset_ + 1 > length_) {
       return FONT_COMPRESSION_FAILURE();
new file mode 100644
--- /dev/null
+++ b/modules/woff2/src/convert_woff2ttf_fuzzer.cc
@@ -0,0 +1,13 @@
+#include <stddef.h>
+#include <stdint.h>
+
+#include "woff2_dec.h"
+
+// Entry point for LibFuzzer.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  std::string buf;
+  woff2::WOFF2StringOut out(&buf);
+  out.SetMaxSize(30 * 1024 * 1024);
+  woff2::ConvertWOFF2ToTTF(data, size, &out);
+  return 0;
+}
new file mode 100644
--- /dev/null
+++ b/modules/woff2/src/convert_woff2ttf_fuzzer_new_entry.cc
@@ -0,0 +1,12 @@
+#include <string>
+#include "woff2_dec.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t data_size) {
+  // Decode using newer entry pattern.
+  // Same pattern as woff2_decompress.
+  std::string output(std::min(woff2::ComputeWOFF2FinalSize(data, data_size),
+                              woff2::kDefaultMaxSize), 0);
+  woff2::WOFF2StringOut out(&output);
+  woff2::ConvertWOFF2ToTTF(data, data_size, &out);
+  return 0;
+}
--- a/modules/woff2/src/font.cc
+++ b/modules/woff2/src/font.cc
@@ -100,16 +100,22 @@ bool ReadTrueTypeFont(Buffer* file, cons
   uint32_t last_offset = 12UL + 16UL * font->num_tables;
   for (const auto& i : intervals) {
     if (i.first < last_offset || i.first + i.second < i.first) {
       return FONT_COMPRESSION_FAILURE();
     }
     last_offset = i.first + i.second;
   }
 
+  // Sanity check key tables
+  const Font::Table* head_table = font->FindTable(kHeadTableTag);
+  if (head_table != NULL && head_table->length < 52) {
+    return FONT_COMPRESSION_FAILURE();
+  }
+
   return true;
 }
 
 bool ReadCollectionFont(Buffer* file, const uint8_t* data, size_t len,
                         Font* font,
                         std::map<uint32_t, Font::Table*>* all_tables) {
   if (!file->ReadU32(&font->flavor)) {
     return FONT_COMPRESSION_FAILURE();
@@ -320,18 +326,21 @@ bool WriteFontCollection(const FontColle
 
 int NumGlyphs(const Font& font) {
   const Font::Table* head_table = font.FindTable(kHeadTableTag);
   const Font::Table* loca_table = font.FindTable(kLocaTableTag);
   if (head_table == NULL || loca_table == NULL || head_table->length < 52) {
     return 0;
   }
   int index_fmt = IndexFormat(font);
-  int num_glyphs = (loca_table->length / (index_fmt == 0 ? 2 : 4)) - 1;
-  return num_glyphs;
+  int loca_record_size = (index_fmt == 0 ? 2 : 4);
+  if (loca_table->length < loca_record_size) {
+    return 0;
+  }
+  return (loca_table->length / loca_record_size) - 1;
 }
 
 int IndexFormat(const Font& font) {
   const Font::Table* head_table = font.FindTable(kHeadTableTag);
   if (head_table == NULL) {
     return 0;
   }
   return head_table->data[51];
--- a/modules/woff2/src/glyph.cc
+++ b/modules/woff2/src/glyph.cc
@@ -113,35 +113,37 @@ bool ReadGlyph(const uint8_t* data, size
     }
     glyph->instructions_data = data + buffer.offset();
     if (!buffer.Skip(glyph->instructions_size)) {
       return FONT_COMPRESSION_FAILURE();
     }
 
     // Read the run-length coded flags.
     std::vector<std::vector<uint8_t> > flags(num_contours);
-    uint8_t flag = 0;
-    uint8_t flag_repeat = 0;
-    for (int i = 0; i < num_contours; ++i) {
-      flags[i].resize(glyph->contours[i].size());
-      for (size_t j = 0; j < glyph->contours[i].size(); ++j) {
-        if (flag_repeat == 0) {
-          if (!buffer.ReadU8(&flag)) {
-            return FONT_COMPRESSION_FAILURE();
-          }
-          if (flag & kFLAG_REPEAT) {
-            if (!buffer.ReadU8(&flag_repeat)) {
+    {
+      uint8_t flag = 0;
+      uint8_t flag_repeat = 0;
+      for (int i = 0; i < num_contours; ++i) {
+        flags[i].resize(glyph->contours[i].size());
+        for (size_t j = 0; j < glyph->contours[i].size(); ++j) {
+          if (flag_repeat == 0) {
+            if (!buffer.ReadU8(&flag)) {
               return FONT_COMPRESSION_FAILURE();
             }
+            if (flag & kFLAG_REPEAT) {
+              if (!buffer.ReadU8(&flag_repeat)) {
+                return FONT_COMPRESSION_FAILURE();
+              }
+            }
+          } else {
+            flag_repeat--;
           }
-        } else {
-          flag_repeat--;
+          flags[i][j] = flag;
+          glyph->contours[i][j].on_curve = flag & kFLAG_ONCURVE;
         }
-        flags[i][j] = flag;
-        glyph->contours[i][j].on_curve = flag & kFLAG_ONCURVE;
       }
     }
 
     // Read the x coordinates.
     int prev_x = 0;
     for (int i = 0; i < num_contours; ++i) {
       for (size_t j = 0; j < glyph->contours[i].size(); ++j) {
         uint8_t flag = flags[i][j];
--- a/modules/woff2/src/normalize.cc
+++ b/modules/woff2/src/normalize.cc
@@ -47,17 +47,17 @@ namespace {
 bool WriteNormalizedLoca(int index_fmt, int num_glyphs, Font* font) {
   Font::Table* glyf_table = font->FindTable(kGlyfTableTag);
   Font::Table* loca_table = font->FindTable(kLocaTableTag);
 
   int glyph_sz = index_fmt == 0 ? 2 : 4;
   loca_table->buffer.resize(Round4(num_glyphs + 1) * glyph_sz);
   loca_table->length = (num_glyphs + 1) * glyph_sz;
 
-  uint8_t* glyf_dst = &glyf_table->buffer[0];
+  uint8_t* glyf_dst = num_glyphs ? &glyf_table->buffer[0] : NULL;
   uint8_t* loca_dst = &loca_table->buffer[0];
   uint32_t glyf_offset = 0;
   size_t loca_offset = 0;
 
   for (int i = 0; i < num_glyphs; ++i) {
     StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst);
     Glyph glyph;
     const uint8_t* glyph_data;
@@ -73,26 +73,23 @@ bool WriteNormalizedLoca(int index_fmt, 
     glyf_dst_size = Round4(glyf_dst_size);
     if (glyf_dst_size > std::numeric_limits<uint32_t>::max() ||
         glyf_offset + static_cast<uint32_t>(glyf_dst_size) < glyf_offset ||
         (index_fmt == 0 && glyf_offset + glyf_dst_size >= (1UL << 17))) {
       return FONT_COMPRESSION_FAILURE();
     }
     glyf_offset += glyf_dst_size;
   }
-  if (glyf_offset == 0) {
-    return false;
-  }
 
   StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst);
 
   glyf_table->buffer.resize(glyf_offset);
-  glyf_table->data = &glyf_table->buffer[0];
+  glyf_table->data = glyf_offset ? &glyf_table->buffer[0] : NULL;
   glyf_table->length = glyf_offset;
-  loca_table->data = &loca_table->buffer[0];
+  loca_table->data = loca_offset ? &loca_table->buffer[0] : NULL;
 
   return true;
 }
 
 }  // namespace
 
 namespace {
 
--- a/modules/woff2/src/port.h
+++ b/modules/woff2/src/port.h
@@ -55,9 +55,20 @@ inline int Log2Floor(uint32 n) {
     (defined(__llvm__) && __has_builtin(__builtin_expect))
 #define PREDICT_FALSE(x) (__builtin_expect(x, 0))
 #define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
 #else
 #define PREDICT_FALSE(x) (x)
 #define PREDICT_TRUE(x) (x)
 #endif
 
+#if (defined(__ARM_ARCH) && (__ARM_ARCH == 7)) || \
+    (defined(M_ARM) && (M_ARM == 7)) || \
+    defined(__aarch64__) || defined(__ARM64_ARCH_8__) || defined(__i386) || \
+    defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
+#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define WOFF_LITTLE_ENDIAN
+#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define WOFF_BIG_ENDIAN
+#endif  /* endianness */
+#endif  /* CPU whitelist */
+
 #endif  // WOFF2_PORT_H_
--- a/modules/woff2/src/store_bytes.h
+++ b/modules/woff2/src/store_bytes.h
@@ -17,56 +17,55 @@
 
 #ifndef WOFF2_STORE_BYTES_H_
 #define WOFF2_STORE_BYTES_H_
 
 #include <inttypes.h>
 #include <stddef.h>
 #include <string.h>
 
+#include "./port.h"
+
 namespace woff2 {
 
 inline 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;
   return offset + 4;
 }
 
 inline size_t Store16(uint8_t* dst, size_t offset, int x) {
-#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
-  uint16_t v = ((x & 0xFF) << 8) | ((x & 0xFF00) >> 8);
-  memcpy(dst + offset, &v, 2);
-#elif (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
-  uint16_t v = static_cast<uint16_t>(x);
-  memcpy(dst + offset, &v, 2);
+#if defined(WOFF_LITTLE_ENDIAN)
+  *reinterpret_cast<uint16_t*>(dst + offset) =
+      ((x & 0xFF) << 8) | ((x & 0xFF00) >> 8);
+#elif defined(WOFF_BIG_ENDIAN)
+  *reinterpret_cast<uint16_t*>(dst + offset) = static_cast<uint16_t>(x);
 #else
   dst[offset] = x >> 8;
   dst[offset + 1] = x;
 #endif
   return offset + 2;
 }
 
 inline void StoreU32(uint32_t val, size_t* offset, uint8_t* dst) {
   dst[(*offset)++] = val >> 24;
   dst[(*offset)++] = val >> 16;
   dst[(*offset)++] = val >> 8;
   dst[(*offset)++] = val;
 }
 
 inline void Store16(int val, size_t* offset, uint8_t* dst) {
-#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
-  uint16_t v = ((val & 0xFF) << 8) | ((val & 0xFF00) >> 8);
-  memcpy(dst + *offset, &v, 2);
+#if defined(WOFF_LITTLE_ENDIAN)
+  *reinterpret_cast<uint16_t*>(dst + *offset) =
       ((val & 0xFF) << 8) | ((val & 0xFF00) >> 8);
   *offset += 2;
-#elif (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
-  uint16_t v = static_cast<uint16_t>(val);
-  memcpy(dst + *offset, &v, 2);
+#elif defined(WOFF_BIG_ENDIAN)
+  *reinterpret_cast<uint16_t*>(dst + *offset) = static_cast<uint16_t>(val);
   *offset += 2;
 #else
   dst[(*offset)++] = val >> 8;
   dst[(*offset)++] = val;
 #endif
 }
 
 inline void StoreBytes(const uint8_t* data, size_t len,
--- a/modules/woff2/src/variable_length.cc
+++ b/modules/woff2/src/variable_length.cc
@@ -44,18 +44,18 @@ void Write255UShort(std::vector<uint8_t>
     out->push_back(value >> 8);
     out->push_back(value & 0xff);
   }
 }
 
 void Store255UShort(int val, size_t* offset, uint8_t* dst) {
   std::vector<uint8_t> packed;
   Write255UShort(&packed, val);
-  for (uint8_t val : packed) {
-    dst[(*offset)++] = val;
+  for (uint8_t packed_byte : packed) {
+    dst[(*offset)++] = packed_byte;
   }
 }
 
 // Based on section 6.1.1 of MicroType Express draft spec
 bool Read255UShort(Buffer* buf, unsigned int* value) {
   static const int kWordCode = 253;
   static const int kOneMoreByteCode2 = 254;
   static const int kOneMoreByteCode1 = 255;
--- a/modules/woff2/src/woff2_common.cc
+++ b/modules/woff2/src/woff2_common.cc
@@ -13,30 +13,31 @@
 // limitations under the License.
 //
 // Helpers common across multiple parts of woff2
 
 #include <algorithm>
 
 #include "./woff2_common.h"
 
+#include "./port.h"
+
 namespace woff2 {
 
 
 uint32_t ComputeULongSum(const uint8_t* buf, size_t size) {
   uint32_t checksum = 0;
   size_t aligned_size = size & ~3;
   for (size_t i = 0; i < aligned_size; i += 4) {
-    uint32_t v;
-    memcpy(&v, buf + i, 4);
-#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+#if defined(WOFF_LITTLE_ENDIAN)
+    uint32_t v = *reinterpret_cast<const uint32_t*>(buf + i);
     checksum += (((v & 0xFF) << 24) | ((v & 0xFF00) << 8) |
       ((v & 0xFF0000) >> 8) | ((v & 0xFF000000) >> 24));
-#elif (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
-    checksum += v;
+#elif defined(WOFF_BIG_ENDIAN)
+    checksum += *reinterpret_cast<const uint32_t*>(buf + i);
 #else
     checksum += (buf[i] << 24) | (buf[i + 1] << 16) |
       (buf[i + 2] << 8) | buf[i + 3];
 #endif
   }
 
   // treat size not aligned on 4 as if it were padded to 4 with 0's
   if (size != aligned_size) {
--- a/modules/woff2/src/woff2_dec.cc
+++ b/modules/woff2/src/woff2_dec.cc
@@ -31,17 +31,17 @@
 namespace std
 {
   using mozilla::DefaultDelete;
   using mozilla::UniquePtr;
   #define default_delete DefaultDelete
   #define unique_ptr UniquePtr
 }
 
-#include "brotli/decode.h"
+#include "./brotli/decode.h"
 #include "./buffer.h"
 #include "./port.h"
 #include "./round.h"
 #include "./store_bytes.h"
 #include "./table_tags.h"
 #include "./variable_length.h"
 #include "./woff2_common.h"
 
@@ -746,19 +746,20 @@ bool ReconstructTransformedHmtx(const ui
   }
 
   return true;
 }
 
 bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
   const uint8_t* src_buf, size_t src_size) {
   size_t uncompressed_size = dst_size;
-  int ok = BrotliDecoderDecompress(src_size, src_buf,
-                                   &uncompressed_size, dst_buf);
-  if (PREDICT_FALSE(!ok || uncompressed_size != dst_size)) {
+  BrotliDecoderResult result = BrotliDecoderDecompress(
+      src_size, src_buf, &uncompressed_size, dst_buf);
+  if (PREDICT_FALSE(result != BROTLI_DECODER_RESULT_SUCCESS ||
+                    uncompressed_size != dst_size)) {
     return FONT_COMPRESSION_FAILURE();
   }
   return true;
 }
 
 bool ReadTableDirectory(Buffer* file, std::vector<Table>* tables,
     size_t num_tables) {
   uint32_t src_offset = 0;
@@ -1302,16 +1303,19 @@ bool ConvertWOFF2ToTTF(const uint8_t* da
 #ifdef FONT_COMPRESSION_BIN
     fprintf(stderr, "Implausible compression ratio %.01f\n", compression_ratio);
 #endif
     return FONT_COMPRESSION_FAILURE();
   }
 
   const uint8_t* src_buf = data + hdr.compressed_offset;
   std::vector<uint8_t> uncompressed_buf(hdr.uncompressed_size);
+  if (PREDICT_FALSE(hdr.uncompressed_size < 1)) {
+    return FONT_COMPRESSION_FAILURE();
+  }
   if (PREDICT_FALSE(!Woff2Uncompress(&uncompressed_buf[0],
                                      hdr.uncompressed_size, src_buf,
                                      hdr.compressed_length))) {
     return FONT_COMPRESSION_FAILURE();
   }
 
   for (size_t i = 0; i < metadata.font_infos.size(); i++) {
     if (PREDICT_FALSE(!ReconstructFont(&uncompressed_buf[0],
--- a/modules/woff2/src/woff2_enc.cc
+++ b/modules/woff2/src/woff2_enc.cc
@@ -18,68 +18,62 @@
 
 #include <stdlib.h>
 #include <complex>
 #include <cstring>
 #include <limits>
 #include <string>
 #include <vector>
 
-#include "./compressor.h"
+#include "./brotli/encode.h"
 #include "./buffer.h"
 #include "./font.h"
 #include "./normalize.h"
 #include "./round.h"
 #include "./store_bytes.h"
 #include "./table_tags.h"
 #include "./transform.h"
 #include "./variable_length.h"
 #include "./woff2_common.h"
 
-
 namespace woff2 {
 
 namespace {
 
 
 using std::string;
 using std::vector;
 
 
 const size_t kWoff2HeaderSize = 48;
 const size_t kWoff2EntrySize = 20;
 
-
-bool Compress(const uint8_t* data, const size_t len,
-              uint8_t* result, uint32_t* result_len,
-              brotli::BrotliParams::Mode mode, int quality) {
+bool Compress(const uint8_t* data, const size_t len, uint8_t* result,
+              uint32_t* result_len, BrotliEncoderMode mode, int quality) {
   size_t compressed_len = *result_len;
-  brotli::BrotliParams params;
-  params.mode = mode;
-  params.quality = quality;
-  if (brotli::BrotliCompressBuffer(params, len, data, &compressed_len, result)
-      == 0) {
+  if (BrotliEncoderCompress(quality, BROTLI_DEFAULT_WINDOW, mode, len, data,
+                            &compressed_len, result) == 0) {
     return false;
   }
   *result_len = compressed_len;
   return true;
 }
 
 bool Woff2Compress(const uint8_t* data, const size_t len,
                    uint8_t* result, uint32_t* result_len,
                    int quality) {
   return Compress(data, len, result, result_len,
-                  brotli::BrotliParams::MODE_FONT, quality);
+                  BROTLI_MODE_FONT, quality);
 }
 
 bool TextCompress(const uint8_t* data, const size_t len,
                   uint8_t* result, uint32_t* result_len,
                   int quality) {
   return Compress(data, len, result, result_len,
-                  brotli::BrotliParams::MODE_TEXT, quality);
+                  BROTLI_MODE_TEXT, quality);
 }
 
 int KnownTableIndex(uint32_t tag) {
   for (int i = 0; i < 63; ++i) {
     if (tag == kKnownTags[i]) return i;
   }
   return 63;
 }
@@ -106,17 +100,18 @@ size_t TableEntrySize(const Table& table
   if ((table.flags & kWoff2FlagsTransform) != 0) {
      size += Base128Size(table.transform_length);
   }
   return size;
 }
 
 size_t ComputeWoff2Length(const FontCollection& font_collection,
                           const std::vector<Table>& tables,
-                          std::map<uint32_t, uint16_t> index_by_offset,
+                          std::map<std::pair<uint32_t, uint32_t>, uint16_t>
+                            index_by_tag_offset,
                           size_t compressed_data_length,
                           size_t extended_metadata_length) {
   size_t size = kWoff2HeaderSize;
 
   for (const auto& table : tables) {
     size += TableEntrySize(table);
   }
 
@@ -129,17 +124,18 @@ size_t ComputeWoff2Length(const FontColl
 
     for (const auto& font : font_collection.fonts) {
       size += Size255UShort(font.tables.size());  // 255UInt16 numTables
       for (const auto& entry : font.tables) {
         const Font::Table& table = entry.second;
         // no collection entry for xform table
         if (table.tag & 0x80808080) continue;
 
-        uint16_t table_index = index_by_offset[table.offset];
+        std::pair<uint32_t, uint32_t> tag_offset(table.tag, table.offset);
+        uint16_t table_index = index_by_tag_offset[tag_offset];
         size += Size255UShort(table_index);  // 255UInt16 index entry
       }
     }
   }
 
   // compressed data
   size += compressed_data_length;
   size = Round4(size);
@@ -321,28 +317,29 @@ bool ConvertTTFToWOFF2(const uint8_t *da
 #endif
       return FONT_COMPRESSION_FAILURE();
     }
   } else {
     compressed_metadata_buf_length = 0;
   }
 
   std::vector<Table> tables;
-  std::map<uint32_t, uint16_t> index_by_offset;
+  std::map<std::pair<uint32_t, uint32_t>, uint16_t> index_by_tag_offset;
 
   for (const auto& font : font_collection.fonts) {
 
     for (const auto tag : font.OutputOrderedTags()) {
       const Font::Table& src_table = font.tables.at(tag);
       if (src_table.IsReused()) {
         continue;
       }
 
-      if (index_by_offset.find(src_table.offset) == index_by_offset.end()) {
-        index_by_offset[src_table.offset] = tables.size();
+      std::pair<uint32_t, uint32_t> tag_offset(src_table.tag, src_table.offset);
+      if (index_by_tag_offset.find(tag_offset) == index_by_tag_offset.end()) {
+        index_by_tag_offset[tag_offset] = tables.size();
       } else {
         return false;
       }
 
       Table table;
       table.tag = src_table.tag;
       table.flags = src_table.flag_byte;
       table.src_length = src_table.length;
@@ -357,17 +354,18 @@ bool ConvertTTFToWOFF2(const uint8_t *da
         transformed_data = transformed_table->data;
 
       }
       tables.push_back(table);
     }
   }
 
   size_t woff2_length = ComputeWoff2Length(font_collection, tables,
-      index_by_offset, total_compressed_length, compressed_metadata_buf_length);
+      index_by_tag_offset, total_compressed_length,
+      compressed_metadata_buf_length);
   if (woff2_length > *result_length) {
 #ifdef FONT_COMPRESSION_BIN
     fprintf(stderr, "Result allocation was too small (%zd vs %zd bytes).\n",
            *result_length, woff2_length);
 #endif
     return FONT_COMPRESSION_FAILURE();
   }
   *result_length = woff2_length;
@@ -430,24 +428,25 @@ bool ConvertTTFToWOFF2(const uint8_t *da
         const Font::Table& table = entry.second;
         if (table.tag & 0x80808080) continue;  // don't write xform tables
 
         // for reused tables, only the original has an updated offset
         uint32_t table_offset =
           table.IsReused() ? table.reuse_of->offset : table.offset;
         uint32_t table_length =
           table.IsReused() ? table.reuse_of->length : table.length;
-        if (index_by_offset.find(table_offset) == index_by_offset.end()) {
+        std::pair<uint32_t, uint32_t> tag_offset(table.tag, table_offset);
+        if (index_by_tag_offset.find(tag_offset) == index_by_tag_offset.end()) {
 #ifdef FONT_COMPRESSION_BIN
           fprintf(stderr, "Missing table index for offset 0x%08x\n",
                   table_offset);
 #endif
           return FONT_COMPRESSION_FAILURE();
         }
-        uint16_t index = index_by_offset[table_offset];
+        uint16_t index = index_by_tag_offset[tag_offset];
         Store255UShort(index, &offset, result);
 
       }
 
     }
   }
 
   // compressed data format (http://www.w3.org/TR/WOFF2/#table_format)