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