Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: src/math.cc

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

Powered by Google App Engine
This is Rietveld 408576698