Bug 1270537 - Update woff2 code to latest upstream. r=milan
authorJonathan Kew <jkew@mozilla.com>
Mon, 27 Jun 2016 17:41:38 +0100
changeset 302759 c9ee3b0069e4841323c512d563ea84df73e5c313
parent 302758 f5b378eddb42ded3553b4199d47c328ee8e5dbed
child 302760 ab8e9e4b893d13748c71c463296840dc356805b9
push id30376
push usercbook@mozilla.com
push dateTue, 28 Jun 2016 14:09:36 +0000
treeherdermozilla-central@e45890951ce7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmilan
bugs1270537
milestone50.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 1270537 - Update woff2 code to latest upstream. r=milan
modules/woff2/README.mozilla
modules/woff2/missing-assert-header.patch
modules/woff2/moz.build
modules/woff2/redefine-unique_ptr.patch
modules/woff2/src/file.h
modules/woff2/src/font.cc
modules/woff2/src/font.h
modules/woff2/src/glyph.cc
modules/woff2/src/store_bytes.h
modules/woff2/src/transform.cc
modules/woff2/src/woff2_common.cc
modules/woff2/src/woff2_compress.cc
modules/woff2/src/woff2_dec.cc
modules/woff2/src/woff2_dec.h
modules/woff2/src/woff2_decompress.cc
modules/woff2/src/woff2_enc.cc
modules/woff2/src/woff2_out.cc
modules/woff2/src/woff2_out.h
modules/woff2/update.sh
--- a/modules/woff2/README.mozilla
+++ b/modules/woff2/README.mozilla
@@ -6,16 +6,16 @@ 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 643c7b45891cbeb5dc1f7599a4c9b53fbe82a08f].
+Current version: [commit afbecce5ff16faf92ce637eab991810f5b66f803].
 
 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
 
 missing-assert-header.patch contains the upstream change from commit
 07cd303dd2959cbf69a6840706c0896e49e42677 adding the missing assert.h header.
