blob: c2e365dbd6d2e1012b9c476a4a544470ee65484b [file] [log] [blame]
Frédéric Wang5fbcb992016-08-25 10:47:15 +02001/*
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
Behdad Esfahbod93ef6842017-01-09 21:11:00 -080027#ifndef HB_OT_MATH_TABLE_HH
28#define HB_OT_MATH_TABLE_HH
Frédéric Wang5fbcb992016-08-25 10:47:15 +020029
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070030#include "hb-open-type.hh"
31#include "hb-ot-layout-common.hh"
Frédéric Wang319ff592016-08-25 11:06:41 +020032#include "hb-ot-math.h"
Frédéric Wang5fbcb992016-08-25 10:47:15 +020033
34namespace OT {
35
Frédéric Wang319ff592016-08-25 11:06:41 +020036
37struct MathValueRecord
38{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033039 hb_position_t get_x_value (hb_font_t *font, const void *base) const
Behdad Esfahbod1a381152016-09-26 11:15:59 +010040 { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033041 hb_position_t get_y_value (hb_font_t *font, const void *base) const
Behdad Esfahbod1a381152016-09-26 11:15:59 +010042 { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); }
Frédéric Wang319ff592016-08-25 11:06:41 +020043
Qunxin Liuca7b9da2021-09-20 14:42:51 -070044 MathValueRecord* copy (hb_serialize_context_t *c, const void *base) const
45 {
46 TRACE_SERIALIZE (this);
47 auto *out = c->embed (this);
48 if (unlikely (!out)) return_trace (nullptr);
49 out->deviceTable.serialize_copy (c, deviceTable, base, 0, hb_serialize_context_t::Head);
50
51 return_trace (out);
52 }
53
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033054 bool sanitize (hb_sanitize_context_t *c, const void *base) const
Frédéric Wang319ff592016-08-25 11:06:41 +020055 {
56 TRACE_SANITIZE (this);
57 return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
58 }
59
Behdad Esfahbod353f4552016-09-26 21:22:48 +020060 protected:
Ebrahim Byagowi08428a12020-04-24 23:45:17 +043061 HBINT16 value; /* The X or Y value in design units */
Behdad Esfahbodad28f972021-03-31 12:49:14 -060062 Offset16To<Device> deviceTable; /* Offset to the device table - from the
Ebrahim Byagowi63109432018-10-13 14:00:05 +033063 * beginning of parent table. May be NULL.
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +010064 * Suggested format for device table is 1. */
Frédéric Wang319ff592016-08-25 11:06:41 +020065
Behdad Esfahbod353f4552016-09-26 21:22:48 +020066 public:
Behdad Esfahbod1a381152016-09-26 11:15:59 +010067 DEFINE_SIZE_STATIC (4);
Frédéric Wang319ff592016-08-25 11:06:41 +020068};
69
70struct MathConstants
71{
Qunxin Liuca7b9da2021-09-20 14:42:51 -070072 MathConstants* copy (hb_serialize_context_t *c) const
73 {
74 TRACE_SERIALIZE (this);
75 auto *out = c->start_embed (this);
76 if (unlikely (!out)) return_trace (nullptr);
77
78 HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2);
79 if (unlikely (!p)) return_trace (nullptr);
80 memcpy (p, percentScaleDown, HBINT16::static_size * 2);
81
82 HBUINT16 *m = c->allocate_size<HBUINT16> (HBUINT16::static_size * 2);
83 if (unlikely (!m)) return_trace (nullptr);
84 memcpy (m, minHeight, HBUINT16::static_size * 2);
85
86 unsigned count = ARRAY_LENGTH (mathValueRecords);
87 for (unsigned i = 0; i < count; i++)
88 if (!c->copy (mathValueRecords[i], this))
89 return_trace (nullptr);
90
91 if (!c->embed (radicalDegreeBottomRaisePercent)) return_trace (nullptr);
92 return_trace (out);
93 }
94
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033095 bool sanitize_math_value_records (hb_sanitize_context_t *c) const
Frédéric Wang319ff592016-08-25 11:06:41 +020096 {
97 TRACE_SANITIZE (this);
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +010098
Behdad Esfahbod6fd2fe42016-09-26 11:24:39 +010099 unsigned int count = ARRAY_LENGTH (mathValueRecords);
Frédéric Wang319ff592016-08-25 11:06:41 +0200100 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100101 if (!mathValueRecords[i].sanitize (c, this))
102 return_trace (false);
103
Frédéric Wang319ff592016-08-25 11:06:41 +0200104 return_trace (true);
105 }
106
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330107 bool sanitize (hb_sanitize_context_t *c) const
Frédéric Wang319ff592016-08-25 11:06:41 +0200108 {
109 TRACE_SANITIZE (this);
Ebrahim Byagowid7c50ff2018-11-15 23:10:49 +0330110 return_trace (c->check_struct (this) && sanitize_math_value_records (c));
Frédéric Wang319ff592016-08-25 11:06:41 +0200111 }
112
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330113 hb_position_t get_value (hb_ot_math_constant_t constant,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +0430114 hb_font_t *font) const
Frédéric Wang319ff592016-08-25 11:06:41 +0200115 {
116 switch (constant) {
Behdad Esfahbod6fd2fe42016-09-26 11:24:39 +0100117
118 case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN:
119 case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN:
120 return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN];
121
Frédéric Wang319ff592016-08-25 11:06:41 +0200122 case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT:
123 case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT:
124 return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]);
125
126 case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE:
127 case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE:
128 case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP:
129 case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT:
Ebrahim Byagowid7c50ff2018-11-15 23:10:49 +0330130 return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this);
Frédéric Wang319ff592016-08-25 11:06:41 +0200131
132 case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT:
133 case HB_OT_MATH_CONSTANT_AXIS_HEIGHT:
134 case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT:
135 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN:
136 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN:
137 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN:
138 case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN:
139 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP:
140 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN:
141 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP:
142 case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN:
143 case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS:
144 case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN:
145 case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN:
146 case HB_OT_MATH_CONSTANT_MATH_LEADING:
147 case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER:
148 case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS:
149 case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP:
150 case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP:
151 case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER:
152 case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS:
153 case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP:
154 case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP:
155 case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN:
156 case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN:
157 case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN:
158 case HB_OT_MATH_CONSTANT_STACK_GAP_MIN:
159 case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP:
160 case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP:
161 case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN:
162 case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN:
163 case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN:
164 case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP:
165 case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN:
166 case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN:
167 case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX:
168 case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN:
169 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX:
170 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT:
171 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN:
172 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP:
173 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED:
174 case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER:
175 case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS:
176 case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP:
177 case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN:
178 case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN:
Ebrahim Byagowid7c50ff2018-11-15 23:10:49 +0330179 return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this);
Frédéric Wang319ff592016-08-25 11:06:41 +0200180
Frédéric Wang319ff592016-08-25 11:06:41 +0200181 case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
182 return radicalDegreeBottomRaisePercent;
Behdad Esfahbod6fd2fe42016-09-26 11:24:39 +0100183
Behdad Esfahbod1a381152016-09-26 11:15:59 +0100184 default:
185 return 0;
Frédéric Wang319ff592016-08-25 11:06:41 +0200186 }
187 }
188
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200189 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100190 HBINT16 percentScaleDown[2];
191 HBUINT16 minHeight[2];
Behdad Esfahbod6fd2fe42016-09-26 11:24:39 +0100192 MathValueRecord mathValueRecords[51];
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100193 HBINT16 radicalDegreeBottomRaisePercent;
Frédéric Wang319ff592016-08-25 11:06:41 +0200194
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200195 public:
Behdad Esfahbod6fd2fe42016-09-26 11:24:39 +0100196 DEFINE_SIZE_STATIC (214);
Frédéric Wang319ff592016-08-25 11:06:41 +0200197};
198
Frédéric Wangd7182d12016-08-25 11:15:31 +0200199struct MathItalicsCorrectionInfo
200{
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700201 bool subset (hb_subset_context_t *c) const
202 {
203 TRACE_SUBSET (this);
204 const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
205 const hb_map_t &glyph_map = *c->plan->glyph_map;
206
207 auto *out = c->serializer->start_embed (*this);
208 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
209
210 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
211 + hb_zip (this+coverage, italicsCorrection)
212 | hb_filter (glyphset, hb_first)
213 | hb_filter (serialize_math_record_array (c->serializer, out->italicsCorrection, this), hb_second)
214 | hb_map (hb_first)
215 | hb_map (glyph_map)
216 | hb_sink (new_coverage)
217 ;
218
219 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
220 return_trace (true);
221 }
222
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330223 bool sanitize (hb_sanitize_context_t *c) const
Frédéric Wangd7182d12016-08-25 11:15:31 +0200224 {
225 TRACE_SANITIZE (this);
226 return_trace (c->check_struct (this) &&
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100227 coverage.sanitize (c, this) &&
228 italicsCorrection.sanitize (c, this));
Frédéric Wangd7182d12016-08-25 11:15:31 +0200229 }
230
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330231 hb_position_t get_value (hb_codepoint_t glyph,
232 hb_font_t *font) const
Frédéric Wangd7182d12016-08-25 11:15:31 +0200233 {
234 unsigned int index = (this+coverage).get_coverage (glyph);
Behdad Esfahbod8bcf5172016-09-26 12:12:41 +0100235 return italicsCorrection[index].get_x_value (font, this);
Frédéric Wangd7182d12016-08-25 11:15:31 +0200236 }
237
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200238 protected:
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600239 Offset16To<Coverage> coverage; /* Offset to Coverage table -
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100240 * from the beginning of
241 * MathItalicsCorrectionInfo
242 * table. */
Behdad Esfahbod5639e252021-03-31 16:04:43 -0600243 Array16Of<MathValueRecord> italicsCorrection; /* Array of MathValueRecords
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100244 * defining italics correction
245 * values for each
246 * covered glyph. */
Frédéric Wangd7182d12016-08-25 11:15:31 +0200247
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200248 public:
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100249 DEFINE_SIZE_ARRAY (4, italicsCorrection);
Frédéric Wangd7182d12016-08-25 11:15:31 +0200250};
251
252struct MathTopAccentAttachment
253{
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700254 bool subset (hb_subset_context_t *c) const
255 {
256 TRACE_SUBSET (this);
257 const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
258 const hb_map_t &glyph_map = *c->plan->glyph_map;
259
260 auto *out = c->serializer->start_embed (*this);
261 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
262
263 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
264 + hb_zip (this+topAccentCoverage, topAccentAttachment)
265 | hb_filter (glyphset, hb_first)
266 | hb_filter (serialize_math_record_array (c->serializer, out->topAccentAttachment, this), hb_second)
267 | hb_map (hb_first)
268 | hb_map (glyph_map)
269 | hb_sink (new_coverage)
270 ;
271
272 out->topAccentCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
273 return_trace (true);
274 }
275
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330276 bool sanitize (hb_sanitize_context_t *c) const
Frédéric Wangd7182d12016-08-25 11:15:31 +0200277 {
278 TRACE_SANITIZE (this);
279 return_trace (c->check_struct (this) &&
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100280 topAccentCoverage.sanitize (c, this) &&
281 topAccentAttachment.sanitize (c, this));
Frédéric Wangd7182d12016-08-25 11:15:31 +0200282 }
283
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330284 hb_position_t get_value (hb_codepoint_t glyph,
285 hb_font_t *font) const
Frédéric Wangd7182d12016-08-25 11:15:31 +0200286 {
287 unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
Behdad Esfahbod17ff30e2016-09-26 12:18:32 +0100288 if (index == NOT_COVERED)
289 return font->get_glyph_h_advance (glyph) / 2;
Ebrahim Byagowid7c50ff2018-11-15 23:10:49 +0330290 return topAccentAttachment[index].get_x_value (font, this);
Frédéric Wangd7182d12016-08-25 11:15:31 +0200291 }
292
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200293 protected:
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600294 Offset16To<Coverage> topAccentCoverage; /* Offset to Coverage table -
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100295 * from the beginning of
296 * MathTopAccentAttachment
297 * table. */
Behdad Esfahbod5639e252021-03-31 16:04:43 -0600298 Array16Of<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100299 * defining top accent
300 * attachment points for each
301 * covered glyph. */
Frédéric Wangd7182d12016-08-25 11:15:31 +0200302
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200303 public:
Frédéric Wangd7182d12016-08-25 11:15:31 +0200304 DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
305};
306
307struct MathKern
308{
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700309 MathKern* copy (hb_serialize_context_t *c) const
310 {
311 TRACE_SERIALIZE (this);
312 auto *out = c->start_embed (this);
313 if (unlikely (!out)) return_trace (nullptr);
314
315 if (unlikely (!c->embed (heightCount))) return_trace (nullptr);
316
317 unsigned count = 2 * heightCount + 1;
318 for (unsigned i = 0; i < count; i++)
319 if (!c->copy (mathValueRecordsZ.arrayZ[i], this))
320 return_trace (nullptr);
321
322 return_trace (out);
323 }
324
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330325 bool sanitize_math_value_records (hb_sanitize_context_t *c) const
Frédéric Wangd7182d12016-08-25 11:15:31 +0200326 {
327 TRACE_SANITIZE (this);
328 unsigned int count = 2 * heightCount + 1;
329 for (unsigned int i = 0; i < count; i++)
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200330 if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false);
Frédéric Wangd7182d12016-08-25 11:15:31 +0200331 return_trace (true);
332 }
333
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330334 bool sanitize (hb_sanitize_context_t *c) const
Frédéric Wangd7182d12016-08-25 11:15:31 +0200335 {
336 TRACE_SANITIZE (this);
337 return_trace (c->check_struct (this) &&
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200338 c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) &&
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100339 sanitize_math_value_records (c));
Frédéric Wangd7182d12016-08-25 11:15:31 +0200340 }
341
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330342 hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
Frédéric Wangd7182d12016-08-25 11:15:31 +0200343 {
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200344 const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
345 const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
Behdad Esfahbod8d58e342016-09-26 13:39:58 +0100346 int sign = font->y_scale < 0 ? -1 : +1;
347
348 /* The description of the MathKern table is a ambiguous, but interpreting
349 * "between the two heights found at those indexes" for 0 < i < len as
350 *
351 * correctionHeight[i-1] < correction_height <= correctionHeight[i]
352 *
353 * makes the result consistent with the limit cases and we can just use the
354 * binary search algorithm of std::upper_bound:
355 */
Frédéric Wangd7182d12016-08-25 11:15:31 +0200356 unsigned int i = 0;
Behdad Esfahbod8d58e342016-09-26 13:39:58 +0100357 unsigned int count = heightCount;
358 while (count > 0)
359 {
Frédéric Wangd7182d12016-08-25 11:15:31 +0200360 unsigned int half = count / 2;
Ebrahim Byagowid7c50ff2018-11-15 23:10:49 +0330361 hb_position_t height = correctionHeight[i + half].get_y_value (font, this);
Behdad Esfahbod8d58e342016-09-26 13:39:58 +0100362 if (sign * height < sign * correction_height)
363 {
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100364 i += half + 1;
365 count -= half + 1;
Frédéric Wangd7182d12016-08-25 11:15:31 +0200366 } else
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100367 count = half;
Frédéric Wangd7182d12016-08-25 11:15:31 +0200368 }
Ebrahim Byagowid7c50ff2018-11-15 23:10:49 +0330369 return kernValue[i].get_x_value (font, this);
Frédéric Wangd7182d12016-08-25 11:15:31 +0200370 }
371
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200372 protected:
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200373 HBUINT16 heightCount;
374 UnsizedArrayOf<MathValueRecord>
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430375 mathValueRecordsZ;
376 /* Array of correction heights at
377 * which the kern value changes.
378 * Sorted by the height value in
379 * design units (heightCount entries),
380 * Followed by:
381 * Array of kern values corresponding
382 * to heights. (heightCount+1 entries).
383 */
Frédéric Wangd7182d12016-08-25 11:15:31 +0200384
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200385 public:
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200386 DEFINE_SIZE_ARRAY (2, mathValueRecordsZ);
Frédéric Wangd7182d12016-08-25 11:15:31 +0200387};
388
389struct MathKernInfoRecord
390{
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700391 MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const
392 {
393 TRACE_SERIALIZE (this);
394 auto *out = c->embed (this);
395 if (unlikely (!out)) return_trace (nullptr);
396
397 unsigned count = ARRAY_LENGTH (mathKern);
398 for (unsigned i = 0; i < count; i++)
399 out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head);
400
401 return_trace (out);
402 }
403
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330404 bool sanitize (hb_sanitize_context_t *c, const void *base) const
Frédéric Wangd7182d12016-08-25 11:15:31 +0200405 {
406 TRACE_SANITIZE (this);
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100407
408 unsigned int count = ARRAY_LENGTH (mathKern);
409 for (unsigned int i = 0; i < count; i++)
410 if (unlikely (!mathKern[i].sanitize (c, base)))
411 return_trace (false);
412
413 return_trace (true);
Frédéric Wangd7182d12016-08-25 11:15:31 +0200414 }
415
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330416 hb_position_t get_kerning (hb_ot_math_kern_t kern,
417 hb_position_t correction_height,
418 hb_font_t *font,
419 const void *base) const
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100420 {
421 unsigned int idx = kern;
Behdad Esfahbod94f5df52016-09-26 13:31:47 +0100422 if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
423 return (base+mathKern[idx]).get_value (correction_height, font);
Frédéric Wangd7182d12016-08-25 11:15:31 +0200424 }
425
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200426 protected:
Frédéric Wangd7182d12016-08-25 11:15:31 +0200427 /* Offset to MathKern table for each corner -
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330428 * from the beginning of MathKernInfo table. May be NULL. */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600429 Offset16To<MathKern> mathKern[4];
Frédéric Wangd7182d12016-08-25 11:15:31 +0200430
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200431 public:
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100432 DEFINE_SIZE_STATIC (8);
Frédéric Wangd7182d12016-08-25 11:15:31 +0200433};
434
435struct MathKernInfo
436{
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700437 bool subset (hb_subset_context_t *c) const
438 {
439 TRACE_SUBSET (this);
440 const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
441 const hb_map_t &glyph_map = *c->plan->glyph_map;
442
443 auto *out = c->serializer->start_embed (*this);
444 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
445
446 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
447 + hb_zip (this+mathKernCoverage, mathKernInfoRecords)
448 | hb_filter (glyphset, hb_first)
449 | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second)
450 | hb_map (hb_first)
451 | hb_map (glyph_map)
452 | hb_sink (new_coverage)
453 ;
454
455 out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
456 return_trace (true);
457 }
458
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330459 bool sanitize (hb_sanitize_context_t *c) const
Frédéric Wangd7182d12016-08-25 11:15:31 +0200460 {
461 TRACE_SANITIZE (this);
462 return_trace (c->check_struct (this) &&
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100463 mathKernCoverage.sanitize (c, this) &&
464 mathKernInfoRecords.sanitize (c, this));
Frédéric Wangd7182d12016-08-25 11:15:31 +0200465 }
466
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330467 hb_position_t get_kerning (hb_codepoint_t glyph,
468 hb_ot_math_kern_t kern,
469 hb_position_t correction_height,
470 hb_font_t *font) const
Frédéric Wangd7182d12016-08-25 11:15:31 +0200471 {
472 unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
Behdad Esfahbod94f5df52016-09-26 13:31:47 +0100473 return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
Frédéric Wangd7182d12016-08-25 11:15:31 +0200474 }
475
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200476 protected:
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600477 Offset16To<Coverage>
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430478 mathKernCoverage;
479 /* Offset to Coverage table -
480 * from the beginning of the
481 * MathKernInfo table. */
Behdad Esfahbod5639e252021-03-31 16:04:43 -0600482 Array16Of<MathKernInfoRecord>
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430483 mathKernInfoRecords;
484 /* Array of MathKernInfoRecords,
485 * per-glyph information for
486 * mathematical positioning
487 * of subscripts and
488 * superscripts. */
Frédéric Wangd7182d12016-08-25 11:15:31 +0200489
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200490 public:
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100491 DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
Frédéric Wangd7182d12016-08-25 11:15:31 +0200492};
493
494struct MathGlyphInfo
495{
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700496 bool subset (hb_subset_context_t *c) const
497 {
498 TRACE_SUBSET (this);
499 auto *out = c->serializer->embed (*this);
500 if (unlikely (!out)) return_trace (false);
501
502 out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this);
503 out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this);
504
505 const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
506 const hb_map_t &glyph_map = *c->plan->glyph_map;
507
508 auto it =
509 + hb_iter (this+extendedShapeCoverage)
510 | hb_filter (glyphset)
511 | hb_map_retains_sorting (glyph_map)
512 ;
513
514 out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
515
516 out->mathKernInfo.serialize_subset (c, mathKernInfo, this);
517 return_trace (true);
518 }
519
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330520 bool sanitize (hb_sanitize_context_t *c) const
Frédéric Wangd7182d12016-08-25 11:15:31 +0200521 {
522 TRACE_SANITIZE (this);
523 return_trace (c->check_struct (this) &&
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100524 mathItalicsCorrectionInfo.sanitize (c, this) &&
525 mathTopAccentAttachment.sanitize (c, this) &&
526 extendedShapeCoverage.sanitize (c, this) &&
Ebrahim Byagowid7c50ff2018-11-15 23:10:49 +0330527 mathKernInfo.sanitize (c, this));
Frédéric Wangd7182d12016-08-25 11:15:31 +0200528 }
529
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330530 hb_position_t
Behdad Esfahbod17ff30e2016-09-26 12:18:32 +0100531 get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const
532 { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
Frédéric Wangd7182d12016-08-25 11:15:31 +0200533
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330534 hb_position_t
Behdad Esfahbod17ff30e2016-09-26 12:18:32 +0100535 get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const
536 { return (this+mathTopAccentAttachment).get_value (glyph, font); }
Frédéric Wangd7182d12016-08-25 11:15:31 +0200537
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330538 bool is_extended_shape (hb_codepoint_t glyph) const
Behdad Esfahbod17ff30e2016-09-26 12:18:32 +0100539 { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
Frédéric Wangd7182d12016-08-25 11:15:31 +0200540
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330541 hb_position_t get_kerning (hb_codepoint_t glyph,
542 hb_ot_math_kern_t kern,
543 hb_position_t correction_height,
544 hb_font_t *font) const
Behdad Esfahbod94f5df52016-09-26 13:31:47 +0100545 { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
Frédéric Wangd7182d12016-08-25 11:15:31 +0200546
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200547 protected:
Frédéric Wangd7182d12016-08-25 11:15:31 +0200548 /* Offset to MathItalicsCorrectionInfo table -
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100549 * from the beginning of MathGlyphInfo table. */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600550 Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
Frédéric Wangd7182d12016-08-25 11:15:31 +0200551
552 /* Offset to MathTopAccentAttachment table -
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100553 * from the beginning of MathGlyphInfo table. */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600554 Offset16To<MathTopAccentAttachment> mathTopAccentAttachment;
Frédéric Wangd7182d12016-08-25 11:15:31 +0200555
556 /* Offset to coverage table for Extended Shape glyphs -
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100557 * from the beginning of MathGlyphInfo table. When the left or right glyph of
558 * a box is an extended shape variant, the (ink) box (and not the default
559 * position defined by values in MathConstants table) should be used for
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330560 * vertical positioning purposes. May be NULL.. */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600561 Offset16To<Coverage> extendedShapeCoverage;
Frédéric Wangd7182d12016-08-25 11:15:31 +0200562
563 /* Offset to MathKernInfo table -
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100564 * from the beginning of MathGlyphInfo table. */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600565 Offset16To<MathKernInfo> mathKernInfo;
Frédéric Wangd7182d12016-08-25 11:15:31 +0200566
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200567 public:
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100568 DEFINE_SIZE_STATIC (8);
Frédéric Wangd7182d12016-08-25 11:15:31 +0200569};
570
Frédéric Wang51da7a12016-08-25 11:17:50 +0200571struct MathGlyphVariantRecord
572{
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200573 friend struct MathGlyphConstruction;
574
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700575 bool subset (hb_subset_context_t *c) const
576 {
577 TRACE_SUBSET (this);
578 auto *out = c->serializer->embed (this);
579 if (unlikely (!out)) return_trace (false);
580
581 const hb_map_t& glyph_map = *c->plan->glyph_map;
582 return_trace (c->serializer->check_assign (out->variantGlyph, glyph_map.get (variantGlyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
583 }
584
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330585 bool sanitize (hb_sanitize_context_t *c) const
Frédéric Wang51da7a12016-08-25 11:17:50 +0200586 {
587 TRACE_SANITIZE (this);
588 return_trace (c->check_struct (this));
589 }
590
Qunxin Liu1afc3872021-09-19 20:41:43 -0700591 void closure_glyphs (hb_set_t *variant_glyphs) const
592 { variant_glyphs->add (variantGlyph); }
593
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200594 protected:
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400595 HBGlyphID16 variantGlyph; /* Glyph ID for the variant. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100596 HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the
Ebrahim Byagowid7c50ff2018-11-15 23:10:49 +0330597 * variant, in the direction of requested
598 * glyph extension. */
Frédéric Wang51da7a12016-08-25 11:17:50 +0200599
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200600 public:
Behdad Esfahbod1f3327f2016-09-26 16:10:08 +0100601 DEFINE_SIZE_STATIC (4);
Frédéric Wang51da7a12016-08-25 11:17:50 +0200602};
603
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100604struct PartFlags : HBUINT16
Frédéric Wang51da7a12016-08-25 11:17:50 +0200605{
606 enum Flags {
Behdad Esfahbod559eb562016-09-26 21:46:05 +0200607 Extender = 0x0001u, /* If set, the part can be skipped or repeated. */
608
609 Defined = 0x0001u, /* All defined flags. */
Frédéric Wang51da7a12016-08-25 11:17:50 +0200610 };
611
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200612 public:
Frédéric Wang51da7a12016-08-25 11:17:50 +0200613 DEFINE_SIZE_STATIC (2);
614};
615
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200616struct MathGlyphPartRecord
Frédéric Wang51da7a12016-08-25 11:17:50 +0200617{
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700618 bool subset (hb_subset_context_t *c) const
619 {
620 TRACE_SUBSET (this);
621 auto *out = c->serializer->embed (this);
622 if (unlikely (!out)) return_trace (false);
623
624 const hb_map_t& glyph_map = *c->plan->glyph_map;
625 return_trace (c->serializer->check_assign (out->glyph, glyph_map.get (glyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
626 }
627
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330628 bool sanitize (hb_sanitize_context_t *c) const
Frédéric Wang51da7a12016-08-25 11:17:50 +0200629 {
630 TRACE_SANITIZE (this);
631 return_trace (c->check_struct (this));
632 }
633
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330634 void extract (hb_ot_math_glyph_part_t &out,
Behdad Esfahbodf18ea1d2019-07-05 13:56:45 -0700635 int64_t mult,
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330636 hb_font_t *font) const
Behdad Esfahbod559eb562016-09-26 21:46:05 +0200637 {
638 out.glyph = glyph;
639
Behdad Esfahbodf18ea1d2019-07-05 13:56:45 -0700640 out.start_connector_length = font->em_mult (startConnectorLength, mult);
641 out.end_connector_length = font->em_mult (endConnectorLength, mult);
642 out.full_advance = font->em_mult (fullAdvance, mult);
Behdad Esfahbod559eb562016-09-26 21:46:05 +0200643
Behdad Esfahbod87dd4bf2019-05-30 11:26:17 -0400644 static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER ==
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200645 (unsigned int) PartFlags::Extender, "");
Behdad Esfahbod559eb562016-09-26 21:46:05 +0200646
Behdad Esfahbod46cc4a32016-09-27 16:44:22 +0200647 out.flags = (hb_ot_math_glyph_part_flags_t)
Behdad Esfahbod559eb562016-09-26 21:46:05 +0200648 (unsigned int)
649 (partFlags & PartFlags::Defined);
650 }
651
Qunxin Liu1afc3872021-09-19 20:41:43 -0700652 void closure_glyphs (hb_set_t *variant_glyphs) const
653 { variant_glyphs->add (glyph); }
654
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200655 protected:
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400656 HBGlyphID16 glyph; /* Glyph ID for the part. */
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430657 HBUINT16 startConnectorLength;
658 /* Advance width/ height of the straight bar
659 * connector material, in design units, is at
660 * the beginning of the glyph, in the
661 * direction of the extension. */
662 HBUINT16 endConnectorLength;
663 /* Advance width/ height of the straight bar
664 * connector material, in design units, is at
665 * the end of the glyph, in the direction of
666 * the extension. */
667 HBUINT16 fullAdvance; /* Full advance width/height for this part,
668 * in the direction of the extension.
669 * In design units. */
670 PartFlags partFlags; /* Part qualifiers. */
Frédéric Wang51da7a12016-08-25 11:17:50 +0200671
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200672 public:
Behdad Esfahbod1f3327f2016-09-26 16:10:08 +0100673 DEFINE_SIZE_STATIC (10);
Frédéric Wang51da7a12016-08-25 11:17:50 +0200674};
675
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200676struct MathGlyphAssembly
Frédéric Wang51da7a12016-08-25 11:17:50 +0200677{
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700678 bool subset (hb_subset_context_t *c) const
679 {
680 TRACE_SUBSET (this);
681 auto *out = c->serializer->start_embed (*this);
682 if (unlikely (!out)) return_trace (false);
683
684 if (!c->serializer->copy (italicsCorrection, this)) return_trace (false);
685 if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false);
686
687 for (const auto& record : partRecords.iter ())
688 if (!record.subset (c)) return_trace (false);
689 return_trace (true);
690 }
691
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330692 bool sanitize (hb_sanitize_context_t *c) const
Frédéric Wang51da7a12016-08-25 11:17:50 +0200693 {
694 TRACE_SANITIZE (this);
695 return_trace (c->check_struct (this) &&
Ebrahim Byagowid7c50ff2018-11-15 23:10:49 +0330696 italicsCorrection.sanitize (c, this) &&
697 partRecords.sanitize (c));
Frédéric Wang51da7a12016-08-25 11:17:50 +0200698 }
699
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330700 unsigned int get_parts (hb_direction_t direction,
701 hb_font_t *font,
702 unsigned int start_offset,
703 unsigned int *parts_count, /* IN/OUT */
704 hb_ot_math_glyph_part_t *parts /* OUT */,
705 hb_position_t *italics_correction /* OUT */) const
Behdad Esfahbod559eb562016-09-26 21:46:05 +0200706 {
707 if (parts_count)
708 {
Behdad Esfahbodf18ea1d2019-07-05 13:56:45 -0700709 int64_t mult = font->dir_mult (direction);
Ebrahim Byagowie541fb42020-06-21 09:49:48 +0430710 for (auto _ : hb_zip (partRecords.sub_array (start_offset, parts_count),
711 hb_array (parts, *parts_count)))
712 _.first.extract (_.second, mult, font);
Behdad Esfahbod559eb562016-09-26 21:46:05 +0200713 }
714
715 if (italics_correction)
716 *italics_correction = italicsCorrection.get_x_value (font, this);
717
718 return partRecords.len;
719 }
Frédéric Wang51da7a12016-08-25 11:17:50 +0200720
Qunxin Liu1afc3872021-09-19 20:41:43 -0700721 void closure_glyphs (hb_set_t *variant_glyphs) const
722 {
723 for (const auto& _ : partRecords.iter ())
724 _.closure_glyphs (variant_glyphs);
725 }
726
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200727 protected:
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430728 MathValueRecord
729 italicsCorrection;
730 /* Italics correction of this
731 * MathGlyphAssembly. Should not
732 * depend on the assembly size. */
Behdad Esfahbod5639e252021-03-31 16:04:43 -0600733 Array16Of<MathGlyphPartRecord>
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430734 partRecords; /* Array of part records, from
735 * left to right and bottom to
736 * top. */
Frédéric Wang51da7a12016-08-25 11:17:50 +0200737
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200738 public:
Behdad Esfahbod1f3327f2016-09-26 16:10:08 +0100739 DEFINE_SIZE_ARRAY (6, partRecords);
Frédéric Wang51da7a12016-08-25 11:17:50 +0200740};
741
742struct MathGlyphConstruction
743{
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700744 bool subset (hb_subset_context_t *c) const
745 {
746 TRACE_SUBSET (this);
747 auto *out = c->serializer->start_embed (*this);
748 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
749
750 out->glyphAssembly.serialize_subset (c, glyphAssembly, this);
751
752 if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW))
753 return_trace (false);
754 for (const auto& record : mathGlyphVariantRecord.iter ())
755 if (!record.subset (c)) return_trace (false);
756
757 return_trace (true);
758 }
759
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330760 bool sanitize (hb_sanitize_context_t *c) const
Frédéric Wang51da7a12016-08-25 11:17:50 +0200761 {
762 TRACE_SANITIZE (this);
763 return_trace (c->check_struct (this) &&
Ebrahim Byagowid7c50ff2018-11-15 23:10:49 +0330764 glyphAssembly.sanitize (c, this) &&
765 mathGlyphVariantRecord.sanitize (c));
Frédéric Wang51da7a12016-08-25 11:17:50 +0200766 }
767
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330768 const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; }
Behdad Esfahbod559eb562016-09-26 21:46:05 +0200769
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330770 unsigned int get_variants (hb_direction_t direction,
771 hb_font_t *font,
772 unsigned int start_offset,
773 unsigned int *variants_count, /* IN/OUT */
774 hb_ot_math_glyph_variant_t *variants /* OUT */) const
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200775 {
776 if (variants_count)
777 {
Behdad Esfahbodf18ea1d2019-07-05 13:56:45 -0700778 int64_t mult = font->dir_mult (direction);
Ebrahim Byagowie541fb42020-06-21 09:49:48 +0430779 for (auto _ : hb_zip (mathGlyphVariantRecord.sub_array (start_offset, variants_count),
780 hb_array (variants, *variants_count)))
781 _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200782 }
783 return mathGlyphVariantRecord.len;
784 }
785
Qunxin Liu1afc3872021-09-19 20:41:43 -0700786 void closure_glyphs (hb_set_t *variant_glyphs) const
787 {
788 (this+glyphAssembly).closure_glyphs (variant_glyphs);
789
790 for (const auto& _ : mathGlyphVariantRecord.iter ())
791 _.closure_glyphs (variant_glyphs);
792 }
793
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200794 protected:
795 /* Offset to MathGlyphAssembly table for this shape - from the beginning of
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330796 MathGlyphConstruction table. May be NULL. */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600797 Offset16To<MathGlyphAssembly> glyphAssembly;
Frédéric Wang51da7a12016-08-25 11:17:50 +0200798
799 /* MathGlyphVariantRecords for alternative variants of the glyphs. */
Behdad Esfahbod5639e252021-03-31 16:04:43 -0600800 Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord;
Frédéric Wang51da7a12016-08-25 11:17:50 +0200801
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200802 public:
Behdad Esfahbod1f3327f2016-09-26 16:10:08 +0100803 DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
Frédéric Wang51da7a12016-08-25 11:17:50 +0200804};
805
806struct MathVariants
807{
Qunxin Liu1afc3872021-09-19 20:41:43 -0700808 void closure_glyphs (const hb_set_t *glyph_set,
809 hb_set_t *variant_glyphs) const
810 {
811 const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount);
812
813 if (vertGlyphCoverage)
814 {
815 const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount);
816 + hb_zip (this+vertGlyphCoverage, vert_offsets)
817 | hb_filter (glyph_set, hb_first)
818 | hb_map (hb_second)
819 | hb_map (hb_add (this))
820 | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
821 ;
822 }
823
824 if (horizGlyphCoverage)
825 {
826 const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount);
827 + hb_zip (this+horizGlyphCoverage, hori_offsets)
828 | hb_filter (glyph_set, hb_first)
829 | hb_map (hb_second)
830 | hb_map (hb_add (this))
831 | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
832 ;
833 }
834 }
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700835
836 void collect_coverage_and_indices (hb_sorted_vector_t<hb_codepoint_t>& new_coverage,
837 const Offset16To<Coverage>& coverage,
838 unsigned i,
Qunxin Liu794b00d2021-09-27 17:21:16 -0700839 unsigned end_index,
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700840 hb_set_t& indices,
841 const hb_set_t& glyphset,
842 const hb_map_t& glyph_map) const
843 {
Qunxin Liu794b00d2021-09-27 17:21:16 -0700844 if (!coverage) return;
845
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700846 for (const auto _ : (this+coverage).iter ())
847 {
Qunxin Liu794b00d2021-09-27 17:21:16 -0700848 if (i >= end_index) return;
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700849 if (glyphset.has (_))
850 {
851 unsigned new_gid = glyph_map.get (_);
852 new_coverage.push (new_gid);
853 indices.add (i);
854 }
855 i++;
856 }
857 }
858
859 bool subset (hb_subset_context_t *c) const
860 {
861 TRACE_SUBSET (this);
862 const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
863 const hb_map_t &glyph_map = *c->plan->glyph_map;
864
865 auto *out = c->serializer->start_embed (*this);
866 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
867 if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW))
868 return_trace (false);
869
870 hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage;
871 hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage;
872 hb_set_t indices;
Qunxin Liu794b00d2021-09-27 17:21:16 -0700873 collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map);
874 collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map);
Qunxin Liuca7b9da2021-09-20 14:42:51 -0700875
876 if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
877 return_trace (false);
878 if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
879 return_trace (false);
880
881 for (unsigned i : indices.iter ())
882 {
883 auto *o = c->serializer->embed (glyphConstruction[i]);
884 if (!o) return_trace (false);
885 o->serialize_subset (c, glyphConstruction[i], this);
886 }
887
888 out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
889 out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
890 return_trace (true);
891 }
892
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330893 bool sanitize_offsets (hb_sanitize_context_t *c) const
Frédéric Wang51da7a12016-08-25 11:17:50 +0200894 {
895 TRACE_SANITIZE (this);
896 unsigned int count = vertGlyphCount + horizGlyphCount;
897 for (unsigned int i = 0; i < count; i++)
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200898 if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false);
Frédéric Wang51da7a12016-08-25 11:17:50 +0200899 return_trace (true);
900 }
901
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330902 bool sanitize (hb_sanitize_context_t *c) const
Frédéric Wang51da7a12016-08-25 11:17:50 +0200903 {
904 TRACE_SANITIZE (this);
905 return_trace (c->check_struct (this) &&
906 vertGlyphCoverage.sanitize (c, this) &&
907 horizGlyphCoverage.sanitize (c, this) &&
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200908 c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) &&
Frédéric Wang51da7a12016-08-25 11:17:50 +0200909 sanitize_offsets (c));
910 }
911
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330912 hb_position_t get_min_connector_overlap (hb_direction_t direction,
Behdad Esfahbod7fe0e282016-09-26 17:51:47 +0100913 hb_font_t *font) const
914 { return font->em_scale_dir (minConnectorOverlap, direction); }
Frédéric Wang51da7a12016-08-25 11:17:50 +0200915
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330916 unsigned int get_glyph_variants (hb_codepoint_t glyph,
917 hb_direction_t direction,
918 hb_font_t *font,
919 unsigned int start_offset,
920 unsigned int *variants_count, /* IN/OUT */
921 hb_ot_math_glyph_variant_t *variants /* OUT */) const
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200922 { return get_glyph_construction (glyph, direction, font)
923 .get_variants (direction, font, start_offset, variants_count, variants); }
Frédéric Wang51da7a12016-08-25 11:17:50 +0200924
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330925 unsigned int get_glyph_parts (hb_codepoint_t glyph,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +0430926 hb_direction_t direction,
927 hb_font_t *font,
928 unsigned int start_offset,
929 unsigned int *parts_count, /* IN/OUT */
930 hb_ot_math_glyph_part_t *parts /* OUT */,
931 hb_position_t *italics_correction /* OUT */) const
Behdad Esfahbod559eb562016-09-26 21:46:05 +0200932 { return get_glyph_construction (glyph, direction, font)
933 .get_assembly ()
934 .get_parts (direction, font,
935 start_offset, parts_count, parts,
936 italics_correction); }
937
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200938 private:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330939 const MathGlyphConstruction &
940 get_glyph_construction (hb_codepoint_t glyph,
941 hb_direction_t direction,
942 hb_font_t *font HB_UNUSED) const
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200943 {
944 bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
945 unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600946 const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200947 : horizGlyphCoverage;
Frédéric Wang51da7a12016-08-25 11:17:50 +0200948
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200949 unsigned int index = (this+coverage).get_coverage (glyph);
Ebrahim Byagowid7c50ff2018-11-15 23:10:49 +0330950 if (unlikely (index >= count)) return Null (MathGlyphConstruction);
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200951
952 if (!vertical)
Frédéric Wang51da7a12016-08-25 11:17:50 +0200953 index += vertGlyphCount;
954
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200955 return this+glyphConstruction[index];
Frédéric Wang51da7a12016-08-25 11:17:50 +0200956 }
957
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200958 protected:
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430959 HBUINT16 minConnectorOverlap;
960 /* Minimum overlap of connecting
961 * glyphs during glyph construction,
962 * in design units. */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600963 Offset16To<Coverage> vertGlyphCoverage;
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430964 /* Offset to Coverage table -
965 * from the beginning of MathVariants
966 * table. */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600967 Offset16To<Coverage> horizGlyphCoverage;
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430968 /* Offset to Coverage table -
969 * from the beginning of MathVariants
970 * table. */
971 HBUINT16 vertGlyphCount; /* Number of glyphs for which
972 * information is provided for
973 * vertically growing variants. */
974 HBUINT16 horizGlyphCount;/* Number of glyphs for which
975 * information is provided for
976 * horizontally growing variants. */
Frédéric Wang51da7a12016-08-25 11:17:50 +0200977
978 /* Array of offsets to MathGlyphConstruction tables - from the beginning of
979 the MathVariants table, for shapes growing in vertical/horizontal
980 direction. */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600981 UnsizedArrayOf<Offset16To<MathGlyphConstruction>>
Ebrahim Byagowice114d62019-12-31 15:53:02 +0330982 glyphConstruction;
Frédéric Wang51da7a12016-08-25 11:17:50 +0200983
Behdad Esfahbod353f4552016-09-26 21:22:48 +0200984 public:
Behdad Esfahbod1f3327f2016-09-26 16:10:08 +0100985 DEFINE_SIZE_ARRAY (10, glyphConstruction);
Frédéric Wang51da7a12016-08-25 11:17:50 +0200986};
987
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +0100988
Frédéric Wang5fbcb992016-08-25 10:47:15 +0200989/*
Ebrahim Byagowia02c3ee2018-04-12 13:38:19 +0430990 * MATH -- Mathematical typesetting
991 * https://docs.microsoft.com/en-us/typography/opentype/spec/math
Frédéric Wang5fbcb992016-08-25 10:47:15 +0200992 */
993
994struct MATH
995{
Behdad Esfahbodef006542019-01-22 12:08:57 +0100996 static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH;
Frédéric Wang5fbcb992016-08-25 10:47:15 +0200997
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330998 bool has_data () const { return version.to_int (); }
Behdad Esfahbodb912fbe2018-08-06 06:30:12 -0700999
Qunxin Liu1afc3872021-09-19 20:41:43 -07001000 void closure_glyphs (hb_set_t *glyph_set) const
1001 {
1002 if (mathVariants)
1003 {
1004 hb_set_t variant_glyphs;
1005 (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs);
1006 hb_set_union (glyph_set, &variant_glyphs);
1007 }
1008 }
1009
Qunxin Liuca7b9da2021-09-20 14:42:51 -07001010 bool subset (hb_subset_context_t *c) const
1011 {
1012 TRACE_SUBSET (this);
1013 auto *out = c->serializer->embed (*this);
1014 if (unlikely (!out)) return_trace (false);
1015
1016 out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head);
1017 out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this);
1018 out->mathVariants.serialize_subset (c, mathVariants, this);
1019 return_trace (true);
1020 }
1021
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301022 bool sanitize (hb_sanitize_context_t *c) const
Frédéric Wang5fbcb992016-08-25 10:47:15 +02001023 {
1024 TRACE_SANITIZE (this);
1025 return_trace (version.sanitize (c) &&
Behdad Esfahbod8a8cfad2016-09-26 11:47:05 +01001026 likely (version.major == 1) &&
1027 mathConstants.sanitize (c, this) &&
Frédéric Wang51da7a12016-08-25 11:17:50 +02001028 mathGlyphInfo.sanitize (c, this) &&
1029 mathVariants.sanitize (c, this));
Frédéric Wang319ff592016-08-25 11:06:41 +02001030 }
1031
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301032 hb_position_t get_constant (hb_ot_math_constant_t constant,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +04301033 hb_font_t *font) const
Behdad Esfahbod54c0cc32016-09-26 11:56:40 +01001034 { return (this+mathConstants).get_value (constant, font); }
Frédéric Wang5fbcb992016-08-25 10:47:15 +02001035
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301036 const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; }
Frédéric Wang51da7a12016-08-25 11:17:50 +02001037
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301038 const MathVariants &get_variants () const { return this+mathVariants; }
Frédéric Wang51da7a12016-08-25 11:17:50 +02001039
Behdad Esfahbod353f4552016-09-26 21:22:48 +02001040 protected:
Ebrahim Byagowi08428a12020-04-24 23:45:17 +04301041 FixedVersion<>version; /* Version of the MATH table
1042 * initially set to 0x00010000u */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06001043 Offset16To<MathConstants>
Ebrahim Byagowi08428a12020-04-24 23:45:17 +04301044 mathConstants; /* MathConstants table */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06001045 Offset16To<MathGlyphInfo>
Ebrahim Byagowi08428a12020-04-24 23:45:17 +04301046 mathGlyphInfo; /* MathGlyphInfo table */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06001047 Offset16To<MathVariants>
Ebrahim Byagowi08428a12020-04-24 23:45:17 +04301048 mathVariants; /* MathVariants table */
Frédéric Wang319ff592016-08-25 11:06:41 +02001049
Behdad Esfahbod353f4552016-09-26 21:22:48 +02001050 public:
Frédéric Wang51da7a12016-08-25 11:17:50 +02001051 DEFINE_SIZE_STATIC (10);
Frédéric Wang5fbcb992016-08-25 10:47:15 +02001052};
1053
Behdad Esfahbod3b5263b2017-01-09 15:49:08 -08001054} /* namespace OT */
Frédéric Wang5fbcb992016-08-25 10:47:15 +02001055
1056
Behdad Esfahbod93ef6842017-01-09 21:11:00 -08001057#endif /* HB_OT_MATH_TABLE_HH */