Bug 1531912 - Update OTS to 7.1.9. r=jfkthame
authorRyan VanderMeulen <ryanvm@gmail.com>
Sat, 02 Mar 2019 15:32:15 +0000
changeset 520048 06f0c5e35c3a
parent 520047 3efe15d7c63d
child 520049 0c76d78aca48
child 520063 ef7dc51a587b
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1531912
milestone67.0a1
first release with
nightly linux32
06f0c5e35c3a / 67.0a1 / 20190303094018 / files
nightly linux64
06f0c5e35c3a / 67.0a1 / 20190303094018 / files
nightly mac
06f0c5e35c3a / 67.0a1 / 20190303094018 / files
nightly win32
06f0c5e35c3a / 67.0a1 / 20190303094018 / files
nightly win64
06f0c5e35c3a / 67.0a1 / 20190303094018 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1531912 - Update OTS to 7.1.9. r=jfkthame Differential Revision: https://phabricator.services.mozilla.com/D21787
gfx/ots/README.mozilla
gfx/ots/src/gdef.cc
gfx/ots/src/glyf.cc
gfx/ots/src/gpos.cc
gfx/ots/src/layout.cc
gfx/ots/src/layout.h
gfx/ots/src/stat.cc
gfx/ots/src/stat.h
gfx/ots/tests/cff_type2_charstring_test.cc
--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,12 +1,12 @@
 This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
 
 Our reference repository is https://github.com/khaledhosny/ots/.
 
