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