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