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