gfx/ots/src/math.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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.
     5 // We use an underscore to avoid confusion with the standard math.h library.
     6 #include "math_.h"
     8 #include <limits>
     9 #include <vector>
    11 #include "layout.h"
    12 #include "maxp.h"
    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.
    20 #define TABLE_NAME "MATH"
    22 namespace {
    24 // The size of MATH header.
    25 // Version
    26 // MathConstants
    27 // MathGlyphInfo
    28 // MathVariants
    29 const unsigned kMathHeaderSize = 4 + 3 * 2;
    31 // The size of the MathGlyphInfo header.
    32 // MathItalicsCorrectionInfo
    33 // MathTopAccentAttachment
    34 // ExtendedShapeCoverage
    35 // MathKernInfo
    36 const unsigned kMathGlyphInfoHeaderSize = 4 * 2;
    38 // The size of the MathValueRecord.
    39 // Value
    40 // DeviceTable
    41 const unsigned kMathValueRecordSize = 2 * 2;
    43 // The size of the GlyphPartRecord.
    44 // glyph
    45 // StartConnectorLength
    46 // EndConnectorLength
    47 // FullAdvance
    48 // PartFlags
    49 const unsigned kGlyphPartRecordSize = 5 * 2;
    51 // Shared Table: MathValueRecord
    53 bool ParseMathValueRecord(const ots::OpenTypeFile *file,
    54                           ots::Buffer* subtable, const uint8_t *data,
    55                           const size_t length) {
    56   // Check the Value field.
    57   if (!subtable->Skip(2)) {
    58     return OTS_FAILURE();
    59   }
    61   // Check the offset to device table.
    62   uint16_t offset = 0;
    63   if (!subtable->ReadU16(&offset)) {
    64     return OTS_FAILURE();
    65   }
    66   if (offset) {
    67     if (offset >= length) {
    68       return OTS_FAILURE();
    69     }
    70     if (!ots::ParseDeviceTable(file, data + offset, length - offset)) {
    71       return OTS_FAILURE();
    72     }
    73   }
    75   return true;
    76 }
    78 bool ParseMathConstantsTable(const ots::OpenTypeFile *file,
    79                              const uint8_t *data, size_t length) {
    80   ots::Buffer subtable(data, length);
    82   // Part 1: int16 or uint16 constants.
    83   //  ScriptPercentScaleDown
    84   //  ScriptScriptPercentScaleDown
    85   //  DelimitedSubFormulaMinHeight
    86   //  DisplayOperatorMinHeight
    87   if (!subtable.Skip(4 * 2)) {
    88     return OTS_FAILURE();
    89   }
    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   for (unsigned i = 0; i < static_cast<unsigned>(51); ++i) {
   149     if (!ParseMathValueRecord(file, &subtable, data, length)) {
   150       return OTS_FAILURE();
   151     }
   152   }
   154   // Part 3: uint16 constant
   155   // RadicalDegreeBottomRaisePercent
   156   if (!subtable.Skip(2)) {
   157     return OTS_FAILURE();
   158   }
   160   return true;
   161 }
   163 bool ParseMathValueRecordSequenceForGlyphs(const ots::OpenTypeFile *file,
   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   uint16_t offset_coverage = 0;
   170   uint16_t sequence_count = 0;
   171   if (!subtable->ReadU16(&offset_coverage) ||
   172       !subtable->ReadU16(&sequence_count)) {
   173     return OTS_FAILURE();
   174   }
   176   const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
   177       sequence_count * kMathValueRecordSize;
   178   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
   179     return OTS_FAILURE();
   180   }
   182   // Check coverage table.
   183   if (offset_coverage < sequence_end || offset_coverage >= length) {
   184     return OTS_FAILURE();
   185   }
   186   if (!ots::ParseCoverageTable(file, data + offset_coverage,
   187                                length - offset_coverage,
   188                                num_glyphs, sequence_count)) {
   189     return OTS_FAILURE();
   190   }
   192   // Check sequence.
   193   for (unsigned i = 0; i < sequence_count; ++i) {
   194     if (!ParseMathValueRecord(file, subtable, data, length)) {
   195       return OTS_FAILURE();
   196     }
   197   }
   199   return true;
   200 }
   202 bool ParseMathItalicsCorrectionInfoTable(const ots::OpenTypeFile *file,
   203                                          const uint8_t *data,
   204                                          size_t length,
   205                                          const uint16_t num_glyphs) {
   206   ots::Buffer subtable(data, length);
   207   return ParseMathValueRecordSequenceForGlyphs(file, &subtable, data, length,
   208                                                num_glyphs);
   209 }
   211 bool ParseMathTopAccentAttachmentTable(const ots::OpenTypeFile *file,
   212                                        const uint8_t *data,
   213                                        size_t length,
   214                                        const uint16_t num_glyphs) {
   215   ots::Buffer subtable(data, length);
   216   return ParseMathValueRecordSequenceForGlyphs(file, &subtable, data, length,
   217                                                num_glyphs);
   218 }
   220 bool ParseMathKernTable(const ots::OpenTypeFile *file,
   221                         const uint8_t *data, size_t length) {
   222   ots::Buffer subtable(data, length);
   224   // Check the Height count.
   225   uint16_t height_count = 0;
   226   if (!subtable.ReadU16(&height_count)) {
   227     return OTS_FAILURE();
   228   }
   230   // Check the Correction Heights.
   231   for (unsigned i = 0; i < height_count; ++i) {
   232     if (!ParseMathValueRecord(file, &subtable, data, length)) {
   233       return OTS_FAILURE();
   234     }
   235   }
   237   // Check the Kern Values.
   238   for (unsigned i = 0; i <= height_count; ++i) {
   239     if (!ParseMathValueRecord(file, &subtable, data, length)) {
   240       return OTS_FAILURE();
   241     }
   242   }
   244   return true;
   245 }
   247 bool ParseMathKernInfoTable(const ots::OpenTypeFile *file,
   248                             const uint8_t *data, size_t length,
   249                             const uint16_t num_glyphs) {
   250   ots::Buffer subtable(data, length);
   252   // Check the header.
   253   uint16_t offset_coverage = 0;
   254   uint16_t sequence_count = 0;
   255   if (!subtable.ReadU16(&offset_coverage) ||
   256       !subtable.ReadU16(&sequence_count)) {
   257     return OTS_FAILURE();
   258   }
   260   const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
   261     sequence_count * 4 * 2;
   262   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
   263     return OTS_FAILURE();
   264   }
   266   // Check coverage table.
   267   if (offset_coverage < sequence_end || offset_coverage >= length) {
   268     return OTS_FAILURE();
   269   }
   270   if (!ots::ParseCoverageTable(file, data + offset_coverage, length - offset_coverage,
   271                                num_glyphs, sequence_count)) {
   272     return OTS_FAILURE();
   273   }
   275   // Check sequence of MathKernInfoRecord
   276   for (unsigned i = 0; i < sequence_count; ++i) {
   277     // Check TopRight, TopLeft, BottomRight and BottomLeft Math Kern.
   278     for (unsigned j = 0; j < 4; ++j) {
   279       uint16_t offset_math_kern = 0;
   280       if (!subtable.ReadU16(&offset_math_kern)) {
   281         return OTS_FAILURE();
   282       }
   283       if (offset_math_kern) {
   284         if (offset_math_kern < sequence_end || offset_math_kern >= length ||
   285             !ParseMathKernTable(file, data + offset_math_kern,
   286                                 length - offset_math_kern)) {
   287           return OTS_FAILURE();
   288         }
   289       }
   290     }
   291   }
   293   return true;
   294 }
   296 bool ParseMathGlyphInfoTable(const ots::OpenTypeFile *file,
   297                              const uint8_t *data, size_t length,
   298                              const uint16_t num_glyphs) {
   299   ots::Buffer subtable(data, length);
   301   // Check Header.
   302   uint16_t offset_math_italics_correction_info = 0;
   303   uint16_t offset_math_top_accent_attachment = 0;
   304   uint16_t offset_extended_shaped_coverage = 0;
   305   uint16_t offset_math_kern_info = 0;
   306   if (!subtable.ReadU16(&offset_math_italics_correction_info) ||
   307       !subtable.ReadU16(&offset_math_top_accent_attachment) ||
   308       !subtable.ReadU16(&offset_extended_shaped_coverage) ||
   309       !subtable.ReadU16(&offset_math_kern_info)) {
   310     return OTS_FAILURE();
   311   }
   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   if (offset_math_italics_correction_info) {
   318     if (offset_math_italics_correction_info >= length ||
   319         offset_math_italics_correction_info < kMathGlyphInfoHeaderSize ||
   320         !ParseMathItalicsCorrectionInfoTable(
   321             file, data + offset_math_italics_correction_info,
   322             length - offset_math_italics_correction_info,
   323             num_glyphs)) {
   324       return OTS_FAILURE();
   325     }
   326   }
   327   if (offset_math_top_accent_attachment) {
   328     if (offset_math_top_accent_attachment >= length ||
   329         offset_math_top_accent_attachment < kMathGlyphInfoHeaderSize ||
   330         !ParseMathTopAccentAttachmentTable(file, data +
   331                                            offset_math_top_accent_attachment,
   332                                            length -
   333                                            offset_math_top_accent_attachment,
   334                                            num_glyphs)) {
   335       return OTS_FAILURE();
   336     }
   337   }
   338   if (offset_extended_shaped_coverage) {
   339     if (offset_extended_shaped_coverage >= length ||
   340         offset_extended_shaped_coverage < kMathGlyphInfoHeaderSize ||
   341         !ots::ParseCoverageTable(file, data + offset_extended_shaped_coverage,
   342                                  length - offset_extended_shaped_coverage,
   343                                  num_glyphs)) {
   344       return OTS_FAILURE();
   345     }
   346   }
   347   if (offset_math_kern_info) {
   348     if (offset_math_kern_info >= length ||
   349         offset_math_kern_info < kMathGlyphInfoHeaderSize ||
   350         !ParseMathKernInfoTable(file, data + offset_math_kern_info,
   351                                 length - offset_math_kern_info, num_glyphs)) {
   352       return OTS_FAILURE();
   353     }
   354   }
   356   return true;
   357 }
   359 bool ParseGlyphAssemblyTable(const ots::OpenTypeFile *file,
   360                              const uint8_t *data,
   361                              size_t length, const uint16_t num_glyphs) {
   362   ots::Buffer subtable(data, length);
   364   // Check the header.
   365   uint16_t part_count = 0;
   366   if (!ParseMathValueRecord(file, &subtable, data, length) ||
   367       !subtable.ReadU16(&part_count)) {
   368     return OTS_FAILURE();
   369   }
   371   const unsigned sequence_end = kMathValueRecordSize +
   372     static_cast<unsigned>(2) + part_count * kGlyphPartRecordSize;
   373   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
   374     return OTS_FAILURE();
   375   }
   377   // Check the sequence of GlyphPartRecord.
   378   for (unsigned i = 0; i < part_count; ++i) {
   379     uint16_t glyph = 0;
   380     uint16_t part_flags = 0;
   381     if (!subtable.ReadU16(&glyph) ||
   382         !subtable.Skip(2 * 3) ||
   383         !subtable.ReadU16(&part_flags)) {
   384       return OTS_FAILURE();
   385     }
   386     if (glyph >= num_glyphs) {
   387       OTS_WARNING("bad glyph ID: %u", glyph);
   388       return OTS_FAILURE();
   389     }
   390     if (part_flags & ~0x00000001) {
   391       OTS_WARNING("unknown part flag: %u", part_flags);
   392       return OTS_FAILURE();
   393     }
   394   }
   396   return true;
   397 }
   399 bool ParseMathGlyphConstructionTable(const ots::OpenTypeFile *file,
   400                                      const uint8_t *data,
   401                                      size_t length, const uint16_t num_glyphs) {
   402   ots::Buffer subtable(data, length);
   404   // Check the header.
   405   uint16_t offset_glyph_assembly = 0;
   406   uint16_t variant_count = 0;
   407   if (!subtable.ReadU16(&offset_glyph_assembly) ||
   408       !subtable.ReadU16(&variant_count)) {
   409     return OTS_FAILURE();
   410   }
   412   const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
   413     variant_count * 2 * 2;
   414   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
   415     return OTS_FAILURE();
   416   }
   418   // Check the GlyphAssembly offset.
   419   if (offset_glyph_assembly) {
   420     if (offset_glyph_assembly >= length ||
   421         offset_glyph_assembly < sequence_end) {
   422       return OTS_FAILURE();
   423     }
   424     if (!ParseGlyphAssemblyTable(file, data + offset_glyph_assembly,
   425                                  length - offset_glyph_assembly, num_glyphs)) {
   426       return OTS_FAILURE();
   427     }
   428   }
   430   // Check the sequence of MathGlyphVariantRecord.
   431   for (unsigned i = 0; i < variant_count; ++i) {
   432     uint16_t glyph = 0;
   433     if (!subtable.ReadU16(&glyph) ||
   434         !subtable.Skip(2)) {
   435       return OTS_FAILURE();
   436     }
   437     if (glyph >= num_glyphs) {
   438       OTS_WARNING("bad glyph ID: %u", glyph);
   439       return OTS_FAILURE();
   440     }
   441   }
   443   return true;
   444 }
   446 bool ParseMathGlyphConstructionSequence(const ots::OpenTypeFile *file,
   447                                         ots::Buffer* subtable,
   448                                         const uint8_t *data,
   449                                         size_t length,
   450                                         const uint16_t num_glyphs,
   451                                         uint16_t offset_coverage,
   452                                         uint16_t glyph_count,
   453                                         const unsigned sequence_end) {
   454   // Check coverage table.
   455   if (offset_coverage < sequence_end || offset_coverage >= length) {
   456     return OTS_FAILURE();
   457   }
   458   if (!ots::ParseCoverageTable(file, data + offset_coverage,
   459                                length - offset_coverage,
   460                                num_glyphs, glyph_count)) {
   461     return OTS_FAILURE();
   462   }
   464   // Check sequence of MathGlyphConstruction.
   465   for (unsigned i = 0; i < glyph_count; ++i) {
   466       uint16_t offset_glyph_construction = 0;
   467       if (!subtable->ReadU16(&offset_glyph_construction)) {
   468         return OTS_FAILURE();
   469       }
   470       if (offset_glyph_construction < sequence_end ||
   471           offset_glyph_construction >= length ||
   472           !ParseMathGlyphConstructionTable(file, data + offset_glyph_construction,
   473                                            length - offset_glyph_construction,
   474                                            num_glyphs)) {
   475         return OTS_FAILURE();
   476       }
   477   }
   479   return true;
   480 }
   482 bool ParseMathVariantsTable(const ots::OpenTypeFile *file,
   483                             const uint8_t *data,
   484                             size_t length, const uint16_t num_glyphs) {
   485   ots::Buffer subtable(data, length);
   487   // Check the header.
   488   uint16_t offset_vert_glyph_coverage = 0;
   489   uint16_t offset_horiz_glyph_coverage = 0;
   490   uint16_t vert_glyph_count = 0;
   491   uint16_t horiz_glyph_count = 0;
   492   if (!subtable.Skip(2) ||  // MinConnectorOverlap
   493       !subtable.ReadU16(&offset_vert_glyph_coverage) ||
   494       !subtable.ReadU16(&offset_horiz_glyph_coverage) ||
   495       !subtable.ReadU16(&vert_glyph_count) ||
   496       !subtable.ReadU16(&horiz_glyph_count)) {
   497     return OTS_FAILURE();
   498   }
   500   const unsigned sequence_end = 5 * 2 + vert_glyph_count * 2 +
   501     horiz_glyph_count * 2;
   502   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
   503     return OTS_FAILURE();
   504   }
   506   if (!ParseMathGlyphConstructionSequence(file, &subtable, data, length, num_glyphs,
   507                                           offset_vert_glyph_coverage,
   508                                           vert_glyph_count,
   509                                           sequence_end) ||
   510       !ParseMathGlyphConstructionSequence(file, &subtable, data, length, num_glyphs,
   511                                           offset_horiz_glyph_coverage,
   512                                           horiz_glyph_count,
   513                                           sequence_end)) {
   514     return OTS_FAILURE();
   515   }
   517   return true;
   518 }
   520 }  // namespace
   522 #define DROP_THIS_TABLE \
   523   do { file->math->data = 0; file->math->length = 0; } while (0)
   525 namespace ots {
   527 bool ots_math_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   528   // Grab the number of glyphs in the file from the maxp table to check
   529   // GlyphIDs in MATH table.
   530   if (!file->maxp) {
   531     return OTS_FAILURE();
   532   }
   533   const uint16_t num_glyphs = file->maxp->num_glyphs;
   535   Buffer table(data, length);
   537   OpenTypeMATH* math = new OpenTypeMATH;
   538   file->math = math;
   540   uint32_t version = 0;
   541   if (!table.ReadU32(&version)) {
   542     return OTS_FAILURE();
   543   }
   544   if (version != 0x00010000) {
   545     OTS_WARNING("bad MATH version");
   546     DROP_THIS_TABLE;
   547     return true;
   548   }
   550   uint16_t offset_math_constants = 0;
   551   uint16_t offset_math_glyph_info = 0;
   552   uint16_t offset_math_variants = 0;
   553   if (!table.ReadU16(&offset_math_constants) ||
   554       !table.ReadU16(&offset_math_glyph_info) ||
   555       !table.ReadU16(&offset_math_variants)) {
   556     return OTS_FAILURE();
   557   }
   559   if (offset_math_constants >= length ||
   560       offset_math_constants < kMathHeaderSize ||
   561       offset_math_glyph_info >= length ||
   562       offset_math_glyph_info < kMathHeaderSize ||
   563       offset_math_variants >= length ||
   564       offset_math_variants < kMathHeaderSize) {
   565     OTS_WARNING("bad offset in MATH header");
   566     DROP_THIS_TABLE;
   567     return true;
   568   }
   570   if (!ParseMathConstantsTable(file, data + offset_math_constants,
   571                                length - offset_math_constants)) {
   572     DROP_THIS_TABLE;
   573     return true;
   574   }
   575   if (!ParseMathGlyphInfoTable(file, data + offset_math_glyph_info,
   576                                length - offset_math_glyph_info, num_glyphs)) {
   577     DROP_THIS_TABLE;
   578     return true;
   579   }
   580   if (!ParseMathVariantsTable(file, data + offset_math_variants,
   581                               length - offset_math_variants, num_glyphs)) {
   582     DROP_THIS_TABLE;
   583     return true;
   584   }
   586   math->data = data;
   587   math->length = length;
   588   return true;
   589 }
   591 bool ots_math_should_serialise(OpenTypeFile *file) {
   592   return file->math != NULL && file->math->data != NULL;
   593 }
   595 bool ots_math_serialise(OTSStream *out, OpenTypeFile *file) {
   596   if (!out->Write(file->math->data, file->math->length)) {
   597     return OTS_FAILURE();
   598   }
   600   return true;
   601 }
   603 void ots_math_free(OpenTypeFile *file) {
   604   delete file->math;
   605 }
   607 }  // namespace ots

mercurial