tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

math.cc (18398B)


      1 // Copyright (c) 2014-2017 The OTS Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // We use an underscore to avoid confusion with the standard math.h library.
      6 #include "math_.h"
      7 
      8 #include <limits>
      9 #include <vector>
     10 
     11 #include "layout.h"
     12 #include "maxp.h"
     13 
     14 // MATH - The MATH Table
     15 // http://www.microsoft.com/typography/otspec/math.htm
     16 
     17 namespace {
     18 
     19 // The size of MATH header.
     20 // Version
     21 // MathConstants
     22 // MathGlyphInfo
     23 // MathVariants
     24 const unsigned kMathHeaderSize = 4 + 3 * 2;
     25 
     26 // The size of the MathGlyphInfo header.
     27 // MathItalicsCorrectionInfo
     28 // MathTopAccentAttachment
     29 // ExtendedShapeCoverage
     30 // MathKernInfo
     31 const unsigned kMathGlyphInfoHeaderSize = 4 * 2;
     32 
     33 // The size of the MathValueRecord.
     34 // Value
     35 // DeviceTable
     36 const unsigned kMathValueRecordSize = 2 * 2;
     37 
     38 // The size of the GlyphPartRecord.
     39 // glyph
     40 // StartConnectorLength
     41 // EndConnectorLength
     42 // FullAdvance
     43 // PartFlags
     44 const unsigned kGlyphPartRecordSize = 5 * 2;
     45 
     46 }  // namespace
     47 
     48 namespace ots {
     49 
     50 // Shared Table: MathValueRecord
     51 
     52 bool OpenTypeMATH::ParseMathValueRecord(ots::Buffer* subtable,
     53                                        const uint8_t *data,
     54                                        const size_t length) {
     55  // Check the Value field.
     56  if (!subtable->Skip(2)) {
     57    return OTS_FAILURE();
     58  }
     59 
     60  // Check the offset to device table.
     61  uint16_t offset = 0;
     62  if (!subtable->ReadU16(&offset)) {
     63    return OTS_FAILURE();
     64  }
     65  if (offset) {
     66    if (offset >= length) {
     67      return OTS_FAILURE();
     68    }
     69    if (!ots::ParseDeviceTable(GetFont(), data + offset, length - offset)) {
     70      return OTS_FAILURE();
     71    }
     72  }
     73 
     74  return true;
     75 }
     76 
     77 bool OpenTypeMATH::ParseMathConstantsTable(const uint8_t *data,
     78                                           size_t length) {
     79  ots::Buffer subtable(data, length);
     80 
     81  // Part 1: int16 or uint16 constants.
     82  //  ScriptPercentScaleDown
     83  //  ScriptScriptPercentScaleDown
     84  //  DelimitedSubFormulaMinHeight
     85  //  DisplayOperatorMinHeight
     86  if (!subtable.Skip(4 * 2)) {
     87    return OTS_FAILURE();
     88  }
     89 
     90  // Part 2: MathValueRecord constants.
     91  // MathLeading
     92  // AxisHeight
     93  // AccentBaseHeight
     94  // FlattenedAccentBaseHeight
     95  // SubscriptShiftDown
     96  // SubscriptTopMax
     97  // SubscriptBaselineDropMin
     98  // SuperscriptShiftUp
     99  // SuperscriptShiftUpCramped
    100  // SuperscriptBottomMin
    101  //
    102  // SuperscriptBaselineDropMax
    103  // SubSuperscriptGapMin
    104  // SuperscriptBottomMaxWithSubscript
    105  // SpaceAfterScript
    106  // UpperLimitGapMin
    107  // UpperLimitBaselineRiseMin
    108  // LowerLimitGapMin
    109  // LowerLimitBaselineDropMin
    110  // StackTopShiftUp
    111  // StackTopDisplayStyleShiftUp
    112  //
    113  // StackBottomShiftDown
    114  // StackBottomDisplayStyleShiftDown
    115  // StackGapMin
    116  // StackDisplayStyleGapMin
    117  // StretchStackTopShiftUp
    118  // StretchStackBottomShiftDown
    119  // StretchStackGapAboveMin
    120  // StretchStackGapBelowMin
    121  // FractionNumeratorShiftUp
    122  // FractionNumeratorDisplayStyleShiftUp
    123  //
    124  // FractionDenominatorShiftDown
    125  // FractionDenominatorDisplayStyleShiftDown
    126  // FractionNumeratorGapMin
    127  // FractionNumDisplayStyleGapMin
    128  // FractionRuleThickness
    129  // FractionDenominatorGapMin
    130  // FractionDenomDisplayStyleGapMin
    131  // SkewedFractionHorizontalGap
    132  // SkewedFractionVerticalGap
    133  // OverbarVerticalGap
    134  //
    135  // OverbarRuleThickness
    136  // OverbarExtraAscender
    137  // UnderbarVerticalGap
    138  // UnderbarRuleThickness
    139  // UnderbarExtraDescender
    140  // RadicalVerticalGap
    141  // RadicalDisplayStyleVerticalGap
    142  // RadicalRuleThickness
    143  // RadicalExtraAscender
    144  // RadicalKernBeforeDegree
    145  //
    146  // RadicalKernAfterDegree
    147  for (unsigned i = 0; i < static_cast<unsigned>(51); ++i) {
    148    if (!ParseMathValueRecord(&subtable, data, length)) {
    149      return OTS_FAILURE();
    150    }
    151  }
    152 
    153  // Part 3: uint16 constant
    154  // RadicalDegreeBottomRaisePercent
    155  if (!subtable.Skip(2)) {
    156    return OTS_FAILURE();
    157  }
    158 
    159  return true;
    160 }
    161 
    162 bool OpenTypeMATH::ParseMathValueRecordSequenceForGlyphs(ots::Buffer* subtable,
    163                                                         const uint8_t *data,
    164                                                         const size_t length,
    165                                                         const uint16_t num_glyphs) {
    166  // Check the header.
    167  uint16_t offset_coverage = 0;
    168  uint16_t sequence_count = 0;
    169  if (!subtable->ReadU16(&offset_coverage) ||
    170      !subtable->ReadU16(&sequence_count)) {
    171    return OTS_FAILURE();
    172  }
    173 
    174  const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
    175      sequence_count * kMathValueRecordSize;
    176  if (sequence_end > std::numeric_limits<uint16_t>::max()) {
    177    return OTS_FAILURE();
    178  }
    179 
    180  // Check coverage table.
    181  if (offset_coverage < sequence_end || offset_coverage >= length) {
    182    return OTS_FAILURE();
    183  }
    184  if (!ots::ParseCoverageTable(GetFont(), data + offset_coverage,
    185                               length - offset_coverage,
    186                               num_glyphs, sequence_count)) {
    187    return OTS_FAILURE();
    188  }
    189 
    190  // Check sequence.
    191  for (unsigned i = 0; i < sequence_count; ++i) {
    192    if (!ParseMathValueRecord(subtable, data, length)) {
    193      return OTS_FAILURE();
    194    }
    195  }
    196 
    197  return true;
    198 }
    199 
    200 bool OpenTypeMATH::ParseMathItalicsCorrectionInfoTable(const uint8_t *data,
    201                                                       size_t length,
    202                                                       const uint16_t num_glyphs) {
    203  ots::Buffer subtable(data, length);
    204  return ParseMathValueRecordSequenceForGlyphs(&subtable, data, length,
    205                                               num_glyphs);
    206 }
    207 
    208 bool OpenTypeMATH::ParseMathTopAccentAttachmentTable(const uint8_t *data,
    209                                                     size_t length,
    210                                                     const uint16_t num_glyphs) {
    211  ots::Buffer subtable(data, length);
    212  return ParseMathValueRecordSequenceForGlyphs(&subtable, data, length,
    213                                               num_glyphs);
    214 }
    215 
    216 bool OpenTypeMATH::ParseMathKernTable(const uint8_t *data, size_t length) {
    217  ots::Buffer subtable(data, length);
    218 
    219  // Check the Height count.
    220  uint16_t height_count = 0;
    221  if (!subtable.ReadU16(&height_count)) {
    222    return OTS_FAILURE();
    223  }
    224 
    225  // Check the Correction Heights.
    226  for (unsigned i = 0; i < height_count; ++i) {
    227    if (!ParseMathValueRecord(&subtable, data, length)) {
    228      return OTS_FAILURE();
    229    }
    230  }
    231 
    232  // Check the Kern Values.
    233  for (unsigned i = 0; i <= height_count; ++i) {
    234    if (!ParseMathValueRecord(&subtable, data, length)) {
    235      return OTS_FAILURE();
    236    }
    237  }
    238 
    239  return true;
    240 }
    241 
    242 bool OpenTypeMATH::ParseMathKernInfoTable(const uint8_t *data,
    243                                          size_t length,
    244                                          const uint16_t num_glyphs) {
    245  ots::Buffer subtable(data, length);
    246 
    247  // Check the header.
    248  uint16_t offset_coverage = 0;
    249  uint16_t sequence_count = 0;
    250  if (!subtable.ReadU16(&offset_coverage) ||
    251      !subtable.ReadU16(&sequence_count)) {
    252    return OTS_FAILURE();
    253  }
    254 
    255  const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
    256    sequence_count * 4 * 2;
    257  if (sequence_end > std::numeric_limits<uint16_t>::max()) {
    258    return OTS_FAILURE();
    259  }
    260 
    261  // Check coverage table.
    262  if (offset_coverage < sequence_end || offset_coverage >= length) {
    263    return OTS_FAILURE();
    264  }
    265  if (!ots::ParseCoverageTable(GetFont(), data + offset_coverage, length - offset_coverage,
    266                               num_glyphs, sequence_count)) {
    267    return OTS_FAILURE();
    268  }
    269 
    270  // Check sequence of MathKernInfoRecord
    271  for (unsigned i = 0; i < sequence_count; ++i) {
    272    // Check TopRight, TopLeft, BottomRight and BottomLeft Math Kern.
    273    for (unsigned j = 0; j < 4; ++j) {
    274      uint16_t offset_math_kern = 0;
    275      if (!subtable.ReadU16(&offset_math_kern)) {
    276        return OTS_FAILURE();
    277      }
    278      if (offset_math_kern) {
    279        if (offset_math_kern < sequence_end || offset_math_kern >= length ||
    280            !ParseMathKernTable(data + offset_math_kern,
    281                                length - offset_math_kern)) {
    282          return OTS_FAILURE();
    283        }
    284      }
    285    }
    286  }
    287 
    288  return true;
    289 }
    290 
    291 bool OpenTypeMATH::ParseMathGlyphInfoTable(const uint8_t *data,
    292                                           size_t length,
    293                                           const uint16_t num_glyphs) {
    294  ots::Buffer subtable(data, length);
    295 
    296  // Check Header.
    297  uint16_t offset_math_italics_correction_info = 0;
    298  uint16_t offset_math_top_accent_attachment = 0;
    299  uint16_t offset_extended_shaped_coverage = 0;
    300  uint16_t offset_math_kern_info = 0;
    301  if (!subtable.ReadU16(&offset_math_italics_correction_info) ||
    302      !subtable.ReadU16(&offset_math_top_accent_attachment) ||
    303      !subtable.ReadU16(&offset_extended_shaped_coverage) ||
    304      !subtable.ReadU16(&offset_math_kern_info)) {
    305    return OTS_FAILURE();
    306  }
    307 
    308  // Check subtables.
    309  // The specification does not say whether the offsets for
    310  // MathItalicsCorrectionInfo, MathTopAccentAttachment and MathKernInfo may
    311  // be NULL, but that's the case in some fonts (e.g STIX) so we accept that.
    312  if (offset_math_italics_correction_info) {
    313    if (offset_math_italics_correction_info >= length ||
    314        offset_math_italics_correction_info < kMathGlyphInfoHeaderSize ||
    315        !ParseMathItalicsCorrectionInfoTable(
    316            data + offset_math_italics_correction_info,
    317            length - offset_math_italics_correction_info,
    318            num_glyphs)) {
    319      return OTS_FAILURE();
    320    }
    321  }
    322  if (offset_math_top_accent_attachment) {
    323    if (offset_math_top_accent_attachment >= length ||
    324        offset_math_top_accent_attachment < kMathGlyphInfoHeaderSize ||
    325        !ParseMathTopAccentAttachmentTable(data +
    326                                           offset_math_top_accent_attachment,
    327                                           length -
    328                                           offset_math_top_accent_attachment,
    329                                           num_glyphs)) {
    330      return OTS_FAILURE();
    331    }
    332  }
    333  if (offset_extended_shaped_coverage) {
    334    if (offset_extended_shaped_coverage >= length ||
    335        offset_extended_shaped_coverage < kMathGlyphInfoHeaderSize ||
    336        !ots::ParseCoverageTable(GetFont(), data + offset_extended_shaped_coverage,
    337                                 length - offset_extended_shaped_coverage,
    338                                 num_glyphs)) {
    339      return OTS_FAILURE();
    340    }
    341  }
    342  if (offset_math_kern_info) {
    343    if (offset_math_kern_info >= length ||
    344        offset_math_kern_info < kMathGlyphInfoHeaderSize ||
    345        !ParseMathKernInfoTable(data + offset_math_kern_info,
    346                                length - offset_math_kern_info, num_glyphs)) {
    347      return OTS_FAILURE();
    348    }
    349  }
    350 
    351  return true;
    352 }
    353 
    354 bool OpenTypeMATH::ParseGlyphAssemblyTable(const uint8_t *data,
    355                                           size_t length,
    356                                           const uint16_t num_glyphs) {
    357  ots::Buffer subtable(data, length);
    358 
    359  // Check the header.
    360  uint16_t part_count = 0;
    361  if (!ParseMathValueRecord(&subtable, data, length) ||
    362      !subtable.ReadU16(&part_count)) {
    363    return OTS_FAILURE();
    364  }
    365 
    366  const unsigned sequence_end = kMathValueRecordSize +
    367    static_cast<unsigned>(2) + part_count * kGlyphPartRecordSize;
    368  if (sequence_end > std::numeric_limits<uint16_t>::max()) {
    369    return OTS_FAILURE();
    370  }
    371 
    372  // Check the sequence of GlyphPartRecord.
    373  for (unsigned i = 0; i < part_count; ++i) {
    374    uint16_t glyph = 0;
    375    uint16_t part_flags = 0;
    376    if (!subtable.ReadU16(&glyph) ||
    377        !subtable.Skip(2 * 3) ||
    378        !subtable.ReadU16(&part_flags)) {
    379      return OTS_FAILURE();
    380    }
    381    if (glyph >= num_glyphs) {
    382      return Error("bad glyph ID: %u", glyph);
    383    }
    384    if (part_flags & ~0x00000001) {
    385      return Error("unknown part flag: %u", part_flags);
    386    }
    387  }
    388 
    389  return true;
    390 }
    391 
    392 bool OpenTypeMATH::ParseMathGlyphConstructionTable(const uint8_t *data,
    393                                                   size_t length,
    394                                                   const uint16_t num_glyphs) {
    395  ots::Buffer subtable(data, length);
    396 
    397  // Check the header.
    398  uint16_t offset_glyph_assembly = 0;
    399  uint16_t variant_count = 0;
    400  if (!subtable.ReadU16(&offset_glyph_assembly) ||
    401      !subtable.ReadU16(&variant_count)) {
    402    return OTS_FAILURE();
    403  }
    404 
    405  const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
    406    variant_count * 2 * 2;
    407  if (sequence_end > std::numeric_limits<uint16_t>::max()) {
    408    return OTS_FAILURE();
    409  }
    410 
    411  // Check the GlyphAssembly offset.
    412  if (offset_glyph_assembly) {
    413    if (offset_glyph_assembly >= length ||
    414        offset_glyph_assembly < sequence_end) {
    415      return OTS_FAILURE();
    416    }
    417    if (!ParseGlyphAssemblyTable(data + offset_glyph_assembly,
    418                                 length - offset_glyph_assembly, num_glyphs)) {
    419      return OTS_FAILURE();
    420    }
    421  }
    422 
    423  // Check the sequence of MathGlyphVariantRecord.
    424  for (unsigned i = 0; i < variant_count; ++i) {
    425    uint16_t glyph = 0;
    426    if (!subtable.ReadU16(&glyph) ||
    427        !subtable.Skip(2)) {
    428      return OTS_FAILURE();
    429    }
    430    if (glyph >= num_glyphs) {
    431      return Error("bad glyph ID: %u", glyph);
    432    }
    433  }
    434 
    435  return true;
    436 }
    437 
    438 bool OpenTypeMATH::ParseMathGlyphConstructionSequence(ots::Buffer* subtable,
    439                                                      const uint8_t *data,
    440                                                      size_t length,
    441                                                      const uint16_t num_glyphs,
    442                                                      uint16_t offset_coverage,
    443                                                      uint16_t glyph_count,
    444                                                      const unsigned sequence_end) {
    445  // Zero glyph count, nothing to parse.
    446  if (!glyph_count) {
    447    return true;
    448  }
    449 
    450  // Check coverage table.
    451  if (offset_coverage < sequence_end || offset_coverage >= length) {
    452    return OTS_FAILURE();
    453  }
    454  if (!ots::ParseCoverageTable(GetFont(), data + offset_coverage,
    455                               length - offset_coverage,
    456                               num_glyphs, glyph_count)) {
    457    return OTS_FAILURE();
    458  }
    459 
    460  // Check sequence of MathGlyphConstruction.
    461  for (unsigned i = 0; i < glyph_count; ++i) {
    462      uint16_t offset_glyph_construction = 0;
    463      if (!subtable->ReadU16(&offset_glyph_construction)) {
    464        return OTS_FAILURE();
    465      }
    466      if (offset_glyph_construction < sequence_end ||
    467          offset_glyph_construction >= length ||
    468          !ParseMathGlyphConstructionTable(data + offset_glyph_construction,
    469                                           length - offset_glyph_construction,
    470                                           num_glyphs)) {
    471        return OTS_FAILURE();
    472      }
    473  }
    474 
    475  return true;
    476 }
    477 
    478 bool OpenTypeMATH::ParseMathVariantsTable(const uint8_t *data,
    479                                          size_t length,
    480                                          const uint16_t num_glyphs) {
    481  ots::Buffer subtable(data, length);
    482 
    483  // Check the header.
    484  uint16_t offset_vert_glyph_coverage = 0;
    485  uint16_t offset_horiz_glyph_coverage = 0;
    486  uint16_t vert_glyph_count = 0;
    487  uint16_t horiz_glyph_count = 0;
    488  if (!subtable.Skip(2) ||  // MinConnectorOverlap
    489      !subtable.ReadU16(&offset_vert_glyph_coverage) ||
    490      !subtable.ReadU16(&offset_horiz_glyph_coverage) ||
    491      !subtable.ReadU16(&vert_glyph_count) ||
    492      !subtable.ReadU16(&horiz_glyph_count)) {
    493    return OTS_FAILURE();
    494  }
    495 
    496  const unsigned sequence_end = 5 * 2 + vert_glyph_count * 2 +
    497    horiz_glyph_count * 2;
    498  if (sequence_end > std::numeric_limits<uint16_t>::max()) {
    499    return OTS_FAILURE();
    500  }
    501 
    502  if (!ParseMathGlyphConstructionSequence(&subtable, data, length, num_glyphs,
    503                                          offset_vert_glyph_coverage,
    504                                          vert_glyph_count,
    505                                          sequence_end) ||
    506      !ParseMathGlyphConstructionSequence(&subtable, data, length, num_glyphs,
    507                                          offset_horiz_glyph_coverage,
    508                                          horiz_glyph_count,
    509                                          sequence_end)) {
    510    return OTS_FAILURE();
    511  }
    512 
    513  return true;
    514 }
    515 
    516 bool OpenTypeMATH::Parse(const uint8_t *data, size_t length) {
    517  // Grab the number of glyphs in the font from the maxp table to check
    518  // GlyphIDs in MATH table.
    519  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
    520      GetFont()->GetTypedTable(OTS_TAG_MAXP));
    521  if (!maxp) {
    522    return Error("Required maxp table missing");
    523  }
    524  const uint16_t num_glyphs = maxp->num_glyphs;
    525 
    526  Buffer table(data, length);
    527 
    528  uint32_t version = 0;
    529  if (!table.ReadU32(&version)) {
    530    return OTS_FAILURE();
    531  }
    532  if (version != 0x00010000) {
    533    return Drop("bad MATH version");
    534  }
    535 
    536  uint16_t offset_math_constants = 0;
    537  uint16_t offset_math_glyph_info = 0;
    538  uint16_t offset_math_variants = 0;
    539  if (!table.ReadU16(&offset_math_constants) ||
    540      !table.ReadU16(&offset_math_glyph_info) ||
    541      !table.ReadU16(&offset_math_variants)) {
    542    return OTS_FAILURE();
    543  }
    544 
    545  if (offset_math_constants >= length ||
    546      offset_math_constants < kMathHeaderSize ||
    547      offset_math_glyph_info >= length ||
    548      offset_math_glyph_info < kMathHeaderSize ||
    549      offset_math_variants >= length ||
    550      offset_math_variants < kMathHeaderSize) {
    551    return Drop("bad offset in MATH header");
    552  }
    553 
    554  if (!ParseMathConstantsTable(data + offset_math_constants,
    555                               length - offset_math_constants)) {
    556    return Drop("failed to parse MathConstants table");
    557  }
    558  if (!ParseMathGlyphInfoTable(data + offset_math_glyph_info,
    559                               length - offset_math_glyph_info, num_glyphs)) {
    560    return Drop("failed to parse MathGlyphInfo table");
    561  }
    562  if (!ParseMathVariantsTable(data + offset_math_variants,
    563                              length - offset_math_variants, num_glyphs)) {
    564    return Drop("failed to parse MathVariants table");
    565  }
    566 
    567  this->m_data = data;
    568  this->m_length = length;
    569  return true;
    570 }
    571 
    572 bool OpenTypeMATH::Serialize(OTSStream *out) {
    573  if (!out->Write(this->m_data, this->m_length)) {
    574    return OTS_FAILURE();
    575  }
    576 
    577  return true;
    578 }
    579 
    580 bool OpenTypeMATH::ShouldSerialize() {
    581  return Table::ShouldSerialize() && this->m_data != NULL;
    582 }
    583 
    584 }  // namespace ots