deleted file mode 100644
--- a/modules/woff2/missing-assert-header.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-diff --git a/modules/woff2/src/port.h b/modules/woff2/src/port.h
---- a/modules/woff2/src/port.h
-+++ b/modules/woff2/src/port.h
-@@ -12,16 +12,18 @@
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- // Helper function for bit twiddling and macros for branch prediction.
- 
- #ifndef WOFF2_PORT_H_
- #define WOFF2_PORT_H_
- 
-+#include <assert.h>
-+
- namespace woff2 {
- 
- typedef unsigned int       uint32;
- 
- inline int Log2Floor(uint32 n) {
- #if defined(__GNUC__)
-   return n == 0 ? -1 : 31 ^ __builtin_clz(n);
- #else
--- a/modules/woff2/moz.build
+++ b/modules/woff2/moz.build
@@ -1,21 +1,23 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 EXPORTS += [
     'src/woff2_dec.h',
+    'src/woff2_out.h',
 ]
 
 UNIFIED_SOURCES += [
     'src/table_tags.cc',
     'src/variable_length.cc',
     'src/woff2_common.cc',
     'src/woff2_dec.cc',
+    'src/woff2_out.cc',
 ]
 
 # We allow warnings for third-party code that can be updated from upstream.
 ALLOW_COMPILER_WARNINGS = True
 
 Library('woff2')
--- a/modules/woff2/redefine-unique_ptr.patch
+++ b/modules/woff2/redefine-unique_ptr.patch
@@ -1,28 +1,29 @@
 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
-@@ -20,16 +20,24 @@
- #include <algorithm>
- #include <complex>
+@@ -22,16 +22,25 @@
  #include <cstring>
  #include <limits>
  #include <string>
  #include <vector>
  #include <map>
  #include <memory>
+ #include <utility>
+ 
 +#include "mozilla/UniquePtr.h"
 +namespace std
 +{
 +  using mozilla::DefaultDelete;
 +  using mozilla::UniquePtr;
 +  #define default_delete DefaultDelete
 +  #define unique_ptr UniquePtr
 +}
- 
++
  #include "./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/file.h
+++ b/modules/woff2/src/file.h
@@ -7,34 +7,36 @@
 // http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
 //
-// File IO helpers
+// File IO helpers.
 
 #ifndef WOFF2_FILE_H_
 #define WOFF2_FILE_H_
 
 #include <fstream>
 #include <iterator>
 
 namespace woff2 {
 
-inline std::string GetFileContent(std::string filename) {
+using std::string;
+
+
+inline string GetFileContent(string filename) {
   std::ifstream ifs(filename.c_str(), std::ios::binary);
-  return std::string(
+  return string(
     std::istreambuf_iterator<char>(ifs.rdbuf()),
     std::istreambuf_iterator<char>());
 }
 
-inline void SetFileContents(std::string filename, std::string content) {
+inline void SetFileContents(string filename, string::iterator start,
+    string::iterator end) {
   std::ofstream ofs(filename.c_str(), std::ios::binary);
-  std::copy(content.begin(),
-            content.end(),
-            std::ostream_iterator<char>(ofs));
+  std::copy(start, end, std::ostream_iterator<char>(ofs));
 }
 
 } // namespace woff2
 #endif  // WOFF2_FILE_H_
--- a/modules/woff2/src/font.cc
+++ b/modules/woff2/src/font.cc
@@ -44,30 +44,26 @@ std::vector<uint32_t> Font::OutputOrdere
     // This is a transformed table, we will write it together with the
     // original version.
     if (table.tag & 0x80808080) {
       continue;
     }
     output_order.push_back(table.tag);
   }
 
-  // Alphabetize and do not put loca immediately after glyf
-  // This violates woff2 spec but results in a font that passes OTS
-  std::sort(output_order.begin(), output_order.end());
-  // TODO(user): change to match spec once browsers are on newer OTS
-  /*
+  // Alphabetize then put loca immediately after glyf
   auto glyf_loc = std::find(output_order.begin(), output_order.end(),
       kGlyfTableTag);
   auto loca_loc = std::find(output_order.begin(), output_order.end(),
       kLocaTableTag);
   if (glyf_loc != output_order.end() && loca_loc != output_order.end()) {
     output_order.erase(loca_loc);
     output_order.insert(std::find(output_order.begin(), output_order.end(),
       kGlyfTableTag) + 1, kLocaTableTag);
-  }*/
+  }
 
   return output_order;
 }
 
 bool ReadTrueTypeFont(Buffer* file, const uint8_t* data, size_t len,
                       Font* font) {
   // We don't care about the search_range, entry_selector and range_shift
   // fields, they will always be computed upon writing the font.
@@ -140,17 +136,17 @@ bool ReadTrueTypeCollection(Buffer* file
     uint32_t num_fonts;
 
     if (!file->ReadU32(&font_collection->header_version) ||
         !file->ReadU32(&num_fonts)) {
       return FONT_COMPRESSION_FAILURE();
     }
 
     std::vector<uint32_t> offsets;
-    for (auto i = 0; i < num_fonts; i++) {
+    for (size_t i = 0; i < num_fonts; i++) {
       uint32_t offset;
       if (!file->ReadU32(&offset)) {
         return FONT_COMPRESSION_FAILURE();
       }
       offsets.push_back(offset);
     }
 
     font_collection->fonts.resize(offsets.size());
@@ -180,25 +176,24 @@ bool ReadFont(const uint8_t* data, size_
   }
   return ReadTrueTypeFont(&file, data, len, font);
 }
 
 bool ReadFontCollection(const uint8_t* data, size_t len,
                         FontCollection* font_collection) {
   Buffer file(data, len);
 
-  uint32_t flavor;
-  if (!file.ReadU32(&flavor)) {
+  if (!file.ReadU32(&font_collection->flavor)) {
     return FONT_COMPRESSION_FAILURE();
   }
 
-  if (flavor != kTtcFontFlavor) {
+  if (font_collection->flavor != kTtcFontFlavor) {
     font_collection->fonts.resize(1);
     Font& font = font_collection->fonts[0];
-    font.flavor = flavor;
+    font.flavor = font_collection->flavor;
     return ReadTrueTypeFont(&file, data, len, &font);
   }
   return ReadTrueTypeCollection(&file, data, len, font_collection);
 }
 
 size_t FontFileSize(const Font& font) {
   size_t max_offset = 12ULL + 16ULL * font.num_tables;
   for (const auto& i : font.tables) {
@@ -285,39 +280,39 @@ bool WriteFont(const Font& font, size_t*
   return true;
 }
 
 bool WriteFontCollection(const FontCollection& font_collection, uint8_t* dst,
                          size_t dst_size) {
   size_t offset = 0;
 
   // It's simpler if this just a simple sfnt
-  if (font_collection.fonts.size() == 1) {
+  if (font_collection.flavor != kTtcFontFlavor) {
     return WriteFont(font_collection.fonts[0], &offset, dst, dst_size);
   }
 
   // Write TTC header
   StoreU32(kTtcFontFlavor, &offset, dst);
   StoreU32(font_collection.header_version, &offset, dst);
   StoreU32(font_collection.fonts.size(), &offset, dst);
 
   // Offset Table, zeroed for now
   size_t offset_table = offset;  // where to write offsets later
-  for (int i = 0; i < font_collection.fonts.size(); i++) {
+  for (size_t i = 0; i < font_collection.fonts.size(); i++) {
     StoreU32(0, &offset, dst);
   }
 
   if (font_collection.header_version == 0x00020000) {
     StoreU32(0, &offset, dst);  // ulDsigTag
     StoreU32(0, &offset, dst);  // ulDsigLength
     StoreU32(0, &offset, dst);  // ulDsigOffset
   }
 
   // Write fonts and their offsets.
-  for (int i = 0; i < font_collection.fonts.size(); i++) {
+  for (size_t i = 0; i < font_collection.fonts.size(); i++) {
     const auto& font = font_collection.fonts[i];
     StoreU32(offset, &offset_table, dst);
     if (!WriteFont(font, &offset, dst, dst_size)) {
       return false;
     }
   }
 
   return true;
--- a/modules/woff2/src/font.h
+++ b/modules/woff2/src/font.h
@@ -56,16 +56,17 @@ struct Font {
   std::vector<uint32_t> OutputOrderedTags() const;
 
   Table* FindTable(uint32_t tag);
   const Table* FindTable(uint32_t tag) const;
 };
 
 // Accomodates both singular (OTF, TTF) and collection (TTC) fonts
 struct FontCollection {
+  uint32_t flavor;
   uint32_t header_version;
   // (offset, first use of table*) pairs
   std::map<uint32_t, Font::Table*> tables;
   std::vector<Font> fonts;
 };
 
 // Parses the font from the given data. Returns false on parsing failure or
 // buffer overflow. The font is valid only so long the input data pointer is
--- a/modules/woff2/src/glyph.cc
+++ b/modules/woff2/src/glyph.cc
@@ -117,17 +117,17 @@ bool ReadGlyph(const uint8_t* data, size
     }
 
     // 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 (int j = 0; j < glyph->contours[i].size(); ++j) {
+      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();
             }
@@ -138,17 +138,17 @@ bool ReadGlyph(const uint8_t* data, size
         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 (int j = 0; j < glyph->contours[i].size(); ++j) {
+      for (size_t j = 0; j < glyph->contours[i].size(); ++j) {
         uint8_t flag = flags[i][j];
         if (flag & kFLAG_XSHORT) {
           // single byte x-delta coord value
           uint8_t x_delta;
           if (!buffer.ReadU8(&x_delta)) {
             return FONT_COMPRESSION_FAILURE();
           }
           int sign = (flag & kFLAG_XREPEATSIGN) ? 1 : -1;
@@ -165,17 +165,17 @@ bool ReadGlyph(const uint8_t* data, size
         }
         prev_x = glyph->contours[i][j].x;
       }
     }
 
     // Read the y coordinates.
     int prev_y = 0;
     for (int i = 0; i < num_contours; ++i) {
-      for (int j = 0; j < glyph->contours[i].size(); ++j) {
+      for (size_t j = 0; j < glyph->contours[i].size(); ++j) {
         uint8_t flag = flags[i][j];
         if (flag & kFLAG_YSHORT) {
           // single byte y-delta coord value
           uint8_t y_delta;
           if (!buffer.ReadU8(&y_delta)) {
             return FONT_COMPRESSION_FAILURE();
           }
           int sign = (flag & kFLAG_YREPEATSIGN) ? 1 : -1;
--- a/modules/woff2/src/store_bytes.h
+++ b/modules/woff2/src/store_bytes.h
@@ -53,18 +53,17 @@ inline void StoreU32(uint32_t val, size_
 }
 
 inline void Store16(int val, size_t* offset, uint8_t* dst) {
 #if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_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__))
-  *reinterpret_cast<uint16_t*>(dst + *offset) =
-      static_cast<uint16_t>(val);
+  *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/transform.cc
+++ b/modules/woff2/src/transform.cc
@@ -34,17 +34,17 @@ const int FLAG_WE_HAVE_INSTRUCTIONS = 1 
 void WriteBytes(std::vector<uint8_t>* out, const uint8_t* data, size_t len) {
   if (len == 0) return;
   size_t offset = out->size();
   out->resize(offset + len);
   memcpy(&(*out)[offset], data, len);
 }
 
 void WriteBytes(std::vector<uint8_t>* out, const std::vector<uint8_t>& in) {
-  for (int i = 0; i < in.size(); ++i) {
+  for (size_t i = 0; i < in.size(); ++i) {
     out->push_back(in[i]);
   }
 }
 
 void WriteUShort(std::vector<uint8_t>* out, int value) {
   out->push_back(value >> 8);
   out->push_back(value & 255);
 }
--- a/modules/woff2/src/woff2_common.cc
+++ b/modules/woff2/src/woff2_common.cc
@@ -18,28 +18,39 @@
 
 #include "./woff2_common.h"
 
 namespace woff2 {
 
 
 uint32_t ComputeULongSum(const uint8_t* buf, size_t size) {
   uint32_t checksum = 0;
-  for (size_t i = 0; i < size; i += 4) {
+  size_t aligned_size = size & ~3;
+  for (size_t i = 0; i < aligned_size; i += 4) {
 #if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_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 += *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) {
+    uint32_t v = 0;
+    for (size_t i = aligned_size; i < size; ++i) {
+      v |= buf[i] << (24 - 8 * (i & 3));
+    }
+    checksum += v;
+  }
+
   return checksum;
 }
 
 size_t CollectionHeaderSize(uint32_t header_version, uint32_t num_fonts) {
   size_t size = 0;
   if (header_version == 0x00020000) {
     size += 12;  // ulDsig{Tag,Length,Offset}
   }
--- a/modules/woff2/src/woff2_compress.cc
+++ b/modules/woff2/src/woff2_compress.cc
@@ -42,12 +42,12 @@ int main(int argc, char **argv) {
   woff2::WOFF2Params params;
   if (!woff2::ConvertTTFToWOFF2(input_data, input.size(),
                                 output_data, &output_size, params)) {
     fprintf(stderr, "Compression failed.\n");
     return 1;
   }
   output.resize(output_size);
 
-  woff2::SetFileContents(outfilename, output);
+  woff2::SetFileContents(outfilename, output.begin(), output.end());
 
   return 0;
 }
--- a/modules/woff2/src/woff2_dec.cc
+++ b/modules/woff2/src/woff2_dec.cc
@@ -20,16 +20,18 @@
 #include <algorithm>
 #include <complex>
 #include <cstring>
 #include <limits>
 #include <string>
 #include <vector>
 #include <map>
 #include <memory>
+#include <utility>
+
 #include "mozilla/UniquePtr.h"
 namespace std
 {
   using mozilla::DefaultDelete;
   using mozilla::UniquePtr;
   #define default_delete DefaultDelete
   #define unique_ptr UniquePtr
 }
@@ -68,23 +70,64 @@ const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE 
 const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
 
 const size_t kCheckSumAdjustmentOffset = 8;
 
 const size_t kEndPtsOfContoursOffset = 10;
 const size_t kCompositeGlyphBegin = 10;
 
+// 98% of Google Fonts have no glyph above 5k bytes
+// Largest glyph ever observed was 72k bytes
+const size_t kDefaultGlyphBuf = 5120;
+
+// Over 14k test fonts the max compression ratio seen to date was ~20.
+// >100 suggests you wrote a bad uncompressed size.
+const float kMaxPlausibleCompressionRatio = 100.0;
+
 // metadata for a TTC font entry
 struct TtcFont {
   uint32_t flavor;
   uint32_t dst_offset;
+  uint32_t header_checksum;
   std::vector<uint16_t> table_indices;
 };
 
+struct WOFF2Header {
+  uint32_t flavor;
+  uint32_t header_version;
+  uint16_t num_tables;
+  uint64_t compressed_offset;
+  uint32_t compressed_length;
+  uint32_t uncompressed_size;
+  std::vector<Table> tables;  // num_tables unique tables
+  std::vector<TtcFont> ttc_fonts;  // metadata to help rebuild font
+};
+
+/**
+ * Accumulates data we may need to reconstruct a single font. One per font
+ * created for a TTC.
+ */
+struct WOFF2FontInfo {
+  uint16_t num_glyphs;
+  uint16_t index_format;
+  uint16_t num_hmetrics;
+  std::vector<int16_t> x_mins;
+  std::map<uint32_t, uint32_t> table_entry_by_tag;
+};
+
+// Accumulates metadata as we rebuild the font
+struct RebuildMetadata {
+  uint32_t header_checksum;  // set by WriteHeaders
+  std::vector<WOFF2FontInfo> font_infos;
+  // checksums for tables that have been written.
+  // (tag, src_offset) => checksum. Need both because 0-length loca.
+  std::map<std::pair<uint32_t, uint32_t>, uint32_t> checksums;
+};
+
 int WithSign(int flag, int baseval) {
   // Precondition: 0 <= baseval < 65536 (to avoid integer overflow)
   return (flag & 1) ? baseval : -baseval;
 }
 
 bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
     unsigned int n_points, Point* result, size_t* in_bytes_consumed) {
   int x = 0;
@@ -247,16 +290,17 @@ bool StorePoints(unsigned int n_points, 
     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.
+// dst should point to the beginning of a 'glyf' record.
 void ComputeBbox(unsigned int n_points, const Point* points, uint8_t* dst) {
   int x_min = 0;
   int y_min = 0;
   int x_max = 0;
   int y_max = 0;
 
   if (n_points > 0) {
     x_min = points[0].x;
@@ -274,175 +318,208 @@ void ComputeBbox(unsigned int n_points, 
   }
   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);
 }
 
-bool ProcessComposite(Buffer* composite_stream, uint8_t* dst,
-    size_t dst_size, size_t* glyph_size, bool* have_instructions) {
-  size_t start_offset = composite_stream->offset();
+
+bool SizeOfComposite(Buffer composite_stream, size_t* size,
+                     bool* have_instructions) {
+  size_t start_offset = composite_stream.offset();
   bool we_have_instructions = false;
 
   uint16_t flags = FLAG_MORE_COMPONENTS;
   while (flags & FLAG_MORE_COMPONENTS) {
-    if (PREDICT_FALSE(!composite_stream->ReadU16(&flags))) {
+    if (PREDICT_FALSE(!composite_stream.ReadU16(&flags))) {
       return FONT_COMPRESSION_FAILURE();
     }
     we_have_instructions |= (flags & FLAG_WE_HAVE_INSTRUCTIONS) != 0;
     size_t arg_size = 2;  // glyph index
     if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) {
       arg_size += 4;
     } else {
       arg_size += 2;
     }
     if (flags & FLAG_WE_HAVE_A_SCALE) {
       arg_size += 2;
     } else if (flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
       arg_size += 4;
     } else if (flags & FLAG_WE_HAVE_A_TWO_BY_TWO) {
       arg_size += 8;
     }
-    if (PREDICT_FALSE(!composite_stream->Skip(arg_size))) {
+    if (PREDICT_FALSE(!composite_stream.Skip(arg_size))) {
       return FONT_COMPRESSION_FAILURE();
     }
   }
-  size_t composite_glyph_size = composite_stream->offset() - start_offset;
-  if (PREDICT_FALSE(composite_glyph_size + kCompositeGlyphBegin > dst_size)) {
+
+  *size = composite_stream.offset() - start_offset;
+  *have_instructions = we_have_instructions;
+
+  return true;
+}
+
+bool Pad4(WOFF2Out* out) {
+  uint8_t zeroes[] = {0, 0, 0};
+  if (PREDICT_FALSE(out->Size() + 3 < out->Size())) {
     return FONT_COMPRESSION_FAILURE();
   }
-  Store16(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;
+  uint32_t pad_bytes = Round4(out->Size()) - out->Size();
+  if (pad_bytes > 0) {
+    if (PREDICT_FALSE(!out->Write(&zeroes, pad_bytes))) {
+      return FONT_COMPRESSION_FAILURE();
+    }
+  }
   return true;
 }
 
 // Build TrueType loca table
 bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format,
-               uint8_t* dst, size_t dst_size) {
+               uint32_t* checksum, WOFF2Out* out) {
+  // TODO(user) figure out what index format to use based on whether max
+  // offset fits into uint16_t or not
   const uint64_t loca_size = loca_values.size();
   const uint64_t offset_size = index_format ? 4 : 2;
   if (PREDICT_FALSE((loca_size << 2) >> 2 != loca_size)) {
     return FONT_COMPRESSION_FAILURE();
   }
-  if (PREDICT_FALSE(offset_size * loca_size > dst_size)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
+  std::vector<uint8_t> loca_content(loca_size * offset_size);
+  uint8_t* dst = &loca_content[0];
   size_t offset = 0;
   for (size_t i = 0; i < loca_values.size(); ++i) {
     uint32_t value = loca_values[i];
     if (index_format) {
       offset = StoreU32(dst, offset, value);
     } else {
       offset = Store16(dst, offset, value >> 1);
     }
   }
+  *checksum = ComputeULongSum(&loca_content[0], loca_content.size());
+  if (PREDICT_FALSE(!out->Write(&loca_content[0], loca_content.size()))) {
+    return FONT_COMPRESSION_FAILURE();
+  }
   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,
-                     uint8_t* loca_buf, size_t loca_size) {
+bool ReconstructGlyf(const uint8_t* data, Table* glyf_table,
+                     uint32_t* glyf_checksum, Table * loca_table,
+                     uint32_t* loca_checksum, WOFF2FontInfo* info,
+                     WOFF2Out* out) {
   static const int kNumSubStreams = 7;
-  Buffer file(data, data_size);
+  Buffer file(data, glyf_table->transform_length);
   uint32_t version;
   std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
+  const size_t glyf_start = out->Size();
 
   if (PREDICT_FALSE(!file.ReadU32(&version))) {
     return FONT_COMPRESSION_FAILURE();
   }
-  uint16_t num_glyphs;
-  uint16_t index_format;
-  if (PREDICT_FALSE(!file.ReadU16(&num_glyphs) ||
-      !file.ReadU16(&index_format))) {
+  if (PREDICT_FALSE(!file.ReadU16(&info->num_glyphs) ||
+      !file.ReadU16(&info->index_format))) {
     return FONT_COMPRESSION_FAILURE();
   }
 
   unsigned int offset = (2 + kNumSubStreams) * 4;
-  if (PREDICT_FALSE(offset > data_size)) {
+  if (PREDICT_FALSE(offset > glyf_table->transform_length)) {
     return FONT_COMPRESSION_FAILURE();
   }
   // Invariant from here on: data_size >= offset
   for (int i = 0; i < kNumSubStreams; ++i) {
     uint32_t substream_size;
     if (PREDICT_FALSE(!file.ReadU32(&substream_size))) {
       return FONT_COMPRESSION_FAILURE();
     }
-    if (PREDICT_FALSE(substream_size > data_size - offset)) {
+    if (PREDICT_FALSE(substream_size > glyf_table->transform_length - offset)) {
       return FONT_COMPRESSION_FAILURE();
     }
     substreams[i] = std::make_pair(data + offset, substream_size);
     offset += substream_size;
   }
   Buffer n_contour_stream(substreams[0].first, substreams[0].second);
   Buffer n_points_stream(substreams[1].first, substreams[1].second);
   Buffer flag_stream(substreams[2].first, substreams[2].second);
   Buffer glyph_stream(substreams[3].first, substreams[3].second);
   Buffer composite_stream(substreams[4].first, substreams[4].second);
   Buffer bbox_stream(substreams[5].first, substreams[5].second);
   Buffer instruction_stream(substreams[6].first, substreams[6].second);
 
-  std::vector<uint32_t> loca_values(num_glyphs + 1);
+  std::vector<uint32_t> loca_values(info->num_glyphs + 1);
   std::vector<unsigned int> n_points_vec;
   std::unique_ptr<Point[]> points;
   size_t points_size = 0;
-  uint32_t loca_offset = 0;
   const uint8_t* bbox_bitmap = bbox_stream.buffer();
   // Safe because num_glyphs is bounded
-  unsigned int bitmap_length = ((num_glyphs + 31) >> 5) << 2;
+  unsigned int bitmap_length = ((info->num_glyphs + 31) >> 5) << 2;
   if (!bbox_stream.Skip(bitmap_length)) {
     return FONT_COMPRESSION_FAILURE();
   }
-  for (unsigned int i = 0; i < num_glyphs; ++i) {
+
+  // Temp buffer for glyph's.
+  size_t glyph_buf_size = kDefaultGlyphBuf;
+  std::unique_ptr<uint8_t[]> glyph_buf(new uint8_t[glyph_buf_size]);
+
+  info->x_mins.resize(info->num_glyphs);
+  for (unsigned int i = 0; i < info->num_glyphs; ++i) {
     size_t glyph_size = 0;
     uint16_t n_contours = 0;
     bool have_bbox = false;
     if (bbox_bitmap[i >> 3] & (0x80 >> (i & 7))) {
       have_bbox = true;
     }
     if (PREDICT_FALSE(!n_contour_stream.ReadU16(&n_contours))) {
       return FONT_COMPRESSION_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;
       if (PREDICT_FALSE(!have_bbox)) {
         // composite glyphs must have an explicit bbox
         return FONT_COMPRESSION_FAILURE();
       }
-      if (PREDICT_FALSE(!ProcessComposite(&composite_stream, glyf_dst,
-            glyf_dst_size, &glyph_size, &have_instructions))) {
-        return FONT_COMPRESSION_FAILURE();
-      }
-      if (PREDICT_FALSE(!bbox_stream.Read(glyf_dst + 2, 8))) {
+
+      size_t composite_size;
+      if (PREDICT_FALSE(!SizeOfComposite(composite_stream, &composite_size,
+                                         &have_instructions))) {
         return FONT_COMPRESSION_FAILURE();
       }
       if (have_instructions) {
         if (PREDICT_FALSE(!Read255UShort(&glyph_stream, &instruction_size))) {
           return FONT_COMPRESSION_FAILURE();
         }
-        if (PREDICT_FALSE(instruction_size + 2 > glyf_dst_size - glyph_size)) {
-          return FONT_COMPRESSION_FAILURE();
-        }
-        Store16(glyf_dst, glyph_size, instruction_size);
-        if (PREDICT_FALSE(!instruction_stream.Read(glyf_dst + glyph_size + 2,
+      }
+
+      size_t size_needed = 12 + composite_size + instruction_size;
+      if (PREDICT_FALSE(glyph_buf_size < size_needed)) {
+        glyph_buf.reset(new uint8_t[size_needed]);
+        glyph_buf_size = size_needed;
+      }
+
+      glyph_size = Store16(glyph_buf.get(), glyph_size, n_contours);
+      if (PREDICT_FALSE(!bbox_stream.Read(glyph_buf.get() + glyph_size, 8))) {
+        return FONT_COMPRESSION_FAILURE();
+      }
+      glyph_size += 8;
+
+      if (PREDICT_FALSE(!composite_stream.Read(glyph_buf.get() + glyph_size,
+            composite_size))) {
+        return FONT_COMPRESSION_FAILURE();
+      }
+      glyph_size += composite_size;
+      if (have_instructions) {
+        glyph_size = Store16(glyph_buf.get(), glyph_size, instruction_size);
+        if (PREDICT_FALSE(!instruction_stream.Read(glyph_buf.get() + glyph_size,
               instruction_size))) {
           return FONT_COMPRESSION_FAILURE();
         }
-        glyph_size += instruction_size + 2;
+        glyph_size += instruction_size;
       }
     } else if (n_contours > 0) {
       // simple glyph
       n_points_vec.clear();
       unsigned int total_n_points = 0;
       unsigned int n_points_contour;
       for (unsigned int j = 0; j < n_contours; ++j) {
         if (PREDICT_FALSE(
@@ -468,192 +545,132 @@ bool ReconstructGlyf(const uint8_t* data
       if (points_size < total_n_points) {
         points_size = total_n_points;
         points.reset(new Point[points_size]);
       }
       if (PREDICT_FALSE(!TripletDecode(flags_buf, triplet_buf, triplet_size,
           total_n_points, points.get(), &triplet_bytes_consumed))) {
         return FONT_COMPRESSION_FAILURE();
       }
-      const uint32_t header_and_endpts_contours_size =
-          kEndPtsOfContoursOffset + 2 * n_contours;
-      if (PREDICT_FALSE(glyf_dst_size < header_and_endpts_contours_size)) {
-        return FONT_COMPRESSION_FAILURE();
-      }
-      Store16(glyf_dst, 0, n_contours);
-      if (have_bbox) {
-        if (PREDICT_FALSE(!bbox_stream.Read(glyf_dst + 2, 8))) {
-          return FONT_COMPRESSION_FAILURE();
-        }
-      } else {
-        ComputeBbox(total_n_points, points.get(), glyf_dst);
-      }
-      size_t offset = kEndPtsOfContoursOffset;
-      int end_point = -1;
-      for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) {
-        end_point += n_points_vec[contour_ix];
-        if (PREDICT_FALSE(end_point >= 65536)) {
-          return FONT_COMPRESSION_FAILURE();
-        }
-        offset = Store16(glyf_dst, offset, end_point);
-      }
       if (PREDICT_FALSE(!flag_stream.Skip(flag_size))) {
         return FONT_COMPRESSION_FAILURE();
       }
       if (PREDICT_FALSE(!glyph_stream.Skip(triplet_bytes_consumed))) {
         return FONT_COMPRESSION_FAILURE();
       }
       unsigned int instruction_size;
       if (PREDICT_FALSE(!Read255UShort(&glyph_stream, &instruction_size))) {
         return FONT_COMPRESSION_FAILURE();
       }
-      if (PREDICT_FALSE(glyf_dst_size - header_and_endpts_contours_size <
-          instruction_size + 2)) {
-        return FONT_COMPRESSION_FAILURE();
-      }
-      uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size;
-      Store16(instruction_dst, 0, instruction_size);
-      if (PREDICT_FALSE(
-          !instruction_stream.Read(instruction_dst + 2, instruction_size))) {
+
+      if (PREDICT_FALSE(total_n_points >= (1 << 27)
+                        || instruction_size >= (1 << 30))) {
         return FONT_COMPRESSION_FAILURE();
       }
-      if (PREDICT_FALSE(!StorePoints(total_n_points, points.get(), n_contours,
-            instruction_size, glyf_dst, glyf_dst_size, &glyph_size))) {
+      size_t size_needed = 12 + 2 * n_contours + 5 * total_n_points
+                           + instruction_size;
+      if (PREDICT_FALSE(glyph_buf_size < size_needed)) {
+        glyph_buf.reset(new uint8_t[size_needed]);
+        glyph_buf_size = size_needed;
+      }
+
+      glyph_size = Store16(glyph_buf.get(), glyph_size, n_contours);
+      if (have_bbox) {
+        if (PREDICT_FALSE(!bbox_stream.Read(glyph_buf.get() + glyph_size, 8))) {
+          return FONT_COMPRESSION_FAILURE();
+        }
+      } else {
+        ComputeBbox(total_n_points, points.get(), glyph_buf.get());
+      }
+      glyph_size = kEndPtsOfContoursOffset;
+      int end_point = -1;
+      for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) {
+        end_point += n_points_vec[contour_ix];
+        if (PREDICT_FALSE(end_point >= 65536)) {
+          return FONT_COMPRESSION_FAILURE();
+        }
+        glyph_size = Store16(glyph_buf.get(), glyph_size, end_point);
+      }
+
+      glyph_size = Store16(glyph_buf.get(), glyph_size, instruction_size);
+      if (PREDICT_FALSE(!instruction_stream.Read(glyph_buf.get() + glyph_size,
+                                                 instruction_size))) {
         return FONT_COMPRESSION_FAILURE();
       }
-    } else {
-      glyph_size = 0;
+      glyph_size += instruction_size;
+
+      if (PREDICT_FALSE(!StorePoints(total_n_points, points.get(), n_contours,
+            instruction_size, glyph_buf.get(), glyph_buf_size, &glyph_size))) {
+        return FONT_COMPRESSION_FAILURE();
+      }
     }
-    loca_values[i] = loca_offset;
-    if (PREDICT_FALSE(glyph_size + 3 < glyph_size)) {
+
+    loca_values[i] = out->Size() - glyf_start;
+    if (PREDICT_FALSE(!out->Write(glyph_buf.get(), glyph_size))) {
       return FONT_COMPRESSION_FAILURE();
     }
-    glyph_size = Round4(glyph_size);
-    if (PREDICT_FALSE(glyph_size > dst_size - loca_offset)) {
-      // This shouldn't happen, but this test defensively maintains the
-      // invariant that loca_offset <= dst_size.
+
+    // TODO(user) Old code aligned glyphs ... but do we actually need to?
+    if (PREDICT_FALSE(!Pad4(out))) {
       return FONT_COMPRESSION_FAILURE();
     }
-    loca_offset += glyph_size;
+
+    *glyf_checksum += ComputeULongSum(glyph_buf.get(), glyph_size);
+
+    // We may need x_min to reconstruct 'hmtx'
+    if (n_contours > 0) {
+      Buffer x_min_buf(glyph_buf.get() + 2, 2);
+      if (PREDICT_FALSE(!x_min_buf.ReadS16(&info->x_mins[i]))) {
+        return FONT_COMPRESSION_FAILURE();
+      }
+    }
   }
-  loca_values[num_glyphs] = loca_offset;
-  return StoreLoca(loca_values, index_format, loca_buf, loca_size);
+
+  // glyf_table dst_offset was set by ReconstructFont
+  glyf_table->dst_length = out->Size() - glyf_table->dst_offset;
+  loca_table->dst_offset = out->Size();
+  // loca[n] will be equal the length of the glyph data ('glyf') table
+  loca_values[info->num_glyphs] = glyf_table->dst_length;
+  if (PREDICT_FALSE(!StoreLoca(loca_values, info->index_format, loca_checksum,
+      out))) {
+    return FONT_COMPRESSION_FAILURE();
+  }
+  loca_table->dst_length = out->Size() - loca_table->dst_offset;
+
+  return true;
 }
 
-// This is linear search, but could be changed to binary because we
-// do have a guarantee that the tables are sorted by tag. But the total
-// cpu time is expected to be very small in any case.
-const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) {
-  size_t n_tables = tables.size();
-  for (size_t i = 0; i < n_tables; ++i) {
-    if (tables[i].tag == tag) {
-      return &tables[i];
+Table* FindTable(std::vector<Table*>* tables, uint32_t tag) {
+  for (Table* table : *tables) {
+    if (table->tag == tag) {
+      return table;
     }
   }
   return NULL;
 }
 
-// https://www.microsoft.com/typography/otspec/maxp.htm
-bool ReadNumGlyphs(const Table* maxp_table,
-                   uint8_t* dst, size_t dst_length, uint16_t* num_glyphs) {
-  if (PREDICT_FALSE(static_cast<uint64_t>(maxp_table->dst_offset +
-      maxp_table->dst_length) > dst_length)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  Buffer buffer(dst + maxp_table->dst_offset, maxp_table->dst_length);
-  // Skip 4 to reach 'maxp' numGlyphs
-  if (PREDICT_FALSE(!buffer.Skip(4) || !buffer.ReadU16(num_glyphs))) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  return true;
-}
-
 // Get numberOfHMetrics, https://www.microsoft.com/typography/otspec/hhea.htm
-bool ReadNumHMetrics(const Table* hhea_table,
-                     uint8_t* dst, size_t dst_length, uint16_t* num_hmetrics) {
-  if (PREDICT_FALSE(static_cast<uint64_t>(hhea_table->dst_offset +
-      hhea_table->dst_length) > dst_length)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
+bool ReadNumHMetrics(const uint8_t* data, size_t data_size,
+                     uint16_t* num_hmetrics) {
   // Skip 34 to reach 'hhea' numberOfHMetrics
-  Buffer buffer(dst + hhea_table->dst_offset, hhea_table->dst_length);
+  Buffer buffer(data, data_size);
   if (PREDICT_FALSE(!buffer.Skip(34) || !buffer.ReadU16(num_hmetrics))) {
     return FONT_COMPRESSION_FAILURE();
   }
   return true;
 }
 
-// x_min for glyph; https://www.microsoft.com/typography/otspec/glyf.htm
-bool ReadGlyphXMin(Buffer* glyf_buff, Buffer* loca_buff, int16_t loca_format,
-                   uint16_t index, int16_t* x_min) {
-  uint32_t offset1, offset2;
-  loca_buff->set_offset((loca_format == 0 ? 2 : 4) * index);
-  if (loca_format == 0) {
-    uint16_t tmp1, tmp2;
-    if (PREDICT_FALSE(!loca_buff->ReadU16(&tmp1) ||
-                      !loca_buff->ReadU16(&tmp2))) {
-      return FONT_COMPRESSION_FAILURE();
-    }
-    // https://www.microsoft.com/typography/otspec/loca.htm
-    // "The actual local offset divided by 2 is stored."
-    offset1 = tmp1 * 2;
-    offset2 = tmp2 * 2;
-  } else if (PREDICT_FALSE(!loca_buff->ReadU32(&offset1) ||
-                           !loca_buff->ReadU32(&offset2))) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-
-  if (offset1 != offset2) {
-    glyf_buff->set_offset(offset1 + 2);
-    if (!glyf_buff->ReadS16(x_min)) {
-      return FONT_COMPRESSION_FAILURE();
-    }
-  } else {
-    *x_min = 0;
-  }
-  return true;
-}
-
 // http://dev.w3.org/webfonts/WOFF2/spec/Overview.html#hmtx_table_format
 bool ReconstructTransformedHmtx(const uint8_t* transformed_buf,
                                 size_t transformed_size,
-                                const Table* glyf_table,
-                                const Table* hhea_table,
-                                const Table* hmtx_table,
-                                const Table* loca_table,
-                                const Table* maxp_table,
-                                uint8_t* dst, size_t dst_length) {
-  if (PREDICT_FALSE(!glyf_table)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  if (PREDICT_FALSE(!hhea_table)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  if (PREDICT_FALSE(!hmtx_table)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  if (PREDICT_FALSE(!loca_table)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  if (PREDICT_FALSE(!maxp_table)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-
-  uint16_t num_glyphs, num_hmetrics;
-  if (!ReadNumGlyphs(maxp_table, dst, dst_length, &num_glyphs)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  if (!ReadNumHMetrics(hhea_table, dst, dst_length, &num_hmetrics)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-
-  if (PREDICT_FALSE(static_cast<uint64_t>(hmtx_table->dst_offset +
-      hmtx_table->dst_length) > dst_length)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
+                                uint16_t num_glyphs,
+                                uint16_t num_hmetrics,
+                                const std::vector<int16_t>& x_mins,
+                                uint32_t* checksum,
+                                WOFF2Out* out) {
   Buffer hmtx_buff_in(transformed_buf, transformed_size);
 
   uint8_t hmtx_flags;
   if (PREDICT_FALSE(!hmtx_buff_in.ReadU8(&hmtx_flags))) {
     return FONT_COMPRESSION_FAILURE();
   }
 
   std::vector<uint16_t> advance_widths;
@@ -661,33 +678,26 @@ bool ReconstructTransformedHmtx(const ui
   bool has_proportional_lsbs = (hmtx_flags & 1) == 0;
   bool has_monospace_lsbs = (hmtx_flags & 2) == 0;
 
   // you say you transformed but there is little evidence of it
   if (has_proportional_lsbs && has_monospace_lsbs) {
     return FONT_COMPRESSION_FAILURE();
   }
 
-  // glyf/loca are done already so we can use them to recover x_min's
-  if (PREDICT_FALSE(static_cast<uint64_t>(glyf_table->dst_offset +
-      glyf_table->dst_length) > dst_length)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  if (PREDICT_FALSE(static_cast<uint64_t>(loca_table->dst_offset +
-      loca_table->dst_length) > dst_length)) {
+  assert(x_mins.size() == num_glyphs);
+
+  // num_glyphs 0 is OK if there is no 'glyf' but cannot then xform 'hmtx'.
+  if (PREDICT_FALSE(num_hmetrics > num_glyphs)) {
     return FONT_COMPRESSION_FAILURE();
   }
-  Buffer glyf_buff(dst + glyf_table->dst_offset, glyf_table->dst_length);
-  Buffer loca_buff(dst + loca_table->dst_offset, loca_table->dst_length);
-  int16_t loca_format;
-  if (loca_table->dst_length == 2 * (num_glyphs + 1)) {
-    loca_format = 0;
-  } else if (loca_table->dst_length == 4 * (num_glyphs + 1)) {
-    loca_format = 1;
-  } else {
+
+  // https://www.microsoft.com/typography/otspec/hmtx.htm
+  // "...only one entry need be in the array, but that entry is required."
+  if (PREDICT_FALSE(num_hmetrics < 1)) {
     return FONT_COMPRESSION_FAILURE();
   }
 
   for (uint16_t i = 0; i < num_hmetrics; i++) {
     uint16_t advance_width;
     if (PREDICT_FALSE(!hmtx_buff_in.ReadU16(&advance_width))) {
       return FONT_COMPRESSION_FAILURE();
     }
@@ -696,216 +706,67 @@ bool ReconstructTransformedHmtx(const ui
 
   for (uint16_t i = 0; i < num_hmetrics; i++) {
     int16_t lsb;
     if (has_proportional_lsbs) {
       if (PREDICT_FALSE(!hmtx_buff_in.ReadS16(&lsb))) {
         return FONT_COMPRESSION_FAILURE();
       }
     } else {
-      if (PREDICT_FALSE(!ReadGlyphXMin(&glyf_buff, &loca_buff, loca_format, i,
-          &lsb))) {
-        return FONT_COMPRESSION_FAILURE();
-      }
+      lsb = x_mins[i];
     }
     lsbs.push_back(lsb);
   }
 
   for (uint16_t i = num_hmetrics; i < num_glyphs; i++) {
     int16_t lsb;
     if (has_monospace_lsbs) {
       if (PREDICT_FALSE(!hmtx_buff_in.ReadS16(&lsb))) {
         return FONT_COMPRESSION_FAILURE();
       }
     } else {
-      if (PREDICT_FALSE(!ReadGlyphXMin(&glyf_buff, &loca_buff, loca_format, i,
-          &lsb))) {
-        return FONT_COMPRESSION_FAILURE();
-      }
+      lsb = x_mins[i];
     }
     lsbs.push_back(lsb);
   }
 
   // bake me a shiny new hmtx table
   uint32_t hmtx_output_size = 2 * num_glyphs + 2 * num_hmetrics;
-  if (hmtx_output_size > hmtx_table->dst_length) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  if (PREDICT_FALSE(static_cast<uint64_t>(hmtx_table->dst_offset +
-      hmtx_table->dst_length) > dst_length)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-
-  size_t dst_offset = hmtx_table->dst_offset;
+  std::vector<uint8_t> hmtx_table(hmtx_output_size);
+  uint8_t* dst = &hmtx_table[0];
+  size_t dst_offset = 0;
   for (uint32_t i = 0; i < num_glyphs; i++) {
     if (i < num_hmetrics) {
       Store16(advance_widths[i], &dst_offset, dst);
     }
     Store16(lsbs[i], &dst_offset, dst);
   }
 
-  return true;
-}
-
-bool ReconstructTransformedGlyf(const uint8_t* transformed_buf,
-    size_t transformed_size, const Table* glyf_table, const Table* loca_table,
-    uint8_t* dst, size_t dst_length) {
-  if (PREDICT_FALSE(glyf_table == NULL || loca_table == NULL)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  if (PREDICT_FALSE(static_cast<uint64_t>(glyf_table->dst_offset +
-      glyf_table->dst_length) > dst_length)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  if (PREDICT_FALSE(static_cast<uint64_t>(loca_table->dst_offset +
-     loca_table->dst_length) > dst_length)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  return ReconstructGlyf(transformed_buf, transformed_size,
-                         dst + glyf_table->dst_offset, glyf_table->dst_length,
-                         dst + loca_table->dst_offset, loca_table->dst_length);
-}
-
-// Reconstructs a single font. tables must not contain duplicates.
-bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag,
-    const uint8_t* transformed_buf, size_t transformed_size,
-    uint8_t* dst, size_t dst_length) {
-
-  if (tag == kGlyfTableTag) {
-    const Table* glyf_table = FindTable(tables, tag);
-    const Table* loca_table = FindTable(tables, kLocaTableTag);
-    return ReconstructTransformedGlyf(transformed_buf, transformed_size,
-                                      glyf_table, loca_table, dst, dst_length);
-  } else if (tag == kLocaTableTag) {
-    // processing was already done by glyf table, but validate
-    if (PREDICT_FALSE(!FindTable(tables, kGlyfTableTag))) {
-      return FONT_COMPRESSION_FAILURE();
-    }
-  } else if (tag == kHmtxTableTag) {
-    // Tables are sorted for a non-collection.
-    // glyf is before hmtx and includes loca so all our accesses are safe.
-    const Table* glyf_table = FindTable(tables, kGlyfTableTag);
-    const Table* hhea_table = FindTable(tables, kHheaTableTag);
-    const Table* hmtx_table = FindTable(tables, kHmtxTableTag);
-    const Table* loca_table = FindTable(tables, kLocaTableTag);
-    const Table* maxp_table = FindTable(tables, kMaxpTableTag);
-
-    if (PREDICT_FALSE(!ReconstructTransformedHmtx(
-        transformed_buf, transformed_size, glyf_table, hhea_table,
-        hmtx_table, loca_table, maxp_table, dst, dst_length))) {
-      return FONT_COMPRESSION_FAILURE();
-    }
-  } else {
-    // transform for the tag is not known
+  *checksum = ComputeULongSum(&hmtx_table[0], hmtx_output_size);
+  if (PREDICT_FALSE(!out->Write(&hmtx_table[0], hmtx_output_size))) {
     return FONT_COMPRESSION_FAILURE();
   }
-  return true;
-}
 
-uint32_t ComputeChecksum(const Table* table, const uint8_t* dst) {
-  return ComputeULongSum(dst + table->dst_offset, table->dst_length);
-}
-
-const Table* FindTable(TtcFont ttc_font, const std::vector<Table>& tables,
-  uint32_t tag) {
-  for (const auto i : ttc_font.table_indices) {
-    if (tables[i].tag == tag) return &tables[i];
-  }
-  return NULL;
-}
-
-bool FixCollectionChecksums(size_t header_version,
-  const std::vector<Table>& tables, const std::vector<TtcFont>& ttc_fonts,
-  uint8_t* dst) {
-  size_t offset = CollectionHeaderSize(header_version, ttc_fonts.size());
-
-  for (const auto& ttc_font : ttc_fonts) {
-    offset += 12;  // move to start of Offset Table
-    const std::vector<uint16_t>& table_indices = ttc_font.table_indices;
-
-    const Table* head_table = FindTable(ttc_font, tables, kHeadTableTag);
-    if (PREDICT_FALSE(head_table == NULL ||
-        head_table->dst_length < kCheckSumAdjustmentOffset + 4)) {
-      return FONT_COMPRESSION_FAILURE();
-    }
-
-    size_t first_table_offset = std::numeric_limits<size_t>::max();
-    for (const auto index : table_indices) {
-      const auto& table = tables[index];
-      if (table.dst_offset < first_table_offset) {
-        first_table_offset = table.dst_offset;
-      }
-    }
-
-    size_t adjustment_offset = head_table->dst_offset
-      + kCheckSumAdjustmentOffset;
-    StoreU32(dst, adjustment_offset, 0);
-
-    uint32_t file_checksum = 0;
-    // compute each tables checksum
-    for (size_t i = 0; i < table_indices.size(); i++) {
-      const Table& table = tables[table_indices[i]];
-      uint32_t table_checksum = ComputeChecksum(&table, dst);
-      size_t checksum_offset = offset + 4;  // skip past tag to checkSum
-
-      // write the checksum for the Table Record
-      StoreU32(dst, checksum_offset, table_checksum);
-      file_checksum += table_checksum;
-      // next Table Record
-      offset += 16;
-    }
-
-    size_t header_size = kSfntHeaderSize +
-      kSfntEntrySize * table_indices.size();
-    uint32_t header_checksum = ComputeULongSum(dst + ttc_font.dst_offset,
-                                               header_size);
-
-    file_checksum += header_checksum;
-    uint32_t checksum_adjustment = 0xb1b0afba - file_checksum;
-    StoreU32(dst, adjustment_offset, checksum_adjustment);
-  }
-
-  return true;
-}
-
-bool FixChecksums(const std::vector<Table>& tables, uint8_t* dst) {
-  const Table* head_table = FindTable(tables, kHeadTableTag);
-  if (PREDICT_FALSE(head_table == NULL ||
-      head_table->dst_length < kCheckSumAdjustmentOffset + 4)) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  size_t adjustment_offset = head_table->dst_offset + kCheckSumAdjustmentOffset;
-  StoreU32(dst, adjustment_offset, 0);
-  size_t n_tables = tables.size();
-  uint32_t file_checksum = 0;
-  for (size_t i = 0; i < n_tables; ++i) {
-    uint32_t checksum = ComputeChecksum(&tables[i], dst);
-    StoreU32(dst, kSfntHeaderSize + i * kSfntEntrySize + 4, checksum);
-    file_checksum += checksum;
-  }
-  file_checksum += ComputeULongSum(dst,
-                                   kSfntHeaderSize + kSfntEntrySize * n_tables);
-  uint32_t checksum_adjustment = 0xb1b0afba - file_checksum;
-  StoreU32(dst, adjustment_offset, checksum_adjustment);
   return true;
 }
 
 bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
   const uint8_t* src_buf, size_t src_size) {
   size_t uncompressed_size = dst_size;
   int ok = BrotliDecompressBuffer(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) {
+  uint32_t src_offset = 0;
   for (size_t i = 0; i < num_tables; ++i) {
     Table* table = &(*tables)[i];
     uint8_t flag_byte;
     if (PREDICT_FALSE(!file->ReadU8(&flag_byte))) {
       return FONT_COMPRESSION_FAILURE();
     }
     uint32_t tag;
     if ((flag_byte & 0x3f) == 0x3f) {
@@ -936,37 +797,31 @@ bool ReadTableDirectory(Buffer* file, st
     if ((flags & kWoff2FlagsTransform) != 0) {
       if (PREDICT_FALSE(!ReadBase128(file, &transform_length))) {
         return FONT_COMPRESSION_FAILURE();
       }
       if (PREDICT_FALSE(tag == kLocaTableTag && transform_length)) {
         return FONT_COMPRESSION_FAILURE();
       }
     }
+    if (PREDICT_FALSE(src_offset + transform_length < src_offset)) {
+      return FONT_COMPRESSION_FAILURE();
+    }
+    table->src_offset = src_offset;
+    table->src_length = transform_length;
+    src_offset += transform_length;
+
     table->tag = tag;
     table->flags = flags;
     table->transform_length = transform_length;
     table->dst_length = dst_length;
   }
   return true;
 }
 
-}  // namespace
-
-size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) {
-  Buffer file(data, length);
-  uint32_t total_length;
-
-  if (!file.Skip(16) ||
-      !file.ReadU32(&total_length)) {
-    return 0;
-  }
-  return total_length;
-}
-
 // Writes a single Offset Table entry
 size_t StoreOffsetTable(uint8_t* result, size_t offset, uint32_t flavor,
                         uint16_t num_tables) {
   offset = StoreU32(result, offset, flavor);  // sfnt version
   offset = Store16(result, offset, num_tables);  // num_tables
   unsigned max_pow2 = 0;
   while (1u << (max_pow2 + 1) <= num_tables) {
     max_pow2++;
@@ -974,94 +829,213 @@ size_t StoreOffsetTable(uint8_t* result,
   const uint16_t output_search_range = (1u << max_pow2) << 4;
   offset = Store16(result, offset, output_search_range);  // searchRange
   offset = Store16(result, offset, max_pow2);  // entrySelector
   // rangeShift
   offset = Store16(result, offset, (num_tables << 4) - output_search_range);
   return offset;
 }
 
-size_t StoreTableEntry(uint8_t* result, const Table& table, size_t offset) {
-  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);
+size_t StoreTableEntry(uint8_t* result, uint32_t offset, uint32_t tag) {
+  offset = StoreU32(result, offset, tag);
+  offset = StoreU32(result, offset, 0);
+  offset = StoreU32(result, offset, 0);
+  offset = StoreU32(result, offset, 0);
   return offset;
 }
 
 // First table goes after all the headers, table directory, etc
-uint64_t ComputeOffsetToFirstTable(const uint32_t header_version,
-                                   const uint16_t num_tables,
-                                   const std::vector<TtcFont>& ttc_fonts) {
+uint64_t ComputeOffsetToFirstTable(const WOFF2Header& hdr) {
   uint64_t offset = kSfntHeaderSize +
-    kSfntEntrySize * static_cast<uint64_t>(num_tables);
-  if (header_version) {
-    offset = CollectionHeaderSize(header_version, ttc_fonts.size())
-      + kSfntHeaderSize * ttc_fonts.size();
-    for (const auto& ttc_font : ttc_fonts) {
-      offset +=
-        kSfntEntrySize * ttc_font.table_indices.size();
+    kSfntEntrySize * static_cast<uint64_t>(hdr.num_tables);
+  if (hdr.header_version) {
+    offset = CollectionHeaderSize(hdr.header_version, hdr.ttc_fonts.size())
+      + kSfntHeaderSize * hdr.ttc_fonts.size();
+    for (const auto& ttc_font : hdr.ttc_fonts) {
+      offset += kSfntEntrySize * ttc_font.table_indices.size();
     }
   }
   return offset;
 }
 
-bool ReconstructTransformedFont(const std::vector<Table>& tables,
-                                std::map<uint32_t, const uint8_t*>* src_by_dest,
-                                uint8_t* result, size_t result_length) {
-  for (const auto& table : tables) {
-    if ((table.flags & kWoff2FlagsTransform) != kWoff2FlagsTransform) {
-      continue;
+std::vector<Table*> Tables(WOFF2Header* hdr, size_t font_index) {
+  std::vector<Table*> tables;
+  if (PREDICT_FALSE(hdr->header_version)) {
+    for (auto index : hdr->ttc_fonts[font_index].table_indices) {
+      tables.push_back(&hdr->tables[index]);
+    }
+  } else {
+    for (auto& table : hdr->tables) {
+      tables.push_back(&table);
+    }
+  }
+  return tables;
+}
+
+// Offset tables assumed to have been written in with 0's initially.
+// WOFF2Header isn't const so we can use [] instead of at() (which upsets FF)
+bool ReconstructFont(uint8_t* transformed_buf,
+                     const uint32_t transformed_buf_size,
+                     RebuildMetadata* metadata,
+                     WOFF2Header* hdr,
+                     size_t font_index,
+                     WOFF2Out* out) {
+  size_t dest_offset = out->Size();
+  uint8_t table_entry[12];
+  WOFF2FontInfo* info = &metadata->font_infos[font_index];
+  std::vector<Table*> tables = Tables(hdr, font_index);
+
+  // 'glyf' without 'loca' doesn't make sense
+  if (PREDICT_FALSE(static_cast<bool>(FindTable(&tables, kGlyfTableTag)) !=
+                    static_cast<bool>(FindTable(&tables, kLocaTableTag)))) {
+    return FONT_COMPRESSION_FAILURE();
+  }
+
+  uint32_t font_checksum = metadata->header_checksum;
+  if (hdr->header_version) {
+    font_checksum = hdr->ttc_fonts[font_index].header_checksum;
+  }
+
+  uint32_t loca_checksum = 0;
+  for (size_t i = 0; i < tables.size(); i++) {
+    Table& table = *tables[i];
+
+    std::pair<uint32_t, uint32_t> checksum_key = {table.tag, table.src_offset};
+    bool reused = metadata->checksums.find(checksum_key)
+               != metadata->checksums.end();
+    if (PREDICT_FALSE(font_index == 0 && reused)) {
+      return FONT_COMPRESSION_FAILURE();
+    }
+
+    // TODO(user) a collection with optimized hmtx that reused glyf/loca
+    // would fail. We don't optimize hmtx for collections yet.
+    if (PREDICT_FALSE(static_cast<uint64_t>(table.src_offset + table.src_length)
+        > transformed_buf_size)) {
+      return FONT_COMPRESSION_FAILURE();
+    }
+
+    if (table.tag == kHheaTableTag) {
+      if (!ReadNumHMetrics(transformed_buf + table.src_offset,
+          table.src_length, &info->num_hmetrics)) {
+        return FONT_COMPRESSION_FAILURE();
+      }
     }
-    const auto it = src_by_dest->find(table.dst_offset);
-    if (it == src_by_dest->end()) {
-      continue;
+
+    uint32_t checksum = 0;
+    if (!reused) {
+      if ((table.flags & kWoff2FlagsTransform) != kWoff2FlagsTransform) {
+        if (table.tag == kHeadTableTag) {
+          if (PREDICT_FALSE(table.src_length < 12)) {
+            return FONT_COMPRESSION_FAILURE();
+          }
+          // checkSumAdjustment = 0
+          StoreU32(transformed_buf + table.src_offset, 8, 0);
+        }
+        table.dst_offset = dest_offset;
+        checksum = ComputeULongSum(transformed_buf + table.src_offset,
+                                   table.src_length);
+        out->Write(transformed_buf + table.src_offset, table.src_length);
+      } else {
+        if (table.tag == kGlyfTableTag) {
+          table.dst_offset = dest_offset;
+
+          Table* loca_table = FindTable(&tables, kLocaTableTag);
+          if (PREDICT_FALSE(!ReconstructGlyf(transformed_buf + table.src_offset,
+              &table, &checksum, loca_table, &loca_checksum, info, out))) {
+            return FONT_COMPRESSION_FAILURE();
+          }
+        } else if (table.tag == kLocaTableTag) {
+          // All the work was done by ReconstructGlyf. We already know checksum.
+          checksum = loca_checksum;
+        } else if (table.tag == kHmtxTableTag) {
+          table.dst_offset = dest_offset;
+          // Tables are sorted so all the info we need has been gathered.
+          if (PREDICT_FALSE(!ReconstructTransformedHmtx(
+              transformed_buf + table.src_offset, table.src_length,
+              info->num_glyphs, info->num_hmetrics, info->x_mins, &checksum,
+              out))) {
+            return FONT_COMPRESSION_FAILURE();
+          }
+        } else {
+          return FONT_COMPRESSION_FAILURE();  // transform unknown
+        }
+      }
+      metadata->checksums[checksum_key] = checksum;
+    } else {
+      checksum = metadata->checksums[checksum_key];
     }
-    const uint8_t* transform_buf = (*it).second;
-    src_by_dest->erase(table.dst_offset);
+    font_checksum += checksum;
+
+    // update the table entry with real values.
+    StoreU32(table_entry, 0, checksum);
+    StoreU32(table_entry, 4, table.dst_offset);
+    StoreU32(table_entry, 8, table.dst_length);
+    if (PREDICT_FALSE(!out->Write(table_entry,
+        info->table_entry_by_tag[table.tag] + 4, 12))) {
+      return FONT_COMPRESSION_FAILURE();
+    }
+
+    // We replaced 0's. Update overall checksum.
+    font_checksum += ComputeULongSum(table_entry, 12);
+
+    if (PREDICT_FALSE(!Pad4(out))) {
+      return FONT_COMPRESSION_FAILURE();
+    }
 
-    size_t transform_length = table.transform_length;
-    if (PREDICT_FALSE(!ReconstructTransformed(tables, table.tag,
-            transform_buf, transform_length, result, result_length))) {
+    if (PREDICT_FALSE(static_cast<uint64_t>(table.dst_offset + table.dst_length)
+        > out->Size())) {
+      return FONT_COMPRESSION_FAILURE();
+    }
+    dest_offset = out->Size();
+  }
+
+  // Update 'head' checkSumAdjustment. We already set it to 0 and summed font.
+  Table* head_table = FindTable(&tables, kHeadTableTag);
+  if (head_table) {
+    if (PREDICT_FALSE(head_table->dst_length < 12)) {
+      return FONT_COMPRESSION_FAILURE();
+    }
+    uint8_t checksum_adjustment[4];
+    StoreU32(checksum_adjustment, 0, 0xB1B0AFBA - font_checksum);
+    if (PREDICT_FALSE(!out->Write(checksum_adjustment,
+                                  head_table->dst_offset + 8, 4))) {
       return FONT_COMPRESSION_FAILURE();
     }
   }
+
   return true;
 }
 
-bool ConvertWOFF2ToTTF(uint8_t* result, size_t result_length,
-                       const uint8_t* data, size_t length) {
+bool ReadWOFF2Header(const uint8_t* data, size_t length, WOFF2Header* hdr) {
   Buffer file(data, length);
 
   uint32_t signature;
-  uint32_t flavor;
   if (PREDICT_FALSE(!file.ReadU32(&signature) || signature != kWoff2Signature ||
-      !file.ReadU32(&flavor))) {
+      !file.ReadU32(&hdr->flavor))) {
     return FONT_COMPRESSION_FAILURE();
   }
 
   // TODO(user): Should call IsValidVersionTag() here.
 
   uint32_t reported_length;
   if (PREDICT_FALSE(
       !file.ReadU32(&reported_length) || length != reported_length)) {
     return FONT_COMPRESSION_FAILURE();
   }
-  uint16_t num_tables;
-  if (PREDICT_FALSE(!file.ReadU16(&num_tables) || !num_tables)) {
+  if (PREDICT_FALSE(!file.ReadU16(&hdr->num_tables) || !hdr->num_tables)) {
     return FONT_COMPRESSION_FAILURE();
   }
+
   // We don't care about these fields of the header:
   //   uint16_t reserved
-  //   uint32_t total_sfnt_size, the caller already passes it as result_length
+  //   uint32_t total_sfnt_size, we don't believe this, will compute later
   if (PREDICT_FALSE(!file.Skip(6))) {
     return FONT_COMPRESSION_FAILURE();
   }
-  uint32_t compressed_length;
-  if (PREDICT_FALSE(!file.ReadU32(&compressed_length))) {
+  if (PREDICT_FALSE(!file.ReadU32(&hdr->compressed_length))) {
     return FONT_COMPRESSION_FAILURE();
   }
   // We don't care about these fields of the header:
   //   uint16_t major_version, minor_version
   if (PREDICT_FALSE(!file.Skip(2 * 2))) {
     return FONT_COMPRESSION_FAILURE();
   }
   uint32_t meta_offset;
@@ -1085,138 +1059,106 @@ bool ConvertWOFF2ToTTF(uint8_t* result, 
     return FONT_COMPRESSION_FAILURE();
   }
   if (priv_offset) {
     if (PREDICT_FALSE(
         priv_offset >= length || length - priv_offset < priv_length)) {
       return FONT_COMPRESSION_FAILURE();
     }
   }
-  std::vector<Table> tables(num_tables);
-  if (PREDICT_FALSE(!ReadTableDirectory(&file, &tables, num_tables))) {
+  hdr->tables.resize(hdr->num_tables);
+  if (PREDICT_FALSE(!ReadTableDirectory(
+          &file, &hdr->tables, hdr->num_tables))) {
     return FONT_COMPRESSION_FAILURE();
   }
 
-  uint32_t header_version = 0;
-  // for each font in a ttc, metadata to use when rebuilding
-  std::vector<TtcFont> ttc_fonts;
-  std::map<const Table*, const Table*> loca_by_glyf;
+  // Before we sort for output the last table end is the uncompressed size.
+  Table& last_table = hdr->tables.back();
+  hdr->uncompressed_size = last_table.src_offset + last_table.src_length;
+  if (PREDICT_FALSE(hdr->uncompressed_size < last_table.src_offset)) {
+    return FONT_COMPRESSION_FAILURE();
+  }
 
-  if (flavor == kTtcFontFlavor) {
-    if (PREDICT_FALSE(!file.ReadU32(&header_version))) {
+  hdr->header_version = 0;
+
+  if (hdr->flavor == kTtcFontFlavor) {
+    if (PREDICT_FALSE(!file.ReadU32(&hdr->header_version))) {
+      return FONT_COMPRESSION_FAILURE();
+    }
+    if (PREDICT_FALSE(hdr->header_version != 0x00010000
+                   && hdr->header_version != 0x00020000)) {
       return FONT_COMPRESSION_FAILURE();
     }
     uint32_t num_fonts;
     if (PREDICT_FALSE(!Read255UShort(&file, &num_fonts) || !num_fonts)) {
       return FONT_COMPRESSION_FAILURE();
     }
-    ttc_fonts.resize(num_fonts);
+    hdr->ttc_fonts.resize(num_fonts);
 
     for (uint32_t i = 0; i < num_fonts; i++) {
-      TtcFont& ttc_font = ttc_fonts[i];
+      TtcFont& ttc_font = hdr->ttc_fonts[i];
       uint32_t num_tables;
       if (PREDICT_FALSE(!Read255UShort(&file, &num_tables) || !num_tables)) {
         return FONT_COMPRESSION_FAILURE();
       }
       if (PREDICT_FALSE(!file.ReadU32(&ttc_font.flavor))) {
         return FONT_COMPRESSION_FAILURE();
       }
 
       ttc_font.table_indices.resize(num_tables);
 
       const Table* glyf_table = NULL;
       const Table* loca_table = NULL;
-      uint16_t glyf_idx;
-      uint16_t loca_idx;
 
       for (uint32_t j = 0; j < num_tables; j++) {
         unsigned int table_idx;
         if (PREDICT_FALSE(!Read255UShort(&file, &table_idx)) ||
-            table_idx >= tables.size()) {
+            table_idx >= hdr->tables.size()) {
           return FONT_COMPRESSION_FAILURE();
         }
         ttc_font.table_indices[j] = table_idx;
 
-        const Table& table = tables[table_idx];
+        const Table& table = hdr->tables[table_idx];
         if (table.tag == kLocaTableTag) {
           loca_table = &table;
-          loca_idx = table_idx;
         }
         if (table.tag == kGlyfTableTag) {
           glyf_table = &table;
-          glyf_idx = table_idx;
         }
 
       }
 
       if (PREDICT_FALSE((glyf_table == NULL) != (loca_table == NULL))) {
 #ifdef FONT_COMPRESSION_BIN
         fprintf(stderr, "Cannot have just one of glyf/loca\n");
 #endif
         return FONT_COMPRESSION_FAILURE();
       }
-
-      if (glyf_table != NULL && loca_table != NULL) {
-        loca_by_glyf[glyf_table] = loca_table;
-      }
     }
   }
 
-  const uint64_t first_table_offset =
-    ComputeOffsetToFirstTable(header_version, num_tables, ttc_fonts);
+  const uint64_t first_table_offset = ComputeOffsetToFirstTable(*hdr);
 
-  if (PREDICT_FALSE(first_table_offset > result_length)) {
+  hdr->compressed_offset = file.offset();
+  if (PREDICT_FALSE(hdr->compressed_offset >
+                    std::numeric_limits<uint32_t>::max())) {
     return FONT_COMPRESSION_FAILURE();
   }
-
-  uint64_t compressed_offset = file.offset();
-  if (PREDICT_FALSE(compressed_offset > std::numeric_limits<uint32_t>::max())) {
-    return FONT_COMPRESSION_FAILURE();
-  }
-  uint64_t src_offset = Round4(compressed_offset + compressed_length);
+  uint64_t src_offset = Round4(hdr->compressed_offset + hdr->compressed_length);
   uint64_t dst_offset = first_table_offset;
 
 
-  for (uint16_t i = 0; i < num_tables; ++i) {
-    Table* table = &tables[i];
-    table->dst_offset = dst_offset;
-    dst_offset += table->dst_length;
-    if (PREDICT_FALSE(dst_offset > std::numeric_limits<uint32_t>::max())) {
-      return FONT_COMPRESSION_FAILURE();
-    }
-    dst_offset = Round4(dst_offset);
-  }
-  if (PREDICT_FALSE(src_offset > length || dst_offset != result_length)) {
+  if (PREDICT_FALSE(src_offset > length)) {
 #ifdef FONT_COMPRESSION_BIN
     fprintf(stderr, "offset fail; src_offset %" PRIu64 " length %lu "
-      "dst_offset %" PRIu64 " result_length %lu\n",
-      src_offset, length, dst_offset, result_length);
+      "dst_offset %" PRIu64 "\n",
+      src_offset, length, dst_offset);
 #endif
     return FONT_COMPRESSION_FAILURE();
   }
-
-  // Re-order tables in output (OTSpec) order
-  std::vector<Table> sorted_tables(tables);
-  if (header_version) {
-    // collection; we have to sort the table offset vector in each font
-    for (auto& ttc_font : ttc_fonts) {
-      std::map<uint32_t, uint16_t> sorted_index_by_tag;
-      for (auto table_index : ttc_font.table_indices) {
-        sorted_index_by_tag[tables[table_index].tag] = table_index;
-      }
-      uint16_t index = 0;
-      for (auto& i : sorted_index_by_tag) {
-        ttc_font.table_indices[index++] = i.second;
-      }
-    }
-  } else {
-    // non-collection; we can just sort the tables
-    std::sort(sorted_tables.begin(), sorted_tables.end());
-  }
-
   if (meta_offset) {
     if (PREDICT_FALSE(src_offset != meta_offset)) {
       return FONT_COMPRESSION_FAILURE();
     }
     src_offset = Round4(meta_offset + meta_length);
     if (PREDICT_FALSE(src_offset > std::numeric_limits<uint32_t>::max())) {
       return FONT_COMPRESSION_FAILURE();
     }
@@ -1231,139 +1173,152 @@ bool ConvertWOFF2ToTTF(uint8_t* result, 
       return FONT_COMPRESSION_FAILURE();
     }
   }
 
   if (PREDICT_FALSE(src_offset != Round4(length))) {
     return FONT_COMPRESSION_FAILURE();
   }
 
+  return true;
+}
+
+// Write everything before the actual table data
+bool WriteHeaders(const uint8_t* data, size_t length, RebuildMetadata* metadata,
+                  WOFF2Header* hdr, WOFF2Out* out) {
+  std::vector<uint8_t> output(ComputeOffsetToFirstTable(*hdr), 0);
+
+  // Re-order tables in output (OTSpec) order
+  std::vector<Table> sorted_tables(hdr->tables);
+  if (hdr->header_version) {
+    // collection; we have to sort the table offset vector in each font
+    for (auto& ttc_font : hdr->ttc_fonts) {
+      std::map<uint32_t, uint16_t> sorted_index_by_tag;
+      for (auto table_index : ttc_font.table_indices) {
+        sorted_index_by_tag[hdr->tables[table_index].tag] = table_index;
+      }
+      uint16_t index = 0;
+      for (auto& i : sorted_index_by_tag) {
+        ttc_font.table_indices[index++] = i.second;
+      }
+    }
+  } else {
+    // non-collection; we can just sort the tables
+    std::sort(sorted_tables.begin(), sorted_tables.end());
+  }
+
   // Start building the font
+  uint8_t* result = &output[0];
   size_t offset = 0;
-  size_t offset_table = 0;
-  if (header_version) {
+  if (hdr->header_version) {
     // TTC header
-    offset = StoreU32(result, offset, flavor);  // TAG TTCTag
-    offset = StoreU32(result, offset, header_version);  // FIXED Version
-    offset = StoreU32(result, offset, ttc_fonts.size());  // ULONG numFonts
+    offset = StoreU32(result, offset, hdr->flavor);  // TAG TTCTag
+    offset = StoreU32(result, offset, hdr->header_version);  // FIXED Version
+    offset = StoreU32(result, offset, hdr->ttc_fonts.size());  // ULONG numFonts
     // Space for ULONG OffsetTable[numFonts] (zeroed initially)
-    offset_table = offset;  // keep start of offset table for later
-    for (size_t i = 0; i < ttc_fonts.size(); i++) {
+    size_t offset_table = offset;  // keep start of offset table for later
+    for (size_t i = 0; i < hdr->ttc_fonts.size(); i++) {
       offset = StoreU32(result, offset, 0);  // will fill real values in later
     }
     // space for DSIG fields for header v2
-    if (header_version == 0x00020000) {
+    if (hdr->header_version == 0x00020000) {
       offset = StoreU32(result, offset, 0);  // ULONG ulDsigTag
       offset = StoreU32(result, offset, 0);  // ULONG ulDsigLength
       offset = StoreU32(result, offset, 0);  // ULONG ulDsigOffset
     }
 
     // write Offset Tables and store the location of each in TTC Header
-    for (auto& ttc_font : ttc_fonts) {
+    metadata->font_infos.resize(hdr->ttc_fonts.size());
+    for (size_t i = 0; i < hdr->ttc_fonts.size(); i++) {
+      TtcFont& ttc_font = hdr->ttc_fonts[i];
+
       // write Offset Table location into TTC Header
       offset_table = StoreU32(result, offset_table, offset);
 
       // write the actual offset table so our header doesn't lie
       ttc_font.dst_offset = offset;
       offset = StoreOffsetTable(result, offset, ttc_font.flavor,
                                 ttc_font.table_indices.size());
 
-      // write table entries
       for (const auto table_index : ttc_font.table_indices) {
-        offset = StoreTableEntry(result, tables[table_index], offset);
+        uint32_t tag = hdr->tables[table_index].tag;
+        metadata->font_infos[i].table_entry_by_tag[tag] = offset;
+        offset = StoreTableEntry(result, offset, tag);
       }
+
+      ttc_font.header_checksum = ComputeULongSum(&output[ttc_font.dst_offset],
+                                                 offset - ttc_font.dst_offset);
     }
   } else {
-    offset = StoreOffsetTable(result, offset, flavor, num_tables);
-    for (uint16_t i = 0; i < num_tables; ++i) {
-      offset = StoreTableEntry(result, sorted_tables[i], offset);
+    metadata->font_infos.resize(1);
+    offset = StoreOffsetTable(result, offset, hdr->flavor, hdr->num_tables);
+    for (uint16_t i = 0; i < hdr->num_tables; ++i) {
+      metadata->font_infos[0].table_entry_by_tag[sorted_tables[i].tag] = offset;
+      offset = StoreTableEntry(result, offset, sorted_tables[i].tag);
     }
   }
 
-  std::vector<uint8_t> uncompressed_buf;
-  const uint8_t* transform_buf = NULL;
-  uint64_t total_size = 0;
-  for (uint16_t i = 0; i < num_tables; ++i) {
-    total_size += tables[i].transform_length;
-    if (PREDICT_FALSE(total_size > std::numeric_limits<uint32_t>::max())) {
-      return FONT_COMPRESSION_FAILURE();
-    }
+  if (PREDICT_FALSE(!out->Write(&output[0], output.size()))) {
+    return FONT_COMPRESSION_FAILURE();
   }
-  uncompressed_buf.resize(total_size);
-  const uint8_t* src_buf = data + compressed_offset;
-  if (PREDICT_FALSE(!Woff2Uncompress(&uncompressed_buf[0], total_size,
-                       src_buf, compressed_length))) {
+  metadata->header_checksum = ComputeULongSum(&output[0], output.size());
+  return true;
+}
+
+}  // namespace
+
+size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) {
+  Buffer file(data, length);
+  uint32_t total_length;
+
+  if (!file.Skip(16) ||
+      !file.ReadU32(&total_length)) {
+    return 0;
+  }
+  return total_length;
+}
+
+bool ConvertWOFF2ToTTF(uint8_t *result, size_t result_length,
+                       const uint8_t *data, size_t length) {
+  WOFF2MemoryOut out(result, result_length);
+  return ConvertWOFF2ToTTF(data, length, &out);
+}
+
+bool ConvertWOFF2ToTTF(const uint8_t* data, size_t length,
+                       WOFF2Out* out) {
+  RebuildMetadata metadata;
+  WOFF2Header hdr;
+  if (!ReadWOFF2Header(data, length, &hdr)) {
     return FONT_COMPRESSION_FAILURE();
   }
 
-  // round 1, copy across all the unmodified tables
-  transform_buf = &uncompressed_buf[0];
-  const uint8_t* const transform_buf_end = &uncompressed_buf[0]
-                                           + uncompressed_buf.size();
+  if (!WriteHeaders(data, length, &metadata, &hdr, out)) {
+    return FONT_COMPRESSION_FAILURE();
+  }
 
-  // We wipe out the values as they get written into the final result to dedup
-  std::map<uint32_t, const uint8_t*> src_by_dest;
-  for (uint16_t i = 0; i < num_tables; ++i) {
-    const Table* table = &tables[i];
-    size_t transform_length = table->transform_length;
-
-    src_by_dest[table->dst_offset] = transform_buf;
-
-    if (PREDICT_FALSE(transform_buf + transform_length > transform_buf_end)) {
-      return FONT_COMPRESSION_FAILURE();
-    }
-    transform_buf += transform_length;
+  const float compression_ratio = (float) hdr.uncompressed_size / length;
+  if (compression_ratio > kMaxPlausibleCompressionRatio) {
+#ifdef FONT_COMPRESSION_BIN
+    fprintf(stderr, "Implausible compression ratio %.01f\n", compression_ratio);
+#endif
+    return FONT_COMPRESSION_FAILURE();
   }
 
-  for (uint16_t i = 0; i < num_tables; ++i) {
-    const Table* table = &tables[i];
-    const size_t transform_length = table->transform_length;
-
-    if ((table->flags & kWoff2FlagsTransform) != kWoff2FlagsTransform) {
-      if (PREDICT_FALSE(transform_length != table->dst_length)) {
-        return FONT_COMPRESSION_FAILURE();
-      }
-      if (PREDICT_FALSE(static_cast<uint64_t>(table->dst_offset +
-          transform_length) > result_length)) {
-        return FONT_COMPRESSION_FAILURE();
-      }
-      transform_buf = src_by_dest[table->dst_offset];
-      src_by_dest.erase(table->dst_offset);
-      std::memcpy(result + table->dst_offset, transform_buf, transform_length);
-    }
+  const uint8_t* src_buf = data + hdr.compressed_offset;
+  std::vector<uint8_t> uncompressed_buf(hdr.uncompressed_size);
+  if (PREDICT_FALSE(!Woff2Uncompress(&uncompressed_buf[0],
+                                     hdr.uncompressed_size, src_buf,
+                                     hdr.compressed_length))) {
+    return FONT_COMPRESSION_FAILURE();
   }
 
-  // round 2, reconstruct transformed tables
-  if (PREDICT_FALSE(header_version)) {
-    // Rebuild collection font by font.
-    std::vector<Table> font_tables;
-    for (const auto& ttc_font : ttc_fonts) {
-      font_tables.resize(ttc_font.table_indices.size());
-      for (auto i = 0; i < ttc_font.table_indices.size(); i++) {
-        font_tables[i] = tables[ttc_font.table_indices[i]];
-      }
-      if (PREDICT_FALSE(!ReconstructTransformedFont(font_tables, &src_by_dest,
-                                                    result, result_length))) {
-        return FONT_COMPRESSION_FAILURE();
-      }
-    }
-  } else {
-    if (PREDICT_FALSE(!ReconstructTransformedFont(tables, &src_by_dest, result,
-                                                  result_length))) {
-      return FONT_COMPRESSION_FAILURE();
-    }
-  }
-
-  if (header_version) {
-    if (PREDICT_FALSE(
-        !FixCollectionChecksums(header_version, tables, ttc_fonts, result))) {
-      return FONT_COMPRESSION_FAILURE();
-    }
-  } else {
-    if (PREDICT_FALSE(!FixChecksums(sorted_tables, result))) {
+  for (size_t i = 0; i < metadata.font_infos.size(); i++) {
+    if (PREDICT_FALSE(!ReconstructFont(&uncompressed_buf[0],
+                                       hdr.uncompressed_size,
+                                       &metadata, &hdr, i, out))) {
       return FONT_COMPRESSION_FAILURE();
     }
   }
 
   return true;
 }
 
 } // namespace woff2
--- a/modules/woff2/src/woff2_dec.h
+++ b/modules/woff2/src/woff2_dec.h
@@ -14,23 +14,29 @@
 //
 // Library for converting WOFF2 format font files to their TTF versions.
 
 #ifndef WOFF2_WOFF2_DEC_H_
 #define WOFF2_WOFF2_DEC_H_
 
 #include <stddef.h>
 #include <inttypes.h>
+#include "./woff2_out.h"
 
 namespace woff2 {
 
 // Compute the size of the final uncompressed font, or 0 on error.
 size_t ComputeWOFF2FinalSize(const uint8_t *data, size_t length);
 
 // Decompresses the font into the target buffer. The result_length should
 // be the same as determined by ComputeFinalSize(). Returns true on successful
 // decompression.
 bool ConvertWOFF2ToTTF(uint8_t *result, size_t result_length,
                        const uint8_t *data, size_t length);
 
+// Decompresses the font into out. Returns true on success.
+// Works even if WOFF2Header totalSfntSize is wrong.
+bool ConvertWOFF2ToTTF(const uint8_t *data, size_t length,
+                       WOFF2Out* out);
+
 } // namespace woff2
 
 #endif  // WOFF2_WOFF2_DEC_H_
--- a/modules/woff2/src/woff2_decompress.cc
+++ b/modules/woff2/src/woff2_decompress.cc
@@ -12,43 +12,37 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 //
 // A very simple commandline tool for decompressing woff2 format files to true
 // type font files.
 
 #include <string>
 
+#include "./file.h"
+#include "./woff2_dec.h"
 
-#include "file.h"
-#include "./woff2_dec.h"
 
 int main(int argc, char **argv) {
   using std::string;
 
   if (argc != 2) {
     fprintf(stderr, "One argument, the input filename, must be provided.\n");
     return 1;
   }
 
   string filename(argv[1]);
   string outfilename = filename.substr(0, filename.find_last_of(".")) + ".ttf";
-  fprintf(stdout, "Processing %s => %s\n",
-    filename.c_str(), outfilename.c_str());
+
   string input = woff2::GetFileContent(filename);
-
-  size_t decompressed_size = woff2::ComputeWOFF2FinalSize(
-      reinterpret_cast<const uint8_t*>(input.data()), input.size());
-  string output(decompressed_size, 0);
-  const bool ok = woff2::ConvertWOFF2ToTTF(
-      reinterpret_cast<uint8_t*>(&output[0]), decompressed_size,
-      reinterpret_cast<const uint8_t*>(input.data()), input.size());
+  const uint8_t* raw_input = reinterpret_cast<const uint8_t*>(input.data());
+  string output(std::min(woff2::ComputeWOFF2FinalSize(raw_input, input.size()),
+                         woff2::kDefaultMaxSize), 0);
+  woff2::WOFF2StringOut out(&output);
 
-  if (!ok) {
-    fprintf(stderr, "Decompression failed\n");
-    return 1;
-  }
+  const bool ok = woff2::ConvertWOFF2ToTTF(raw_input, input.size(), &out);
 
-  woff2::SetFileContents(outfilename, output);
-
-  return 0;
+  if (ok) {
+    woff2::SetFileContents(outfilename, output.begin(),
+        output.begin() + out.Size());
+  }
+  return ok ? 0 : 1;
 }
-
--- a/modules/woff2/src/woff2_enc.cc
+++ b/modules/woff2/src/woff2_enc.cc
@@ -18,18 +18,18 @@
 
 #include <stdlib.h>
 #include <complex>
 #include <cstring>
 #include <limits>
 #include <string>
 #include <vector>
 
+#include "./compressor.h"
 #include "./buffer.h"
-#include "./encode.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"
@@ -42,16 +42,17 @@ 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) {
   size_t compressed_len = *result_len;
   brotli::BrotliParams params;
   params.mode = mode;
   params.quality = quality;
   if (brotli::BrotliCompressBuffer(params, len, data, &compressed_len, result)
@@ -115,17 +116,17 @@ size_t ComputeWoff2Length(const FontColl
                           size_t extended_metadata_length) {
   size_t size = kWoff2HeaderSize;
 
   for (const auto& table : tables) {
     size += TableEntrySize(table);
   }
 
   // for collections only, collection tables
-  if (font_collection.fonts.size() > 1) {
+  if (font_collection.flavor == kTtcFontFlavor) {
     size += 4;  // UInt32 Version of TTC Header
     size += Size255UShort(font_collection.fonts.size());  // 255UInt16 numFonts
 
     size += 4 * font_collection.fonts.size();  // UInt32 flavor for each
 
     for (const auto& font : font_collection.fonts) {
       size += Size255UShort(font.tables.size());  // 255UInt16 numTables
       for (const auto& entry : font.tables) {
@@ -142,38 +143,30 @@ size_t ComputeWoff2Length(const FontColl
   // compressed data
   size += compressed_data_length;
   size = Round4(size);
 
   size += extended_metadata_length;
   return size;
 }
 
-size_t ComputeTTFLength(const std::vector<Table>& tables) {
-  size_t size = 12 + 16 * tables.size();  // sfnt header
-  for (const auto& table : tables) {
-    size += Round4(table.src_length);
-  }
-  return size;
-}
-
 size_t ComputeUncompressedLength(const Font& font) {
   // sfnt header + offset table
   size_t size = 12 + 16 * font.num_tables;
   for (const auto& entry : font.tables) {
     const Font::Table& table = entry.second;
     if (table.tag & 0x80808080) continue;  // xform tables don't stay
     if (table.IsReused()) continue;  // don't have to pay twice
     size += Round4(table.length);
   }
   return size;
 }
 
 size_t ComputeUncompressedLength(const FontCollection& font_collection) {
-  if (font_collection.fonts.size() == 1) {
+  if (font_collection.flavor != kTtcFontFlavor) {
     return ComputeUncompressedLength(font_collection.fonts[0]);
   }
   size_t size = CollectionHeaderSize(font_collection.header_version,
     font_collection.fonts.size());
   for (const auto& font : font_collection.fonts) {
     size += ComputeUncompressedLength(font);
   }
   return size;
@@ -274,30 +267,32 @@ bool ConvertTTFToWOFF2(const uint8_t *da
   size_t total_transform_length = 0;
   for (const auto& font : font_collection.fonts) {
     total_transform_length += ComputeTotalTransformLength(font);
   }
   size_t compression_buffer_size = CompressedBufferSize(total_transform_length);
   std::vector<uint8_t> compression_buf(compression_buffer_size);
   uint32_t total_compressed_length = compression_buffer_size;
 
-  // Collect all transformed data into one place.
+  // Collect all transformed data into one place in output order.
   std::vector<uint8_t> transform_buf(total_transform_length);
   size_t transform_offset = 0;
   for (const auto& font : font_collection.fonts) {
-    for (const auto& i : font.tables) {
-      const Font::Table* table = font.FindTable(i.second.tag ^ 0x80808080);
-      if (i.second.IsReused()) continue;
-      if (i.second.tag & 0x80808080) continue;
+    for (const auto tag : font.OutputOrderedTags()) {
+      const Font::Table& original = font.tables.at(tag);
+      if (original.IsReused()) continue;
+      if (tag & 0x80808080) continue;
+      const Font::Table* table_to_store = font.FindTable(tag ^ 0x80808080);
+      if (table_to_store == NULL) table_to_store = &original;
 
-      if (table == NULL) table = &i.second;
-      StoreBytes(table->data, table->length,
+      StoreBytes(table_to_store->data, table_to_store->length,
                  &transform_offset, &transform_buf[0]);
     }
   }
+
   // Compress all transformed data in one stream.
   if (!Woff2Compress(transform_buf.data(), total_transform_length,
                      &compression_buf[0],
                      &total_compressed_length,
                      params.brotli_quality)) {
 #ifdef FONT_COMPRESSION_BIN
     fprintf(stderr, "Compression of combined table failed.\n");
 #endif
@@ -372,36 +367,35 @@ bool ConvertTTFToWOFF2(const uint8_t *da
 #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;
 
-  const Font& first_font = font_collection.fonts[0];
   size_t offset = 0;
 
   // start of woff2 header (http://www.w3.org/TR/WOFF2/#woff20Header)
   StoreU32(kWoff2Signature, &offset, result);
-  if (font_collection.fonts.size() == 1) {
-    StoreU32(first_font.flavor, &offset, result);
+  if (font_collection.flavor != kTtcFontFlavor) {
+    StoreU32(font_collection.fonts[0].flavor, &offset, result);
   } else {
     StoreU32(kTtcFontFlavor, &offset, result);
   }
   StoreU32(woff2_length, &offset, result);
   Store16(tables.size(), &offset, result);
   Store16(0, &offset, result);  // reserved
   // totalSfntSize
   StoreU32(ComputeUncompressedLength(font_collection), &offset, result);
   StoreU32(total_compressed_length, &offset, result);  // totalCompressedSize
 
-  // TODO(user): is always taking this from the first tables head OK?
-  // font revision
-  StoreBytes(first_font.FindTable(kHeadTableTag)->data + 4, 4, &offset, result);
+  // Let's just all be v1.0
+  Store16(1, &offset, result);  // majorVersion
+  Store16(0, &offset, result);  // minorVersion
   if (compressed_metadata_buf_length > 0) {
     StoreU32(woff2_length - compressed_metadata_buf_length,
              &offset, result);  // metaOffset
     StoreU32(compressed_metadata_buf_length, &offset, result);  // metaLength
     StoreU32(params.extended_metadata.length(),
              &offset, result);  // metaOrigLength
   } else {
     StoreU32(0, &offset, result);  // metaOffset
@@ -413,17 +407,17 @@ bool ConvertTTFToWOFF2(const uint8_t *da
   // end of woff2 header
 
   // table directory (http://www.w3.org/TR/WOFF2/#table_dir_format)
   for (const auto& table : tables) {
     StoreTableEntry(table, &offset, result);
   }
 
   // for collections only, collection table directory
-  if (font_collection.fonts.size() > 1) {
+  if (font_collection.flavor == kTtcFontFlavor) {
     StoreU32(font_collection.header_version, &offset, result);
     Store255UShort(font_collection.fonts.size(), &offset, result);
     for (const Font& font : font_collection.fonts) {
 
       uint16_t num_tables = 0;
       for (const auto& entry : font.tables) {
         const Font::Table& table = entry.second;
         if (table.tag & 0x80808080) continue;  // don't write xform tables
new file mode 100644
--- /dev/null
+++ b/modules/woff2/src/woff2_out.cc
@@ -0,0 +1,73 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Output buffer for WOFF2 decompression.
+
+#include "./woff2_out.h"
+
+namespace woff2 {
+
+WOFF2StringOut::WOFF2StringOut(string* buf)
+  : buf_(buf),
+    max_size_(kDefaultMaxSize),
+    offset_(0) {}
+
+bool WOFF2StringOut::Write(const void *buf, size_t n) {
+  return Write(buf, offset_, n);
+}
+
+bool WOFF2StringOut::Write(const void *buf, size_t offset, size_t n) {
+  if (offset > max_size_ || n > max_size_ - offset) {
+    return false;
+  }
+  if (offset == buf_->size()) {
+    buf_->append(static_cast<const char*>(buf), n);
+  } else {
+    if (offset + n > buf_->size()) {
+      buf_->append(offset + n - buf_->size(), 0);
+    }
+    buf_->replace(offset, n, static_cast<const char*>(buf), n);
+  }
+  offset_ = std::max(offset_, offset + n);
+
+  return true;
+}
+
+void WOFF2StringOut::SetMaxSize(size_t max_size) {
+  max_size_ = max_size;
+  if (offset_ > max_size_) {
+    offset_ = max_size_;
+  }
+}
+
+WOFF2MemoryOut::WOFF2MemoryOut(uint8_t* buf, size_t buf_size)
+  : buf_(buf),
+    buf_size_(buf_size),
+    offset_(0) {}
+
+bool WOFF2MemoryOut::Write(const void *buf, size_t n) {
+  return Write(buf, offset_, n);
+}
+
+bool WOFF2MemoryOut::Write(const void *buf, size_t offset, size_t n) {
+  if (offset > buf_size_ || n > buf_size_ - offset) {
+    return false;
+  }
+  std::memcpy(buf_ + offset, buf, n);
+  offset_ = std::max(offset_, offset + n);
+
+  return true;
+}
+
+} // namespace woff2
new file mode 100644
--- /dev/null
+++ b/modules/woff2/src/woff2_out.h
@@ -0,0 +1,114 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Output buffer for WOFF2 decompression.
+
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Output buffer for WOFF2 decompression.
+
+#ifndef WOFF2_WOFF2_OUT_H_
+#define WOFF2_WOFF2_OUT_H_
+
+#include <algorithm>
+#include <cstring>
+#include <memory>
+#include <string>
+#include "./port.h"
+
+namespace woff2 {
+
+// Suggested max size for output.
+const size_t kDefaultMaxSize = 30 * 1024 * 1024;
+
+using std::string;
+
+
+/**
+ * Output interface for the woff2 decoding.
+ *
+ * Writes to arbitrary offsets are supported to facilitate updating offset
+ * table and checksums after tables are ready. Reading the current size is
+ * supported so a 'loca' table can be built up while writing glyphs.
+ *
+ * By default limits size to kDefaultMaxSize.
+ */
+class WOFF2Out {
+ public:
+  virtual ~WOFF2Out(void) {}
+
+  // Append n bytes of data from buf.
+  // Return true if all written, false otherwise.
+  virtual bool Write(const void *buf, size_t n) = 0;
+
+  // Write n bytes of data from buf at offset.
+  // Return true if all written, false otherwise.
+  virtual bool Write(const void *buf, size_t offset, size_t n) = 0;
+
+  virtual size_t Size() = 0;
+};
+
+/**
+ * Expanding memory block for woff2 out. By default limited to kDefaultMaxSize.
+ */
+class WOFF2StringOut : public WOFF2Out {
+ public:
+  // Create a writer that writes its data to buf.
+  // buf->size() will grow to at most max_size
+  // buf may be sized (e.g. using EstimateWOFF2FinalSize) or empty.
+  explicit WOFF2StringOut(string* buf);
+
+  bool Write(const void *buf, size_t n) override;
+  bool Write(const void *buf, size_t offset, size_t n) override;
+  size_t Size() override { return offset_; }
+  size_t MaxSize() { return max_size_; }
+  void SetMaxSize(size_t max_size);
+ private:
+  string* buf_;
+  size_t max_size_;
+  size_t offset_;
+};
+
+/**
+ * Fixed memory block for woff2 out.
+ */
+class WOFF2MemoryOut : public WOFF2Out {
+ public:
+  // Create a writer that writes its data to buf.
+  WOFF2MemoryOut(uint8_t* buf, size_t buf_size);
+
+  bool Write(const void *buf, size_t n) override;
+  bool Write(const void *buf, size_t offset, size_t n) override;
+  size_t Size() override { return offset_; }
+ private:
+  uint8_t* buf_;
+  size_t buf_size_;
+  size_t offset_;
+};
+
+} // namespace woff2
+
+#endif  // WOFF2_WOFF2_OUT_H_
--- a/modules/woff2/update.sh
+++ b/modules/woff2/update.sh
@@ -8,16 +8,15 @@ MY_TEMP_DIR=`mktemp -d -t woff2_update.X
 git clone https://github.com/google/woff2 ${MY_TEMP_DIR}/woff2
 
 COMMIT=`(cd ${MY_TEMP_DIR}/woff2 && git log | head -n 1)`
 perl -p -i -e "s/\[commit [0-9a-f]{40}\]/[${COMMIT}]/" README.mozilla;
 
 rm -rf src
 mv ${MY_TEMP_DIR}/woff2/src src
 patch -p3 < redefine-unique_ptr.patch
-patch -p3 < missing-assert-header.patch
 rm -rf ${MY_TEMP_DIR}
 hg add src
 
 echo "###"
 echo "### Updated woff2/src to $COMMIT."
 echo "### Remember to verify and commit the changes to source control!"
 echo "###"