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

Side by Side Diff: third_party/ots/src/math.cc

Issue 775893002: Updating OTS repo from https://github.com/khaledhosny/ots.git (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updating with 4800 warning fix Created 6 years 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 | « third_party/ots/src/ltsh.cc ('k') | third_party/ots/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 #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 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 }
60
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 }
74
75 return true;
76 }
77
78 bool ParseMathConstantsTable(const ots::OpenTypeFile *file,
79 const uint8_t *data, size_t length) {
80 ots::Buffer subtable(data, length);
81
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 }
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 for (unsigned i = 0; i < static_cast<unsigned>(51); ++i) {
149 if (!ParseMathValueRecord(file, &subtable, data, length)) {
150 return OTS_FAILURE();
151 }
152 }
153
154 // Part 3: uint16 constant
155 // RadicalDegreeBottomRaisePercent
156 if (!subtable.Skip(2)) {
157 return OTS_FAILURE();
158 }
159
160 return true;
161 }
162
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 }
175
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 }
181
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 }
191
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 }
198
199 return true;
200 }
201
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 }
210
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 }
219
220 bool ParseMathKernTable(const ots::OpenTypeFile *file,
221 const uint8_t *data, size_t length) {
222 ots::Buffer subtable(data, length);
223
224 // Check the Height count.
225 uint16_t height_count = 0;
226 if (!subtable.ReadU16(&height_count)) {
227 return OTS_FAILURE();
228 }
229
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 }
236
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 }
243
244 return true;
245 }
246
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);
251
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 }
259
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 }
265
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_cov erage,
271 num_glyphs, sequence_count)) {
272 return OTS_FAILURE();
273 }
274
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 }
292
293 return true;
294 }
295
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);
300
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 }
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 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 }
355
356 return true;
357 }
358
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);
363
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 }
370
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 }
376
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 return OTS_FAILURE_MSG("bad glyph ID: %u", glyph);
388 }
389 if (part_flags & ~0x00000001) {
390 return OTS_FAILURE_MSG("unknown part flag: %u", part_flags);
391 }
392 }
393
394 return true;
395 }
396
397 bool ParseMathGlyphConstructionTable(const ots::OpenTypeFile *file,
398 const uint8_t *data,
399 size_t length, const uint16_t num_glyphs) {
400 ots::Buffer subtable(data, length);
401
402 // Check the header.
403 uint16_t offset_glyph_assembly = 0;
404 uint16_t variant_count = 0;
405 if (!subtable.ReadU16(&offset_glyph_assembly) ||
406 !subtable.ReadU16(&variant_count)) {
407 return OTS_FAILURE();
408 }
409
410 const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
411 variant_count * 2 * 2;
412 if (sequence_end > std::numeric_limits<uint16_t>::max()) {
413 return OTS_FAILURE();
414 }
415
416 // Check the GlyphAssembly offset.
417 if (offset_glyph_assembly) {
418 if (offset_glyph_assembly >= length ||
419 offset_glyph_assembly < sequence_end) {
420 return OTS_FAILURE();
421 }
422 if (!ParseGlyphAssemblyTable(file, data + offset_glyph_assembly,
423 length - offset_glyph_assembly, num_glyphs)) {
424 return OTS_FAILURE();
425 }
426 }
427
428 // Check the sequence of MathGlyphVariantRecord.
429 for (unsigned i = 0; i < variant_count; ++i) {
430 uint16_t glyph = 0;
431 if (!subtable.ReadU16(&glyph) ||
432 !subtable.Skip(2)) {
433 return OTS_FAILURE();
434 }
435 if (glyph >= num_glyphs) {
436 return OTS_FAILURE_MSG("bad glyph ID: %u", glyph);
437 }
438 }
439
440 return true;
441 }
442
443 bool ParseMathGlyphConstructionSequence(const ots::OpenTypeFile *file,
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 // Check coverage table.
452 if (offset_coverage < sequence_end || offset_coverage >= length) {
453 return OTS_FAILURE();
454 }
455 if (!ots::ParseCoverageTable(file, data + offset_coverage,
456 length - offset_coverage,
457 num_glyphs, glyph_count)) {
458 return OTS_FAILURE();
459 }
460
461 // Check sequence of MathGlyphConstruction.
462 for (unsigned i = 0; i < glyph_count; ++i) {
463 uint16_t offset_glyph_construction = 0;
464 if (!subtable->ReadU16(&offset_glyph_construction)) {
465 return OTS_FAILURE();
466 }
467 if (offset_glyph_construction < sequence_end ||
468 offset_glyph_construction >= length ||
469 !ParseMathGlyphConstructionTable(file, data + offset_glyph_constructio n,
470 length - offset_glyph_construction,
471 num_glyphs)) {
472 return OTS_FAILURE();
473 }
474 }
475
476 return true;
477 }
478
479 bool ParseMathVariantsTable(const ots::OpenTypeFile *file,
480 const uint8_t *data,
481 size_t length, const uint16_t num_glyphs) {
482 ots::Buffer subtable(data, length);
483
484 // Check the header.
485 uint16_t offset_vert_glyph_coverage = 0;
486 uint16_t offset_horiz_glyph_coverage = 0;
487 uint16_t vert_glyph_count = 0;
488 uint16_t horiz_glyph_count = 0;
489 if (!subtable.Skip(2) || // MinConnectorOverlap
490 !subtable.ReadU16(&offset_vert_glyph_coverage) ||
491 !subtable.ReadU16(&offset_horiz_glyph_coverage) ||
492 !subtable.ReadU16(&vert_glyph_count) ||
493 !subtable.ReadU16(&horiz_glyph_count)) {
494 return OTS_FAILURE();
495 }
496
497 const unsigned sequence_end = 5 * 2 + vert_glyph_count * 2 +
498 horiz_glyph_count * 2;
499 if (sequence_end > std::numeric_limits<uint16_t>::max()) {
500 return OTS_FAILURE();
501 }
502
503 if (!ParseMathGlyphConstructionSequence(file, &subtable, data, length, num_gly phs,
504 offset_vert_glyph_coverage,
505 vert_glyph_count,
506 sequence_end) ||
507 !ParseMathGlyphConstructionSequence(file, &subtable, data, length, num_gly phs,
508 offset_horiz_glyph_coverage,
509 horiz_glyph_count,
510 sequence_end)) {
511 return OTS_FAILURE();
512 }
513
514 return true;
515 }
516
517 } // namespace
518
519 #define DROP_THIS_TABLE(msg_) \
520 do { \
521 OTS_FAILURE_MSG(msg_ ", table discarded"); \
522 file->math->data = 0; \
523 file->math->length = 0; \
524 } while (0)
525
526 namespace ots {
527
528 bool ots_math_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
529 // Grab the number of glyphs in the file from the maxp table to check
530 // GlyphIDs in MATH table.
531 if (!file->maxp) {
532 return OTS_FAILURE();
533 }
534 const uint16_t num_glyphs = file->maxp->num_glyphs;
535
536 Buffer table(data, length);
537
538 OpenTypeMATH* math = new OpenTypeMATH;
539 file->math = math;
540
541 uint32_t version = 0;
542 if (!table.ReadU32(&version)) {
543 return OTS_FAILURE();
544 }
545 if (version != 0x00010000) {
546 DROP_THIS_TABLE("bad MATH version");
547 return true;
548 }
549
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 }
558
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 DROP_THIS_TABLE("bad offset in MATH header");
566 return true;
567 }
568
569 if (!ParseMathConstantsTable(file, data + offset_math_constants,
570 length - offset_math_constants)) {
571 DROP_THIS_TABLE("failed to parse MathConstants table");
572 return true;
573 }
574 if (!ParseMathGlyphInfoTable(file, data + offset_math_glyph_info,
575 length - offset_math_glyph_info, num_glyphs)) {
576 DROP_THIS_TABLE("failed to parse MathGlyphInfo table");
577 return true;
578 }
579 if (!ParseMathVariantsTable(file, data + offset_math_variants,
580 length - offset_math_variants, num_glyphs)) {
581 DROP_THIS_TABLE("failed to parse MathVariants table");
582 return true;
583 }
584
585 math->data = data;
586 math->length = length;
587 return true;
588 }
589
590 bool ots_math_should_serialise(OpenTypeFile *file) {
591 return file->math != NULL && file->math->data != NULL;
592 }
593
594 bool ots_math_serialise(OTSStream *out, OpenTypeFile *file) {
595 if (!out->Write(file->math->data, file->math->length)) {
596 return OTS_FAILURE();
597 }
598
599 return true;
600 }
601
602 void ots_math_free(OpenTypeFile *file) {
603 delete file->math;
604 }
605
606 } // namespace ots
607
608 #undef TABLE_NAME
609 #undef DROP_THIS_TABLE
OLDNEW
« no previous file with comments | « third_party/ots/src/ltsh.cc ('k') | third_party/ots/src/math_.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698