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.

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

mercurial