comparison mupdf-source/thirdparty/harfbuzz/src/hb-ot-math-table.hh @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*
2 * Copyright © 2016 Igalia S.L.
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Igalia Author(s): Frédéric Wang
25 */
26
27 #ifndef HB_OT_MATH_TABLE_HH
28 #define HB_OT_MATH_TABLE_HH
29
30 #include "hb-open-type.hh"
31 #include "hb-ot-layout-common.hh"
32 #include "hb-ot-math.h"
33
34 namespace OT {
35
36
37 struct MathValueRecord
38 {
39 hb_position_t get_x_value (hb_font_t *font, const void *base) const
40 { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); }
41 hb_position_t get_y_value (hb_font_t *font, const void *base) const
42 { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); }
43
44 MathValueRecord* copy (hb_serialize_context_t *c, const void *base) const
45 {
46 TRACE_SERIALIZE (this);
47 auto *out = c->embed (this);
48 if (unlikely (!out)) return_trace (nullptr);
49 out->deviceTable.serialize_copy (c, deviceTable, base, 0, hb_serialize_context_t::Head);
50
51 return_trace (out);
52 }
53
54 bool sanitize (hb_sanitize_context_t *c, const void *base) const
55 {
56 TRACE_SANITIZE (this);
57 return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
58 }
59
60 protected:
61 HBINT16 value; /* The X or Y value in design units */
62 Offset16To<Device> deviceTable; /* Offset to the device table - from the
63 * beginning of parent table. May be NULL.
64 * Suggested format for device table is 1. */
65
66 public:
67 DEFINE_SIZE_STATIC (4);
68 };
69
70 struct MathConstants
71 {
72 MathConstants* copy (hb_serialize_context_t *c) const
73 {
74 TRACE_SERIALIZE (this);
75 auto *out = c->start_embed (this);
76 if (unlikely (!out)) return_trace (nullptr);
77
78 HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2);
79 if (unlikely (!p)) return_trace (nullptr);
80 hb_memcpy (p, percentScaleDown, HBINT16::static_size * 2);
81
82 HBUINT16 *m = c->allocate_size<HBUINT16> (HBUINT16::static_size * 2);
83 if (unlikely (!m)) return_trace (nullptr);
84 hb_memcpy (m, minHeight, HBUINT16::static_size * 2);
85
86 unsigned count = ARRAY_LENGTH (mathValueRecords);
87 for (unsigned i = 0; i < count; i++)
88 if (!c->copy (mathValueRecords[i], this))
89 return_trace (nullptr);
90
91 if (!c->embed (radicalDegreeBottomRaisePercent)) return_trace (nullptr);
92 return_trace (out);
93 }
94
95 bool sanitize_math_value_records (hb_sanitize_context_t *c) const
96 {
97 TRACE_SANITIZE (this);
98
99 unsigned int count = ARRAY_LENGTH (mathValueRecords);
100 for (unsigned int i = 0; i < count; i++)
101 if (!mathValueRecords[i].sanitize (c, this))
102 return_trace (false);
103
104 return_trace (true);
105 }
106
107 bool sanitize (hb_sanitize_context_t *c) const
108 {
109 TRACE_SANITIZE (this);
110 return_trace (c->check_struct (this) && sanitize_math_value_records (c));
111 }
112
113 hb_position_t get_value (hb_ot_math_constant_t constant,
114 hb_font_t *font) const
115 {
116 switch (constant) {
117
118 case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN:
119 case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN:
120 return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN];
121
122 case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT:
123 case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT:
124 return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]);
125
126 case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE:
127 case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE:
128 case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP:
129 case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT:
130 return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this);
131
132 case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT:
133 case HB_OT_MATH_CONSTANT_AXIS_HEIGHT:
134 case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT:
135 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN:
136 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN:
137 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN:
138 case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN:
139 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP:
140 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN:
141 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP:
142 case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN:
143 case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS:
144 case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN:
145 case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN:
146 case HB_OT_MATH_CONSTANT_MATH_LEADING:
147 case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER:
148 case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS:
149 case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP:
150 case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP:
151 case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER:
152 case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS:
153 case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP:
154 case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP:
155 case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN:
156 case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN:
157 case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN:
158 case HB_OT_MATH_CONSTANT_STACK_GAP_MIN:
159 case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP:
160 case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP:
161 case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN:
162 case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN:
163 case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN:
164 case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP:
165 case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN:
166 case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN:
167 case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX:
168 case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN:
169 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX:
170 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT:
171 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN:
172 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP:
173 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED:
174 case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER:
175 case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS:
176 case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP:
177 case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN:
178 case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN:
179 return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this);
180
181 case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
182 return radicalDegreeBottomRaisePercent;
183
184 default:
185 return 0;
186 }
187 }
188
189 protected:
190 HBINT16 percentScaleDown[2];
191 HBUINT16 minHeight[2];
192 MathValueRecord mathValueRecords[51];
193 HBINT16 radicalDegreeBottomRaisePercent;
194
195 public:
196 DEFINE_SIZE_STATIC (214);
197 };
198
199 struct MathItalicsCorrectionInfo
200 {
201 bool subset (hb_subset_context_t *c) const
202 {
203 TRACE_SUBSET (this);
204 const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
205 const hb_map_t &glyph_map = *c->plan->glyph_map;
206
207 auto *out = c->serializer->start_embed (*this);
208 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
209
210 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
211 + hb_zip (this+coverage, italicsCorrection)
212 | hb_filter (glyphset, hb_first)
213 | hb_filter (serialize_math_record_array (c->serializer, out->italicsCorrection, this), hb_second)
214 | hb_map (hb_first)
215 | hb_map (glyph_map)
216 | hb_sink (new_coverage)
217 ;
218
219 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
220 return_trace (true);
221 }
222
223 bool sanitize (hb_sanitize_context_t *c) const
224 {
225 TRACE_SANITIZE (this);
226 return_trace (c->check_struct (this) &&
227 coverage.sanitize (c, this) &&
228 italicsCorrection.sanitize (c, this));
229 }
230
231 hb_position_t get_value (hb_codepoint_t glyph,
232 hb_font_t *font) const
233 {
234 unsigned int index = (this+coverage).get_coverage (glyph);
235 return italicsCorrection[index].get_x_value (font, this);
236 }
237
238 protected:
239 Offset16To<Coverage> coverage; /* Offset to Coverage table -
240 * from the beginning of
241 * MathItalicsCorrectionInfo
242 * table. */
243 Array16Of<MathValueRecord> italicsCorrection; /* Array of MathValueRecords
244 * defining italics correction
245 * values for each
246 * covered glyph. */
247
248 public:
249 DEFINE_SIZE_ARRAY (4, italicsCorrection);
250 };
251
252 struct MathTopAccentAttachment
253 {
254 bool subset (hb_subset_context_t *c) const
255 {
256 TRACE_SUBSET (this);
257 const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
258 const hb_map_t &glyph_map = *c->plan->glyph_map;
259
260 auto *out = c->serializer->start_embed (*this);
261 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
262
263 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
264 + hb_zip (this+topAccentCoverage, topAccentAttachment)
265 | hb_filter (glyphset, hb_first)
266 | hb_filter (serialize_math_record_array (c->serializer, out->topAccentAttachment, this), hb_second)
267 | hb_map (hb_first)
268 | hb_map (glyph_map)
269 | hb_sink (new_coverage)
270 ;
271
272 out->topAccentCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
273 return_trace (true);
274 }
275
276 bool sanitize (hb_sanitize_context_t *c) const
277 {
278 TRACE_SANITIZE (this);
279 return_trace (c->check_struct (this) &&
280 topAccentCoverage.sanitize (c, this) &&
281 topAccentAttachment.sanitize (c, this));
282 }
283
284 hb_position_t get_value (hb_codepoint_t glyph,
285 hb_font_t *font) const
286 {
287 unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
288 if (index == NOT_COVERED)
289 return font->get_glyph_h_advance (glyph) / 2;
290 return topAccentAttachment[index].get_x_value (font, this);
291 }
292
293 protected:
294 Offset16To<Coverage> topAccentCoverage; /* Offset to Coverage table -
295 * from the beginning of
296 * MathTopAccentAttachment
297 * table. */
298 Array16Of<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
299 * defining top accent
300 * attachment points for each
301 * covered glyph. */
302
303 public:
304 DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
305 };
306
307 struct MathKern
308 {
309 MathKern* copy (hb_serialize_context_t *c) const
310 {
311 TRACE_SERIALIZE (this);
312 auto *out = c->start_embed (this);
313 if (unlikely (!out)) return_trace (nullptr);
314
315 if (unlikely (!c->embed (heightCount))) return_trace (nullptr);
316
317 unsigned count = 2 * heightCount + 1;
318 for (unsigned i = 0; i < count; i++)
319 if (!c->copy (mathValueRecordsZ.arrayZ[i], this))
320 return_trace (nullptr);
321
322 return_trace (out);
323 }
324
325 bool sanitize_math_value_records (hb_sanitize_context_t *c) const
326 {
327 TRACE_SANITIZE (this);
328 unsigned int count = 2 * heightCount + 1;
329 for (unsigned int i = 0; i < count; i++)
330 if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false);
331 return_trace (true);
332 }
333
334 bool sanitize (hb_sanitize_context_t *c) const
335 {
336 TRACE_SANITIZE (this);
337 return_trace (c->check_struct (this) &&
338 c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) &&
339 sanitize_math_value_records (c));
340 }
341
342 hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
343 {
344 const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
345 const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
346 int sign = font->y_scale < 0 ? -1 : +1;
347
348 /* The description of the MathKern table is a ambiguous, but interpreting
349 * "between the two heights found at those indexes" for 0 < i < len as
350 *
351 * correctionHeight[i-1] < correction_height <= correctionHeight[i]
352 *
353 * makes the result consistent with the limit cases and we can just use the
354 * binary search algorithm of std::upper_bound:
355 */
356 unsigned int i = 0;
357 unsigned int count = heightCount;
358 while (count > 0)
359 {
360 unsigned int half = count / 2;
361 hb_position_t height = correctionHeight[i + half].get_y_value (font, this);
362 if (sign * height < sign * correction_height)
363 {
364 i += half + 1;
365 count -= half + 1;
366 } else
367 count = half;
368 }
369 return kernValue[i].get_x_value (font, this);
370 }
371
372 unsigned int get_entries (unsigned int start_offset,
373 unsigned int *entries_count, /* IN/OUT */
374 hb_ot_math_kern_entry_t *kern_entries, /* OUT */
375 hb_font_t *font) const
376 {
377 const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
378 const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
379 const unsigned int entriesCount = heightCount + 1;
380
381 if (entries_count)
382 {
383 unsigned int start = hb_min (start_offset, entriesCount);
384 unsigned int end = hb_min (start + *entries_count, entriesCount);
385 *entries_count = end - start;
386
387 for (unsigned int i = 0; i < *entries_count; i++) {
388 unsigned int j = start + i;
389
390 hb_position_t max_height;
391 if (j == heightCount) {
392 max_height = INT32_MAX;
393 } else {
394 max_height = correctionHeight[j].get_y_value (font, this);
395 }
396
397 kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)};
398 }
399 }
400 return entriesCount;
401 }
402
403 protected:
404 HBUINT16 heightCount;
405 UnsizedArrayOf<MathValueRecord>
406 mathValueRecordsZ;
407 /* Array of correction heights at
408 * which the kern value changes.
409 * Sorted by the height value in
410 * design units (heightCount entries),
411 * Followed by:
412 * Array of kern values corresponding
413 * to heights. (heightCount+1 entries).
414 */
415
416 public:
417 DEFINE_SIZE_ARRAY (2, mathValueRecordsZ);
418 };
419
420 struct MathKernInfoRecord
421 {
422 MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const
423 {
424 TRACE_SERIALIZE (this);
425 auto *out = c->embed (this);
426 if (unlikely (!out)) return_trace (nullptr);
427
428 unsigned count = ARRAY_LENGTH (mathKern);
429 for (unsigned i = 0; i < count; i++)
430 out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head);
431
432 return_trace (out);
433 }
434
435 bool sanitize (hb_sanitize_context_t *c, const void *base) const
436 {
437 TRACE_SANITIZE (this);
438
439 unsigned int count = ARRAY_LENGTH (mathKern);
440 for (unsigned int i = 0; i < count; i++)
441 if (unlikely (!mathKern[i].sanitize (c, base)))
442 return_trace (false);
443
444 return_trace (true);
445 }
446
447 hb_position_t get_kerning (hb_ot_math_kern_t kern,
448 hb_position_t correction_height,
449 hb_font_t *font,
450 const void *base) const
451 {
452 unsigned int idx = kern;
453 if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
454 return (base+mathKern[idx]).get_value (correction_height, font);
455 }
456
457 unsigned int get_kernings (hb_ot_math_kern_t kern,
458 unsigned int start_offset,
459 unsigned int *entries_count, /* IN/OUT */
460 hb_ot_math_kern_entry_t *kern_entries, /* OUT */
461 hb_font_t *font,
462 const void *base) const
463 {
464 unsigned int idx = kern;
465 if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) {
466 if (entries_count) *entries_count = 0;
467 return 0;
468 }
469 return (base+mathKern[idx]).get_entries (start_offset,
470 entries_count,
471 kern_entries,
472 font);
473 }
474
475 protected:
476 /* Offset to MathKern table for each corner -
477 * from the beginning of MathKernInfo table. May be NULL. */
478 Offset16To<MathKern> mathKern[4];
479
480 public:
481 DEFINE_SIZE_STATIC (8);
482 };
483
484 struct MathKernInfo
485 {
486 bool subset (hb_subset_context_t *c) const
487 {
488 TRACE_SUBSET (this);
489 const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
490 const hb_map_t &glyph_map = *c->plan->glyph_map;
491
492 auto *out = c->serializer->start_embed (*this);
493 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
494
495 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
496 + hb_zip (this+mathKernCoverage, mathKernInfoRecords)
497 | hb_filter (glyphset, hb_first)
498 | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second)
499 | hb_map (hb_first)
500 | hb_map (glyph_map)
501 | hb_sink (new_coverage)
502 ;
503
504 out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
505 return_trace (true);
506 }
507
508 bool sanitize (hb_sanitize_context_t *c) const
509 {
510 TRACE_SANITIZE (this);
511 return_trace (c->check_struct (this) &&
512 mathKernCoverage.sanitize (c, this) &&
513 mathKernInfoRecords.sanitize (c, this));
514 }
515
516 hb_position_t get_kerning (hb_codepoint_t glyph,
517 hb_ot_math_kern_t kern,
518 hb_position_t correction_height,
519 hb_font_t *font) const
520 {
521 unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
522 return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
523 }
524
525 unsigned int get_kernings (hb_codepoint_t glyph,
526 hb_ot_math_kern_t kern,
527 unsigned int start_offset,
528 unsigned int *entries_count, /* IN/OUT */
529 hb_ot_math_kern_entry_t *kern_entries, /* OUT */
530 hb_font_t *font) const
531 {
532 unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
533 return mathKernInfoRecords[index].get_kernings (kern,
534 start_offset,
535 entries_count,
536 kern_entries,
537 font,
538 this);
539 }
540
541 protected:
542 Offset16To<Coverage>
543 mathKernCoverage;
544 /* Offset to Coverage table -
545 * from the beginning of the
546 * MathKernInfo table. */
547 Array16Of<MathKernInfoRecord>
548 mathKernInfoRecords;
549 /* Array of MathKernInfoRecords,
550 * per-glyph information for
551 * mathematical positioning
552 * of subscripts and
553 * superscripts. */
554
555 public:
556 DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
557 };
558
559 struct MathGlyphInfo
560 {
561 bool subset (hb_subset_context_t *c) const
562 {
563 TRACE_SUBSET (this);
564 auto *out = c->serializer->embed (*this);
565 if (unlikely (!out)) return_trace (false);
566
567 out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this);
568 out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this);
569
570 const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
571 const hb_map_t &glyph_map = *c->plan->glyph_map;
572
573 auto it =
574 + hb_iter (this+extendedShapeCoverage)
575 | hb_filter (glyphset)
576 | hb_map_retains_sorting (glyph_map)
577 ;
578
579 if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
580 else out->extendedShapeCoverage = 0;
581
582 out->mathKernInfo.serialize_subset (c, mathKernInfo, this);
583 return_trace (true);
584 }
585
586 bool sanitize (hb_sanitize_context_t *c) const
587 {
588 TRACE_SANITIZE (this);
589 return_trace (c->check_struct (this) &&
590 mathItalicsCorrectionInfo.sanitize (c, this) &&
591 mathTopAccentAttachment.sanitize (c, this) &&
592 extendedShapeCoverage.sanitize (c, this) &&
593 mathKernInfo.sanitize (c, this));
594 }
595
596 hb_position_t
597 get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const
598 { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
599
600 hb_position_t
601 get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const
602 { return (this+mathTopAccentAttachment).get_value (glyph, font); }
603
604 bool is_extended_shape (hb_codepoint_t glyph) const
605 { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
606
607 hb_position_t get_kerning (hb_codepoint_t glyph,
608 hb_ot_math_kern_t kern,
609 hb_position_t correction_height,
610 hb_font_t *font) const
611 { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
612
613 hb_position_t get_kernings (hb_codepoint_t glyph,
614 hb_ot_math_kern_t kern,
615 unsigned int start_offset,
616 unsigned int *entries_count, /* IN/OUT */
617 hb_ot_math_kern_entry_t *kern_entries, /* OUT */
618 hb_font_t *font) const
619 { return (this+mathKernInfo).get_kernings (glyph,
620 kern,
621 start_offset,
622 entries_count,
623 kern_entries,
624 font); }
625
626 protected:
627 /* Offset to MathItalicsCorrectionInfo table -
628 * from the beginning of MathGlyphInfo table. */
629 Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
630
631 /* Offset to MathTopAccentAttachment table -
632 * from the beginning of MathGlyphInfo table. */
633 Offset16To<MathTopAccentAttachment> mathTopAccentAttachment;
634
635 /* Offset to coverage table for Extended Shape glyphs -
636 * from the beginning of MathGlyphInfo table. When the left or right glyph of
637 * a box is an extended shape variant, the (ink) box (and not the default
638 * position defined by values in MathConstants table) should be used for
639 * vertical positioning purposes. May be NULL.. */
640 Offset16To<Coverage> extendedShapeCoverage;
641
642 /* Offset to MathKernInfo table -
643 * from the beginning of MathGlyphInfo table. */
644 Offset16To<MathKernInfo> mathKernInfo;
645
646 public:
647 DEFINE_SIZE_STATIC (8);
648 };
649
650 struct MathGlyphVariantRecord
651 {
652 friend struct MathGlyphConstruction;
653
654 bool subset (hb_subset_context_t *c) const
655 {
656 TRACE_SUBSET (this);
657 auto *out = c->serializer->embed (this);
658 if (unlikely (!out)) return_trace (false);
659
660 const hb_map_t& glyph_map = *c->plan->glyph_map;
661 return_trace (c->serializer->check_assign (out->variantGlyph, glyph_map.get (variantGlyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
662 }
663
664 bool sanitize (hb_sanitize_context_t *c) const
665 {
666 TRACE_SANITIZE (this);
667 return_trace (c->check_struct (this));
668 }
669
670 void closure_glyphs (hb_set_t *variant_glyphs) const
671 { variant_glyphs->add (variantGlyph); }
672
673 protected:
674 HBGlyphID16 variantGlyph; /* Glyph ID for the variant. */
675 HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the
676 * variant, in the direction of requested
677 * glyph extension. */
678
679 public:
680 DEFINE_SIZE_STATIC (4);
681 };
682
683 struct PartFlags : HBUINT16
684 {
685 enum Flags {
686 Extender = 0x0001u, /* If set, the part can be skipped or repeated. */
687
688 Defined = 0x0001u, /* All defined flags. */
689 };
690
691 public:
692 DEFINE_SIZE_STATIC (2);
693 };
694
695 struct MathGlyphPartRecord
696 {
697 bool subset (hb_subset_context_t *c) const
698 {
699 TRACE_SUBSET (this);
700 auto *out = c->serializer->embed (this);
701 if (unlikely (!out)) return_trace (false);
702
703 const hb_map_t& glyph_map = *c->plan->glyph_map;
704 return_trace (c->serializer->check_assign (out->glyph, glyph_map.get (glyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
705 }
706
707 bool sanitize (hb_sanitize_context_t *c) const
708 {
709 TRACE_SANITIZE (this);
710 return_trace (c->check_struct (this));
711 }
712
713 void extract (hb_ot_math_glyph_part_t &out,
714 int64_t mult,
715 hb_font_t *font) const
716 {
717 out.glyph = glyph;
718
719 out.start_connector_length = font->em_mult (startConnectorLength, mult);
720 out.end_connector_length = font->em_mult (endConnectorLength, mult);
721 out.full_advance = font->em_mult (fullAdvance, mult);
722
723 static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER ==
724 (unsigned int) PartFlags::Extender, "");
725
726 out.flags = (hb_ot_math_glyph_part_flags_t)
727 (unsigned int)
728 (partFlags & PartFlags::Defined);
729 }
730
731 void closure_glyphs (hb_set_t *variant_glyphs) const
732 { variant_glyphs->add (glyph); }
733
734 protected:
735 HBGlyphID16 glyph; /* Glyph ID for the part. */
736 HBUINT16 startConnectorLength;
737 /* Advance width/ height of the straight bar
738 * connector material, in design units, is at
739 * the beginning of the glyph, in the
740 * direction of the extension. */
741 HBUINT16 endConnectorLength;
742 /* Advance width/ height of the straight bar
743 * connector material, in design units, is at
744 * the end of the glyph, in the direction of
745 * the extension. */
746 HBUINT16 fullAdvance; /* Full advance width/height for this part,
747 * in the direction of the extension.
748 * In design units. */
749 PartFlags partFlags; /* Part qualifiers. */
750
751 public:
752 DEFINE_SIZE_STATIC (10);
753 };
754
755 struct MathGlyphAssembly
756 {
757 bool subset (hb_subset_context_t *c) const
758 {
759 TRACE_SUBSET (this);
760 auto *out = c->serializer->start_embed (*this);
761 if (unlikely (!out)) return_trace (false);
762
763 if (!c->serializer->copy (italicsCorrection, this)) return_trace (false);
764 if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false);
765
766 for (const auto& record : partRecords.iter ())
767 if (!record.subset (c)) return_trace (false);
768 return_trace (true);
769 }
770
771 bool sanitize (hb_sanitize_context_t *c) const
772 {
773 TRACE_SANITIZE (this);
774 return_trace (c->check_struct (this) &&
775 italicsCorrection.sanitize (c, this) &&
776 partRecords.sanitize (c));
777 }
778
779 unsigned int get_parts (hb_direction_t direction,
780 hb_font_t *font,
781 unsigned int start_offset,
782 unsigned int *parts_count, /* IN/OUT */
783 hb_ot_math_glyph_part_t *parts /* OUT */,
784 hb_position_t *italics_correction /* OUT */) const
785 {
786 if (parts_count)
787 {
788 int64_t mult = font->dir_mult (direction);
789 for (auto _ : hb_zip (partRecords.as_array ().sub_array (start_offset, parts_count),
790 hb_array (parts, *parts_count)))
791 _.first.extract (_.second, mult, font);
792 }
793
794 if (italics_correction)
795 *italics_correction = italicsCorrection.get_x_value (font, this);
796
797 return partRecords.len;
798 }
799
800 void closure_glyphs (hb_set_t *variant_glyphs) const
801 {
802 for (const auto& _ : partRecords.iter ())
803 _.closure_glyphs (variant_glyphs);
804 }
805
806 protected:
807 MathValueRecord
808 italicsCorrection;
809 /* Italics correction of this
810 * MathGlyphAssembly. Should not
811 * depend on the assembly size. */
812 Array16Of<MathGlyphPartRecord>
813 partRecords; /* Array of part records, from
814 * left to right and bottom to
815 * top. */
816
817 public:
818 DEFINE_SIZE_ARRAY (6, partRecords);
819 };
820
821 struct MathGlyphConstruction
822 {
823 bool subset (hb_subset_context_t *c) const
824 {
825 TRACE_SUBSET (this);
826 auto *out = c->serializer->start_embed (*this);
827 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
828
829 out->glyphAssembly.serialize_subset (c, glyphAssembly, this);
830
831 if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW))
832 return_trace (false);
833 for (const auto& record : mathGlyphVariantRecord.iter ())
834 if (!record.subset (c)) return_trace (false);
835
836 return_trace (true);
837 }
838
839 bool sanitize (hb_sanitize_context_t *c) const
840 {
841 TRACE_SANITIZE (this);
842 return_trace (c->check_struct (this) &&
843 glyphAssembly.sanitize (c, this) &&
844 mathGlyphVariantRecord.sanitize (c));
845 }
846
847 const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; }
848
849 unsigned int get_variants (hb_direction_t direction,
850 hb_font_t *font,
851 unsigned int start_offset,
852 unsigned int *variants_count, /* IN/OUT */
853 hb_ot_math_glyph_variant_t *variants /* OUT */) const
854 {
855 if (variants_count)
856 {
857 int64_t mult = font->dir_mult (direction);
858 for (auto _ : hb_zip (mathGlyphVariantRecord.as_array ().sub_array (start_offset, variants_count),
859 hb_array (variants, *variants_count)))
860 _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
861 }
862 return mathGlyphVariantRecord.len;
863 }
864
865 void closure_glyphs (hb_set_t *variant_glyphs) const
866 {
867 (this+glyphAssembly).closure_glyphs (variant_glyphs);
868
869 for (const auto& _ : mathGlyphVariantRecord.iter ())
870 _.closure_glyphs (variant_glyphs);
871 }
872
873 protected:
874 /* Offset to MathGlyphAssembly table for this shape - from the beginning of
875 MathGlyphConstruction table. May be NULL. */
876 Offset16To<MathGlyphAssembly> glyphAssembly;
877
878 /* MathGlyphVariantRecords for alternative variants of the glyphs. */
879 Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord;
880
881 public:
882 DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
883 };
884
885 struct MathVariants
886 {
887 void closure_glyphs (const hb_set_t *glyph_set,
888 hb_set_t *variant_glyphs) const
889 {
890 const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount);
891
892 if (vertGlyphCoverage)
893 {
894 const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount);
895 + hb_zip (this+vertGlyphCoverage, vert_offsets)
896 | hb_filter (glyph_set, hb_first)
897 | hb_map (hb_second)
898 | hb_map (hb_add (this))
899 | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
900 ;
901 }
902
903 if (horizGlyphCoverage)
904 {
905 const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount);
906 + hb_zip (this+horizGlyphCoverage, hori_offsets)
907 | hb_filter (glyph_set, hb_first)
908 | hb_map (hb_second)
909 | hb_map (hb_add (this))
910 | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
911 ;
912 }
913 }
914
915 void collect_coverage_and_indices (hb_sorted_vector_t<hb_codepoint_t>& new_coverage,
916 const Offset16To<Coverage>& coverage,
917 unsigned i,
918 unsigned end_index,
919 hb_set_t& indices,
920 const hb_set_t& glyphset,
921 const hb_map_t& glyph_map) const
922 {
923 if (!coverage) return;
924
925 for (const auto _ : (this+coverage).iter ())
926 {
927 if (i >= end_index) return;
928 if (glyphset.has (_))
929 {
930 unsigned new_gid = glyph_map.get (_);
931 new_coverage.push (new_gid);
932 indices.add (i);
933 }
934 i++;
935 }
936 }
937
938 bool subset (hb_subset_context_t *c) const
939 {
940 TRACE_SUBSET (this);
941 const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
942 const hb_map_t &glyph_map = *c->plan->glyph_map;
943
944 auto *out = c->serializer->start_embed (*this);
945 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
946 if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW))
947 return_trace (false);
948
949 hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage;
950 hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage;
951 hb_set_t indices;
952 collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map);
953 collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map);
954
955 if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
956 return_trace (false);
957 if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
958 return_trace (false);
959
960 for (unsigned i : indices.iter ())
961 {
962 auto *o = c->serializer->embed (glyphConstruction[i]);
963 if (!o) return_trace (false);
964 o->serialize_subset (c, glyphConstruction[i], this);
965 }
966
967 if (new_vert_coverage)
968 out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
969
970 if (new_hori_coverage)
971 out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
972 return_trace (true);
973 }
974
975 bool sanitize_offsets (hb_sanitize_context_t *c) const
976 {
977 TRACE_SANITIZE (this);
978 unsigned int count = vertGlyphCount + horizGlyphCount;
979 for (unsigned int i = 0; i < count; i++)
980 if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false);
981 return_trace (true);
982 }
983
984 bool sanitize (hb_sanitize_context_t *c) const
985 {
986 TRACE_SANITIZE (this);
987 return_trace (c->check_struct (this) &&
988 vertGlyphCoverage.sanitize (c, this) &&
989 horizGlyphCoverage.sanitize (c, this) &&
990 c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) &&
991 sanitize_offsets (c));
992 }
993
994 hb_position_t get_min_connector_overlap (hb_direction_t direction,
995 hb_font_t *font) const
996 { return font->em_scale_dir (minConnectorOverlap, direction); }
997
998 unsigned int get_glyph_variants (hb_codepoint_t glyph,
999 hb_direction_t direction,
1000 hb_font_t *font,
1001 unsigned int start_offset,
1002 unsigned int *variants_count, /* IN/OUT */
1003 hb_ot_math_glyph_variant_t *variants /* OUT */) const
1004 { return get_glyph_construction (glyph, direction, font)
1005 .get_variants (direction, font, start_offset, variants_count, variants); }
1006
1007 unsigned int get_glyph_parts (hb_codepoint_t glyph,
1008 hb_direction_t direction,
1009 hb_font_t *font,
1010 unsigned int start_offset,
1011 unsigned int *parts_count, /* IN/OUT */
1012 hb_ot_math_glyph_part_t *parts /* OUT */,
1013 hb_position_t *italics_correction /* OUT */) const
1014 { return get_glyph_construction (glyph, direction, font)
1015 .get_assembly ()
1016 .get_parts (direction, font,
1017 start_offset, parts_count, parts,
1018 italics_correction); }
1019
1020 private:
1021 const MathGlyphConstruction &
1022 get_glyph_construction (hb_codepoint_t glyph,
1023 hb_direction_t direction,
1024 hb_font_t *font HB_UNUSED) const
1025 {
1026 bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
1027 unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
1028 const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage
1029 : horizGlyphCoverage;
1030
1031 unsigned int index = (this+coverage).get_coverage (glyph);
1032 if (unlikely (index >= count)) return Null (MathGlyphConstruction);
1033
1034 if (!vertical)
1035 index += vertGlyphCount;
1036
1037 return this+glyphConstruction[index];
1038 }
1039
1040 protected:
1041 HBUINT16 minConnectorOverlap;
1042 /* Minimum overlap of connecting
1043 * glyphs during glyph construction,
1044 * in design units. */
1045 Offset16To<Coverage> vertGlyphCoverage;
1046 /* Offset to Coverage table -
1047 * from the beginning of MathVariants
1048 * table. */
1049 Offset16To<Coverage> horizGlyphCoverage;
1050 /* Offset to Coverage table -
1051 * from the beginning of MathVariants
1052 * table. */
1053 HBUINT16 vertGlyphCount; /* Number of glyphs for which
1054 * information is provided for
1055 * vertically growing variants. */
1056 HBUINT16 horizGlyphCount;/* Number of glyphs for which
1057 * information is provided for
1058 * horizontally growing variants. */
1059
1060 /* Array of offsets to MathGlyphConstruction tables - from the beginning of
1061 the MathVariants table, for shapes growing in vertical/horizontal
1062 direction. */
1063 UnsizedArrayOf<Offset16To<MathGlyphConstruction>>
1064 glyphConstruction;
1065
1066 public:
1067 DEFINE_SIZE_ARRAY (10, glyphConstruction);
1068 };
1069
1070
1071 /*
1072 * MATH -- Mathematical typesetting
1073 * https://docs.microsoft.com/en-us/typography/opentype/spec/math
1074 */
1075
1076 struct MATH
1077 {
1078 static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH;
1079
1080 bool has_data () const { return version.to_int (); }
1081
1082 void closure_glyphs (hb_set_t *glyph_set) const
1083 {
1084 if (mathVariants)
1085 {
1086 hb_set_t variant_glyphs;
1087 (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs);
1088 hb_set_union (glyph_set, &variant_glyphs);
1089 }
1090 }
1091
1092 bool subset (hb_subset_context_t *c) const
1093 {
1094 TRACE_SUBSET (this);
1095 auto *out = c->serializer->embed (*this);
1096 if (unlikely (!out)) return_trace (false);
1097
1098 out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head);
1099 out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this);
1100 out->mathVariants.serialize_subset (c, mathVariants, this);
1101 return_trace (true);
1102 }
1103
1104 bool sanitize (hb_sanitize_context_t *c) const
1105 {
1106 TRACE_SANITIZE (this);
1107 return_trace (version.sanitize (c) &&
1108 likely (version.major == 1) &&
1109 mathConstants.sanitize (c, this) &&
1110 mathGlyphInfo.sanitize (c, this) &&
1111 mathVariants.sanitize (c, this));
1112 }
1113
1114 hb_position_t get_constant (hb_ot_math_constant_t constant,
1115 hb_font_t *font) const
1116 { return (this+mathConstants).get_value (constant, font); }
1117
1118 const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; }
1119
1120 const MathVariants &get_variants () const { return this+mathVariants; }
1121
1122 protected:
1123 FixedVersion<>version; /* Version of the MATH table
1124 * initially set to 0x00010000u */
1125 Offset16To<MathConstants>
1126 mathConstants; /* MathConstants table */
1127 Offset16To<MathGlyphInfo>
1128 mathGlyphInfo; /* MathGlyphInfo table */
1129 Offset16To<MathVariants>
1130 mathVariants; /* MathVariants table */
1131
1132 public:
1133 DEFINE_SIZE_STATIC (10);
1134 };
1135
1136 } /* namespace OT */
1137
1138
1139 #endif /* HB_OT_MATH_TABLE_HH */