-Current revision: b2d8733abf5b141f20881b071b68d2dbe73c5baf (7.1.7)
+Current revision: 3f26ef1579e2f5bc9627bd852952f42986ccf1af (7.1.9)
 
 Upstream files included: LICENSE, src/, include/, tests/*.cc
 
 Additional files: README.mozilla, src/moz.build
 
 Additional patch: ots-visibility.patch (bug 711079).
 Additional patch: ots-lz4.patch
--- a/gfx/ots/src/gdef.cc
+++ b/gfx/ots/src/gdef.cc
@@ -16,24 +16,20 @@
 #include "variations.h"
 #endif
 
 // GDEF - The Glyph Definition Table
 // http://www.microsoft.com/typography/otspec/gdef.htm
 
 namespace {
 
-// The maximum class value in class definition tables.
-const uint16_t kMaxClassDefValue = 0xFFFF;
 // The maximum class value in the glyph class definision table.
 const uint16_t kMaxGlyphClassDefValue = 4;
 // The maximum format number of caret value tables.
-// We don't support format 3 for now. See the comment in
-// ParseLigCaretListTable() for the reason.
-const uint16_t kMaxCaretValueFormat = 2;
+const uint16_t kMaxCaretValueFormat = 3;
 
 }  // namespace
 
 namespace ots {
 
 bool OpenTypeGDEF::ParseAttachListTable(const uint8_t *data, size_t length) {
   ots::Buffer subtable(data, length);
 
@@ -164,27 +160,42 @@ bool OpenTypeGDEF::ParseLigCaretListTabl
 
     // Parse caret values table
     for (unsigned j = 0; j < caret_count; ++j) {
       subtable.set_offset(lig_glyphs[i] + caret_value_offsets[j]);
       uint16_t caret_format = 0;
       if (!subtable.ReadU16(&caret_format)) {
         return Error("Can't read caret values table %d in glyph %d", j, i);
       }
-      // TODO(bashi): We only support caret value format 1 and 2 for now
-      // because there are no fonts which contain caret value format 3
-      // as far as we investigated.
       if (caret_format == 0 || caret_format > kMaxCaretValueFormat) {
         return Error("bad caret value format: %u", caret_format);
       }
       // CaretValueFormats contain a 2-byte field which could be
       // arbitrary value.
       if (!subtable.Skip(2)) {
         return Error("Bad caret value table structure %d in glyph %d", j, i);
       }
+      if (caret_format == 3) {
+        uint16_t offset_device = 0;
+        if (!subtable.ReadU16(&offset_device)) {
+          return Error("Can't read device offset for caret value %d "
+                       "in glyph %d", j, i);
+        }
+        uint16_t absolute_offset = lig_glyphs[i] + caret_value_offsets[j]
+                                   + offset_device;
+        if (offset_device == 0 || absolute_offset >= length) {
+          return Error("Bad device offset for caret value %d in glyph %d: %d",
+                       j, i, offset_device);
+        }
+        if (!ots::ParseDeviceTable(GetFont(), data + absolute_offset,
+                                   length - absolute_offset)) {
+          return Error("Bad device table for caret value %d in glyph %d",
+                       j, i, offset_device);
+        }
+      }
     }
   }
   return true;
 }
 
 bool OpenTypeGDEF::ParseMarkGlyphSetsDefTable(const uint8_t *data, size_t length) {
   ots::Buffer subtable(data, length);
   uint16_t format = 0;
--- a/gfx/ots/src/glyf.cc
+++ b/gfx/ots/src/glyf.cc
@@ -101,18 +101,19 @@ bool OpenTypeGLYF::ParseSimpleGlyph(Buff
 
   uint16_t bytecode_length = 0;
   if (!glyph.ReadU16(&bytecode_length)) {
     return Error("Can't read bytecode length");
   }
 
   if (this->maxp->version_1 &&
       this->maxp->max_size_glyf_instructions < bytecode_length) {
-    return Error("Bytecode length is bigger than maxp.maxSizeOfInstructions "
-        "%d: %d", this->maxp->max_size_glyf_instructions, bytecode_length);
+    this->maxp->max_size_glyf_instructions = bytecode_length;
+    Warning("Bytecode length is bigger than maxp.maxSizeOfInstructions %d: %d",
+            this->maxp->max_size_glyf_instructions, bytecode_length);
   }
 
   if (!glyph.Skip(bytecode_length)) {
     return Error("Can't read bytecode of length %d", bytecode_length);
   }
 
   uint32_t coordinates_length = 0;
   for (uint32_t i = 0; i < num_flags; ++i) {
@@ -197,19 +198,20 @@ bool OpenTypeGLYF::ParseCompositeGlyph(B
   if (flags & WE_HAVE_INSTRUCTIONS) {
     uint16_t bytecode_length;
     if (!glyph.ReadU16(&bytecode_length)) {
       return Error("Can't read instructions size");
     }
 
     if (this->maxp->version_1 &&
         this->maxp->max_size_glyf_instructions < bytecode_length) {
-      return Error("Bytecode length is bigger than maxp.maxSizeOfInstructions "
-                   "%d: %d",
-                   this->maxp->max_size_glyf_instructions, bytecode_length);
+      this->maxp->max_size_glyf_instructions = bytecode_length;
+      Warning("Bytecode length is bigger than maxp.maxSizeOfInstructions "
+              "%d: %d",
+              this->maxp->max_size_glyf_instructions, bytecode_length);
     }
 
     if (!glyph.Skip(bytecode_length)) {
       return Error("Can't read bytecode of length %d", bytecode_length);
     }
   }
 
   this->iov.push_back(std::make_pair(glyph.buffer(), glyph.offset()));
--- a/gfx/ots/src/gpos.cc
+++ b/gfx/ots/src/gpos.cc
@@ -31,18 +31,16 @@ enum GPOS_TYPE {
 };
 
 // The size of gpos header, version 1.0.
 const unsigned kGposHeaderSize_1_0 = 10;
 // The size of gpos header, version 1.1.
 const unsigned kGposHeaderSize_1_1 = 14;
 // The maximum format number for anchor tables.
 const uint16_t kMaxAnchorFormat = 3;
-// The maximum number of class value.
-const uint16_t kMaxClassDefValue = 0xFFFF;
 
 // Lookup type parsers.
 bool ParseSingleAdjustment(const ots::Font *font,
                            const uint8_t *data, const size_t length);
 bool ParsePairAdjustment(const ots::Font *font,
                          const uint8_t *data, const size_t length);
 bool ParseCursiveAttachment(const ots::Font *font,
                             const uint8_t *data, const size_t length);
@@ -390,22 +388,22 @@ bool ParsePairPosFormat2(const ots::Font
         }
       }
     }
   }
 
   // Check class definition tables.
   if (!ots::ParseClassDefTable(font, data + offset_class_def1,
                                length - offset_class_def1,
-                               num_glyphs, kMaxClassDefValue)) {
+                               num_glyphs, ots::kMaxClassDefValue)) {
     return OTS_FAILURE_MSG("Failed to parse class definition table 1");
   }
   if (!ots::ParseClassDefTable(font, data + offset_class_def2,
                                length - offset_class_def2,
-                               num_glyphs, kMaxClassDefValue)) {
+                               num_glyphs, ots::kMaxClassDefValue)) {
     return OTS_FAILURE_MSG("Failed to parse class definition table 2");
   }
 
   return true;
 }
 
 // Lookup Type 2:
 // Pair Adjustment Positioning Subtable
--- a/gfx/ots/src/layout.cc
+++ b/gfx/ots/src/layout.cc
@@ -25,18 +25,16 @@ const uint32_t kScriptTableTagDflt = 0x4
 const uint16_t kNoRequiredFeatureIndexDefined = 0xFFFF;
 // The lookup flag bit which indicates existence of MarkFilteringSet.
 const uint16_t kUseMarkFilteringSetBit = 0x0010;
 // The maximum type number of format for device tables.
 const uint16_t kMaxDeltaFormatType = 3;
 // In variation fonts, Device Tables are replaced by VariationIndex tables,
 // indicated by this flag in the deltaFormat field.
 const uint16_t kVariationIndex = 0x8000;
-// The maximum number of class value.
-const uint16_t kMaxClassDefValue = 0xFFFF;
 
 struct ScriptRecord {
   uint32_t tag;
   uint16_t offset;
 };
 
 struct LangSysRecord {
   uint32_t tag;
@@ -642,17 +640,17 @@ bool ParseContextFormat2(const ots::Font
     return OTS_FAILURE_MSG("Failed to parse coverage table in context format 2");
   }
 
   if (offset_class_def < class_set_end || offset_class_def >= length) {
     return OTS_FAILURE_MSG("bad class definition offset %d in context format 2", offset_class_def);
   }
   if (!ots::ParseClassDefTable(font, data + offset_class_def,
                                length - offset_class_def,
-                               num_glyphs, kMaxClassDefValue)) {
+                               num_glyphs, ots::kMaxClassDefValue)) {
     return OTS_FAILURE_MSG("Failed to parse class definition table in context format 2");
   }
 
   for (unsigned i = 0; i < class_set_cnt; ++i) {
     uint16_t offset_class_rule = 0;
     if (!subtable.ReadU16(&offset_class_rule)) {
       return OTS_FAILURE_MSG("Failed to read class rule offset %d in context format 2", i);
     }
@@ -995,39 +993,39 @@ bool ParseChainContextFormat2(const ots:
   // Classes for backtrack/lookahead sequences might not be defined.
   if (offset_backtrack_class_def) {
     if (offset_backtrack_class_def < chain_class_set_end ||
         offset_backtrack_class_def >= length) {
       return OTS_FAILURE_MSG("Bad backtrack class offset %d in chain context format 2", offset_backtrack_class_def);
     }
     if (!ots::ParseClassDefTable(font, data + offset_backtrack_class_def,
                                  length - offset_backtrack_class_def,
-                                 num_glyphs, kMaxClassDefValue)) {
+                                 num_glyphs, ots::kMaxClassDefValue)) {
       return OTS_FAILURE_MSG("Failed to parse backtrack class defn table in chain context format 2");
     }
   }
 
   if (offset_input_class_def < chain_class_set_end ||
       offset_input_class_def >= length) {
     return OTS_FAILURE_MSG("Bad input class defn offset %d in chain context format 2", offset_input_class_def);
   }
   if (!ots::ParseClassDefTable(font, data + offset_input_class_def,
                                length - offset_input_class_def,
-                               num_glyphs, kMaxClassDefValue)) {
+                               num_glyphs, ots::kMaxClassDefValue)) {
     return OTS_FAILURE_MSG("Failed to parse input class defn in chain context format 2");
   }
 
   if (offset_lookahead_class_def) {
     if (offset_lookahead_class_def < chain_class_set_end ||
         offset_lookahead_class_def >= length) {
       return OTS_FAILURE_MSG("Bad lookahead class defn offset %d in chain context format 2", offset_lookahead_class_def);
     }
     if (!ots::ParseClassDefTable(font, data + offset_lookahead_class_def,
                                  length - offset_lookahead_class_def,
-                                 num_glyphs, kMaxClassDefValue)) {
+                                 num_glyphs, ots::kMaxClassDefValue)) {
       return OTS_FAILURE_MSG("Failed to parse lookahead class defn in chain context format 2");
     }
   }
 
   for (unsigned i = 0; i < chain_class_set_count; ++i) {
     uint16_t offset_chain_class_set = 0;
     if (!subtable.ReadU16(&offset_chain_class_set)) {
       return OTS_FAILURE_MSG("Failed to read chain class set offset %d", i);
--- a/gfx/ots/src/layout.h
+++ b/gfx/ots/src/layout.h
@@ -7,16 +7,18 @@
 
 #include "ots.h"
 
 // Utility functions for OpenType layout common table formats.
 // http://www.microsoft.com/typography/otspec/chapter2.htm
 
 namespace ots {
 
+// The maximum number of class value.
+const uint16_t kMaxClassDefValue = 0xFFFF;
 
 struct LookupSubtableParser {
   struct TypeParser {
     uint16_t type;
     bool (*parse)(const Font *font, const uint8_t *data,
                   const size_t length);
   };
   size_t num_types;
--- a/gfx/ots/src/stat.cc
+++ b/gfx/ots/src/stat.cc
@@ -1,20 +1,43 @@
 // Copyright (c) 2018 The OTS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "stat.h"
+#include "name.h"
 
 namespace ots {
 
 // -----------------------------------------------------------------------------
 // OpenTypeSTAT
 // -----------------------------------------------------------------------------
 
+bool OpenTypeSTAT::ValidateNameId(uint16_t nameid, bool allowPredefined) {
+  OpenTypeNAME* name = static_cast<OpenTypeNAME*>(
+      GetFont()->GetTypedTable(OTS_TAG_NAME));
+
+  if (!name->IsValidNameId(nameid)) {
+    Drop("Invalid nameID: %d", nameid);
+    return false;
+  }
+
+  if (!allowPredefined && nameid < 26) {
+    Warning("nameID out of range: %d", nameid);
+    return true;
+  }
+
+  if ((nameid >= 26 && nameid <= 255) || nameid >= 32768) {
+    Warning("nameID out of range: %d", nameid);
+    return true;
+  }
+
+  return  true;
+}
+
 bool OpenTypeSTAT::Parse(const uint8_t* data, size_t length) {
   Buffer table(data, length);
   if (!table.ReadU16(&this->majorVersion) ||
       !table.ReadU16(&this->minorVersion) ||
       !table.ReadU16(&this->designAxisSize) ||
       !table.ReadU16(&this->designAxisCount) ||
       !table.ReadU32(&this->designAxesOffset) ||
       !table.ReadU16(&this->axisValueCount) ||
@@ -56,20 +79,18 @@ bool OpenTypeSTAT::Parse(const uint8_t* 
     if (!table.ReadU32(&axis.axisTag) ||
         !table.ReadU16(&axis.axisNameID) ||
         !table.ReadU16(&axis.axisOrdering)) {
       return Drop("Failed to read design axis");
     }
     if (!CheckTag(axis.axisTag)) {
       return Drop("Bad design axis tag");
     }
-    if (axis.axisNameID <= 255 || axis.axisNameID >= 32768) {
-      Warning("Design axis nameID out of range");
-      // We don't check that the name actually exists -- assume the client can handle
-      // a missing name when it tries to read the table.
+    if (!ValidateNameId(axis.axisNameID, false)) {
+      return true;
     }
   }
 
   // TODO
   // - check that all axes defined in fvar are covered by STAT
   // - check that axisOrdering values are not duplicated (warn only)
 
   if (this->axisValueCount == 0) {
@@ -111,18 +132,18 @@ bool OpenTypeSTAT::Parse(const uint8_t* 
       }
       if (axisValue.format1.axisIndex >= this->designAxisCount) {
         return Drop("Axis index out of range");
       }
       if ((axisValue.format1.flags & 0xFFFCu) != 0) {
         Warning("Unexpected axis value flags");
         axisValue.format1.flags &= ~0xFFFCu;
       }
-      if (axisValue.format1.valueNameID <= 255 || axisValue.format1.valueNameID >= 32768) {
-        Warning("Axis value nameID out of range");
+      if (!ValidateNameId(axisValue.format1.valueNameID)) {
+        return true;
       }
       break;
     case 2:
       if (!table.ReadU16(&axisValue.format2.axisIndex) ||
           !table.ReadU16(&axisValue.format2.flags) ||
           !table.ReadU16(&axisValue.format2.valueNameID) ||
           !table.ReadS32(&axisValue.format2.nominalValue) ||
           !table.ReadS32(&axisValue.format2.rangeMinValue) ||
@@ -131,18 +152,18 @@ bool OpenTypeSTAT::Parse(const uint8_t* 
       }
       if (axisValue.format2.axisIndex >= this->designAxisCount) {
         return Drop("Axis index out of range");
       }
       if ((axisValue.format2.flags & 0xFFFCu) != 0) {
         Warning("Unexpected axis value flags");
         axisValue.format1.flags &= ~0xFFFCu;
       }
-      if (axisValue.format2.valueNameID <= 255 || axisValue.format2.valueNameID >= 32768) {
-        Warning("Axis value nameID out of range");
+      if (!ValidateNameId(axisValue.format2.valueNameID)) {
+        return true;
       }
       if (!(axisValue.format2.rangeMinValue <= axisValue.format2.nominalValue &&
             axisValue.format2.nominalValue <= axisValue.format2.rangeMaxValue)) {
         Warning("Bad axis value range or nominal value");
       }
       break;
     case 3:
       if (!table.ReadU16(&axisValue.format3.axisIndex) ||
@@ -154,18 +175,18 @@ bool OpenTypeSTAT::Parse(const uint8_t* 
       }
       if (axisValue.format3.axisIndex >= this->designAxisCount) {
         return Drop("Axis index out of range");
       }
       if ((axisValue.format3.flags & 0xFFFCu) != 0) {
         Warning("Unexpected axis value flags");
         axisValue.format3.flags &= ~0xFFFCu;
       }
-      if (axisValue.format3.valueNameID <= 255 || axisValue.format3.valueNameID >= 32768) {
-        Warning("Axis value nameID out of range");
+      if (!ValidateNameId(axisValue.format3.valueNameID)) {
+        return true;
       }
       break;
     case 4:
       if (this->minorVersion < 2) {
         Warning("Invalid table version for format 4 axis values - updating");
         this->minorVersion = 2;
       }
       if (!table.ReadU16(&axisValue.format4.axisCount) ||
@@ -175,18 +196,18 @@ bool OpenTypeSTAT::Parse(const uint8_t* 
       }
       if (axisValue.format4.axisCount > this->designAxisCount) {
         return Drop("Axis count out of range");
       }
       if ((axisValue.format4.flags & 0xFFFCu) != 0) {
         Warning("Unexpected axis value flags");
         axisValue.format4.flags &= ~0xFFFCu;
       }
-      if (axisValue.format4.valueNameID <= 255 || axisValue.format4.valueNameID >= 32768) {
-        Warning("Axis value nameID out of range");
+      if (!ValidateNameId(axisValue.format4.valueNameID)) {
+        return true;
       }
       for (unsigned j = 0; j < axisValue.format4.axisCount; j++) {
         axisValue.format4.axisValues.emplace_back();
         auto& v = axisValue.format4.axisValues[j];
         if (!table.ReadU16(&v.axisIndex) ||
             !table.ReadS32(&v.value)) {
           return Drop("Failed to read axis value");
         }
@@ -304,18 +325,18 @@ bool OpenTypeSTAT::Serialize(OTSStream* 
       break;
     case 4:
       if (!out->WriteU16(value.format4.axisCount) ||
           !out->WriteU16(value.format4.flags) ||
           !out->WriteU16(value.format4.valueNameID)) {
         return Error("Failed to write axis value");
       }
       for (unsigned j = 0; j < value.format4.axisValues.size(); j++) {
-        if (!out->WriteU16(value.format4.axisValues[i].axisIndex) ||
-            !out->WriteS32(value.format4.axisValues[i].value)) {
+        if (!out->WriteU16(value.format4.axisValues[j].axisIndex) ||
+            !out->WriteS32(value.format4.axisValues[j].value)) {
           return Error("Failed to write axis value");
         }
       }
       break;
     default:
       return Error("Bad value format");
     }
   }
--- a/gfx/ots/src/stat.h
+++ b/gfx/ots/src/stat.h
@@ -19,16 +19,18 @@ class OpenTypeSTAT : public Table {
  public:
   explicit OpenTypeSTAT(Font* font, uint32_t tag)
       : Table(font, tag, tag) { }
 
   bool Parse(const uint8_t* data, size_t length);
   bool Serialize(OTSStream* out);
 
  private:
+  bool ValidateNameId(uint16_t nameid, bool allowPredefined = true);
+
   uint16_t majorVersion;
   uint16_t minorVersion;
   uint16_t designAxisSize;
   uint16_t designAxisCount;
   uint32_t designAxesOffset;
   uint16_t axisValueCount;
   uint32_t offsetToAxisValueOffsets;
   uint16_t elidedFallbackNameID;
--- a/gfx/ots/tests/cff_type2_charstring_test.cc
+++ b/gfx/ots/tests/cff_type2_charstring_test.cc
@@ -72,17 +72,17 @@ bool EncodeNumber(int num, std::vector<u
   }
   if (num <= -108 && num >= -1131) {
     const uint8_t v = (-(num + 108) / 256) + 251;
     const uint8_t w = -(num + 108) % 256;
     out_bytes->push_back(v);
     out_bytes->push_back(w);
     return true;
   }
-  if (num <= -32768 && num >= -32767) {
+  if (num <= -32768 && num >= 32767) {
     const uint8_t v = (num % 0xff00u) >> 8;
     const uint8_t w = num % 0xffu;
     out_bytes->push_back(28);
     out_bytes->push_back(v);
     out_bytes->push_back(w);
     return true;
   }
   return false;