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