Bug 1057488 - Part 2: Update OTS to 2a1859a6629bdb6f2915b1d3041621dbd396a4f7. r=jfkthame
authorFrédéric Wang <fred.wang@free.fr>
Sat, 23 Aug 2014 01:59:00 -0400
changeset 201303 a2a702cbbf55c796914404aa35660746e03fa145
parent 201302 a7e585d5299f3f3bac6c0ae00be687e864179c2a
child 201304 96312bdb2fb49b5ff951b863944c8b6ba8840bde
push id48155
push userryanvm@gmail.com
push dateMon, 25 Aug 2014 13:57:31 +0000
treeherdermozilla-inbound@822c7f854920 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1057488
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1057488 - Part 2: Update OTS to 2a1859a6629bdb6f2915b1d3041621dbd396a4f7. r=jfkthame
gfx/ots/README.mozilla
gfx/ots/src/cff.cc
gfx/ots/src/woff2.cc
--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,11 +1,11 @@
 This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
 
 Our reference repository is https://github.com/khaledhosny/ots/.
 
-Current revision: d6018b62bf41f6b419aeae6d2795725a55715481
+Current revision: 2a1859a6629bdb6f2915b1d3041621dbd396a4f7
 
 Upstream files included: LICENSE, src/, include/
 
 Additional files: README.mozilla, src/moz.build
 
 Additional patch: ots-visibility.patch (bug 711079).
--- a/gfx/ots/src/cff.cc
+++ b/gfx/ots/src/cff.cc
@@ -3,16 +3,17 @@
 // found in the LICENSE file.
 
 #include "cff.h"
 
 #include <cstring>
 #include <utility>
 #include <vector>
 
+#include "maxp.h"
 #include "cff_type2_charstring.h"
 
 // CFF - PostScript font program (Compact Font Format) table
 // http://www.microsoft.com/typography/otspec/cff.htm
 // http://www.microsoft.com/typography/otspec/cffspec.htm
 
 #define TABLE_NAME "CFF"
 
