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