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 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 sanitize_math_value_recordsOT::MathConstants95 bool sanitize_math_value_records (hb_sanitize_context_t *c) const 96 { 97 TRACE_SANITIZE (this); 98 99 unsigned int count = ARRAY_LENGTH (mathValueRecords); 100 for (unsigned int i = 0; i < count; i++) 101 if (!mathValueRecords[i].sanitize (c, this)) 102 return_trace (false); 103 104 return_trace (true); 105 } 106 sanitizeOT::MathConstants107 bool sanitize (hb_sanitize_context_t *c) const 108 { 109 TRACE_SANITIZE (this); 110 return_trace (c->check_struct (this) && sanitize_math_value_records (c)); 111 } 112 get_valueOT::MathConstants113 hb_position_t get_value (hb_ot_math_constant_t constant, 114 hb_font_t *font) const 115 { 116 switch (constant) { 117 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 122 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: 130 return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this); 131 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: 179 return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this); 180 181 case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT: 182 return radicalDegreeBottomRaisePercent; 183 184 default: 185 return 0; 186 } 187 } 188 189 protected: 190 HBINT16 percentScaleDown[2]; 191 HBUINT16 minHeight[2]; 192 MathValueRecord mathValueRecords[51]; 193 HBINT16 radicalDegreeBottomRaisePercent; 194 195 public: 196 DEFINE_SIZE_STATIC (214); 197 }; 198 199 struct MathItalicsCorrectionInfo 200 { subsetOT::MathItalicsCorrectionInfo201 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 sanitizeOT::MathItalicsCorrectionInfo223 bool sanitize (hb_sanitize_context_t *c) const 224 { 225 TRACE_SANITIZE (this); 226 return_trace (c->check_struct (this) && 227 coverage.sanitize (c, this) && 228 italicsCorrection.sanitize (c, this)); 229 } 230 get_valueOT::MathItalicsCorrectionInfo231 hb_position_t get_value (hb_codepoint_t glyph, 232 hb_font_t *font) const 233 { 234 unsigned int index = (this+coverage).get_coverage (glyph); 235 return italicsCorrection[index].get_x_value (font, this); 236 } 237 238 protected: 239 Offset16To<Coverage> coverage; /* Offset to Coverage table - 240 * from the beginning of 241 * MathItalicsCorrectionInfo 242 * table. */ 243 Array16Of<MathValueRecord> italicsCorrection; /* Array of MathValueRecords 244 * defining italics correction 245 * values for each 246 * covered glyph. */ 247 248 public: 249 DEFINE_SIZE_ARRAY (4, italicsCorrection); 250 }; 251 252 struct MathTopAccentAttachment 253 { subsetOT::MathTopAccentAttachment254 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 sanitizeOT::MathTopAccentAttachment276 bool sanitize (hb_sanitize_context_t *c) const 277 { 278 TRACE_SANITIZE (this); 279 return_trace (c->check_struct (this) && 280 topAccentCoverage.sanitize (c, this) && 281 topAccentAttachment.sanitize (c, this)); 282 } 283 get_valueOT::MathTopAccentAttachment284 hb_position_t get_value (hb_codepoint_t glyph, 285 hb_font_t *font) const 286 { 287 unsigned int index = (this+topAccentCoverage).get_coverage (glyph); 288 if (index == NOT_COVERED) 289 return font->get_glyph_h_advance (glyph) / 2; 290 return topAccentAttachment[index].get_x_value (font, this); 291 } 292 293 protected: 294 Offset16To<Coverage> topAccentCoverage; /* Offset to Coverage table - 295 * from the beginning of 296 * MathTopAccentAttachment 297 * table. */ 298 Array16Of<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords 299 * defining top accent 300 * attachment points for each 301 * covered glyph. */ 302 303 public: 304 DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment); 305 }; 306 307 struct MathKern 308 { copyOT::MathKern309 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 sanitize_math_value_recordsOT::MathKern325 bool sanitize_math_value_records (hb_sanitize_context_t *c) const 326 { 327 TRACE_SANITIZE (this); 328 unsigned int count = 2 * heightCount + 1; 329 for (unsigned int i = 0; i < count; i++) 330 if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false); 331 return_trace (true); 332 } 333 sanitizeOT::MathKern334 bool sanitize (hb_sanitize_context_t *c) const 335 { 336 TRACE_SANITIZE (this); 337 return_trace (c->check_struct (this) && 338 c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) && 339 sanitize_math_value_records (c)); 340 } 341 get_valueOT::MathKern342 hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const 343 { 344 const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; 345 const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; 346 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 */ 356 unsigned int i = 0; 357 unsigned int count = heightCount; 358 while (count > 0) 359 { 360 unsigned int half = count / 2; 361 hb_position_t height = correctionHeight[i + half].get_y_value (font, this); 362 if (sign * height < sign * correction_height) 363 { 364 i += half + 1; 365 count -= half + 1; 366 } else 367 count = half; 368 } 369 return kernValue[i].get_x_value (font, this); 370 } 371 get_entriesOT::MathKern372 unsigned int get_entries (unsigned int start_offset, 373 unsigned int *entries_count, /* IN/OUT */ 374 hb_ot_math_kern_entry_t *kern_entries, /* OUT */ 375 hb_font_t *font) const 376 { 377 const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; 378 const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; 379 const unsigned int entriesCount = heightCount + 1; 380 381 if (entries_count) 382 { 383 unsigned int start = hb_min (start_offset, entriesCount); 384 unsigned int end = hb_min (start + *entries_count, entriesCount); 385 *entries_count = end - start; 386 387 for (unsigned int i = 0; i < *entries_count; i++) { 388 unsigned int j = start + i; 389 390 hb_position_t max_height; 391 if (j == heightCount) { 392 max_height = INT32_MAX; 393 } else { 394 max_height = correctionHeight[j].get_y_value (font, this); 395 } 396 397 kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)}; 398 } 399 } 400 return entriesCount; 401 } 402 403 protected: 404 HBUINT16 heightCount; 405 UnsizedArrayOf<MathValueRecord> 406 mathValueRecordsZ; 407 /* Array of correction heights at 408 * which the kern value changes. 409 * Sorted by the height value in 410 * design units (heightCount entries), 411 * Followed by: 412 * Array of kern values corresponding 413 * to heights. (heightCount+1 entries). 414 */ 415 416 public: 417 DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); 418 }; 419 420 struct MathKernInfoRecord 421 { copyOT::MathKernInfoRecord422 MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const 423 { 424 TRACE_SERIALIZE (this); 425 auto *out = c->embed (this); 426 if (unlikely (!out)) return_trace (nullptr); 427 428 unsigned count = ARRAY_LENGTH (mathKern); 429 for (unsigned i = 0; i < count; i++) 430 out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head); 431 432 return_trace (out); 433 } 434 sanitizeOT::MathKernInfoRecord435 bool sanitize (hb_sanitize_context_t *c, const void *base) const 436 { 437 TRACE_SANITIZE (this); 438 439 unsigned int count = ARRAY_LENGTH (mathKern); 440 for (unsigned int i = 0; i < count; i++) 441 if (unlikely (!mathKern[i].sanitize (c, base))) 442 return_trace (false); 443 444 return_trace (true); 445 } 446 get_kerningOT::MathKernInfoRecord447 hb_position_t get_kerning (hb_ot_math_kern_t kern, 448 hb_position_t correction_height, 449 hb_font_t *font, 450 const void *base) const 451 { 452 unsigned int idx = kern; 453 if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0; 454 return (base+mathKern[idx]).get_value (correction_height, font); 455 } 456 get_kerningsOT::MathKernInfoRecord457 unsigned int get_kernings (hb_ot_math_kern_t kern, 458 unsigned int start_offset, 459 unsigned int *entries_count, /* IN/OUT */ 460 hb_ot_math_kern_entry_t *kern_entries, /* OUT */ 461 hb_font_t *font, 462 const void *base) const 463 { 464 unsigned int idx = kern; 465 if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) { 466 if (entries_count) *entries_count = 0; 467 return 0; 468 } 469 return (base+mathKern[idx]).get_entries (start_offset, 470 entries_count, 471 kern_entries, 472 font); 473 } 474 475 protected: 476 /* Offset to MathKern table for each corner - 477 * from the beginning of MathKernInfo table. May be NULL. */ 478 Offset16To<MathKern> mathKern[4]; 479 480 public: 481 DEFINE_SIZE_STATIC (8); 482 }; 483 484 struct MathKernInfo 485 { subsetOT::MathKernInfo486 bool subset (hb_subset_context_t *c) const 487 { 488 TRACE_SUBSET (this); 489 const hb_set_t &glyphset = *c->plan->_glyphset_mathed; 490 const hb_map_t &glyph_map = *c->plan->glyph_map; 491 492 auto *out = c->serializer->start_embed (*this); 493 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 494 495 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 496 + hb_zip (this+mathKernCoverage, mathKernInfoRecords) 497 | hb_filter (glyphset, hb_first) 498 | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second) 499 | hb_map (hb_first) 500 | hb_map (glyph_map) 501 | hb_sink (new_coverage) 502 ; 503 504 out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ()); 505 return_trace (true); 506 } 507 sanitizeOT::MathKernInfo508 bool sanitize (hb_sanitize_context_t *c) const 509 { 510 TRACE_SANITIZE (this); 511 return_trace (c->check_struct (this) && 512 mathKernCoverage.sanitize (c, this) && 513 mathKernInfoRecords.sanitize (c, this)); 514 } 515 get_kerningOT::MathKernInfo516 hb_position_t get_kerning (hb_codepoint_t glyph, 517 hb_ot_math_kern_t kern, 518 hb_position_t correction_height, 519 hb_font_t *font) const 520 { 521 unsigned int index = (this+mathKernCoverage).get_coverage (glyph); 522 return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); 523 } 524 get_kerningsOT::MathKernInfo525 unsigned int get_kernings (hb_codepoint_t glyph, 526 hb_ot_math_kern_t kern, 527 unsigned int start_offset, 528 unsigned int *entries_count, /* IN/OUT */ 529 hb_ot_math_kern_entry_t *kern_entries, /* OUT */ 530 hb_font_t *font) const 531 { 532 unsigned int index = (this+mathKernCoverage).get_coverage (glyph); 533 return mathKernInfoRecords[index].get_kernings (kern, 534 start_offset, 535 entries_count, 536 kern_entries, 537 font, 538 this); 539 } 540 541 protected: 542 Offset16To<Coverage> 543 mathKernCoverage; 544 /* Offset to Coverage table - 545 * from the beginning of the 546 * MathKernInfo table. */ 547 Array16Of<MathKernInfoRecord> 548 mathKernInfoRecords; 549 /* Array of MathKernInfoRecords, 550 * per-glyph information for 551 * mathematical positioning 552 * of subscripts and 553 * superscripts. */ 554 555 public: 556 DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); 557 }; 558 559 struct MathGlyphInfo 560 { subsetOT::MathGlyphInfo561 bool subset (hb_subset_context_t *c) const 562 { 563 TRACE_SUBSET (this); 564 auto *out = c->serializer->embed (*this); 565 if (unlikely (!out)) return_trace (false); 566 567 out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this); 568 out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this); 569 570 const hb_set_t &glyphset = *c->plan->_glyphset_mathed; 571 const hb_map_t &glyph_map = *c->plan->glyph_map; 572 573 auto it = 574 + hb_iter (this+extendedShapeCoverage) 575 | hb_filter (glyphset) 576 | hb_map_retains_sorting (glyph_map) 577 ; 578 579 if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it); 580 else out->extendedShapeCoverage = 0; 581 582 out->mathKernInfo.serialize_subset (c, mathKernInfo, this); 583 return_trace (true); 584 } 585 sanitizeOT::MathGlyphInfo586 bool sanitize (hb_sanitize_context_t *c) const 587 { 588 TRACE_SANITIZE (this); 589 return_trace (c->check_struct (this) && 590 mathItalicsCorrectionInfo.sanitize (c, this) && 591 mathTopAccentAttachment.sanitize (c, this) && 592 extendedShapeCoverage.sanitize (c, this) && 593 mathKernInfo.sanitize (c, this)); 594 } 595 596 hb_position_t get_italics_correctionOT::MathGlyphInfo597 get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const 598 { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } 599 600 hb_position_t get_top_accent_attachmentOT::MathGlyphInfo601 get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const 602 { return (this+mathTopAccentAttachment).get_value (glyph, font); } 603 is_extended_shapeOT::MathGlyphInfo604 bool is_extended_shape (hb_codepoint_t glyph) const 605 { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } 606 get_kerningOT::MathGlyphInfo607 hb_position_t get_kerning (hb_codepoint_t glyph, 608 hb_ot_math_kern_t kern, 609 hb_position_t correction_height, 610 hb_font_t *font) const 611 { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } 612 get_kerningsOT::MathGlyphInfo613 hb_position_t get_kernings (hb_codepoint_t glyph, 614 hb_ot_math_kern_t kern, 615 unsigned int start_offset, 616 unsigned int *entries_count, /* IN/OUT */ 617 hb_ot_math_kern_entry_t *kern_entries, /* OUT */ 618 hb_font_t *font) const 619 { return (this+mathKernInfo).get_kernings (glyph, 620 kern, 621 start_offset, 622 entries_count, 623 kern_entries, 624 font); } 625 626 protected: 627 /* Offset to MathItalicsCorrectionInfo table - 628 * from the beginning of MathGlyphInfo table. */ 629 Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo; 630 631 /* Offset to MathTopAccentAttachment table - 632 * from the beginning of MathGlyphInfo table. */ 633 Offset16To<MathTopAccentAttachment> mathTopAccentAttachment; 634 635 /* Offset to coverage table for Extended Shape glyphs - 636 * from the beginning of MathGlyphInfo table. When the left or right glyph of 637 * a box is an extended shape variant, the (ink) box (and not the default 638 * position defined by values in MathConstants table) should be used for 639 * vertical positioning purposes. May be NULL.. */ 640 Offset16To<Coverage> extendedShapeCoverage; 641 642 /* Offset to MathKernInfo table - 643 * from the beginning of MathGlyphInfo table. */ 644 Offset16To<MathKernInfo> mathKernInfo; 645 646 public: 647 DEFINE_SIZE_STATIC (8); 648 }; 649 650 struct MathGlyphVariantRecord 651 { 652 friend struct MathGlyphConstruction; 653 subsetOT::MathGlyphVariantRecord654 bool subset (hb_subset_context_t *c) const 655 { 656 TRACE_SUBSET (this); 657 auto *out = c->serializer->embed (this); 658 if (unlikely (!out)) return_trace (false); 659 660 const hb_map_t& glyph_map = *c->plan->glyph_map; 661 return_trace (c->serializer->check_assign (out->variantGlyph, glyph_map.get (variantGlyph), HB_SERIALIZE_ERROR_INT_OVERFLOW)); 662 } 663 sanitizeOT::MathGlyphVariantRecord664 bool sanitize (hb_sanitize_context_t *c) const 665 { 666 TRACE_SANITIZE (this); 667 return_trace (c->check_struct (this)); 668 } 669 closure_glyphsOT::MathGlyphVariantRecord670 void closure_glyphs (hb_set_t *variant_glyphs) const 671 { variant_glyphs->add (variantGlyph); } 672 673 protected: 674 HBGlyphID16 variantGlyph; /* Glyph ID for the variant. */ 675 HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the 676 * variant, in the direction of requested 677 * glyph extension. */ 678 679 public: 680 DEFINE_SIZE_STATIC (4); 681 }; 682 683 struct PartFlags : HBUINT16 684 { 685 enum Flags { 686 Extender = 0x0001u, /* If set, the part can be skipped or repeated. */ 687 688 Defined = 0x0001u, /* All defined flags. */ 689 }; 690 691 public: 692 DEFINE_SIZE_STATIC (2); 693 }; 694 695 struct MathGlyphPartRecord 696 { subsetOT::MathGlyphPartRecord697 bool subset (hb_subset_context_t *c) const 698 { 699 TRACE_SUBSET (this); 700 auto *out = c->serializer->embed (this); 701 if (unlikely (!out)) return_trace (false); 702 703 const hb_map_t& glyph_map = *c->plan->glyph_map; 704 return_trace (c->serializer->check_assign (out->glyph, glyph_map.get (glyph), HB_SERIALIZE_ERROR_INT_OVERFLOW)); 705 } 706 sanitizeOT::MathGlyphPartRecord707 bool sanitize (hb_sanitize_context_t *c) const 708 { 709 TRACE_SANITIZE (this); 710 return_trace (c->check_struct (this)); 711 } 712 extractOT::MathGlyphPartRecord713 void extract (hb_ot_math_glyph_part_t &out, 714 int64_t mult, 715 hb_font_t *font) const 716 { 717 out.glyph = glyph; 718 719 out.start_connector_length = font->em_mult (startConnectorLength, mult); 720 out.end_connector_length = font->em_mult (endConnectorLength, mult); 721 out.full_advance = font->em_mult (fullAdvance, mult); 722 723 static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER == 724 (unsigned int) PartFlags::Extender, ""); 725 726 out.flags = (hb_ot_math_glyph_part_flags_t) 727 (unsigned int) 728 (partFlags & PartFlags::Defined); 729 } 730 closure_glyphsOT::MathGlyphPartRecord731 void closure_glyphs (hb_set_t *variant_glyphs) const 732 { variant_glyphs->add (glyph); } 733 734 protected: 735 HBGlyphID16 glyph; /* Glyph ID for the part. */ 736 HBUINT16 startConnectorLength; 737 /* Advance width/ height of the straight bar 738 * connector material, in design units, is at 739 * the beginning of the glyph, in the 740 * direction of the extension. */ 741 HBUINT16 endConnectorLength; 742 /* Advance width/ height of the straight bar 743 * connector material, in design units, is at 744 * the end of the glyph, in the direction of 745 * the extension. */ 746 HBUINT16 fullAdvance; /* Full advance width/height for this part, 747 * in the direction of the extension. 748 * In design units. */ 749 PartFlags partFlags; /* Part qualifiers. */ 750 751 public: 752 DEFINE_SIZE_STATIC (10); 753 }; 754 755 struct MathGlyphAssembly 756 { subsetOT::MathGlyphAssembly757 bool subset (hb_subset_context_t *c) const 758 { 759 TRACE_SUBSET (this); 760 auto *out = c->serializer->start_embed (*this); 761 if (unlikely (!out)) return_trace (false); 762 763 if (!c->serializer->copy (italicsCorrection, this)) return_trace (false); 764 if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false); 765 766 for (const auto& record : partRecords.iter ()) 767 if (!record.subset (c)) return_trace (false); 768 return_trace (true); 769 } 770 sanitizeOT::MathGlyphAssembly771 bool sanitize (hb_sanitize_context_t *c) const 772 { 773 TRACE_SANITIZE (this); 774 return_trace (c->check_struct (this) && 775 italicsCorrection.sanitize (c, this) && 776 partRecords.sanitize (c)); 777 } 778 get_partsOT::MathGlyphAssembly779 unsigned int get_parts (hb_direction_t direction, 780 hb_font_t *font, 781 unsigned int start_offset, 782 unsigned int *parts_count, /* IN/OUT */ 783 hb_ot_math_glyph_part_t *parts /* OUT */, 784 hb_position_t *italics_correction /* OUT */) const 785 { 786 if (parts_count) 787 { 788 int64_t mult = font->dir_mult (direction); 789 for (auto _ : hb_zip (partRecords.sub_array (start_offset, parts_count), 790 hb_array (parts, *parts_count))) 791 _.first.extract (_.second, mult, font); 792 } 793 794 if (italics_correction) 795 *italics_correction = italicsCorrection.get_x_value (font, this); 796 797 return partRecords.len; 798 } 799 closure_glyphsOT::MathGlyphAssembly800 void closure_glyphs (hb_set_t *variant_glyphs) const 801 { 802 for (const auto& _ : partRecords.iter ()) 803 _.closure_glyphs (variant_glyphs); 804 } 805 806 protected: 807 MathValueRecord 808 italicsCorrection; 809 /* Italics correction of this 810 * MathGlyphAssembly. Should not 811 * depend on the assembly size. */ 812 Array16Of<MathGlyphPartRecord> 813 partRecords; /* Array of part records, from 814 * left to right and bottom to 815 * top. */ 816 817 public: 818 DEFINE_SIZE_ARRAY (6, partRecords); 819 }; 820 821 struct MathGlyphConstruction 822 { subsetOT::MathGlyphConstruction823 bool subset (hb_subset_context_t *c) const 824 { 825 TRACE_SUBSET (this); 826 auto *out = c->serializer->start_embed (*this); 827 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 828 829 out->glyphAssembly.serialize_subset (c, glyphAssembly, this); 830 831 if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 832 return_trace (false); 833 for (const auto& record : mathGlyphVariantRecord.iter ()) 834 if (!record.subset (c)) return_trace (false); 835 836 return_trace (true); 837 } 838 sanitizeOT::MathGlyphConstruction839 bool sanitize (hb_sanitize_context_t *c) const 840 { 841 TRACE_SANITIZE (this); 842 return_trace (c->check_struct (this) && 843 glyphAssembly.sanitize (c, this) && 844 mathGlyphVariantRecord.sanitize (c)); 845 } 846 get_assemblyOT::MathGlyphConstruction847 const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; } 848 get_variantsOT::MathGlyphConstruction849 unsigned int get_variants (hb_direction_t direction, 850 hb_font_t *font, 851 unsigned int start_offset, 852 unsigned int *variants_count, /* IN/OUT */ 853 hb_ot_math_glyph_variant_t *variants /* OUT */) const 854 { 855 if (variants_count) 856 { 857 int64_t mult = font->dir_mult (direction); 858 for (auto _ : hb_zip (mathGlyphVariantRecord.sub_array (start_offset, variants_count), 859 hb_array (variants, *variants_count))) 860 _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)}; 861 } 862 return mathGlyphVariantRecord.len; 863 } 864 closure_glyphsOT::MathGlyphConstruction865 void closure_glyphs (hb_set_t *variant_glyphs) const 866 { 867 (this+glyphAssembly).closure_glyphs (variant_glyphs); 868 869 for (const auto& _ : mathGlyphVariantRecord.iter ()) 870 _.closure_glyphs (variant_glyphs); 871 } 872 873 protected: 874 /* Offset to MathGlyphAssembly table for this shape - from the beginning of 875 MathGlyphConstruction table. May be NULL. */ 876 Offset16To<MathGlyphAssembly> glyphAssembly; 877 878 /* MathGlyphVariantRecords for alternative variants of the glyphs. */ 879 Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord; 880 881 public: 882 DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord); 883 }; 884 885 struct MathVariants 886 { closure_glyphsOT::MathVariants887 void closure_glyphs (const hb_set_t *glyph_set, 888 hb_set_t *variant_glyphs) const 889 { 890 const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount); 891 892 if (vertGlyphCoverage) 893 { 894 const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount); 895 + hb_zip (this+vertGlyphCoverage, vert_offsets) 896 | hb_filter (glyph_set, hb_first) 897 | hb_map (hb_second) 898 | hb_map (hb_add (this)) 899 | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); }) 900 ; 901 } 902 903 if (horizGlyphCoverage) 904 { 905 const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount); 906 + hb_zip (this+horizGlyphCoverage, hori_offsets) 907 | hb_filter (glyph_set, hb_first) 908 | hb_map (hb_second) 909 | hb_map (hb_add (this)) 910 | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); }) 911 ; 912 } 913 } 914 collect_coverage_and_indicesOT::MathVariants915 void collect_coverage_and_indices (hb_sorted_vector_t<hb_codepoint_t>& new_coverage, 916 const Offset16To<Coverage>& coverage, 917 unsigned i, 918 unsigned end_index, 919 hb_set_t& indices, 920 const hb_set_t& glyphset, 921 const hb_map_t& glyph_map) const 922 { 923 if (!coverage) return; 924 925 for (const auto _ : (this+coverage).iter ()) 926 { 927 if (i >= end_index) return; 928 if (glyphset.has (_)) 929 { 930 unsigned new_gid = glyph_map.get (_); 931 new_coverage.push (new_gid); 932 indices.add (i); 933 } 934 i++; 935 } 936 } 937 subsetOT::MathVariants938 bool subset (hb_subset_context_t *c) const 939 { 940 TRACE_SUBSET (this); 941 const hb_set_t &glyphset = *c->plan->_glyphset_mathed; 942 const hb_map_t &glyph_map = *c->plan->glyph_map; 943 944 auto *out = c->serializer->start_embed (*this); 945 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 946 if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 947 return_trace (false); 948 949 hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage; 950 hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage; 951 hb_set_t indices; 952 collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map); 953 collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map); 954 955 if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 956 return_trace (false); 957 if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 958 return_trace (false); 959 960 for (unsigned i : indices.iter ()) 961 { 962 auto *o = c->serializer->embed (glyphConstruction[i]); 963 if (!o) return_trace (false); 964 o->serialize_subset (c, glyphConstruction[i], this); 965 } 966 967 if (new_vert_coverage) 968 out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ()); 969 970 if (new_hori_coverage) 971 out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ()); 972 return_trace (true); 973 } 974 sanitize_offsetsOT::MathVariants975 bool sanitize_offsets (hb_sanitize_context_t *c) const 976 { 977 TRACE_SANITIZE (this); 978 unsigned int count = vertGlyphCount + horizGlyphCount; 979 for (unsigned int i = 0; i < count; i++) 980 if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false); 981 return_trace (true); 982 } 983 sanitizeOT::MathVariants984 bool sanitize (hb_sanitize_context_t *c) const 985 { 986 TRACE_SANITIZE (this); 987 return_trace (c->check_struct (this) && 988 vertGlyphCoverage.sanitize (c, this) && 989 horizGlyphCoverage.sanitize (c, this) && 990 c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && 991 sanitize_offsets (c)); 992 } 993 get_min_connector_overlapOT::MathVariants994 hb_position_t get_min_connector_overlap (hb_direction_t direction, 995 hb_font_t *font) const 996 { return font->em_scale_dir (minConnectorOverlap, direction); } 997 get_glyph_variantsOT::MathVariants998 unsigned int get_glyph_variants (hb_codepoint_t glyph, 999 hb_direction_t direction, 1000 hb_font_t *font, 1001 unsigned int start_offset, 1002 unsigned int *variants_count, /* IN/OUT */ 1003 hb_ot_math_glyph_variant_t *variants /* OUT */) const 1004 { return get_glyph_construction (glyph, direction, font) 1005 .get_variants (direction, font, start_offset, variants_count, variants); } 1006 get_glyph_partsOT::MathVariants1007 unsigned int get_glyph_parts (hb_codepoint_t glyph, 1008 hb_direction_t direction, 1009 hb_font_t *font, 1010 unsigned int start_offset, 1011 unsigned int *parts_count, /* IN/OUT */ 1012 hb_ot_math_glyph_part_t *parts /* OUT */, 1013 hb_position_t *italics_correction /* OUT */) const 1014 { return get_glyph_construction (glyph, direction, font) 1015 .get_assembly () 1016 .get_parts (direction, font, 1017 start_offset, parts_count, parts, 1018 italics_correction); } 1019 1020 private: 1021 const MathGlyphConstruction & get_glyph_constructionOT::MathVariants1022 get_glyph_construction (hb_codepoint_t glyph, 1023 hb_direction_t direction, 1024 hb_font_t *font HB_UNUSED) const 1025 { 1026 bool vertical = HB_DIRECTION_IS_VERTICAL (direction); 1027 unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; 1028 const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage 1029 : horizGlyphCoverage; 1030 1031 unsigned int index = (this+coverage).get_coverage (glyph); 1032 if (unlikely (index >= count)) return Null (MathGlyphConstruction); 1033 1034 if (!vertical) 1035 index += vertGlyphCount; 1036 1037 return this+glyphConstruction[index]; 1038 } 1039 1040 protected: 1041 HBUINT16 minConnectorOverlap; 1042 /* Minimum overlap of connecting 1043 * glyphs during glyph construction, 1044 * in design units. */ 1045 Offset16To<Coverage> vertGlyphCoverage; 1046 /* Offset to Coverage table - 1047 * from the beginning of MathVariants 1048 * table. */ 1049 Offset16To<Coverage> horizGlyphCoverage; 1050 /* Offset to Coverage table - 1051 * from the beginning of MathVariants 1052 * table. */ 1053 HBUINT16 vertGlyphCount; /* Number of glyphs for which 1054 * information is provided for 1055 * vertically growing variants. */ 1056 HBUINT16 horizGlyphCount;/* Number of glyphs for which 1057 * information is provided for 1058 * horizontally growing variants. */ 1059 1060 /* Array of offsets to MathGlyphConstruction tables - from the beginning of 1061 the MathVariants table, for shapes growing in vertical/horizontal 1062 direction. */ 1063 UnsizedArrayOf<Offset16To<MathGlyphConstruction>> 1064 glyphConstruction; 1065 1066 public: 1067 DEFINE_SIZE_ARRAY (10, glyphConstruction); 1068 }; 1069 1070 1071 /* 1072 * MATH -- Mathematical typesetting 1073 * https://docs.microsoft.com/en-us/typography/opentype/spec/math 1074 */ 1075 1076 struct MATH 1077 { 1078 static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH; 1079 has_dataOT::MATH1080 bool has_data () const { return version.to_int (); } 1081 closure_glyphsOT::MATH1082 void closure_glyphs (hb_set_t *glyph_set) const 1083 { 1084 if (mathVariants) 1085 { 1086 hb_set_t variant_glyphs; 1087 (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs); 1088 hb_set_union (glyph_set, &variant_glyphs); 1089 } 1090 } 1091 subsetOT::MATH1092 bool subset (hb_subset_context_t *c) const 1093 { 1094 TRACE_SUBSET (this); 1095 auto *out = c->serializer->embed (*this); 1096 if (unlikely (!out)) return_trace (false); 1097 1098 out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head); 1099 out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this); 1100 out->mathVariants.serialize_subset (c, mathVariants, this); 1101 return_trace (true); 1102 } 1103 sanitizeOT::MATH1104 bool sanitize (hb_sanitize_context_t *c) const 1105 { 1106 TRACE_SANITIZE (this); 1107 return_trace (version.sanitize (c) && 1108 likely (version.major == 1) && 1109 mathConstants.sanitize (c, this) && 1110 mathGlyphInfo.sanitize (c, this) && 1111 mathVariants.sanitize (c, this)); 1112 } 1113 get_constantOT::MATH1114 hb_position_t get_constant (hb_ot_math_constant_t constant, 1115 hb_font_t *font) const 1116 { return (this+mathConstants).get_value (constant, font); } 1117 get_glyph_infoOT::MATH1118 const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; } 1119 get_variantsOT::MATH1120 const MathVariants &get_variants () const { return this+mathVariants; } 1121 1122 protected: 1123 FixedVersion<>version; /* Version of the MATH table 1124 * initially set to 0x00010000u */ 1125 Offset16To<MathConstants> 1126 mathConstants; /* MathConstants table */ 1127 Offset16To<MathGlyphInfo> 1128 mathGlyphInfo; /* MathGlyphInfo table */ 1129 Offset16To<MathVariants> 1130 mathVariants; /* MathVariants table */ 1131 1132 public: 1133 DEFINE_SIZE_STATIC (10); 1134 }; 1135 1136 } /* namespace OT */ 1137 1138 1139 #endif /* HB_OT_MATH_TABLE_HH */ 1140