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