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 hb_barrier () && 337 c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) && 338 sanitize_math_value_records (c)); 339 } 340 get_valueOT::MathKern341 hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const 342 { 343 const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; 344 const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; 345 int sign = font->y_scale < 0 ? -1 : +1; 346 347 /* According to OpenType spec (v1.9), except for the boundary cases, the index 348 * chosen for kern value should be i such that 349 * correctionHeight[i-1] <= correction_height < correctionHeight[i] 350 * We can use the binary search algorithm of std::upper_bound(). Or, we can 351 * use the internal hb_bsearch_impl. 352 */ 353 unsigned int pos; 354 auto cmp = +[](const void* key, const void* p, 355 int sign, hb_font_t* font, const MathKern* mathKern) -> int { 356 return sign * *(hb_position_t*)key - sign * ((MathValueRecord*)p)->get_y_value(font, mathKern); 357 }; 358 unsigned int i = hb_bsearch_impl(&pos, correction_height, correctionHeight, 359 heightCount, MathValueRecord::static_size, 360 cmp, sign, font, this) ? pos + 1 : pos; 361 return kernValue[i].get_x_value (font, this); 362 } 363 get_entriesOT::MathKern364 unsigned int get_entries (unsigned int start_offset, 365 unsigned int *entries_count, /* IN/OUT */ 366 hb_ot_math_kern_entry_t *kern_entries, /* OUT */ 367 hb_font_t *font) const 368 { 369 const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; 370 const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; 371 const unsigned int entriesCount = heightCount + 1; 372 373 if (entries_count) 374 { 375 unsigned int start = hb_min (start_offset, entriesCount); 376 unsigned int end = hb_min (start + *entries_count, entriesCount); 377 *entries_count = end - start; 378 379 for (unsigned int i = 0; i < *entries_count; i++) { 380 unsigned int j = start + i; 381 382 hb_position_t max_height; 383 if (j == heightCount) { 384 max_height = INT32_MAX; 385 } else { 386 max_height = correctionHeight[j].get_y_value (font, this); 387 } 388 389 kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)}; 390 } 391 } 392 return entriesCount; 393 } 394 395 protected: 396 HBUINT16 heightCount; 397 UnsizedArrayOf<MathValueRecord> 398 mathValueRecordsZ; 399 /* Array of correction heights at 400 * which the kern value changes. 401 * Sorted by the height value in 402 * design units (heightCount entries), 403 * Followed by: 404 * Array of kern values corresponding 405 * to heights. (heightCount+1 entries). 406 */ 407 408 public: 409 DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); 410 }; 411 412 struct MathKernInfoRecord 413 { copyOT::MathKernInfoRecord414 MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const 415 { 416 TRACE_SERIALIZE (this); 417 auto *out = c->embed (this); 418 if (unlikely (!out)) return_trace (nullptr); 419 420 unsigned count = ARRAY_LENGTH (mathKern); 421 for (unsigned i = 0; i < count; i++) 422 out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head); 423 424 return_trace (out); 425 } 426 sanitizeOT::MathKernInfoRecord427 bool sanitize (hb_sanitize_context_t *c, const void *base) const 428 { 429 TRACE_SANITIZE (this); 430 431 unsigned int count = ARRAY_LENGTH (mathKern); 432 for (unsigned int i = 0; i < count; i++) 433 if (unlikely (!mathKern[i].sanitize (c, base))) 434 return_trace (false); 435 436 return_trace (true); 437 } 438 get_kerningOT::MathKernInfoRecord439 hb_position_t get_kerning (hb_ot_math_kern_t kern, 440 hb_position_t correction_height, 441 hb_font_t *font, 442 const void *base) const 443 { 444 unsigned int idx = kern; 445 if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0; 446 return (base+mathKern[idx]).get_value (correction_height, font); 447 } 448 get_kerningsOT::MathKernInfoRecord449 unsigned int get_kernings (hb_ot_math_kern_t kern, 450 unsigned int start_offset, 451 unsigned int *entries_count, /* IN/OUT */ 452 hb_ot_math_kern_entry_t *kern_entries, /* OUT */ 453 hb_font_t *font, 454 const void *base) const 455 { 456 unsigned int idx = kern; 457 if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) { 458 if (entries_count) *entries_count = 0; 459 return 0; 460 } 461 return (base+mathKern[idx]).get_entries (start_offset, 462 entries_count, 463 kern_entries, 464 font); 465 } 466 467 protected: 468 /* Offset to MathKern table for each corner - 469 * from the beginning of MathKernInfo table. May be NULL. */ 470 Offset16To<MathKern> mathKern[4]; 471 472 public: 473 DEFINE_SIZE_STATIC (8); 474 }; 475 476 struct MathKernInfo 477 { subsetOT::MathKernInfo478 bool subset (hb_subset_context_t *c) const 479 { 480 TRACE_SUBSET (this); 481 const hb_set_t &glyphset = c->plan->_glyphset_mathed; 482 const hb_map_t &glyph_map = *c->plan->glyph_map; 483 484 auto *out = c->serializer->start_embed (*this); 485 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 486 487 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 488 + hb_zip (this+mathKernCoverage, mathKernInfoRecords) 489 | hb_filter (glyphset, hb_first) 490 | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second) 491 | hb_map (hb_first) 492 | hb_map (glyph_map) 493 | hb_sink (new_coverage) 494 ; 495 496 out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ()); 497 return_trace (true); 498 } 499 sanitizeOT::MathKernInfo500 bool sanitize (hb_sanitize_context_t *c) const 501 { 502 TRACE_SANITIZE (this); 503 return_trace (c->check_struct (this) && 504 mathKernCoverage.sanitize (c, this) && 505 mathKernInfoRecords.sanitize (c, this)); 506 } 507 get_kerningOT::MathKernInfo508 hb_position_t get_kerning (hb_codepoint_t glyph, 509 hb_ot_math_kern_t kern, 510 hb_position_t correction_height, 511 hb_font_t *font) const 512 { 513 unsigned int index = (this+mathKernCoverage).get_coverage (glyph); 514 return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); 515 } 516 get_kerningsOT::MathKernInfo517 unsigned int get_kernings (hb_codepoint_t glyph, 518 hb_ot_math_kern_t kern, 519 unsigned int start_offset, 520 unsigned int *entries_count, /* IN/OUT */ 521 hb_ot_math_kern_entry_t *kern_entries, /* OUT */ 522 hb_font_t *font) const 523 { 524 unsigned int index = (this+mathKernCoverage).get_coverage (glyph); 525 return mathKernInfoRecords[index].get_kernings (kern, 526 start_offset, 527 entries_count, 528 kern_entries, 529 font, 530 this); 531 } 532 533 protected: 534 Offset16To<Coverage> 535 mathKernCoverage; 536 /* Offset to Coverage table - 537 * from the beginning of the 538 * MathKernInfo table. */ 539 Array16Of<MathKernInfoRecord> 540 mathKernInfoRecords; 541 /* Array of MathKernInfoRecords, 542 * per-glyph information for 543 * mathematical positioning 544 * of subscripts and 545 * superscripts. */ 546 547 public: 548 DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); 549 }; 550 551 struct MathGlyphInfo 552 { subsetOT::MathGlyphInfo553 bool subset (hb_subset_context_t *c) const 554 { 555 TRACE_SUBSET (this); 556 auto *out = c->serializer->embed (*this); 557 if (unlikely (!out)) return_trace (false); 558 559 out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this); 560 out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this); 561 562 const hb_set_t &glyphset = c->plan->_glyphset_mathed; 563 const hb_map_t &glyph_map = *c->plan->glyph_map; 564 565 auto it = 566 + hb_iter (this+extendedShapeCoverage) 567 | hb_take (c->plan->source->get_num_glyphs ()) 568 | hb_filter (glyphset) 569 | hb_map_retains_sorting (glyph_map) 570 ; 571 572 if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it); 573 else out->extendedShapeCoverage = 0; 574 575 out->mathKernInfo.serialize_subset (c, mathKernInfo, this); 576 return_trace (true); 577 } 578 sanitizeOT::MathGlyphInfo579 bool sanitize (hb_sanitize_context_t *c) const 580 { 581 TRACE_SANITIZE (this); 582 return_trace (c->check_struct (this) && 583 mathItalicsCorrectionInfo.sanitize (c, this) && 584 mathTopAccentAttachment.sanitize (c, this) && 585 extendedShapeCoverage.sanitize (c, this) && 586 mathKernInfo.sanitize (c, this)); 587 } 588 589 hb_position_t get_italics_correctionOT::MathGlyphInfo590 get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const 591 { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } 592 593 hb_position_t get_top_accent_attachmentOT::MathGlyphInfo594 get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const 595 { return (this+mathTopAccentAttachment).get_value (glyph, font); } 596 is_extended_shapeOT::MathGlyphInfo597 bool is_extended_shape (hb_codepoint_t glyph) const 598 { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } 599 get_kerningOT::MathGlyphInfo600 hb_position_t get_kerning (hb_codepoint_t glyph, 601 hb_ot_math_kern_t kern, 602 hb_position_t correction_height, 603 hb_font_t *font) const 604 { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } 605 get_kerningsOT::MathGlyphInfo606 hb_position_t get_kernings (hb_codepoint_t glyph, 607 hb_ot_math_kern_t kern, 608 unsigned int start_offset, 609 unsigned int *entries_count, /* IN/OUT */ 610 hb_ot_math_kern_entry_t *kern_entries, /* OUT */ 611 hb_font_t *font) const 612 { return (this+mathKernInfo).get_kernings (glyph, 613 kern, 614 start_offset, 615 entries_count, 616 kern_entries, 617 font); } 618 619 protected: 620 /* Offset to MathItalicsCorrectionInfo table - 621 * from the beginning of MathGlyphInfo table. */ 622 Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo; 623 624 /* Offset to MathTopAccentAttachment table - 625 * from the beginning of MathGlyphInfo table. */ 626 Offset16To<MathTopAccentAttachment> mathTopAccentAttachment; 627 628 /* Offset to coverage table for Extended Shape glyphs - 629 * from the beginning of MathGlyphInfo table. When the left or right glyph of 630 * a box is an extended shape variant, the (ink) box (and not the default 631 * position defined by values in MathConstants table) should be used for 632 * vertical positioning purposes. May be NULL.. */ 633 Offset16To<Coverage> extendedShapeCoverage; 634 635 /* Offset to MathKernInfo table - 636 * from the beginning of MathGlyphInfo table. */ 637 Offset16To<MathKernInfo> mathKernInfo; 638 639 public: 640 DEFINE_SIZE_STATIC (8); 641 }; 642 643 struct MathGlyphVariantRecord 644 { 645 friend struct MathGlyphConstruction; 646 subsetOT::MathGlyphVariantRecord647 bool subset (hb_subset_context_t *c) const 648 { 649 TRACE_SUBSET (this); 650 auto *out = c->serializer->embed (this); 651 if (unlikely (!out)) return_trace (false); 652 653 const hb_map_t& glyph_map = *c->plan->glyph_map; 654 return_trace (c->serializer->check_assign (out->variantGlyph, glyph_map.get (variantGlyph), HB_SERIALIZE_ERROR_INT_OVERFLOW)); 655 } 656 sanitizeOT::MathGlyphVariantRecord657 bool sanitize (hb_sanitize_context_t *c) const 658 { 659 TRACE_SANITIZE (this); 660 return_trace (c->check_struct (this)); 661 } 662 closure_glyphsOT::MathGlyphVariantRecord663 void closure_glyphs (hb_set_t *variant_glyphs) const 664 { variant_glyphs->add (variantGlyph); } 665 666 protected: 667 HBGlyphID16 variantGlyph; /* Glyph ID for the variant. */ 668 HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the 669 * variant, in the direction of requested 670 * glyph extension. */ 671 672 public: 673 DEFINE_SIZE_STATIC (4); 674 }; 675 676 struct PartFlags : HBUINT16 677 { 678 enum Flags { 679 Extender = 0x0001u, /* If set, the part can be skipped or repeated. */ 680 681 Defined = 0x0001u, /* All defined flags. */ 682 }; 683 684 public: 685 DEFINE_SIZE_STATIC (2); 686 }; 687 688 struct MathGlyphPartRecord 689 { subsetOT::MathGlyphPartRecord690 bool subset (hb_subset_context_t *c) const 691 { 692 TRACE_SUBSET (this); 693 auto *out = c->serializer->embed (this); 694 if (unlikely (!out)) return_trace (false); 695 696 const hb_map_t& glyph_map = *c->plan->glyph_map; 697 return_trace (c->serializer->check_assign (out->glyph, glyph_map.get (glyph), HB_SERIALIZE_ERROR_INT_OVERFLOW)); 698 } 699 sanitizeOT::MathGlyphPartRecord700 bool sanitize (hb_sanitize_context_t *c) const 701 { 702 TRACE_SANITIZE (this); 703 return_trace (c->check_struct (this)); 704 } 705 extractOT::MathGlyphPartRecord706 void extract (hb_ot_math_glyph_part_t &out, 707 int64_t mult, 708 hb_font_t *font) const 709 { 710 out.glyph = glyph; 711 712 out.start_connector_length = font->em_mult (startConnectorLength, mult); 713 out.end_connector_length = font->em_mult (endConnectorLength, mult); 714 out.full_advance = font->em_mult (fullAdvance, mult); 715 716 static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER == 717 (unsigned int) PartFlags::Extender, ""); 718 719 out.flags = (hb_ot_math_glyph_part_flags_t) 720 (unsigned int) 721 (partFlags & PartFlags::Defined); 722 } 723 closure_glyphsOT::MathGlyphPartRecord724 void closure_glyphs (hb_set_t *variant_glyphs) const 725 { variant_glyphs->add (glyph); } 726 727 protected: 728 HBGlyphID16 glyph; /* Glyph ID for the part. */ 729 HBUINT16 startConnectorLength; 730 /* Advance width/ height of the straight bar 731 * connector material, in design units, is at 732 * the beginning of the glyph, in the 733 * direction of the extension. */ 734 HBUINT16 endConnectorLength; 735 /* Advance width/ height of the straight bar 736 * connector material, in design units, is at 737 * the end of the glyph, in the direction of 738 * the extension. */ 739 HBUINT16 fullAdvance; /* Full advance width/height for this part, 740 * in the direction of the extension. 741 * In design units. */ 742 PartFlags partFlags; /* Part qualifiers. */ 743 744 public: 745 DEFINE_SIZE_STATIC (10); 746 }; 747 748 struct MathGlyphAssembly 749 { subsetOT::MathGlyphAssembly750 bool subset (hb_subset_context_t *c) const 751 { 752 TRACE_SUBSET (this); 753 754 if (!c->serializer->copy (italicsCorrection, this)) return_trace (false); 755 if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false); 756 757 for (const auto& record : partRecords.iter ()) 758 if (!record.subset (c)) return_trace (false); 759 return_trace (true); 760 } 761 sanitizeOT::MathGlyphAssembly762 bool sanitize (hb_sanitize_context_t *c) const 763 { 764 TRACE_SANITIZE (this); 765 return_trace (c->check_struct (this) && 766 italicsCorrection.sanitize (c, this) && 767 partRecords.sanitize (c)); 768 } 769 get_partsOT::MathGlyphAssembly770 unsigned int get_parts (hb_direction_t direction, 771 hb_font_t *font, 772 unsigned int start_offset, 773 unsigned int *parts_count, /* IN/OUT */ 774 hb_ot_math_glyph_part_t *parts /* OUT */, 775 hb_position_t *italics_correction /* OUT */) const 776 { 777 if (parts_count) 778 { 779 int64_t mult = font->dir_mult (direction); 780 for (auto _ : hb_zip (partRecords.as_array ().sub_array (start_offset, parts_count), 781 hb_array (parts, *parts_count))) 782 _.first.extract (_.second, mult, font); 783 } 784 785 if (italics_correction) 786 *italics_correction = italicsCorrection.get_x_value (font, this); 787 788 return partRecords.len; 789 } 790 closure_glyphsOT::MathGlyphAssembly791 void closure_glyphs (hb_set_t *variant_glyphs) const 792 { 793 for (const auto& _ : partRecords.iter ()) 794 _.closure_glyphs (variant_glyphs); 795 } 796 797 protected: 798 MathValueRecord 799 italicsCorrection; 800 /* Italics correction of this 801 * MathGlyphAssembly. Should not 802 * depend on the assembly size. */ 803 Array16Of<MathGlyphPartRecord> 804 partRecords; /* Array of part records, from 805 * left to right and bottom to 806 * top. */ 807 808 public: 809 DEFINE_SIZE_ARRAY (6, partRecords); 810 }; 811 812 struct MathGlyphConstruction 813 { subsetOT::MathGlyphConstruction814 bool subset (hb_subset_context_t *c) const 815 { 816 TRACE_SUBSET (this); 817 auto *out = c->serializer->start_embed (*this); 818 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 819 820 out->glyphAssembly.serialize_subset (c, glyphAssembly, this); 821 822 if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 823 return_trace (false); 824 for (const auto& record : mathGlyphVariantRecord.iter ()) 825 if (!record.subset (c)) return_trace (false); 826 827 return_trace (true); 828 } 829 sanitizeOT::MathGlyphConstruction830 bool sanitize (hb_sanitize_context_t *c) const 831 { 832 TRACE_SANITIZE (this); 833 return_trace (c->check_struct (this) && 834 glyphAssembly.sanitize (c, this) && 835 mathGlyphVariantRecord.sanitize (c)); 836 } 837 get_assemblyOT::MathGlyphConstruction838 const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; } 839 get_variantsOT::MathGlyphConstruction840 unsigned int get_variants (hb_direction_t direction, 841 hb_font_t *font, 842 unsigned int start_offset, 843 unsigned int *variants_count, /* IN/OUT */ 844 hb_ot_math_glyph_variant_t *variants /* OUT */) const 845 { 846 if (variants_count) 847 { 848 int64_t mult = font->dir_mult (direction); 849 for (auto _ : hb_zip (mathGlyphVariantRecord.as_array ().sub_array (start_offset, variants_count), 850 hb_array (variants, *variants_count))) 851 _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)}; 852 } 853 return mathGlyphVariantRecord.len; 854 } 855 closure_glyphsOT::MathGlyphConstruction856 void closure_glyphs (hb_set_t *variant_glyphs) const 857 { 858 (this+glyphAssembly).closure_glyphs (variant_glyphs); 859 860 for (const auto& _ : mathGlyphVariantRecord.iter ()) 861 _.closure_glyphs (variant_glyphs); 862 } 863 864 protected: 865 /* Offset to MathGlyphAssembly table for this shape - from the beginning of 866 MathGlyphConstruction table. May be NULL. */ 867 Offset16To<MathGlyphAssembly> glyphAssembly; 868 869 /* MathGlyphVariantRecords for alternative variants of the glyphs. */ 870 Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord; 871 872 public: 873 DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord); 874 }; 875 876 struct MathVariants 877 { closure_glyphsOT::MathVariants878 void closure_glyphs (const hb_set_t *glyph_set, 879 hb_set_t *variant_glyphs) const 880 { 881 const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount); 882 883 if (vertGlyphCoverage) 884 { 885 const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount); 886 + hb_zip (this+vertGlyphCoverage, vert_offsets) 887 | hb_filter (glyph_set, hb_first) 888 | hb_map (hb_second) 889 | hb_map (hb_add (this)) 890 | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); }) 891 ; 892 } 893 894 if (horizGlyphCoverage) 895 { 896 const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount); 897 + hb_zip (this+horizGlyphCoverage, hori_offsets) 898 | hb_filter (glyph_set, hb_first) 899 | hb_map (hb_second) 900 | hb_map (hb_add (this)) 901 | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); }) 902 ; 903 } 904 } 905 collect_coverage_and_indicesOT::MathVariants906 void collect_coverage_and_indices (hb_sorted_vector_t<hb_codepoint_t>& new_coverage, 907 const Offset16To<Coverage>& coverage, 908 unsigned i, 909 unsigned end_index, 910 hb_set_t& indices, 911 const hb_set_t& glyphset, 912 const hb_map_t& glyph_map) const 913 { 914 if (!coverage) return; 915 916 for (const auto _ : (this+coverage).iter ()) 917 { 918 if (i >= end_index) return; 919 if (glyphset.has (_)) 920 { 921 unsigned new_gid = glyph_map.get (_); 922 new_coverage.push (new_gid); 923 indices.add (i); 924 } 925 i++; 926 } 927 } 928 subsetOT::MathVariants929 bool subset (hb_subset_context_t *c) const 930 { 931 TRACE_SUBSET (this); 932 const hb_set_t &glyphset = c->plan->_glyphset_mathed; 933 const hb_map_t &glyph_map = *c->plan->glyph_map; 934 935 auto *out = c->serializer->start_embed (*this); 936 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 937 if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 938 return_trace (false); 939 940 hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage; 941 hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage; 942 hb_set_t indices; 943 collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map); 944 collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map); 945 946 if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 947 return_trace (false); 948 if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 949 return_trace (false); 950 951 for (unsigned i : indices.iter ()) 952 { 953 auto *o = c->serializer->embed (glyphConstruction[i]); 954 if (!o) return_trace (false); 955 o->serialize_subset (c, glyphConstruction[i], this); 956 } 957 958 if (new_vert_coverage) 959 out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ()); 960 961 if (new_hori_coverage) 962 out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ()); 963 return_trace (true); 964 } 965 sanitize_offsetsOT::MathVariants966 bool sanitize_offsets (hb_sanitize_context_t *c) const 967 { 968 TRACE_SANITIZE (this); 969 unsigned int count = vertGlyphCount + horizGlyphCount; 970 for (unsigned int i = 0; i < count; i++) 971 if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false); 972 return_trace (true); 973 } 974 sanitizeOT::MathVariants975 bool sanitize (hb_sanitize_context_t *c) const 976 { 977 TRACE_SANITIZE (this); 978 return_trace (c->check_struct (this) && 979 vertGlyphCoverage.sanitize (c, this) && 980 horizGlyphCoverage.sanitize (c, this) && 981 hb_barrier () && 982 c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && 983 sanitize_offsets (c)); 984 } 985 get_min_connector_overlapOT::MathVariants986 hb_position_t get_min_connector_overlap (hb_direction_t direction, 987 hb_font_t *font) const 988 { return font->em_scale_dir (minConnectorOverlap, direction); } 989 get_glyph_variantsOT::MathVariants990 unsigned int get_glyph_variants (hb_codepoint_t glyph, 991 hb_direction_t direction, 992 hb_font_t *font, 993 unsigned int start_offset, 994 unsigned int *variants_count, /* IN/OUT */ 995 hb_ot_math_glyph_variant_t *variants /* OUT */) const 996 { return get_glyph_construction (glyph, direction, font) 997 .get_variants (direction, font, start_offset, variants_count, variants); } 998 get_glyph_partsOT::MathVariants999 unsigned int get_glyph_parts (hb_codepoint_t glyph, 1000 hb_direction_t direction, 1001 hb_font_t *font, 1002 unsigned int start_offset, 1003 unsigned int *parts_count, /* IN/OUT */ 1004 hb_ot_math_glyph_part_t *parts /* OUT */, 1005 hb_position_t *italics_correction /* OUT */) const 1006 { return get_glyph_construction (glyph, direction, font) 1007 .get_assembly () 1008 .get_parts (direction, font, 1009 start_offset, parts_count, parts, 1010 italics_correction); } 1011 1012 private: 1013 const MathGlyphConstruction & get_glyph_constructionOT::MathVariants1014 get_glyph_construction (hb_codepoint_t glyph, 1015 hb_direction_t direction, 1016 hb_font_t *font HB_UNUSED) const 1017 { 1018 bool vertical = HB_DIRECTION_IS_VERTICAL (direction); 1019 unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; 1020 const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage 1021 : horizGlyphCoverage; 1022 1023 unsigned int index = (this+coverage).get_coverage (glyph); 1024 if (unlikely (index >= count)) return Null (MathGlyphConstruction); 1025 1026 if (!vertical) 1027 index += vertGlyphCount; 1028 1029 return this+glyphConstruction[index]; 1030 } 1031 1032 protected: 1033 HBUINT16 minConnectorOverlap; 1034 /* Minimum overlap of connecting 1035 * glyphs during glyph construction, 1036 * in design units. */ 1037 Offset16To<Coverage> vertGlyphCoverage; 1038 /* Offset to Coverage table - 1039 * from the beginning of MathVariants 1040 * table. */ 1041 Offset16To<Coverage> horizGlyphCoverage; 1042 /* Offset to Coverage table - 1043 * from the beginning of MathVariants 1044 * table. */ 1045 HBUINT16 vertGlyphCount; /* Number of glyphs for which 1046 * information is provided for 1047 * vertically growing variants. */ 1048 HBUINT16 horizGlyphCount;/* Number of glyphs for which 1049 * information is provided for 1050 * horizontally growing variants. */ 1051 1052 /* Array of offsets to MathGlyphConstruction tables - from the beginning of 1053 the MathVariants table, for shapes growing in vertical/horizontal 1054 direction. */ 1055 UnsizedArrayOf<Offset16To<MathGlyphConstruction>> 1056 glyphConstruction; 1057 1058 public: 1059 DEFINE_SIZE_ARRAY (10, glyphConstruction); 1060 }; 1061 1062 1063 /* 1064 * MATH -- Mathematical typesetting 1065 * https://docs.microsoft.com/en-us/typography/opentype/spec/math 1066 */ 1067 1068 struct MATH 1069 { 1070 static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH; 1071 has_dataOT::MATH1072 bool has_data () const { return version.to_int (); } 1073 closure_glyphsOT::MATH1074 void closure_glyphs (hb_set_t *glyph_set) const 1075 { 1076 if (mathVariants) 1077 { 1078 hb_set_t variant_glyphs; 1079 (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs); 1080 hb_set_union (glyph_set, &variant_glyphs); 1081 } 1082 } 1083 subsetOT::MATH1084 bool subset (hb_subset_context_t *c) const 1085 { 1086 TRACE_SUBSET (this); 1087 auto *out = c->serializer->embed (*this); 1088 if (unlikely (!out)) return_trace (false); 1089 1090 out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head); 1091 out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this); 1092 out->mathVariants.serialize_subset (c, mathVariants, this); 1093 return_trace (true); 1094 } 1095 sanitizeOT::MATH1096 bool sanitize (hb_sanitize_context_t *c) const 1097 { 1098 TRACE_SANITIZE (this); 1099 return_trace (version.sanitize (c) && 1100 likely (version.major == 1) && 1101 hb_barrier () && 1102 mathConstants.sanitize (c, this) && 1103 mathGlyphInfo.sanitize (c, this) && 1104 mathVariants.sanitize (c, this)); 1105 } 1106 get_constantOT::MATH1107 hb_position_t get_constant (hb_ot_math_constant_t constant, 1108 hb_font_t *font) const 1109 { return (this+mathConstants).get_value (constant, font); } 1110 get_glyph_infoOT::MATH1111 const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; } 1112 get_variantsOT::MATH1113 const MathVariants &get_variants () const { return this+mathVariants; } 1114 1115 protected: 1116 FixedVersion<>version; /* Version of the MATH table 1117 * initially set to 0x00010000u */ 1118 Offset16To<MathConstants> 1119 mathConstants; /* MathConstants table */ 1120 Offset16To<MathGlyphInfo> 1121 mathGlyphInfo; /* MathGlyphInfo table */ 1122 Offset16To<MathVariants> 1123 mathVariants; /* MathVariants table */ 1124 1125 public: 1126 DEFINE_SIZE_STATIC (10); 1127 }; 1128 1129 } /* namespace OT */ 1130 1131 1132 #endif /* HB_OT_MATH_TABLE_HH */ 1133