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