@@ -456,30 +457,31 @@ bool ParsePrivateDictData(
     }
     operands.clear();
   }
 
   return true;
 }
 
 bool ParseDictData(const uint8_t *data, size_t table_length,
-                   const ots::CFFIndex &index, size_t sid_max,
-                   DICT_DATA_TYPE type, ots::OpenTypeCFF *out_cff) {
+                   const ots::CFFIndex &index, size_t glyphs,
+                   size_t sid_max, DICT_DATA_TYPE type,
+                   ots::OpenTypeCFF *out_cff) {
   for (unsigned i = 1; i < index.offsets.size(); ++i) {
     if (type == DICT_DATA_TOPLEVEL) {
       out_cff->char_strings_array.push_back(new ots::CFFIndex);
     }
     size_t dict_length = index.offsets[i] - index.offsets[i - 1];
     ots::Buffer table(data + index.offsets[i - 1], dict_length);
 
     std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > operands;
 
     FONT_FORMAT font_format = FORMAT_UNKNOWN;
     bool have_ros = false;
-    size_t glyphs = 0;
+    size_t charstring_glyphs = 0;
     size_t charset_offset = 0;
 
     while (table.offset() < dict_length) {
       if (!ParseDictDataReadNext(&table, &operands)) {
         return OTS_FAILURE();
       }
       if (operands.empty()) {
         return OTS_FAILURE();
@@ -633,20 +635,23 @@ bool ParseDictData(const uint8_t *data, 
           cff_table.set_offset(operands.back().first);
           ots::CFFIndex *charstring_index = out_cff->char_strings_array.back();
           if (!ParseIndex(&cff_table, charstring_index)) {
             return OTS_FAILURE();
           }
           if (charstring_index->count < 2) {
             return OTS_FAILURE();
           }
-          if (glyphs) {
+          if (charstring_glyphs) {
             return OTS_FAILURE();  // multiple charstring tables?
           }
-          glyphs = charstring_index->count;
+          charstring_glyphs = charstring_index->count;
+          if (charstring_glyphs != glyphs) {
+            return OTS_FAILURE();  // CFF and maxp have different number of glyphs?
+          }
           break;
         }
 
         case (12U << 8) + 36: {  // FDArray
           if (type != DICT_DATA_TOPLEVEL) {
             return OTS_FAILURE();
           }
           if (operands.size() != 1) {
@@ -659,17 +664,18 @@ bool ParseDictData(const uint8_t *data, 
           // parse sub dictionary INDEX.
           ots::Buffer cff_table(data, table_length);
           cff_table.set_offset(operands.back().first);
           ots::CFFIndex sub_dict_index;
           if (!ParseIndex(&cff_table, &sub_dict_index)) {
             return OTS_FAILURE();
           }
           if (!ParseDictData(data, table_length,
-                             sub_dict_index, sid_max, DICT_DATA_FDARRAY,
+                             sub_dict_index,
+                             glyphs, sid_max, DICT_DATA_FDARRAY,
                              out_cff)) {
             return OTS_FAILURE();
           }
           if (out_cff->font_dict_length != 0) {
             return OTS_FAILURE();  // two or more FDArray found.
           }
           out_cff->font_dict_length = sub_dict_index.count;
           break;
@@ -956,22 +962,24 @@ bool ots_cff_parse(OpenTypeFile *file, c
   CFFIndex string_index;
   if (!ParseIndex(&table, &string_index)) {
     return OTS_FAILURE();
   }
   if (string_index.count >= 65000 - kNStdString) {
     return OTS_FAILURE();
   }
 
+  const size_t num_glyphs = file->maxp->num_glyphs;
   const size_t sid_max = string_index.count + kNStdString;
   // string_index.count == 0 is allowed.
 
   // parse "9. Top DICT Data"
   if (!ParseDictData(data, length, top_dict_index,
-                     sid_max, DICT_DATA_TOPLEVEL, file->cff)) {
+                     num_glyphs, sid_max,
+                     DICT_DATA_TOPLEVEL, file->cff)) {
     return OTS_FAILURE();
   }
 
   // parse "16. Global Subrs INDEX"
   table.set_offset(string_index.offset_to_next);
   CFFIndex global_subrs_index;
   if (!ParseIndex(&table, &global_subrs_index)) {
     return OTS_FAILURE();
@@ -989,17 +997,17 @@ bool ots_cff_parse(OpenTypeFile *file, c
   // Check if all charstrings (font hinting code for each glyph) are valid.
   for (size_t i = 0; i < file->cff->char_strings_array.size(); ++i) {
     if (!ValidateType2CharStringIndex(*(file->cff->char_strings_array.at(i)),
                                       global_subrs_index,
                                       file->cff->fd_select,
                                       file->cff->local_subrs_per_font,
                                       file->cff->local_subrs,
                                       &table)) {
-      return OTS_FAILURE();
+      return OTS_FAILURE_MSG("Failed validating charstring set %d", (int) i);
     }
   }
 
   return true;
 }
 
 bool ots_cff_should_serialise(OpenTypeFile *file) {
   return file->cff != NULL;
--- a/gfx/ots/src/woff2.cc
+++ b/gfx/ots/src/woff2.cc
@@ -50,20 +50,16 @@ const unsigned int kWoff2FlagsContinueSt
 const unsigned int kWoff2FlagsTransform = 1 << 5;
 
 // Compression type values common to both short and long formats
 const uint32_t kCompressionTypeMask = 0xf;
 const uint32_t kCompressionTypeNone = 0;
 const uint32_t kCompressionTypeGzip = 1;
 const uint32_t kCompressionTypeBrotli = 2;
 
-// This is a special value for the short format only, as described in
-// "Design for compressed header format" in draft doc.
-const uint32_t kShortFlagsContinue = 3;
-
 const uint32_t kKnownTags[] = {
   TAG('c', 'm', 'a', 'p'),  // 0
   TAG('h', 'e', 'a', 'd'),  // 1
   TAG('h', 'h', 'e', 'a'),  // 2
   TAG('h', 'm', 't', 'x'),  // 3
   TAG('m', 'a', 'x', 'p'),  // 4
   TAG('n', 'a', 'm', 'e'),  // 5
   TAG('O', 'S', '/', '2'),  // 6
@@ -84,16 +80,50 @@ const uint32_t kKnownTags[] = {
   TAG('P', 'C', 'L', 'T'),  // 21
   TAG('V', 'D', 'M', 'X'),  // 22
   TAG('v', 'h', 'e', 'a'),  // 23
   TAG('v', 'm', 't', 'x'),  // 24
   TAG('B', 'A', 'S', 'E'),  // 25
   TAG('G', 'D', 'E', 'F'),  // 26
   TAG('G', 'P', 'O', 'S'),  // 27
   TAG('G', 'S', 'U', 'B'),  // 28
+  TAG('E', 'B', 'S', 'C'),  // 29
+  TAG('J', 'S', 'T', 'F'),  // 30
+  TAG('M', 'A', 'T', 'H'),  // 31
+  TAG('C', 'B', 'D', 'T'),  // 32
+  TAG('C', 'B', 'L', 'C'),  // 33
+  TAG('C', 'O', 'L', 'R'),  // 34
+  TAG('C', 'P', 'A', 'L'),  // 35
+  TAG('S', 'V', 'G', ' '),  // 36
+  TAG('s', 'b', 'i', 'x'),  // 37
+  TAG('a', 'c', 'n', 't'),  // 38
+  TAG('a', 'v', 'a', 'r'),  // 39
+  TAG('b', 'd', 'a', 't'),  // 40
+  TAG('b', 'l', 'o', 'c'),  // 41
+  TAG('b', 's', 'l', 'n'),  // 42
+  TAG('c', 'v', 'a', 'r'),  // 43
+  TAG('f', 'd', 's', 'c'),  // 44
+  TAG('f', 'e', 'a', 't'),  // 45
+  TAG('f', 'm', 't', 'x'),  // 46
+  TAG('f', 'v', 'a', 'r'),  // 47
+  TAG('g', 'v', 'a', 'r'),  // 48
+  TAG('h', 's', 't', 'y'),  // 49
+  TAG('j', 'u', 's', 't'),  // 50
+  TAG('l', 'c', 'a', 'r'),  // 51
+  TAG('m', 'o', 'r', 't'),  // 52
+  TAG('m', 'o', 'r', 'x'),  // 53
+  TAG('o', 'p', 'b', 'd'),  // 54
+  TAG('p', 'r', 'o', 'p'),  // 55
+  TAG('t', 'r', 'a', 'k'),  // 56
+  TAG('Z', 'a', 'p', 'f'),  // 57
+  TAG('S', 'i', 'l', 'f'),  // 58
+  TAG('G', 'l', 'a', 't'),  // 59
+  TAG('G', 'l', 'o', 'c'),  // 60
+  TAG('F', 'e', 'a', 't'),  // 61
+  TAG('S', 'i', 'l', 'l'),  // 62
 };
 
 struct Point {
   int x;
   int y;
   bool on_curve;
 };
 
@@ -764,79 +794,60 @@ bool Woff2Uncompress(uint8_t* dst_buf, s
     return true;
   }
   // Unknown compression type
   return OTS_FAILURE();
 }
 
 bool ReadShortDirectory(ots::Buffer* file, std::vector<Table>* tables,
     size_t num_tables) {
-  uint32_t last_compression_type = 0;
   for (size_t i = 0; i < num_tables; ++i) {
     Table* table = &tables->at(i);
     uint8_t flag_byte;
     if (!file->ReadU8(&flag_byte)) {
       return OTS_FAILURE();
     }
     uint32_t tag;
-    if ((flag_byte & 0x1f) == 0x1f) {
+    if ((flag_byte & 0x3f) == 0x3f) {
       if (!file->ReadU32(&tag)) {
         return OTS_FAILURE();
       }
     } else {
-      if ((flag_byte & 0x1f) >= arraysize(kKnownTags)) {
-        return OTS_FAILURE();
-      }
-      tag = kKnownTags[flag_byte & 0x1f];
+      tag = kKnownTags[flag_byte & 0x3f];
+    }
+    // Bits 6 and 7 are reserved and must be 0.
+    if ((flag_byte & 0xc0) != 0) {
+      return OTS_FAILURE();
     }
-    uint32_t flags = flag_byte >> 6;
-    if (flags == kShortFlagsContinue) {
-      flags = last_compression_type | kWoff2FlagsContinueStream;
-    } else {
-      if (flags == kCompressionTypeNone ||
-          flags == kCompressionTypeGzip ||
-          flags == kCompressionTypeBrotli) {
-        last_compression_type = flags;
-      } else {
-        return OTS_FAILURE();
-      }
+    uint32_t flags = kCompressionTypeBrotli;
+    if (i > 0) {
+      flags |= kWoff2FlagsContinueStream;
     }
-    if ((flag_byte & 0x20) != 0) {
+    // Always transform the glyf and loca tables
+    if (tag == TAG('g', 'l', 'y', 'f') ||
+        tag == TAG('l', 'o', 'c', 'a')) {
       flags |= kWoff2FlagsTransform;
     }
     uint32_t dst_length;
     if (!ReadBase128(file, &dst_length)) {
       return OTS_FAILURE();
     }
     uint32_t transform_length = dst_length;
     if ((flags & kWoff2FlagsTransform) != 0) {
       if (!ReadBase128(file, &transform_length)) {
         return OTS_FAILURE();
       }
     }
-    uint32_t src_length = transform_length;
-    if ((flag_byte >> 6) == 1 || (flag_byte >> 6) == 2) {
-      if (!ReadBase128(file, &src_length)) {
-        return OTS_FAILURE();
-      }
-    } else if (static_cast<uint32_t>(flag_byte >> 6) == kShortFlagsContinue) {
-      // The compressed data for this table is in a previuos table, so we set
-      // the src_length to zero.
-      src_length = 0;
-    }
     // Disallow huge numbers (> 1GB) for sanity.
-    if (src_length > 1024 * 1024 * 1024 ||
-        transform_length > 1024 * 1024 * 1024 ||
+    if (transform_length > 1024 * 1024 * 1024 ||
         dst_length > 1024 * 1024 * 1024) {
       return OTS_FAILURE();
     }
-
     table->tag = tag;
     table->flags = flags;
-    table->src_length = src_length;
     table->transform_length = transform_length;
     table->dst_length = dst_length;
   }
   return true;
 }
 
 }  // namespace
 
@@ -875,33 +886,42 @@ bool ConvertWOFF2ToTTF(uint8_t* result, 
   }
   uint16_t num_tables;
   if (!file.ReadU16(&num_tables) || !num_tables) {
     return OTS_FAILURE();
   }
   // We don't care about these fields of the header:
   //   uint16_t reserved
   //   uint32_t total_sfnt_size
+  if (!file.Skip(6)) {
+    return OTS_FAILURE();
+  }
+  uint32_t compressed_length;
+  if (!file.ReadU32(&compressed_length)) {
+    return OTS_FAILURE();
+  }
+  // We don't care about these fields of the header:
   //   uint16_t major_version, minor_version
   //   uint32_t meta_offset, meta_length, meta_orig_length
   //   uint32_t priv_offset, priv_length
-  if (!file.Skip(30)) {
+  if (!file.Skip(24)) {
     return OTS_FAILURE();
   }
   std::vector<Table> tables(num_tables);
   if (!ReadShortDirectory(&file, &tables, num_tables)) {
     return OTS_FAILURE();
   }
   uint64_t src_offset = file.offset();
   uint64_t dst_offset = kSfntHeaderSize +
       kSfntEntrySize * static_cast<uint64_t>(num_tables);
   uint64_t uncompressed_sum = 0;
   for (uint16_t i = 0; i < num_tables; ++i) {
     Table* table = &tables.at(i);
     table->src_offset = src_offset;
+    table->src_length = (i == 0 ? compressed_length : 0);
     src_offset += table->src_length;
     if (src_offset > std::numeric_limits<uint32_t>::max()) {
       return OTS_FAILURE();
     }
     src_offset = ots::Round4(src_offset);
     table->dst_offset = dst_offset;
     dst_offset += table->dst_length;
     if (dst_offset > std::numeric_limits<uint32_t>::max()) {
@@ -978,17 +998,17 @@ bool ConvertWOFF2ToTTF(uint8_t* result, 
         }
       }
       // Enforce same 30M limit on uncompressed tables as OTS
       if (total_size > 30 * 1024 * 1024) {
         return OTS_FAILURE();
       }
       uncompressed_buf.resize(total_size);
       if (!Woff2Uncompress(&uncompressed_buf[0], total_size,
-          src_buf, table->src_length, compression_type)) {
+          src_buf, compressed_length, compression_type)) {
         return OTS_FAILURE();
       }
       transform_buf = &uncompressed_buf[0];
       continue_valid = true;
     } else {
       return OTS_FAILURE();
     }