2 * Copyright © 2016 Igalia S.L.
4 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
24 * Igalia Author(s): Frédéric Wang
27 #ifndef HB_OT_MATH_TABLE_HH
28 #define HB_OT_MATH_TABLE_HH
30 #include "hb-open-type.hh"
31 #include "hb-ot-layout-common.hh"
32 #include "hb-ot-math.h"
37 struct MathValueRecord
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
); }
44 MathValueRecord
* copy (hb_serialize_context_t
*c
, const void *base
) const
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
);
54 bool sanitize (hb_sanitize_context_t
*c
, const void *base
) const
56 TRACE_SANITIZE (this);
57 return_trace (c
->check_struct (this) && deviceTable
.sanitize (c
, base
));
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. */
67 DEFINE_SIZE_STATIC (4);
72 MathConstants
* copy (hb_serialize_context_t
*c
) const
74 TRACE_SERIALIZE (this);
75 auto *out
= c
->start_embed (this);
77 HBINT16
*p
= c
->allocate_size
<HBINT16
> (HBINT16::static_size
* 2);
78 if (unlikely (!p
)) return_trace (nullptr);
79 hb_memcpy (p
, percentScaleDown
, HBINT16::static_size
* 2);
81 HBUINT16
*m
= c
->allocate_size
<HBUINT16
> (HBUINT16::static_size
* 2);
82 if (unlikely (!m
)) return_trace (nullptr);
83 hb_memcpy (m
, minHeight
, HBUINT16::static_size
* 2);
85 unsigned count
= ARRAY_LENGTH (mathValueRecords
);
86 for (unsigned i
= 0; i
< count
; i
++)
87 if (!c
->copy (mathValueRecords
[i
], this))
88 return_trace (nullptr);
90 if (!c
->embed (radicalDegreeBottomRaisePercent
)) return_trace (nullptr);
94 bool sanitize_math_value_records (hb_sanitize_context_t
*c
) const
96 TRACE_SANITIZE (this);
98 unsigned int count
= ARRAY_LENGTH (mathValueRecords
);
99 for (unsigned int i
= 0; i
< count
; i
++)
100 if (!mathValueRecords
[i
].sanitize (c
, this))
101 return_trace (false);
106 bool sanitize (hb_sanitize_context_t
*c
) const
108 TRACE_SANITIZE (this);
109 return_trace (c
->check_struct (this) && sanitize_math_value_records (c
));
112 hb_position_t
get_value (hb_ot_math_constant_t constant
,
113 hb_font_t
*font
) const
117 case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN
:
118 case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN
:
119 return percentScaleDown
[constant
- HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN
];
121 case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT
:
122 case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT
:
123 return font
->em_scale_y (minHeight
[constant
- HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT
]);
125 case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE
:
126 case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE
:
127 case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP
:
128 case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT
:
129 return mathValueRecords
[constant
- HB_OT_MATH_CONSTANT_MATH_LEADING
].get_x_value (font
, this);
131 case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT
:
132 case HB_OT_MATH_CONSTANT_AXIS_HEIGHT
:
133 case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT
:
134 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN
:
135 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN
:
136 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN
:
137 case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN
:
138 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP
:
139 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN
:
140 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP
:
141 case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN
:
142 case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS
:
143 case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN
:
144 case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN
:
145 case HB_OT_MATH_CONSTANT_MATH_LEADING
:
146 case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER
:
147 case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS
:
148 case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP
:
149 case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP
:
150 case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER
:
151 case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS
:
152 case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP
:
153 case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP
:
154 case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN
:
155 case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN
:
156 case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN
:
157 case HB_OT_MATH_CONSTANT_STACK_GAP_MIN
:
158 case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP
:
159 case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP
:
160 case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN
:
161 case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN
:
162 case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN
:
163 case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP
:
164 case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN
:
165 case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN
:
166 case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX
:
167 case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN
:
168 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX
:
169 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT
:
170 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN
:
171 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP
:
172 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED
:
173 case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER
:
174 case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS
:
175 case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP
:
176 case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN
:
177 case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN
:
178 return mathValueRecords
[constant
- HB_OT_MATH_CONSTANT_MATH_LEADING
].get_y_value (font
, this);
180 case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT
:
181 return radicalDegreeBottomRaisePercent
;
189 HBINT16 percentScaleDown
[2];
190 HBUINT16 minHeight
[2];
191 MathValueRecord mathValueRecords
[51];
192 HBINT16 radicalDegreeBottomRaisePercent
;
195 DEFINE_SIZE_STATIC (214);
198 struct MathItalicsCorrectionInfo
200 bool subset (hb_subset_context_t
*c
) const
203 const hb_set_t
&glyphset
= c
->plan
->_glyphset_mathed
;
204 const hb_map_t
&glyph_map
= *c
->plan
->glyph_map
;
206 auto *out
= c
->serializer
->start_embed (*this);
207 if (unlikely (!c
->serializer
->extend_min (out
))) return_trace (false);
209 hb_sorted_vector_t
<hb_codepoint_t
> new_coverage
;
210 + hb_zip (this+coverage
, italicsCorrection
)
211 | hb_filter (glyphset
, hb_first
)
212 | hb_filter (serialize_math_record_array (c
->serializer
, out
->italicsCorrection
, this), hb_second
)
215 | hb_sink (new_coverage
)
218 out
->coverage
.serialize_serialize (c
->serializer
, new_coverage
.iter ());
222 bool sanitize (hb_sanitize_context_t
*c
) const
224 TRACE_SANITIZE (this);
225 return_trace (c
->check_struct (this) &&
226 coverage
.sanitize (c
, this) &&
227 italicsCorrection
.sanitize (c
, this));
230 hb_position_t
get_value (hb_codepoint_t glyph
,
231 hb_font_t
*font
) const
233 unsigned int index
= (this+coverage
).get_coverage (glyph
);
234 return italicsCorrection
[index
].get_x_value (font
, this);
238 Offset16To
<Coverage
> coverage
; /* Offset to Coverage table -
239 * from the beginning of
240 * MathItalicsCorrectionInfo
242 Array16Of
<MathValueRecord
> italicsCorrection
; /* Array of MathValueRecords
243 * defining italics correction
248 DEFINE_SIZE_ARRAY (4, italicsCorrection
);
251 struct MathTopAccentAttachment
253 bool subset (hb_subset_context_t
*c
) const
256 const hb_set_t
&glyphset
= c
->plan
->_glyphset_mathed
;
257 const hb_map_t
&glyph_map
= *c
->plan
->glyph_map
;
259 auto *out
= c
->serializer
->start_embed (*this);
260 if (unlikely (!c
->serializer
->extend_min (out
))) return_trace (false);
262 hb_sorted_vector_t
<hb_codepoint_t
> new_coverage
;
263 + hb_zip (this+topAccentCoverage
, topAccentAttachment
)
264 | hb_filter (glyphset
, hb_first
)
265 | hb_filter (serialize_math_record_array (c
->serializer
, out
->topAccentAttachment
, this), hb_second
)
268 | hb_sink (new_coverage
)
271 out
->topAccentCoverage
.serialize_serialize (c
->serializer
, new_coverage
.iter ());
275 bool sanitize (hb_sanitize_context_t
*c
) const
277 TRACE_SANITIZE (this);
278 return_trace (c
->check_struct (this) &&
279 topAccentCoverage
.sanitize (c
, this) &&
280 topAccentAttachment
.sanitize (c
, this));
283 hb_position_t
get_value (hb_codepoint_t glyph
,
284 hb_font_t
*font
) const
286 unsigned int index
= (this+topAccentCoverage
).get_coverage (glyph
);
287 if (index
== NOT_COVERED
)
288 return font
->get_glyph_h_advance (glyph
) / 2;
289 return topAccentAttachment
[index
].get_x_value (font
, this);
293 Offset16To
<Coverage
> topAccentCoverage
; /* Offset to Coverage table -
294 * from the beginning of
295 * MathTopAccentAttachment
297 Array16Of
<MathValueRecord
> topAccentAttachment
; /* Array of MathValueRecords
298 * defining top accent
299 * attachment points for each
303 DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment
);
308 MathKern
* copy (hb_serialize_context_t
*c
) const
310 TRACE_SERIALIZE (this);
311 auto *out
= c
->start_embed (this);
313 if (unlikely (!c
->embed (heightCount
))) return_trace (nullptr);
315 unsigned count
= 2 * heightCount
+ 1;
316 for (unsigned i
= 0; i
< count
; i
++)
317 if (!c
->copy (mathValueRecordsZ
.arrayZ
[i
], this))
318 return_trace (nullptr);
323 bool sanitize_math_value_records (hb_sanitize_context_t
*c
) const
325 TRACE_SANITIZE (this);
326 unsigned int count
= 2 * heightCount
+ 1;
327 for (unsigned int i
= 0; i
< count
; i
++)
328 if (!mathValueRecordsZ
.arrayZ
[i
].sanitize (c
, this)) return_trace (false);
332 bool sanitize (hb_sanitize_context_t
*c
) const
334 TRACE_SANITIZE (this);
335 return_trace (c
->check_struct (this) &&
337 c
->check_array (mathValueRecordsZ
.arrayZ
, 2 * heightCount
+ 1) &&
338 sanitize_math_value_records (c
));
341 hb_position_t
get_value (hb_position_t correction_height
, hb_font_t
*font
) const
343 const MathValueRecord
* correctionHeight
= mathValueRecordsZ
.arrayZ
;
344 const MathValueRecord
* kernValue
= mathValueRecordsZ
.arrayZ
+ heightCount
;
345 int sign
= font
->y_scale
< 0 ? -1 : +1;
347 /* The description of the MathKern table is a ambiguous, but interpreting
348 * "between the two heights found at those indexes" for 0 < i < len as
350 * correctionHeight[i-1] < correction_height <= correctionHeight[i]
352 * makes the result consistent with the limit cases and we can just use the
353 * binary search algorithm of std::upper_bound:
356 unsigned int count
= heightCount
;
359 unsigned int half
= count
/ 2;
360 hb_position_t height
= correctionHeight
[i
+ half
].get_y_value (font
, this);
361 if (sign
* height
< sign
* correction_height
)
368 return kernValue
[i
].get_x_value (font
, this);
371 unsigned int get_entries (unsigned int start_offset
,
372 unsigned int *entries_count
, /* IN/OUT */
373 hb_ot_math_kern_entry_t
*kern_entries
, /* OUT */
374 hb_font_t
*font
) const
376 const MathValueRecord
* correctionHeight
= mathValueRecordsZ
.arrayZ
;
377 const MathValueRecord
* kernValue
= mathValueRecordsZ
.arrayZ
+ heightCount
;
378 const unsigned int entriesCount
= heightCount
+ 1;
382 unsigned int start
= hb_min (start_offset
, entriesCount
);
383 unsigned int end
= hb_min (start
+ *entries_count
, entriesCount
);
384 *entries_count
= end
- start
;
386 for (unsigned int i
= 0; i
< *entries_count
; i
++) {
387 unsigned int j
= start
+ i
;
389 hb_position_t max_height
;
390 if (j
== heightCount
) {
391 max_height
= INT32_MAX
;
393 max_height
= correctionHeight
[j
].get_y_value (font
, this);
396 kern_entries
[i
] = {max_height
, kernValue
[j
].get_x_value (font
, this)};
403 HBUINT16 heightCount
;
404 UnsizedArrayOf
<MathValueRecord
>
406 /* Array of correction heights at
407 * which the kern value changes.
408 * Sorted by the height value in
409 * design units (heightCount entries),
411 * Array of kern values corresponding
412 * to heights. (heightCount+1 entries).
416 DEFINE_SIZE_ARRAY (2, mathValueRecordsZ
);
419 struct MathKernInfoRecord
421 MathKernInfoRecord
* copy (hb_serialize_context_t
*c
, const void *base
) const
423 TRACE_SERIALIZE (this);
424 auto *out
= c
->embed (this);
425 if (unlikely (!out
)) return_trace (nullptr);
427 unsigned count
= ARRAY_LENGTH (mathKern
);
428 for (unsigned i
= 0; i
< count
; i
++)
429 out
->mathKern
[i
].serialize_copy (c
, mathKern
[i
], base
, 0, hb_serialize_context_t::Head
);
434 bool sanitize (hb_sanitize_context_t
*c
, const void *base
) const
436 TRACE_SANITIZE (this);
438 unsigned int count
= ARRAY_LENGTH (mathKern
);
439 for (unsigned int i
= 0; i
< count
; i
++)
440 if (unlikely (!mathKern
[i
].sanitize (c
, base
)))
441 return_trace (false);
446 hb_position_t
get_kerning (hb_ot_math_kern_t kern
,
447 hb_position_t correction_height
,
449 const void *base
) const
451 unsigned int idx
= kern
;
452 if (unlikely (idx
>= ARRAY_LENGTH (mathKern
))) return 0;
453 return (base
+mathKern
[idx
]).get_value (correction_height
, font
);
456 unsigned int get_kernings (hb_ot_math_kern_t kern
,
457 unsigned int start_offset
,
458 unsigned int *entries_count
, /* IN/OUT */
459 hb_ot_math_kern_entry_t
*kern_entries
, /* OUT */
461 const void *base
) const
463 unsigned int idx
= kern
;
464 if (unlikely (idx
>= ARRAY_LENGTH (mathKern
)) || !mathKern
[idx
]) {
465 if (entries_count
) *entries_count
= 0;
468 return (base
+mathKern
[idx
]).get_entries (start_offset
,
475 /* Offset to MathKern table for each corner -
476 * from the beginning of MathKernInfo table. May be NULL. */
477 Offset16To
<MathKern
> mathKern
[4];
480 DEFINE_SIZE_STATIC (8);
485 bool subset (hb_subset_context_t
*c
) const
488 const hb_set_t
&glyphset
= c
->plan
->_glyphset_mathed
;
489 const hb_map_t
&glyph_map
= *c
->plan
->glyph_map
;
491 auto *out
= c
->serializer
->start_embed (*this);
492 if (unlikely (!c
->serializer
->extend_min (out
))) return_trace (false);
494 hb_sorted_vector_t
<hb_codepoint_t
> new_coverage
;
495 + hb_zip (this+mathKernCoverage
, mathKernInfoRecords
)
496 | hb_filter (glyphset
, hb_first
)
497 | hb_filter (serialize_math_record_array (c
->serializer
, out
->mathKernInfoRecords
, this), hb_second
)
500 | hb_sink (new_coverage
)
503 out
->mathKernCoverage
.serialize_serialize (c
->serializer
, new_coverage
.iter ());
507 bool sanitize (hb_sanitize_context_t
*c
) const
509 TRACE_SANITIZE (this);
510 return_trace (c
->check_struct (this) &&
511 mathKernCoverage
.sanitize (c
, this) &&
512 mathKernInfoRecords
.sanitize (c
, this));
515 hb_position_t
get_kerning (hb_codepoint_t glyph
,
516 hb_ot_math_kern_t kern
,
517 hb_position_t correction_height
,
518 hb_font_t
*font
) const
520 unsigned int index
= (this+mathKernCoverage
).get_coverage (glyph
);
521 return mathKernInfoRecords
[index
].get_kerning (kern
, correction_height
, font
, this);
524 unsigned int get_kernings (hb_codepoint_t glyph
,
525 hb_ot_math_kern_t kern
,
526 unsigned int start_offset
,
527 unsigned int *entries_count
, /* IN/OUT */
528 hb_ot_math_kern_entry_t
*kern_entries
, /* OUT */
529 hb_font_t
*font
) const
531 unsigned int index
= (this+mathKernCoverage
).get_coverage (glyph
);
532 return mathKernInfoRecords
[index
].get_kernings (kern
,
543 /* Offset to Coverage table -
544 * from the beginning of the
545 * MathKernInfo table. */
546 Array16Of
<MathKernInfoRecord
>
548 /* Array of MathKernInfoRecords,
549 * per-glyph information for
550 * mathematical positioning
555 DEFINE_SIZE_ARRAY (4, mathKernInfoRecords
);
560 bool subset (hb_subset_context_t
*c
) const
563 auto *out
= c
->serializer
->embed (*this);
564 if (unlikely (!out
)) return_trace (false);
566 out
->mathItalicsCorrectionInfo
.serialize_subset (c
, mathItalicsCorrectionInfo
, this);
567 out
->mathTopAccentAttachment
.serialize_subset (c
, mathTopAccentAttachment
, this);
569 const hb_set_t
&glyphset
= c
->plan
->_glyphset_mathed
;
570 const hb_map_t
&glyph_map
= *c
->plan
->glyph_map
;
573 + hb_iter (this+extendedShapeCoverage
)
574 | hb_take (c
->plan
->source
->get_num_glyphs ())
575 | hb_filter (glyphset
)
576 | hb_map_retains_sorting (glyph_map
)
579 if (it
) out
->extendedShapeCoverage
.serialize_serialize (c
->serializer
, it
);
580 else out
->extendedShapeCoverage
= 0;
582 out
->mathKernInfo
.serialize_subset (c
, mathKernInfo
, this);
586 bool sanitize (hb_sanitize_context_t
*c
) const
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));
597 get_italics_correction (hb_codepoint_t glyph
, hb_font_t
*font
) const
598 { return (this+mathItalicsCorrectionInfo
).get_value (glyph
, font
); }
601 get_top_accent_attachment (hb_codepoint_t glyph
, hb_font_t
*font
) const
602 { return (this+mathTopAccentAttachment
).get_value (glyph
, font
); }
604 bool is_extended_shape (hb_codepoint_t glyph
) const
605 { return (this+extendedShapeCoverage
).get_coverage (glyph
) != NOT_COVERED
; }
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
); }
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
,
627 /* Offset to MathItalicsCorrectionInfo table -
628 * from the beginning of MathGlyphInfo table. */
629 Offset16To
<MathItalicsCorrectionInfo
> mathItalicsCorrectionInfo
;
631 /* Offset to MathTopAccentAttachment table -
632 * from the beginning of MathGlyphInfo table. */
633 Offset16To
<MathTopAccentAttachment
> mathTopAccentAttachment
;
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
;
642 /* Offset to MathKernInfo table -
643 * from the beginning of MathGlyphInfo table. */
644 Offset16To
<MathKernInfo
> mathKernInfo
;
647 DEFINE_SIZE_STATIC (8);
650 struct MathGlyphVariantRecord
652 friend struct MathGlyphConstruction
;
654 bool subset (hb_subset_context_t
*c
) const
657 auto *out
= c
->serializer
->embed (this);
658 if (unlikely (!out
)) return_trace (false);
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
));
664 bool sanitize (hb_sanitize_context_t
*c
) const
666 TRACE_SANITIZE (this);
667 return_trace (c
->check_struct (this));
670 void closure_glyphs (hb_set_t
*variant_glyphs
) const
671 { variant_glyphs
->add (variantGlyph
); }
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. */
680 DEFINE_SIZE_STATIC (4);
683 struct PartFlags
: HBUINT16
686 Extender
= 0x0001u
, /* If set, the part can be skipped or repeated. */
688 Defined
= 0x0001u
, /* All defined flags. */
692 DEFINE_SIZE_STATIC (2);
695 struct MathGlyphPartRecord
697 bool subset (hb_subset_context_t
*c
) const
700 auto *out
= c
->serializer
->embed (this);
701 if (unlikely (!out
)) return_trace (false);
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
));
707 bool sanitize (hb_sanitize_context_t
*c
) const
709 TRACE_SANITIZE (this);
710 return_trace (c
->check_struct (this));
713 void extract (hb_ot_math_glyph_part_t
&out
,
715 hb_font_t
*font
) const
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
);
723 static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER
==
724 (unsigned int) PartFlags::Extender
, "");
726 out
.flags
= (hb_ot_math_glyph_part_flags_t
)
728 (partFlags
& PartFlags::Defined
);
731 void closure_glyphs (hb_set_t
*variant_glyphs
) const
732 { variant_glyphs
->add (glyph
); }
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
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. */
752 DEFINE_SIZE_STATIC (10);
755 struct MathGlyphAssembly
757 bool subset (hb_subset_context_t
*c
) const
761 if (!c
->serializer
->copy (italicsCorrection
, this)) return_trace (false);
762 if (!c
->serializer
->copy
<HBUINT16
> (partRecords
.len
)) return_trace (false);
764 for (const auto& record
: partRecords
.iter ())
765 if (!record
.subset (c
)) return_trace (false);
769 bool sanitize (hb_sanitize_context_t
*c
) const
771 TRACE_SANITIZE (this);
772 return_trace (c
->check_struct (this) &&
773 italicsCorrection
.sanitize (c
, this) &&
774 partRecords
.sanitize (c
));
777 unsigned int get_parts (hb_direction_t direction
,
779 unsigned int start_offset
,
780 unsigned int *parts_count
, /* IN/OUT */
781 hb_ot_math_glyph_part_t
*parts
/* OUT */,
782 hb_position_t
*italics_correction
/* OUT */) const
786 int64_t mult
= font
->dir_mult (direction
);
787 for (auto _
: hb_zip (partRecords
.as_array ().sub_array (start_offset
, parts_count
),
788 hb_array (parts
, *parts_count
)))
789 _
.first
.extract (_
.second
, mult
, font
);
792 if (italics_correction
)
793 *italics_correction
= italicsCorrection
.get_x_value (font
, this);
795 return partRecords
.len
;
798 void closure_glyphs (hb_set_t
*variant_glyphs
) const
800 for (const auto& _
: partRecords
.iter ())
801 _
.closure_glyphs (variant_glyphs
);
807 /* Italics correction of this
808 * MathGlyphAssembly. Should not
809 * depend on the assembly size. */
810 Array16Of
<MathGlyphPartRecord
>
811 partRecords
; /* Array of part records, from
812 * left to right and bottom to
816 DEFINE_SIZE_ARRAY (6, partRecords
);
819 struct MathGlyphConstruction
821 bool subset (hb_subset_context_t
*c
) const
824 auto *out
= c
->serializer
->start_embed (*this);
825 if (unlikely (!c
->serializer
->extend_min (out
))) return_trace (false);
827 out
->glyphAssembly
.serialize_subset (c
, glyphAssembly
, this);
829 if (!c
->serializer
->check_assign (out
->mathGlyphVariantRecord
.len
, mathGlyphVariantRecord
.len
, HB_SERIALIZE_ERROR_INT_OVERFLOW
))
830 return_trace (false);
831 for (const auto& record
: mathGlyphVariantRecord
.iter ())
832 if (!record
.subset (c
)) return_trace (false);
837 bool sanitize (hb_sanitize_context_t
*c
) const
839 TRACE_SANITIZE (this);
840 return_trace (c
->check_struct (this) &&
841 glyphAssembly
.sanitize (c
, this) &&
842 mathGlyphVariantRecord
.sanitize (c
));
845 const MathGlyphAssembly
&get_assembly () const { return this+glyphAssembly
; }
847 unsigned int get_variants (hb_direction_t direction
,
849 unsigned int start_offset
,
850 unsigned int *variants_count
, /* IN/OUT */
851 hb_ot_math_glyph_variant_t
*variants
/* OUT */) const
855 int64_t mult
= font
->dir_mult (direction
);
856 for (auto _
: hb_zip (mathGlyphVariantRecord
.as_array ().sub_array (start_offset
, variants_count
),
857 hb_array (variants
, *variants_count
)))
858 _
.second
= {_
.first
.variantGlyph
, font
->em_mult (_
.first
.advanceMeasurement
, mult
)};
860 return mathGlyphVariantRecord
.len
;
863 void closure_glyphs (hb_set_t
*variant_glyphs
) const
865 (this+glyphAssembly
).closure_glyphs (variant_glyphs
);
867 for (const auto& _
: mathGlyphVariantRecord
.iter ())
868 _
.closure_glyphs (variant_glyphs
);
872 /* Offset to MathGlyphAssembly table for this shape - from the beginning of
873 MathGlyphConstruction table. May be NULL. */
874 Offset16To
<MathGlyphAssembly
> glyphAssembly
;
876 /* MathGlyphVariantRecords for alternative variants of the glyphs. */
877 Array16Of
<MathGlyphVariantRecord
> mathGlyphVariantRecord
;
880 DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord
);
885 void closure_glyphs (const hb_set_t
*glyph_set
,
886 hb_set_t
*variant_glyphs
) const
888 const hb_array_t
<const Offset16To
<MathGlyphConstruction
>> glyph_construction_offsets
= glyphConstruction
.as_array (vertGlyphCount
+ horizGlyphCount
);
890 if (vertGlyphCoverage
)
892 const auto vert_offsets
= glyph_construction_offsets
.sub_array (0, vertGlyphCount
);
893 + hb_zip (this+vertGlyphCoverage
, vert_offsets
)
894 | hb_filter (glyph_set
, hb_first
)
896 | hb_map (hb_add (this))
897 | hb_apply ([=] (const MathGlyphConstruction
&_
) { _
.closure_glyphs (variant_glyphs
); })
901 if (horizGlyphCoverage
)
903 const auto hori_offsets
= glyph_construction_offsets
.sub_array (vertGlyphCount
, horizGlyphCount
);
904 + hb_zip (this+horizGlyphCoverage
, hori_offsets
)
905 | hb_filter (glyph_set
, hb_first
)
907 | hb_map (hb_add (this))
908 | hb_apply ([=] (const MathGlyphConstruction
&_
) { _
.closure_glyphs (variant_glyphs
); })
913 void collect_coverage_and_indices (hb_sorted_vector_t
<hb_codepoint_t
>& new_coverage
,
914 const Offset16To
<Coverage
>& coverage
,
918 const hb_set_t
& glyphset
,
919 const hb_map_t
& glyph_map
) const
921 if (!coverage
) return;
923 for (const auto _
: (this+coverage
).iter ())
925 if (i
>= end_index
) return;
926 if (glyphset
.has (_
))
928 unsigned new_gid
= glyph_map
.get (_
);
929 new_coverage
.push (new_gid
);
936 bool subset (hb_subset_context_t
*c
) const
939 const hb_set_t
&glyphset
= c
->plan
->_glyphset_mathed
;
940 const hb_map_t
&glyph_map
= *c
->plan
->glyph_map
;
942 auto *out
= c
->serializer
->start_embed (*this);
943 if (unlikely (!c
->serializer
->extend_min (out
))) return_trace (false);
944 if (!c
->serializer
->check_assign (out
->minConnectorOverlap
, minConnectorOverlap
, HB_SERIALIZE_ERROR_INT_OVERFLOW
))
945 return_trace (false);
947 hb_sorted_vector_t
<hb_codepoint_t
> new_vert_coverage
;
948 hb_sorted_vector_t
<hb_codepoint_t
> new_hori_coverage
;
950 collect_coverage_and_indices (new_vert_coverage
, vertGlyphCoverage
, 0, vertGlyphCount
, indices
, glyphset
, glyph_map
);
951 collect_coverage_and_indices (new_hori_coverage
, horizGlyphCoverage
, vertGlyphCount
, vertGlyphCount
+ horizGlyphCount
, indices
, glyphset
, glyph_map
);
953 if (!c
->serializer
->check_assign (out
->vertGlyphCount
, new_vert_coverage
.length
, HB_SERIALIZE_ERROR_INT_OVERFLOW
))
954 return_trace (false);
955 if (!c
->serializer
->check_assign (out
->horizGlyphCount
, new_hori_coverage
.length
, HB_SERIALIZE_ERROR_INT_OVERFLOW
))
956 return_trace (false);
958 for (unsigned i
: indices
.iter ())
960 auto *o
= c
->serializer
->embed (glyphConstruction
[i
]);
961 if (!o
) return_trace (false);
962 o
->serialize_subset (c
, glyphConstruction
[i
], this);
965 if (new_vert_coverage
)
966 out
->vertGlyphCoverage
.serialize_serialize (c
->serializer
, new_vert_coverage
.iter ());
968 if (new_hori_coverage
)
969 out
->horizGlyphCoverage
.serialize_serialize (c
->serializer
, new_hori_coverage
.iter ());
973 bool sanitize_offsets (hb_sanitize_context_t
*c
) const
975 TRACE_SANITIZE (this);
976 unsigned int count
= vertGlyphCount
+ horizGlyphCount
;
977 for (unsigned int i
= 0; i
< count
; i
++)
978 if (!glyphConstruction
.arrayZ
[i
].sanitize (c
, this)) return_trace (false);
982 bool sanitize (hb_sanitize_context_t
*c
) const
984 TRACE_SANITIZE (this);
985 return_trace (c
->check_struct (this) &&
986 vertGlyphCoverage
.sanitize (c
, this) &&
987 horizGlyphCoverage
.sanitize (c
, this) &&
989 c
->check_array (glyphConstruction
.arrayZ
, vertGlyphCount
+ horizGlyphCount
) &&
990 sanitize_offsets (c
));
993 hb_position_t
get_min_connector_overlap (hb_direction_t direction
,
994 hb_font_t
*font
) const
995 { return font
->em_scale_dir (minConnectorOverlap
, direction
); }
997 unsigned int get_glyph_variants (hb_codepoint_t glyph
,
998 hb_direction_t direction
,
1000 unsigned int start_offset
,
1001 unsigned int *variants_count
, /* IN/OUT */
1002 hb_ot_math_glyph_variant_t
*variants
/* OUT */) const
1003 { return get_glyph_construction (glyph
, direction
, font
)
1004 .get_variants (direction
, font
, start_offset
, variants_count
, variants
); }
1006 unsigned int get_glyph_parts (hb_codepoint_t glyph
,
1007 hb_direction_t direction
,
1009 unsigned int start_offset
,
1010 unsigned int *parts_count
, /* IN/OUT */
1011 hb_ot_math_glyph_part_t
*parts
/* OUT */,
1012 hb_position_t
*italics_correction
/* OUT */) const
1013 { return get_glyph_construction (glyph
, direction
, font
)
1015 .get_parts (direction
, font
,
1016 start_offset
, parts_count
, parts
,
1017 italics_correction
); }
1020 const MathGlyphConstruction
&
1021 get_glyph_construction (hb_codepoint_t glyph
,
1022 hb_direction_t direction
,
1023 hb_font_t
*font HB_UNUSED
) const
1025 bool vertical
= HB_DIRECTION_IS_VERTICAL (direction
);
1026 unsigned int count
= vertical
? vertGlyphCount
: horizGlyphCount
;
1027 const Offset16To
<Coverage
> &coverage
= vertical
? vertGlyphCoverage
1028 : horizGlyphCoverage
;
1030 unsigned int index
= (this+coverage
).get_coverage (glyph
);
1031 if (unlikely (index
>= count
)) return Null (MathGlyphConstruction
);
1034 index
+= vertGlyphCount
;
1036 return this+glyphConstruction
[index
];
1040 HBUINT16 minConnectorOverlap
;
1041 /* Minimum overlap of connecting
1042 * glyphs during glyph construction,
1043 * in design units. */
1044 Offset16To
<Coverage
> vertGlyphCoverage
;
1045 /* Offset to Coverage table -
1046 * from the beginning of MathVariants
1048 Offset16To
<Coverage
> horizGlyphCoverage
;
1049 /* Offset to Coverage table -
1050 * from the beginning of MathVariants
1052 HBUINT16 vertGlyphCount
; /* Number of glyphs for which
1053 * information is provided for
1054 * vertically growing variants. */
1055 HBUINT16 horizGlyphCount
;/* Number of glyphs for which
1056 * information is provided for
1057 * horizontally growing variants. */
1059 /* Array of offsets to MathGlyphConstruction tables - from the beginning of
1060 the MathVariants table, for shapes growing in vertical/horizontal
1062 UnsizedArrayOf
<Offset16To
<MathGlyphConstruction
>>
1066 DEFINE_SIZE_ARRAY (10, glyphConstruction
);
1071 * MATH -- Mathematical typesetting
1072 * https://docs.microsoft.com/en-us/typography/opentype/spec/math
1077 static constexpr hb_tag_t tableTag
= HB_OT_TAG_MATH
;
1079 bool has_data () const { return version
.to_int (); }
1081 void closure_glyphs (hb_set_t
*glyph_set
) const
1085 hb_set_t variant_glyphs
;
1086 (this+mathVariants
).closure_glyphs (glyph_set
, &variant_glyphs
);
1087 hb_set_union (glyph_set
, &variant_glyphs
);
1091 bool subset (hb_subset_context_t
*c
) const
1093 TRACE_SUBSET (this);
1094 auto *out
= c
->serializer
->embed (*this);
1095 if (unlikely (!out
)) return_trace (false);
1097 out
->mathConstants
.serialize_copy (c
->serializer
, mathConstants
, this, 0, hb_serialize_context_t::Head
);
1098 out
->mathGlyphInfo
.serialize_subset (c
, mathGlyphInfo
, this);
1099 out
->mathVariants
.serialize_subset (c
, mathVariants
, this);
1100 return_trace (true);
1103 bool sanitize (hb_sanitize_context_t
*c
) const
1105 TRACE_SANITIZE (this);
1106 return_trace (version
.sanitize (c
) &&
1107 likely (version
.major
== 1) &&
1109 mathConstants
.sanitize (c
, this) &&
1110 mathGlyphInfo
.sanitize (c
, this) &&
1111 mathVariants
.sanitize (c
, this));
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
); }
1118 const MathGlyphInfo
&get_glyph_info () const { return this+mathGlyphInfo
; }
1120 const MathVariants
&get_variants () const { return this+mathVariants
; }
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 */
1133 DEFINE_SIZE_STATIC (10);
1136 } /* namespace OT */
1139 #endif /* HB_OT_MATH_TABLE_HH */