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 sanitizeOT::MathValueRecord44 bool sanitize (hb_sanitize_context_t *c, const void *base) const 45 { 46 TRACE_SANITIZE (this); 47 return_trace (c->check_struct (this) && deviceTable.sanitize (c, base)); 48 } 49 50 protected: 51 HBINT16 value; /* The X or Y value in design units */ 52 Offset16To<Device> deviceTable; /* Offset to the device table - from the 53 * beginning of parent table. May be NULL. 54 * Suggested format for device table is 1. */ 55 56 public: 57 DEFINE_SIZE_STATIC (4); 58 }; 59 60 struct MathConstants 61 { sanitize_math_value_recordsOT::MathConstants62 bool sanitize_math_value_records (hb_sanitize_context_t *c) const 63 { 64 TRACE_SANITIZE (this); 65 66 unsigned int count = ARRAY_LENGTH (mathValueRecords); 67 for (unsigned int i = 0; i < count; i++) 68 if (!mathValueRecords[i].sanitize (c, this)) 69 return_trace (false); 70 71 return_trace (true); 72 } 73 sanitizeOT::MathConstants74 bool sanitize (hb_sanitize_context_t *c) const 75 { 76 TRACE_SANITIZE (this); 77 return_trace (c->check_struct (this) && sanitize_math_value_records (c)); 78 } 79 get_valueOT::MathConstants80 hb_position_t get_value (hb_ot_math_constant_t constant, 81 hb_font_t *font) const 82 { 83 switch (constant) { 84 85 case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN: 86 case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN: 87 return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN]; 88 89 case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT: 90 case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT: 91 return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]); 92 93 case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE: 94 case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE: 95 case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP: 96 case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT: 97 return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this); 98 99 case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT: 100 case HB_OT_MATH_CONSTANT_AXIS_HEIGHT: 101 case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT: 102 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN: 103 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN: 104 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN: 105 case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN: 106 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP: 107 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN: 108 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP: 109 case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN: 110 case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS: 111 case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN: 112 case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN: 113 case HB_OT_MATH_CONSTANT_MATH_LEADING: 114 case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER: 115 case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS: 116 case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP: 117 case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP: 118 case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER: 119 case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS: 120 case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP: 121 case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP: 122 case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN: 123 case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN: 124 case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN: 125 case HB_OT_MATH_CONSTANT_STACK_GAP_MIN: 126 case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP: 127 case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP: 128 case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN: 129 case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN: 130 case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN: 131 case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP: 132 case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN: 133 case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN: 134 case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX: 135 case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN: 136 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX: 137 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT: 138 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN: 139 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP: 140 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED: 141 case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER: 142 case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS: 143 case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP: 144 case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN: 145 case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN: 146 return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this); 147 148 case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT: 149 return radicalDegreeBottomRaisePercent; 150 151 default: 152 return 0; 153 } 154 } 155 156 protected: 157 HBINT16 percentScaleDown[2]; 158 HBUINT16 minHeight[2]; 159 MathValueRecord mathValueRecords[51]; 160 HBINT16 radicalDegreeBottomRaisePercent; 161 162 public: 163 DEFINE_SIZE_STATIC (214); 164 }; 165 166 struct MathItalicsCorrectionInfo 167 { sanitizeOT::MathItalicsCorrectionInfo168 bool sanitize (hb_sanitize_context_t *c) const 169 { 170 TRACE_SANITIZE (this); 171 return_trace (c->check_struct (this) && 172 coverage.sanitize (c, this) && 173 italicsCorrection.sanitize (c, this)); 174 } 175 get_valueOT::MathItalicsCorrectionInfo176 hb_position_t get_value (hb_codepoint_t glyph, 177 hb_font_t *font) const 178 { 179 unsigned int index = (this+coverage).get_coverage (glyph); 180 return italicsCorrection[index].get_x_value (font, this); 181 } 182 183 protected: 184 Offset16To<Coverage> coverage; /* Offset to Coverage table - 185 * from the beginning of 186 * MathItalicsCorrectionInfo 187 * table. */ 188 Array16Of<MathValueRecord> italicsCorrection; /* Array of MathValueRecords 189 * defining italics correction 190 * values for each 191 * covered glyph. */ 192 193 public: 194 DEFINE_SIZE_ARRAY (4, italicsCorrection); 195 }; 196 197 struct MathTopAccentAttachment 198 { sanitizeOT::MathTopAccentAttachment199 bool sanitize (hb_sanitize_context_t *c) const 200 { 201 TRACE_SANITIZE (this); 202 return_trace (c->check_struct (this) && 203 topAccentCoverage.sanitize (c, this) && 204 topAccentAttachment.sanitize (c, this)); 205 } 206 get_valueOT::MathTopAccentAttachment207 hb_position_t get_value (hb_codepoint_t glyph, 208 hb_font_t *font) const 209 { 210 unsigned int index = (this+topAccentCoverage).get_coverage (glyph); 211 if (index == NOT_COVERED) 212 return font->get_glyph_h_advance (glyph) / 2; 213 return topAccentAttachment[index].get_x_value (font, this); 214 } 215 216 protected: 217 Offset16To<Coverage> topAccentCoverage; /* Offset to Coverage table - 218 * from the beginning of 219 * MathTopAccentAttachment 220 * table. */ 221 Array16Of<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords 222 * defining top accent 223 * attachment points for each 224 * covered glyph. */ 225 226 public: 227 DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment); 228 }; 229 230 struct MathKern 231 { sanitize_math_value_recordsOT::MathKern232 bool sanitize_math_value_records (hb_sanitize_context_t *c) const 233 { 234 TRACE_SANITIZE (this); 235 unsigned int count = 2 * heightCount + 1; 236 for (unsigned int i = 0; i < count; i++) 237 if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false); 238 return_trace (true); 239 } 240 sanitizeOT::MathKern241 bool sanitize (hb_sanitize_context_t *c) const 242 { 243 TRACE_SANITIZE (this); 244 return_trace (c->check_struct (this) && 245 c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) && 246 sanitize_math_value_records (c)); 247 } 248 get_valueOT::MathKern249 hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const 250 { 251 const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; 252 const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; 253 int sign = font->y_scale < 0 ? -1 : +1; 254 255 /* The description of the MathKern table is a ambiguous, but interpreting 256 * "between the two heights found at those indexes" for 0 < i < len as 257 * 258 * correctionHeight[i-1] < correction_height <= correctionHeight[i] 259 * 260 * makes the result consistent with the limit cases and we can just use the 261 * binary search algorithm of std::upper_bound: 262 */ 263 unsigned int i = 0; 264 unsigned int count = heightCount; 265 while (count > 0) 266 { 267 unsigned int half = count / 2; 268 hb_position_t height = correctionHeight[i + half].get_y_value (font, this); 269 if (sign * height < sign * correction_height) 270 { 271 i += half + 1; 272 count -= half + 1; 273 } else 274 count = half; 275 } 276 return kernValue[i].get_x_value (font, this); 277 } 278 279 protected: 280 HBUINT16 heightCount; 281 UnsizedArrayOf<MathValueRecord> 282 mathValueRecordsZ; 283 /* Array of correction heights at 284 * which the kern value changes. 285 * Sorted by the height value in 286 * design units (heightCount entries), 287 * Followed by: 288 * Array of kern values corresponding 289 * to heights. (heightCount+1 entries). 290 */ 291 292 public: 293 DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); 294 }; 295 296 struct MathKernInfoRecord 297 { sanitizeOT::MathKernInfoRecord298 bool sanitize (hb_sanitize_context_t *c, const void *base) const 299 { 300 TRACE_SANITIZE (this); 301 302 unsigned int count = ARRAY_LENGTH (mathKern); 303 for (unsigned int i = 0; i < count; i++) 304 if (unlikely (!mathKern[i].sanitize (c, base))) 305 return_trace (false); 306 307 return_trace (true); 308 } 309 get_kerningOT::MathKernInfoRecord310 hb_position_t get_kerning (hb_ot_math_kern_t kern, 311 hb_position_t correction_height, 312 hb_font_t *font, 313 const void *base) const 314 { 315 unsigned int idx = kern; 316 if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0; 317 return (base+mathKern[idx]).get_value (correction_height, font); 318 } 319 320 protected: 321 /* Offset to MathKern table for each corner - 322 * from the beginning of MathKernInfo table. May be NULL. */ 323 Offset16To<MathKern> mathKern[4]; 324 325 public: 326 DEFINE_SIZE_STATIC (8); 327 }; 328 329 struct MathKernInfo 330 { sanitizeOT::MathKernInfo331 bool sanitize (hb_sanitize_context_t *c) const 332 { 333 TRACE_SANITIZE (this); 334 return_trace (c->check_struct (this) && 335 mathKernCoverage.sanitize (c, this) && 336 mathKernInfoRecords.sanitize (c, this)); 337 } 338 get_kerningOT::MathKernInfo339 hb_position_t get_kerning (hb_codepoint_t glyph, 340 hb_ot_math_kern_t kern, 341 hb_position_t correction_height, 342 hb_font_t *font) const 343 { 344 unsigned int index = (this+mathKernCoverage).get_coverage (glyph); 345 return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); 346 } 347 348 protected: 349 Offset16To<Coverage> 350 mathKernCoverage; 351 /* Offset to Coverage table - 352 * from the beginning of the 353 * MathKernInfo table. */ 354 Array16Of<MathKernInfoRecord> 355 mathKernInfoRecords; 356 /* Array of MathKernInfoRecords, 357 * per-glyph information for 358 * mathematical positioning 359 * of subscripts and 360 * superscripts. */ 361 362 public: 363 DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); 364 }; 365 366 struct MathGlyphInfo 367 { sanitizeOT::MathGlyphInfo368 bool sanitize (hb_sanitize_context_t *c) const 369 { 370 TRACE_SANITIZE (this); 371 return_trace (c->check_struct (this) && 372 mathItalicsCorrectionInfo.sanitize (c, this) && 373 mathTopAccentAttachment.sanitize (c, this) && 374 extendedShapeCoverage.sanitize (c, this) && 375 mathKernInfo.sanitize (c, this)); 376 } 377 378 hb_position_t get_italics_correctionOT::MathGlyphInfo379 get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const 380 { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } 381 382 hb_position_t get_top_accent_attachmentOT::MathGlyphInfo383 get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const 384 { return (this+mathTopAccentAttachment).get_value (glyph, font); } 385 is_extended_shapeOT::MathGlyphInfo386 bool is_extended_shape (hb_codepoint_t glyph) const 387 { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } 388 get_kerningOT::MathGlyphInfo389 hb_position_t get_kerning (hb_codepoint_t glyph, 390 hb_ot_math_kern_t kern, 391 hb_position_t correction_height, 392 hb_font_t *font) const 393 { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } 394 395 protected: 396 /* Offset to MathItalicsCorrectionInfo table - 397 * from the beginning of MathGlyphInfo table. */ 398 Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo; 399 400 /* Offset to MathTopAccentAttachment table - 401 * from the beginning of MathGlyphInfo table. */ 402 Offset16To<MathTopAccentAttachment> mathTopAccentAttachment; 403 404 /* Offset to coverage table for Extended Shape glyphs - 405 * from the beginning of MathGlyphInfo table. When the left or right glyph of 406 * a box is an extended shape variant, the (ink) box (and not the default 407 * position defined by values in MathConstants table) should be used for 408 * vertical positioning purposes. May be NULL.. */ 409 Offset16To<Coverage> extendedShapeCoverage; 410 411 /* Offset to MathKernInfo table - 412 * from the beginning of MathGlyphInfo table. */ 413 Offset16To<MathKernInfo> mathKernInfo; 414 415 public: 416 DEFINE_SIZE_STATIC (8); 417 }; 418 419 struct MathGlyphVariantRecord 420 { 421 friend struct MathGlyphConstruction; 422 sanitizeOT::MathGlyphVariantRecord423 bool sanitize (hb_sanitize_context_t *c) const 424 { 425 TRACE_SANITIZE (this); 426 return_trace (c->check_struct (this)); 427 } 428 429 protected: 430 HBGlyphID variantGlyph; /* Glyph ID for the variant. */ 431 HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the 432 * variant, in the direction of requested 433 * glyph extension. */ 434 435 public: 436 DEFINE_SIZE_STATIC (4); 437 }; 438 439 struct PartFlags : HBUINT16 440 { 441 enum Flags { 442 Extender = 0x0001u, /* If set, the part can be skipped or repeated. */ 443 444 Defined = 0x0001u, /* All defined flags. */ 445 }; 446 447 public: 448 DEFINE_SIZE_STATIC (2); 449 }; 450 451 struct MathGlyphPartRecord 452 { sanitizeOT::MathGlyphPartRecord453 bool sanitize (hb_sanitize_context_t *c) const 454 { 455 TRACE_SANITIZE (this); 456 return_trace (c->check_struct (this)); 457 } 458 extractOT::MathGlyphPartRecord459 void extract (hb_ot_math_glyph_part_t &out, 460 int64_t mult, 461 hb_font_t *font) const 462 { 463 out.glyph = glyph; 464 465 out.start_connector_length = font->em_mult (startConnectorLength, mult); 466 out.end_connector_length = font->em_mult (endConnectorLength, mult); 467 out.full_advance = font->em_mult (fullAdvance, mult); 468 469 static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER == 470 (unsigned int) PartFlags::Extender, ""); 471 472 out.flags = (hb_ot_math_glyph_part_flags_t) 473 (unsigned int) 474 (partFlags & PartFlags::Defined); 475 } 476 477 protected: 478 HBGlyphID glyph; /* Glyph ID for the part. */ 479 HBUINT16 startConnectorLength; 480 /* Advance width/ height of the straight bar 481 * connector material, in design units, is at 482 * the beginning of the glyph, in the 483 * direction of the extension. */ 484 HBUINT16 endConnectorLength; 485 /* Advance width/ height of the straight bar 486 * connector material, in design units, is at 487 * the end of the glyph, in the direction of 488 * the extension. */ 489 HBUINT16 fullAdvance; /* Full advance width/height for this part, 490 * in the direction of the extension. 491 * In design units. */ 492 PartFlags partFlags; /* Part qualifiers. */ 493 494 public: 495 DEFINE_SIZE_STATIC (10); 496 }; 497 498 struct MathGlyphAssembly 499 { sanitizeOT::MathGlyphAssembly500 bool sanitize (hb_sanitize_context_t *c) const 501 { 502 TRACE_SANITIZE (this); 503 return_trace (c->check_struct (this) && 504 italicsCorrection.sanitize (c, this) && 505 partRecords.sanitize (c)); 506 } 507 get_partsOT::MathGlyphAssembly508 unsigned int get_parts (hb_direction_t direction, 509 hb_font_t *font, 510 unsigned int start_offset, 511 unsigned int *parts_count, /* IN/OUT */ 512 hb_ot_math_glyph_part_t *parts /* OUT */, 513 hb_position_t *italics_correction /* OUT */) const 514 { 515 if (parts_count) 516 { 517 int64_t mult = font->dir_mult (direction); 518 for (auto _ : hb_zip (partRecords.sub_array (start_offset, parts_count), 519 hb_array (parts, *parts_count))) 520 _.first.extract (_.second, mult, font); 521 } 522 523 if (italics_correction) 524 *italics_correction = italicsCorrection.get_x_value (font, this); 525 526 return partRecords.len; 527 } 528 529 protected: 530 MathValueRecord 531 italicsCorrection; 532 /* Italics correction of this 533 * MathGlyphAssembly. Should not 534 * depend on the assembly size. */ 535 Array16Of<MathGlyphPartRecord> 536 partRecords; /* Array of part records, from 537 * left to right and bottom to 538 * top. */ 539 540 public: 541 DEFINE_SIZE_ARRAY (6, partRecords); 542 }; 543 544 struct MathGlyphConstruction 545 { sanitizeOT::MathGlyphConstruction546 bool sanitize (hb_sanitize_context_t *c) const 547 { 548 TRACE_SANITIZE (this); 549 return_trace (c->check_struct (this) && 550 glyphAssembly.sanitize (c, this) && 551 mathGlyphVariantRecord.sanitize (c)); 552 } 553 get_assemblyOT::MathGlyphConstruction554 const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; } 555 get_variantsOT::MathGlyphConstruction556 unsigned int get_variants (hb_direction_t direction, 557 hb_font_t *font, 558 unsigned int start_offset, 559 unsigned int *variants_count, /* IN/OUT */ 560 hb_ot_math_glyph_variant_t *variants /* OUT */) const 561 { 562 if (variants_count) 563 { 564 int64_t mult = font->dir_mult (direction); 565 for (auto _ : hb_zip (mathGlyphVariantRecord.sub_array (start_offset, variants_count), 566 hb_array (variants, *variants_count))) 567 _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)}; 568 } 569 return mathGlyphVariantRecord.len; 570 } 571 572 protected: 573 /* Offset to MathGlyphAssembly table for this shape - from the beginning of 574 MathGlyphConstruction table. May be NULL. */ 575 Offset16To<MathGlyphAssembly> glyphAssembly; 576 577 /* MathGlyphVariantRecords for alternative variants of the glyphs. */ 578 Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord; 579 580 public: 581 DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord); 582 }; 583 584 struct MathVariants 585 { sanitize_offsetsOT::MathVariants586 bool sanitize_offsets (hb_sanitize_context_t *c) const 587 { 588 TRACE_SANITIZE (this); 589 unsigned int count = vertGlyphCount + horizGlyphCount; 590 for (unsigned int i = 0; i < count; i++) 591 if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false); 592 return_trace (true); 593 } 594 sanitizeOT::MathVariants595 bool sanitize (hb_sanitize_context_t *c) const 596 { 597 TRACE_SANITIZE (this); 598 return_trace (c->check_struct (this) && 599 vertGlyphCoverage.sanitize (c, this) && 600 horizGlyphCoverage.sanitize (c, this) && 601 c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && 602 sanitize_offsets (c)); 603 } 604 get_min_connector_overlapOT::MathVariants605 hb_position_t get_min_connector_overlap (hb_direction_t direction, 606 hb_font_t *font) const 607 { return font->em_scale_dir (minConnectorOverlap, direction); } 608 get_glyph_variantsOT::MathVariants609 unsigned int get_glyph_variants (hb_codepoint_t glyph, 610 hb_direction_t direction, 611 hb_font_t *font, 612 unsigned int start_offset, 613 unsigned int *variants_count, /* IN/OUT */ 614 hb_ot_math_glyph_variant_t *variants /* OUT */) const 615 { return get_glyph_construction (glyph, direction, font) 616 .get_variants (direction, font, start_offset, variants_count, variants); } 617 get_glyph_partsOT::MathVariants618 unsigned int get_glyph_parts (hb_codepoint_t glyph, 619 hb_direction_t direction, 620 hb_font_t *font, 621 unsigned int start_offset, 622 unsigned int *parts_count, /* IN/OUT */ 623 hb_ot_math_glyph_part_t *parts /* OUT */, 624 hb_position_t *italics_correction /* OUT */) const 625 { return get_glyph_construction (glyph, direction, font) 626 .get_assembly () 627 .get_parts (direction, font, 628 start_offset, parts_count, parts, 629 italics_correction); } 630 631 private: 632 const MathGlyphConstruction & get_glyph_constructionOT::MathVariants633 get_glyph_construction (hb_codepoint_t glyph, 634 hb_direction_t direction, 635 hb_font_t *font HB_UNUSED) const 636 { 637 bool vertical = HB_DIRECTION_IS_VERTICAL (direction); 638 unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; 639 const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage 640 : horizGlyphCoverage; 641 642 unsigned int index = (this+coverage).get_coverage (glyph); 643 if (unlikely (index >= count)) return Null (MathGlyphConstruction); 644 645 if (!vertical) 646 index += vertGlyphCount; 647 648 return this+glyphConstruction[index]; 649 } 650 651 protected: 652 HBUINT16 minConnectorOverlap; 653 /* Minimum overlap of connecting 654 * glyphs during glyph construction, 655 * in design units. */ 656 Offset16To<Coverage> vertGlyphCoverage; 657 /* Offset to Coverage table - 658 * from the beginning of MathVariants 659 * table. */ 660 Offset16To<Coverage> horizGlyphCoverage; 661 /* Offset to Coverage table - 662 * from the beginning of MathVariants 663 * table. */ 664 HBUINT16 vertGlyphCount; /* Number of glyphs for which 665 * information is provided for 666 * vertically growing variants. */ 667 HBUINT16 horizGlyphCount;/* Number of glyphs for which 668 * information is provided for 669 * horizontally growing variants. */ 670 671 /* Array of offsets to MathGlyphConstruction tables - from the beginning of 672 the MathVariants table, for shapes growing in vertical/horizontal 673 direction. */ 674 UnsizedArrayOf<Offset16To<MathGlyphConstruction>> 675 glyphConstruction; 676 677 public: 678 DEFINE_SIZE_ARRAY (10, glyphConstruction); 679 }; 680 681 682 /* 683 * MATH -- Mathematical typesetting 684 * https://docs.microsoft.com/en-us/typography/opentype/spec/math 685 */ 686 687 struct MATH 688 { 689 static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH; 690 has_dataOT::MATH691 bool has_data () const { return version.to_int (); } 692 sanitizeOT::MATH693 bool sanitize (hb_sanitize_context_t *c) const 694 { 695 TRACE_SANITIZE (this); 696 return_trace (version.sanitize (c) && 697 likely (version.major == 1) && 698 mathConstants.sanitize (c, this) && 699 mathGlyphInfo.sanitize (c, this) && 700 mathVariants.sanitize (c, this)); 701 } 702 get_constantOT::MATH703 hb_position_t get_constant (hb_ot_math_constant_t constant, 704 hb_font_t *font) const 705 { return (this+mathConstants).get_value (constant, font); } 706 get_glyph_infoOT::MATH707 const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; } 708 get_variantsOT::MATH709 const MathVariants &get_variants () const { return this+mathVariants; } 710 711 protected: 712 FixedVersion<>version; /* Version of the MATH table 713 * initially set to 0x00010000u */ 714 Offset16To<MathConstants> 715 mathConstants; /* MathConstants table */ 716 Offset16To<MathGlyphInfo> 717 mathGlyphInfo; /* MathGlyphInfo table */ 718 Offset16To<MathVariants> 719 mathVariants; /* MathVariants table */ 720 721 public: 722 DEFINE_SIZE_STATIC (10); 723 }; 724 725 } /* namespace OT */ 726 727 728 #endif /* HB_OT_MATH_TABLE_HH */ 729