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 OffsetTo<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 OffsetTo<Coverage> coverage; /* Offset to Coverage table - 185 * from the beginning of 186 * MathItalicsCorrectionInfo 187 * table. */ 188 ArrayOf<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 OffsetTo<Coverage> topAccentCoverage; /* Offset to Coverage table - 218 * from the beginning of 219 * MathTopAccentAttachment 220 * table. */ 221 ArrayOf<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; /* Array of correction heights at 283 * which the kern value changes. 284 * Sorted by the height value in 285 * design units (heightCount entries), 286 * Followed by: 287 * Array of kern values corresponding 288 * to heights. (heightCount+1 entries). 289 */ 290 291 public: 292 DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); 293 }; 294 295 struct MathKernInfoRecord 296 { sanitizeOT::MathKernInfoRecord297 bool sanitize (hb_sanitize_context_t *c, const void *base) const 298 { 299 TRACE_SANITIZE (this); 300 301 unsigned int count = ARRAY_LENGTH (mathKern); 302 for (unsigned int i = 0; i < count; i++) 303 if (unlikely (!mathKern[i].sanitize (c, base))) 304 return_trace (false); 305 306 return_trace (true); 307 } 308 get_kerningOT::MathKernInfoRecord309 hb_position_t get_kerning (hb_ot_math_kern_t kern, 310 hb_position_t correction_height, 311 hb_font_t *font, 312 const void *base) const 313 { 314 unsigned int idx = kern; 315 if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0; 316 return (base+mathKern[idx]).get_value (correction_height, font); 317 } 318 319 protected: 320 /* Offset to MathKern table for each corner - 321 * from the beginning of MathKernInfo table. May be NULL. */ 322 OffsetTo<MathKern> mathKern[4]; 323 324 public: 325 DEFINE_SIZE_STATIC (8); 326 }; 327 328 struct MathKernInfo 329 { sanitizeOT::MathKernInfo330 bool sanitize (hb_sanitize_context_t *c) const 331 { 332 TRACE_SANITIZE (this); 333 return_trace (c->check_struct (this) && 334 mathKernCoverage.sanitize (c, this) && 335 mathKernInfoRecords.sanitize (c, this)); 336 } 337 get_kerningOT::MathKernInfo338 hb_position_t get_kerning (hb_codepoint_t glyph, 339 hb_ot_math_kern_t kern, 340 hb_position_t correction_height, 341 hb_font_t *font) const 342 { 343 unsigned int index = (this+mathKernCoverage).get_coverage (glyph); 344 return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); 345 } 346 347 protected: 348 OffsetTo<Coverage> mathKernCoverage; /* Offset to Coverage table - 349 * from the beginning of the 350 * MathKernInfo table. */ 351 ArrayOf<MathKernInfoRecord> mathKernInfoRecords; /* Array of 352 * MathKernInfoRecords, 353 * per-glyph information for 354 * mathematical positioning 355 * of subscripts and 356 * superscripts. */ 357 358 public: 359 DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); 360 }; 361 362 struct MathGlyphInfo 363 { sanitizeOT::MathGlyphInfo364 bool sanitize (hb_sanitize_context_t *c) const 365 { 366 TRACE_SANITIZE (this); 367 return_trace (c->check_struct (this) && 368 mathItalicsCorrectionInfo.sanitize (c, this) && 369 mathTopAccentAttachment.sanitize (c, this) && 370 extendedShapeCoverage.sanitize (c, this) && 371 mathKernInfo.sanitize (c, this)); 372 } 373 374 hb_position_t get_italics_correctionOT::MathGlyphInfo375 get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const 376 { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } 377 378 hb_position_t get_top_accent_attachmentOT::MathGlyphInfo379 get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const 380 { return (this+mathTopAccentAttachment).get_value (glyph, font); } 381 is_extended_shapeOT::MathGlyphInfo382 bool is_extended_shape (hb_codepoint_t glyph) const 383 { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } 384 get_kerningOT::MathGlyphInfo385 hb_position_t get_kerning (hb_codepoint_t glyph, 386 hb_ot_math_kern_t kern, 387 hb_position_t correction_height, 388 hb_font_t *font) const 389 { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } 390 391 protected: 392 /* Offset to MathItalicsCorrectionInfo table - 393 * from the beginning of MathGlyphInfo table. */ 394 OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo; 395 396 /* Offset to MathTopAccentAttachment table - 397 * from the beginning of MathGlyphInfo table. */ 398 OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment; 399 400 /* Offset to coverage table for Extended Shape glyphs - 401 * from the beginning of MathGlyphInfo table. When the left or right glyph of 402 * a box is an extended shape variant, the (ink) box (and not the default 403 * position defined by values in MathConstants table) should be used for 404 * vertical positioning purposes. May be NULL.. */ 405 OffsetTo<Coverage> extendedShapeCoverage; 406 407 /* Offset to MathKernInfo table - 408 * from the beginning of MathGlyphInfo table. */ 409 OffsetTo<MathKernInfo> mathKernInfo; 410 411 public: 412 DEFINE_SIZE_STATIC (8); 413 }; 414 415 struct MathGlyphVariantRecord 416 { 417 friend struct MathGlyphConstruction; 418 sanitizeOT::MathGlyphVariantRecord419 bool sanitize (hb_sanitize_context_t *c) const 420 { 421 TRACE_SANITIZE (this); 422 return_trace (c->check_struct (this)); 423 } 424 425 protected: 426 HBGlyphID variantGlyph; /* Glyph ID for the variant. */ 427 HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the 428 * variant, in the direction of requested 429 * glyph extension. */ 430 431 public: 432 DEFINE_SIZE_STATIC (4); 433 }; 434 435 struct PartFlags : HBUINT16 436 { 437 enum Flags { 438 Extender = 0x0001u, /* If set, the part can be skipped or repeated. */ 439 440 Defined = 0x0001u, /* All defined flags. */ 441 }; 442 443 public: 444 DEFINE_SIZE_STATIC (2); 445 }; 446 447 struct MathGlyphPartRecord 448 { sanitizeOT::MathGlyphPartRecord449 bool sanitize (hb_sanitize_context_t *c) const 450 { 451 TRACE_SANITIZE (this); 452 return_trace (c->check_struct (this)); 453 } 454 extractOT::MathGlyphPartRecord455 void extract (hb_ot_math_glyph_part_t &out, 456 int64_t mult, 457 hb_font_t *font) const 458 { 459 out.glyph = glyph; 460 461 out.start_connector_length = font->em_mult (startConnectorLength, mult); 462 out.end_connector_length = font->em_mult (endConnectorLength, mult); 463 out.full_advance = font->em_mult (fullAdvance, mult); 464 465 static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER == 466 (unsigned int) PartFlags::Extender, ""); 467 468 out.flags = (hb_ot_math_glyph_part_flags_t) 469 (unsigned int) 470 (partFlags & PartFlags::Defined); 471 } 472 473 protected: 474 HBGlyphID glyph; /* Glyph ID for the part. */ 475 HBUINT16 startConnectorLength; /* Advance width/ height of the straight bar 476 * connector material, in design units, is at 477 * the beginning of the glyph, in the 478 * direction of the extension. */ 479 HBUINT16 endConnectorLength; /* Advance width/ height of the straight bar 480 * connector material, in design units, is at 481 * the end of the glyph, in the direction of 482 * the extension. */ 483 HBUINT16 fullAdvance; /* Full advance width/height for this part, 484 * in the direction of the extension. 485 * In design units. */ 486 PartFlags partFlags; /* Part qualifiers. */ 487 488 public: 489 DEFINE_SIZE_STATIC (10); 490 }; 491 492 struct MathGlyphAssembly 493 { sanitizeOT::MathGlyphAssembly494 bool sanitize (hb_sanitize_context_t *c) const 495 { 496 TRACE_SANITIZE (this); 497 return_trace (c->check_struct (this) && 498 italicsCorrection.sanitize (c, this) && 499 partRecords.sanitize (c)); 500 } 501 get_partsOT::MathGlyphAssembly502 unsigned int get_parts (hb_direction_t direction, 503 hb_font_t *font, 504 unsigned int start_offset, 505 unsigned int *parts_count, /* IN/OUT */ 506 hb_ot_math_glyph_part_t *parts /* OUT */, 507 hb_position_t *italics_correction /* OUT */) const 508 { 509 if (parts_count) 510 { 511 int64_t mult = font->dir_mult (direction); 512 hb_array_t<const MathGlyphPartRecord> arr = partRecords.sub_array (start_offset, parts_count); 513 unsigned int count = arr.length; 514 for (unsigned int i = 0; i < count; i++) 515 arr[i].extract (parts[i], mult, font); 516 } 517 518 if (italics_correction) 519 *italics_correction = italicsCorrection.get_x_value (font, this); 520 521 return partRecords.len; 522 } 523 524 protected: 525 MathValueRecord italicsCorrection; /* Italics correction of this 526 * MathGlyphAssembly. Should not 527 * depend on the assembly size. */ 528 ArrayOf<MathGlyphPartRecord> partRecords; /* Array of part records, from 529 * left to right and bottom to 530 * top. */ 531 532 public: 533 DEFINE_SIZE_ARRAY (6, partRecords); 534 }; 535 536 struct MathGlyphConstruction 537 { sanitizeOT::MathGlyphConstruction538 bool sanitize (hb_sanitize_context_t *c) const 539 { 540 TRACE_SANITIZE (this); 541 return_trace (c->check_struct (this) && 542 glyphAssembly.sanitize (c, this) && 543 mathGlyphVariantRecord.sanitize (c)); 544 } 545 get_assemblyOT::MathGlyphConstruction546 const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; } 547 get_variantsOT::MathGlyphConstruction548 unsigned int get_variants (hb_direction_t direction, 549 hb_font_t *font, 550 unsigned int start_offset, 551 unsigned int *variants_count, /* IN/OUT */ 552 hb_ot_math_glyph_variant_t *variants /* OUT */) const 553 { 554 if (variants_count) 555 { 556 int64_t mult = font->dir_mult (direction); 557 hb_array_t<const MathGlyphVariantRecord> arr = mathGlyphVariantRecord.sub_array (start_offset, variants_count); 558 unsigned int count = arr.length; 559 for (unsigned int i = 0; i < count; i++) 560 { 561 variants[i].glyph = arr[i].variantGlyph; 562 variants[i].advance = font->em_mult (arr[i].advanceMeasurement, mult); 563 } 564 } 565 return mathGlyphVariantRecord.len; 566 } 567 568 protected: 569 /* Offset to MathGlyphAssembly table for this shape - from the beginning of 570 MathGlyphConstruction table. May be NULL. */ 571 OffsetTo<MathGlyphAssembly> glyphAssembly; 572 573 /* MathGlyphVariantRecords for alternative variants of the glyphs. */ 574 ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord; 575 576 public: 577 DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord); 578 }; 579 580 struct MathVariants 581 { sanitize_offsetsOT::MathVariants582 bool sanitize_offsets (hb_sanitize_context_t *c) const 583 { 584 TRACE_SANITIZE (this); 585 unsigned int count = vertGlyphCount + horizGlyphCount; 586 for (unsigned int i = 0; i < count; i++) 587 if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false); 588 return_trace (true); 589 } 590 sanitizeOT::MathVariants591 bool sanitize (hb_sanitize_context_t *c) const 592 { 593 TRACE_SANITIZE (this); 594 return_trace (c->check_struct (this) && 595 vertGlyphCoverage.sanitize (c, this) && 596 horizGlyphCoverage.sanitize (c, this) && 597 c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && 598 sanitize_offsets (c)); 599 } 600 get_min_connector_overlapOT::MathVariants601 hb_position_t get_min_connector_overlap (hb_direction_t direction, 602 hb_font_t *font) const 603 { return font->em_scale_dir (minConnectorOverlap, direction); } 604 get_glyph_variantsOT::MathVariants605 unsigned int get_glyph_variants (hb_codepoint_t glyph, 606 hb_direction_t direction, 607 hb_font_t *font, 608 unsigned int start_offset, 609 unsigned int *variants_count, /* IN/OUT */ 610 hb_ot_math_glyph_variant_t *variants /* OUT */) const 611 { return get_glyph_construction (glyph, direction, font) 612 .get_variants (direction, font, start_offset, variants_count, variants); } 613 get_glyph_partsOT::MathVariants614 unsigned int get_glyph_parts (hb_codepoint_t glyph, 615 hb_direction_t direction, 616 hb_font_t *font, 617 unsigned int start_offset, 618 unsigned int *parts_count, /* IN/OUT */ 619 hb_ot_math_glyph_part_t *parts /* OUT */, 620 hb_position_t *italics_correction /* OUT */) const 621 { return get_glyph_construction (glyph, direction, font) 622 .get_assembly () 623 .get_parts (direction, font, 624 start_offset, parts_count, parts, 625 italics_correction); } 626 627 private: 628 const MathGlyphConstruction & get_glyph_constructionOT::MathVariants629 get_glyph_construction (hb_codepoint_t glyph, 630 hb_direction_t direction, 631 hb_font_t *font HB_UNUSED) const 632 { 633 bool vertical = HB_DIRECTION_IS_VERTICAL (direction); 634 unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; 635 const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage 636 : horizGlyphCoverage; 637 638 unsigned int index = (this+coverage).get_coverage (glyph); 639 if (unlikely (index >= count)) return Null (MathGlyphConstruction); 640 641 if (!vertical) 642 index += vertGlyphCount; 643 644 return this+glyphConstruction[index]; 645 } 646 647 protected: 648 HBUINT16 minConnectorOverlap; /* Minimum overlap of connecting 649 * glyphs during glyph construction, 650 * in design units. */ 651 OffsetTo<Coverage> vertGlyphCoverage; /* Offset to Coverage table - 652 * from the beginning of MathVariants 653 * table. */ 654 OffsetTo<Coverage> horizGlyphCoverage; /* Offset to Coverage table - 655 * from the beginning of MathVariants 656 * table. */ 657 HBUINT16 vertGlyphCount; /* Number of glyphs for which 658 * information is provided for 659 * vertically growing variants. */ 660 HBUINT16 horizGlyphCount; /* Number of glyphs for which 661 * information is provided for 662 * horizontally growing variants. */ 663 664 /* Array of offsets to MathGlyphConstruction tables - from the beginning of 665 the MathVariants table, for shapes growing in vertical/horizontal 666 direction. */ 667 UnsizedArrayOf<OffsetTo<MathGlyphConstruction>> 668 glyphConstruction; 669 670 public: 671 DEFINE_SIZE_ARRAY (10, glyphConstruction); 672 }; 673 674 675 /* 676 * MATH -- Mathematical typesetting 677 * https://docs.microsoft.com/en-us/typography/opentype/spec/math 678 */ 679 680 struct MATH 681 { 682 static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH; 683 has_dataOT::MATH684 bool has_data () const { return version.to_int (); } 685 sanitizeOT::MATH686 bool sanitize (hb_sanitize_context_t *c) const 687 { 688 TRACE_SANITIZE (this); 689 return_trace (version.sanitize (c) && 690 likely (version.major == 1) && 691 mathConstants.sanitize (c, this) && 692 mathGlyphInfo.sanitize (c, this) && 693 mathVariants.sanitize (c, this)); 694 } 695 get_constantOT::MATH696 hb_position_t get_constant (hb_ot_math_constant_t constant, 697 hb_font_t *font) const 698 { return (this+mathConstants).get_value (constant, font); } 699 get_glyph_infoOT::MATH700 const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; } 701 get_variantsOT::MATH702 const MathVariants &get_variants () const { return this+mathVariants; } 703 704 protected: 705 FixedVersion<>version; /* Version of the MATH table 706 * initially set to 0x00010000u */ 707 OffsetTo<MathConstants> mathConstants;/* MathConstants table */ 708 OffsetTo<MathGlyphInfo> mathGlyphInfo;/* MathGlyphInfo table */ 709 OffsetTo<MathVariants> mathVariants; /* MathVariants table */ 710 711 public: 712 DEFINE_SIZE_STATIC (10); 713 }; 714 715 } /* namespace OT */ 716 717 718 #endif /* HB_OT_MATH_TABLE_HH */ 719