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