Line | Count | Source |
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 | 95.0k | const size_t length) { |
55 | | // Check the Value field. |
56 | 95.0k | if (!subtable->Skip(2)) { |
57 | 32 | return OTS_FAILURE(); |
58 | 32 | } |
59 | | |
60 | | // Check the offset to device table. |
61 | 95.0k | uint16_t offset = 0; |
62 | 95.0k | if (!subtable->ReadU16(&offset)) { |
63 | 21 | return OTS_FAILURE(); |
64 | 21 | } |
65 | 94.9k | if (offset) { |
66 | 711 | if (offset >= length) { |
67 | 155 | return OTS_FAILURE(); |
68 | 155 | } |
69 | 556 | if (!ots::ParseDeviceTable(GetFont(), data + offset, length - offset)) { |
70 | 215 | return OTS_FAILURE(); |
71 | 215 | } |
72 | 556 | } |
73 | | |
74 | 94.6k | return true; |
75 | 94.9k | } |
76 | | |
77 | | bool OpenTypeMATH::ParseMathConstantsTable(const uint8_t *data, |
78 | 1.86k | size_t length) { |
79 | 1.86k | ots::Buffer subtable(data, length); |
80 | | |
81 | | // Part 1: int16 or uint16 constants. |
82 | | // ScriptPercentScaleDown |
83 | | // ScriptScriptPercentScaleDown |
84 | | // DelimitedSubFormulaMinHeight |
85 | | // DisplayOperatorMinHeight |
86 | 1.86k | if (!subtable.Skip(4 * 2)) { |
87 | 21 | return OTS_FAILURE(); |
88 | 21 | } |
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 | 88.5k | for (unsigned i = 0; i < static_cast<unsigned>(51); ++i) { |
148 | 86.9k | if (!ParseMathValueRecord(&subtable, data, length)) { |
149 | 229 | return OTS_FAILURE(); |
150 | 229 | } |
151 | 86.9k | } |
152 | | |
153 | | // Part 3: uint16 constant |
154 | | // RadicalDegreeBottomRaisePercent |
155 | 1.61k | if (!subtable.Skip(2)) { |
156 | 0 | return OTS_FAILURE(); |
157 | 0 | } |
158 | | |
159 | 1.61k | return true; |
160 | 1.61k | } |
161 | | |
162 | | bool OpenTypeMATH::ParseMathValueRecordSequenceForGlyphs(ots::Buffer* subtable, |
163 | | const uint8_t *data, |
164 | | const size_t length, |
165 | 255 | const uint16_t num_glyphs) { |
166 | | // Check the header. |
167 | 255 | uint16_t offset_coverage = 0; |
168 | 255 | uint16_t sequence_count = 0; |
169 | 255 | if (!subtable->ReadU16(&offset_coverage) || |
170 | 253 | !subtable->ReadU16(&sequence_count)) { |
171 | 9 | return OTS_FAILURE(); |
172 | 9 | } |
173 | | |
174 | 246 | const unsigned sequence_end = static_cast<unsigned>(2 * 2) + |
175 | 246 | sequence_count * kMathValueRecordSize; |
176 | 246 | if (sequence_end > std::numeric_limits<uint16_t>::max()) { |
177 | 27 | return OTS_FAILURE(); |
178 | 27 | } |
179 | | |
180 | | // Check coverage table. |
181 | 219 | if (offset_coverage < sequence_end || offset_coverage >= length) { |
182 | 103 | return OTS_FAILURE(); |
183 | 103 | } |
184 | 116 | if (!ots::ParseCoverageTable(GetFont(), data + offset_coverage, |
185 | 116 | length - offset_coverage, |
186 | 116 | num_glyphs, sequence_count)) { |
187 | 49 | return OTS_FAILURE(); |
188 | 49 | } |
189 | | |
190 | | // Check sequence. |
191 | 119 | for (unsigned i = 0; i < sequence_count; ++i) { |
192 | 62 | if (!ParseMathValueRecord(subtable, data, length)) { |
193 | 10 | return OTS_FAILURE(); |
194 | 10 | } |
195 | 62 | } |
196 | | |
197 | 57 | return true; |
198 | 67 | } |
199 | | |
200 | | bool OpenTypeMATH::ParseMathItalicsCorrectionInfoTable(const uint8_t *data, |
201 | | size_t length, |
202 | 129 | const uint16_t num_glyphs) { |
203 | 129 | ots::Buffer subtable(data, length); |
204 | 129 | return ParseMathValueRecordSequenceForGlyphs(&subtable, data, length, |
205 | 129 | num_glyphs); |
206 | 129 | } |
207 | | |
208 | | bool OpenTypeMATH::ParseMathTopAccentAttachmentTable(const uint8_t *data, |
209 | | size_t length, |
210 | 126 | const uint16_t num_glyphs) { |
211 | 126 | ots::Buffer subtable(data, length); |
212 | 126 | return ParseMathValueRecordSequenceForGlyphs(&subtable, data, length, |
213 | 126 | num_glyphs); |
214 | 126 | } |
215 | | |
216 | 508 | bool OpenTypeMATH::ParseMathKernTable(const uint8_t *data, size_t length) { |
217 | 508 | ots::Buffer subtable(data, length); |
218 | | |
219 | | // Check the Height count. |
220 | 508 | uint16_t height_count = 0; |
221 | 508 | if (!subtable.ReadU16(&height_count)) { |
222 | 0 | return OTS_FAILURE(); |
223 | 0 | } |
224 | | |
225 | | // Check the Correction Heights. |
226 | 7.07k | for (unsigned i = 0; i < height_count; ++i) { |
227 | 6.65k | if (!ParseMathValueRecord(&subtable, data, length)) { |
228 | 95 | return OTS_FAILURE(); |
229 | 95 | } |
230 | 6.65k | } |
231 | | |
232 | | // Check the Kern Values. |
233 | 1.61k | for (unsigned i = 0; i <= height_count; ++i) { |
234 | 1.24k | if (!ParseMathValueRecord(&subtable, data, length)) { |
235 | 48 | return OTS_FAILURE(); |
236 | 48 | } |
237 | 1.24k | } |
238 | | |
239 | 365 | return true; |
240 | 413 | } |
241 | | |
242 | | bool OpenTypeMATH::ParseMathKernInfoTable(const uint8_t *data, |
243 | | size_t length, |
244 | 502 | const uint16_t num_glyphs) { |
245 | 502 | ots::Buffer subtable(data, length); |
246 | | |
247 | | // Check the header. |
248 | 502 | uint16_t offset_coverage = 0; |
249 | 502 | uint16_t sequence_count = 0; |
250 | 502 | if (!subtable.ReadU16(&offset_coverage) || |
251 | 462 | !subtable.ReadU16(&sequence_count)) { |
252 | 45 | return OTS_FAILURE(); |
253 | 45 | } |
254 | | |
255 | 457 | const unsigned sequence_end = static_cast<unsigned>(2 * 2) + |
256 | 457 | sequence_count * 4 * 2; |
257 | 457 | if (sequence_end > std::numeric_limits<uint16_t>::max()) { |
258 | 31 | return OTS_FAILURE(); |
259 | 31 | } |
260 | | |
261 | | // Check coverage table. |
262 | 426 | if (offset_coverage < sequence_end || offset_coverage >= length) { |
263 | 67 | return OTS_FAILURE(); |
264 | 67 | } |
265 | 359 | if (!ots::ParseCoverageTable(GetFont(), data + offset_coverage, length - offset_coverage, |
266 | 359 | num_glyphs, sequence_count)) { |
267 | 41 | return OTS_FAILURE(); |
268 | 41 | } |
269 | | |
270 | | // Check sequence of MathKernInfoRecord |
271 | 348 | for (unsigned i = 0; i < sequence_count; ++i) { |
272 | | // Check TopRight, TopLeft, BottomRight and BottomLeft Math Kern. |
273 | 793 | for (unsigned j = 0; j < 4; ++j) { |
274 | 763 | uint16_t offset_math_kern = 0; |
275 | 763 | if (!subtable.ReadU16(&offset_math_kern)) { |
276 | 0 | return OTS_FAILURE(); |
277 | 0 | } |
278 | 763 | if (offset_math_kern) { |
279 | 644 | if (offset_math_kern < sequence_end || offset_math_kern >= length || |
280 | 508 | !ParseMathKernTable(data + offset_math_kern, |
281 | 508 | length - offset_math_kern)) { |
282 | 279 | return OTS_FAILURE(); |
283 | 279 | } |
284 | 644 | } |
285 | 763 | } |
286 | 309 | } |
287 | | |
288 | 39 | return true; |
289 | 318 | } |
290 | | |
291 | | bool OpenTypeMATH::ParseMathGlyphInfoTable(const uint8_t *data, |
292 | | size_t length, |
293 | 1.61k | const uint16_t num_glyphs) { |
294 | 1.61k | ots::Buffer subtable(data, length); |
295 | | |
296 | | // Check Header. |
297 | 1.61k | uint16_t offset_math_italics_correction_info = 0; |
298 | 1.61k | uint16_t offset_math_top_accent_attachment = 0; |
299 | 1.61k | uint16_t offset_extended_shaped_coverage = 0; |
300 | 1.61k | uint16_t offset_math_kern_info = 0; |
301 | 1.61k | if (!subtable.ReadU16(&offset_math_italics_correction_info) || |
302 | 1.59k | !subtable.ReadU16(&offset_math_top_accent_attachment) || |
303 | 1.59k | !subtable.ReadU16(&offset_extended_shaped_coverage) || |
304 | 1.55k | !subtable.ReadU16(&offset_math_kern_info)) { |
305 | 88 | return OTS_FAILURE(); |
306 | 88 | } |
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 | 1.53k | if (offset_math_italics_correction_info) { |
313 | 160 | if (offset_math_italics_correction_info >= length || |
314 | 139 | offset_math_italics_correction_info < kMathGlyphInfoHeaderSize || |
315 | 129 | !ParseMathItalicsCorrectionInfoTable( |
316 | 129 | data + offset_math_italics_correction_info, |
317 | 129 | length - offset_math_italics_correction_info, |
318 | 136 | num_glyphs)) { |
319 | 136 | return OTS_FAILURE(); |
320 | 136 | } |
321 | 160 | } |
322 | 1.39k | if (offset_math_top_accent_attachment) { |
323 | 179 | if (offset_math_top_accent_attachment >= length || |
324 | 164 | offset_math_top_accent_attachment < kMathGlyphInfoHeaderSize || |
325 | 126 | !ParseMathTopAccentAttachmentTable(data + |
326 | 126 | offset_math_top_accent_attachment, |
327 | 126 | length - |
328 | 126 | offset_math_top_accent_attachment, |
329 | 146 | num_glyphs)) { |
330 | 146 | return OTS_FAILURE(); |
331 | 146 | } |
332 | 179 | } |
333 | 1.24k | if (offset_extended_shaped_coverage) { |
334 | 376 | if (offset_extended_shaped_coverage >= length || |
335 | 368 | offset_extended_shaped_coverage < kMathGlyphInfoHeaderSize || |
336 | 342 | !ots::ParseCoverageTable(GetFont(), data + offset_extended_shaped_coverage, |
337 | 342 | length - offset_extended_shaped_coverage, |
338 | 342 | num_glyphs)) { |
339 | 119 | return OTS_FAILURE(); |
340 | 119 | } |
341 | 376 | } |
342 | 1.13k | if (offset_math_kern_info) { |
343 | 542 | if (offset_math_kern_info >= length || |
344 | 528 | offset_math_kern_info < kMathGlyphInfoHeaderSize || |
345 | 502 | !ParseMathKernInfoTable(data + offset_math_kern_info, |
346 | 503 | length - offset_math_kern_info, num_glyphs)) { |
347 | 503 | return OTS_FAILURE(); |
348 | 503 | } |
349 | 542 | } |
350 | | |
351 | 627 | return true; |
352 | 1.13k | } |
353 | | |
354 | | bool OpenTypeMATH::ParseGlyphAssemblyTable(const uint8_t *data, |
355 | | size_t length, |
356 | 107 | const uint16_t num_glyphs) { |
357 | 107 | ots::Buffer subtable(data, length); |
358 | | |
359 | | // Check the header. |
360 | 107 | uint16_t part_count = 0; |
361 | 107 | if (!ParseMathValueRecord(&subtable, data, length) || |
362 | 66 | !subtable.ReadU16(&part_count)) { |
363 | 44 | return OTS_FAILURE(); |
364 | 44 | } |
365 | | |
366 | 63 | const unsigned sequence_end = kMathValueRecordSize + |
367 | 63 | static_cast<unsigned>(2) + part_count * kGlyphPartRecordSize; |
368 | 63 | if (sequence_end > std::numeric_limits<uint16_t>::max()) { |
369 | 10 | return OTS_FAILURE(); |
370 | 10 | } |
371 | | |
372 | | // Check the sequence of GlyphPartRecord. |
373 | 735 | for (unsigned i = 0; i < part_count; ++i) { |
374 | 720 | uint16_t glyph = 0; |
375 | 720 | uint16_t part_flags = 0; |
376 | 720 | if (!subtable.ReadU16(&glyph) || |
377 | 705 | !subtable.Skip(2 * 3) || |
378 | 692 | !subtable.ReadU16(&part_flags)) { |
379 | 29 | return OTS_FAILURE(); |
380 | 29 | } |
381 | 691 | if (glyph >= num_glyphs) { |
382 | 5 | return Error("bad glyph ID: %u", glyph); |
383 | 5 | } |
384 | 686 | if (part_flags & ~0x00000001) { |
385 | 4 | return Error("unknown part flag: %u", part_flags); |
386 | 4 | } |
387 | 686 | } |
388 | | |
389 | 15 | return true; |
390 | 53 | } |
391 | | |
392 | | bool OpenTypeMATH::ParseMathGlyphConstructionTable(const uint8_t *data, |
393 | | size_t length, |
394 | 259 | const uint16_t num_glyphs) { |
395 | 259 | ots::Buffer subtable(data, length); |
396 | | |
397 | | // Check the header. |
398 | 259 | uint16_t offset_glyph_assembly = 0; |
399 | 259 | uint16_t variant_count = 0; |
400 | 259 | if (!subtable.ReadU16(&offset_glyph_assembly) || |
401 | 251 | !subtable.ReadU16(&variant_count)) { |
402 | 10 | return OTS_FAILURE(); |
403 | 10 | } |
404 | | |
405 | 249 | const unsigned sequence_end = static_cast<unsigned>(2 * 2) + |
406 | 249 | variant_count * 2 * 2; |
407 | 249 | if (sequence_end > std::numeric_limits<uint16_t>::max()) { |
408 | 26 | return OTS_FAILURE(); |
409 | 26 | } |
410 | | |
411 | | // Check the GlyphAssembly offset. |
412 | 223 | if (offset_glyph_assembly) { |
413 | 142 | if (offset_glyph_assembly >= length || |
414 | 123 | offset_glyph_assembly < sequence_end) { |
415 | 35 | return OTS_FAILURE(); |
416 | 35 | } |
417 | 107 | if (!ParseGlyphAssemblyTable(data + offset_glyph_assembly, |
418 | 107 | length - offset_glyph_assembly, num_glyphs)) { |
419 | 92 | return OTS_FAILURE(); |
420 | 92 | } |
421 | 107 | } |
422 | | |
423 | | // Check the sequence of MathGlyphVariantRecord. |
424 | 422 | for (unsigned i = 0; i < variant_count; ++i) { |
425 | 403 | uint16_t glyph = 0; |
426 | 403 | if (!subtable.ReadU16(&glyph) || |
427 | 390 | !subtable.Skip(2)) { |
428 | 20 | return OTS_FAILURE(); |
429 | 20 | } |
430 | 383 | if (glyph >= num_glyphs) { |
431 | 57 | return Error("bad glyph ID: %u", glyph); |
432 | 57 | } |
433 | 383 | } |
434 | | |
435 | 19 | return true; |
436 | 96 | } |
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 | 715 | const unsigned sequence_end) { |
445 | | // Zero glyph count, nothing to parse. |
446 | 715 | if (!glyph_count) { |
447 | 217 | return true; |
448 | 217 | } |
449 | | |
450 | | // Check coverage table. |
451 | 498 | if (offset_coverage < sequence_end || offset_coverage >= length) { |
452 | 108 | return OTS_FAILURE(); |
453 | 108 | } |
454 | 390 | if (!ots::ParseCoverageTable(GetFont(), data + offset_coverage, |
455 | 390 | length - offset_coverage, |
456 | 390 | num_glyphs, glyph_count)) { |
457 | 81 | return OTS_FAILURE(); |
458 | 81 | } |
459 | | |
460 | | // Check sequence of MathGlyphConstruction. |
461 | 328 | for (unsigned i = 0; i < glyph_count; ++i) { |
462 | 309 | uint16_t offset_glyph_construction = 0; |
463 | 309 | if (!subtable->ReadU16(&offset_glyph_construction)) { |
464 | 0 | return OTS_FAILURE(); |
465 | 0 | } |
466 | 309 | if (offset_glyph_construction < sequence_end || |
467 | 295 | offset_glyph_construction >= length || |
468 | 259 | !ParseMathGlyphConstructionTable(data + offset_glyph_construction, |
469 | 259 | length - offset_glyph_construction, |
470 | 290 | num_glyphs)) { |
471 | 290 | return OTS_FAILURE(); |
472 | 290 | } |
473 | 309 | } |
474 | | |
475 | 19 | return true; |
476 | 309 | } |
477 | | |
478 | | bool OpenTypeMATH::ParseMathVariantsTable(const uint8_t *data, |
479 | | size_t length, |
480 | 627 | const uint16_t num_glyphs) { |
481 | 627 | ots::Buffer subtable(data, length); |
482 | | |
483 | | // Check the header. |
484 | 627 | uint16_t offset_vert_glyph_coverage = 0; |
485 | 627 | uint16_t offset_horiz_glyph_coverage = 0; |
486 | 627 | uint16_t vert_glyph_count = 0; |
487 | 627 | uint16_t horiz_glyph_count = 0; |
488 | 627 | if (!subtable.Skip(2) || // MinConnectorOverlap |
489 | 627 | !subtable.ReadU16(&offset_vert_glyph_coverage) || |
490 | 619 | !subtable.ReadU16(&offset_horiz_glyph_coverage) || |
491 | 614 | !subtable.ReadU16(&vert_glyph_count) || |
492 | 603 | !subtable.ReadU16(&horiz_glyph_count)) { |
493 | 41 | return OTS_FAILURE(); |
494 | 41 | } |
495 | | |
496 | 586 | const unsigned sequence_end = 5 * 2 + vert_glyph_count * 2 + |
497 | 586 | horiz_glyph_count * 2; |
498 | 586 | if (sequence_end > std::numeric_limits<uint16_t>::max()) { |
499 | 35 | return OTS_FAILURE(); |
500 | 35 | } |
501 | | |
502 | 551 | if (!ParseMathGlyphConstructionSequence(&subtable, data, length, num_glyphs, |
503 | 551 | offset_vert_glyph_coverage, |
504 | 551 | vert_glyph_count, |
505 | 551 | sequence_end) || |
506 | 164 | !ParseMathGlyphConstructionSequence(&subtable, data, length, num_glyphs, |
507 | 164 | offset_horiz_glyph_coverage, |
508 | 164 | horiz_glyph_count, |
509 | 479 | sequence_end)) { |
510 | 479 | return OTS_FAILURE(); |
511 | 479 | } |
512 | | |
513 | 72 | return true; |
514 | 551 | } |
515 | | |
516 | 2.93k | 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 | 2.93k | OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>( |
520 | 2.93k | GetFont()->GetTypedTable(OTS_TAG_MAXP)); |
521 | 2.93k | if (!maxp) { |
522 | 0 | return Error("Required maxp table missing"); |
523 | 0 | } |
524 | 2.93k | const uint16_t num_glyphs = maxp->num_glyphs; |
525 | | |
526 | 2.93k | Buffer table(data, length); |
527 | | |
528 | 2.93k | uint32_t version = 0; |
529 | 2.93k | if (!table.ReadU32(&version)) { |
530 | 1 | return OTS_FAILURE(); |
531 | 1 | } |
532 | 2.93k | if (version != 0x00010000) { |
533 | 844 | return Drop("bad MATH version"); |
534 | 844 | } |
535 | | |
536 | 2.08k | uint16_t offset_math_constants = 0; |
537 | 2.08k | uint16_t offset_math_glyph_info = 0; |
538 | 2.08k | uint16_t offset_math_variants = 0; |
539 | 2.08k | if (!table.ReadU16(&offset_math_constants) || |
540 | 2.07k | !table.ReadU16(&offset_math_glyph_info) || |
541 | 2.06k | !table.ReadU16(&offset_math_variants)) { |
542 | 34 | return OTS_FAILURE(); |
543 | 34 | } |
544 | | |
545 | 2.05k | if (offset_math_constants >= length || |
546 | 2.01k | offset_math_constants < kMathHeaderSize || |
547 | 1.97k | offset_math_glyph_info >= length || |
548 | 1.95k | offset_math_glyph_info < kMathHeaderSize || |
549 | 1.93k | offset_math_variants >= length || |
550 | 1.90k | offset_math_variants < kMathHeaderSize) { |
551 | 184 | return Drop("bad offset in MATH header"); |
552 | 184 | } |
553 | | |
554 | 1.86k | if (!ParseMathConstantsTable(data + offset_math_constants, |
555 | 1.86k | length - offset_math_constants)) { |
556 | 250 | return Drop("failed to parse MathConstants table"); |
557 | 250 | } |
558 | 1.61k | if (!ParseMathGlyphInfoTable(data + offset_math_glyph_info, |
559 | 1.61k | length - offset_math_glyph_info, num_glyphs)) { |
560 | 992 | return Drop("failed to parse MathGlyphInfo table"); |
561 | 992 | } |
562 | 627 | if (!ParseMathVariantsTable(data + offset_math_variants, |
563 | 627 | length - offset_math_variants, num_glyphs)) { |
564 | 555 | return Drop("failed to parse MathVariants table"); |
565 | 555 | } |
566 | | |
567 | 72 | this->m_data = data; |
568 | 72 | this->m_length = length; |
569 | 72 | return true; |
570 | 627 | } |
571 | | |
572 | 70 | bool OpenTypeMATH::Serialize(OTSStream *out) { |
573 | 70 | if (!out->Write(this->m_data, this->m_length)) { |
574 | 0 | return OTS_FAILURE(); |
575 | 0 | } |
576 | | |
577 | 70 | return true; |
578 | 70 | } |
579 | | |
580 | 15.6k | bool OpenTypeMATH::ShouldSerialize() { |
581 | 15.6k | return Table::ShouldSerialize() && this->m_data != NULL; |
582 | 15.6k | } |
583 | | |
584 | | } // namespace ots |