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