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