LCOV - code coverage report
Current view: top level - gfx/ots/src - math.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 250 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 17 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13