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-private.hh" 31 #include "hb-ot-layout-common-private.hh" 32 #include "hb-ot-math.h" 33 34 namespace OT { 35 36 37 struct MathValueRecord 38 { get_x_valueOT::MathValueRecord39 inline 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 inline 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 inline 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 INT16 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 nullptr. 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 inline 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 inline 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 inline 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 INT16 percentScaleDown[2]; 158 UINT16 minHeight[2]; 159 MathValueRecord mathValueRecords[51]; 160 INT16 radicalDegreeBottomRaisePercent; 161 162 public: 163 DEFINE_SIZE_STATIC (214); 164 }; 165 166 struct MathItalicsCorrectionInfo 167 { sanitizeOT::MathItalicsCorrectionInfo168 inline 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 inline 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 inline 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 inline 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 inline 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 (!mathValueRecords[i].sanitize (c, this)) return_trace (false); 238 return_trace (true); 239 } 240 sanitizeOT::MathKern241 inline bool sanitize (hb_sanitize_context_t *c) const 242 { 243 TRACE_SANITIZE (this); 244 return_trace (c->check_struct (this) && 245 c->check_array (mathValueRecords, 246 mathValueRecords[0].static_size, 247 2 * heightCount + 1) && 248 sanitize_math_value_records (c)); 249 } 250 get_valueOT::MathKern251 inline hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const 252 { 253 const MathValueRecord* correctionHeight = mathValueRecords; 254 const MathValueRecord* kernValue = mathValueRecords + heightCount; 255 int sign = font->y_scale < 0 ? -1 : +1; 256 257 /* The description of the MathKern table is a ambiguous, but interpreting 258 * "between the two heights found at those indexes" for 0 < i < len as 259 * 260 * correctionHeight[i-1] < correction_height <= correctionHeight[i] 261 * 262 * makes the result consistent with the limit cases and we can just use the 263 * binary search algorithm of std::upper_bound: 264 */ 265 unsigned int i = 0; 266 unsigned int count = heightCount; 267 while (count > 0) 268 { 269 unsigned int half = count / 2; 270 hb_position_t height = correctionHeight[i + half].get_y_value(font, this); 271 if (sign * height < sign * correction_height) 272 { 273 i += half + 1; 274 count -= half + 1; 275 } else 276 count = half; 277 } 278 return kernValue[i].get_x_value(font, this); 279 } 280 281 protected: 282 UINT16 heightCount; 283 MathValueRecord mathValueRecords[VAR]; /* 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, mathValueRecords); 294 }; 295 296 struct MathKernInfoRecord 297 { sanitizeOT::MathKernInfoRecord298 inline 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 inline 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 nullptr. */ 323 OffsetTo<MathKern> mathKern[4]; 324 325 public: 326 DEFINE_SIZE_STATIC (8); 327 }; 328 329 struct MathKernInfo 330 { sanitizeOT::MathKernInfo331 inline 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 inline 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 OffsetTo<Coverage> mathKernCoverage; /* Offset to Coverage table - 350 * from the beginning of the 351 * MathKernInfo table. */ 352 ArrayOf<MathKernInfoRecord> mathKernInfoRecords; /* Array of 353 * MathKernInfoRecords, 354 * per-glyph information for 355 * mathematical positioning 356 * of subscripts and 357 * superscripts. */ 358 359 public: 360 DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); 361 }; 362 363 struct MathGlyphInfo 364 { sanitizeOT::MathGlyphInfo365 inline bool sanitize (hb_sanitize_context_t *c) const 366 { 367 TRACE_SANITIZE (this); 368 return_trace (c->check_struct (this) && 369 mathItalicsCorrectionInfo.sanitize (c, this) && 370 mathTopAccentAttachment.sanitize (c, this) && 371 extendedShapeCoverage.sanitize (c, this) && 372 mathKernInfo.sanitize(c, this)); 373 } 374 375 inline hb_position_t get_italics_correctionOT::MathGlyphInfo376 get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const 377 { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } 378 379 inline hb_position_t get_top_accent_attachmentOT::MathGlyphInfo380 get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const 381 { return (this+mathTopAccentAttachment).get_value (glyph, font); } 382 is_extended_shapeOT::MathGlyphInfo383 inline bool is_extended_shape (hb_codepoint_t glyph) const 384 { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } 385 get_kerningOT::MathGlyphInfo386 inline hb_position_t get_kerning (hb_codepoint_t glyph, 387 hb_ot_math_kern_t kern, 388 hb_position_t correction_height, 389 hb_font_t *font) const 390 { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } 391 392 protected: 393 /* Offset to MathItalicsCorrectionInfo table - 394 * from the beginning of MathGlyphInfo table. */ 395 OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo; 396 397 /* Offset to MathTopAccentAttachment table - 398 * from the beginning of MathGlyphInfo table. */ 399 OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment; 400 401 /* Offset to coverage table for Extended Shape glyphs - 402 * from the beginning of MathGlyphInfo table. When the left or right glyph of 403 * a box is an extended shape variant, the (ink) box (and not the default 404 * position defined by values in MathConstants table) should be used for 405 * vertical positioning purposes. May be nullptr.. */ 406 OffsetTo<Coverage> extendedShapeCoverage; 407 408 /* Offset to MathKernInfo table - 409 * from the beginning of MathGlyphInfo table. */ 410 OffsetTo<MathKernInfo> mathKernInfo; 411 412 public: 413 DEFINE_SIZE_STATIC (8); 414 }; 415 416 struct MathGlyphVariantRecord 417 { 418 friend struct MathGlyphConstruction; 419 sanitizeOT::MathGlyphVariantRecord420 inline bool sanitize (hb_sanitize_context_t *c) const 421 { 422 TRACE_SANITIZE (this); 423 return_trace (c->check_struct (this)); 424 } 425 426 protected: 427 GlyphID variantGlyph; /* Glyph ID for the variant. */ 428 UINT16 advanceMeasurement; /* Advance width/height, in design units, of the 429 * variant, in the direction of requested 430 * glyph extension. */ 431 432 public: 433 DEFINE_SIZE_STATIC (4); 434 }; 435 436 struct PartFlags : UINT16 437 { 438 enum Flags { 439 Extender = 0x0001u, /* If set, the part can be skipped or repeated. */ 440 441 Defined = 0x0001u, /* All defined flags. */ 442 }; 443 444 public: 445 DEFINE_SIZE_STATIC (2); 446 }; 447 448 struct MathGlyphPartRecord 449 { sanitizeOT::MathGlyphPartRecord450 inline bool sanitize (hb_sanitize_context_t *c) const 451 { 452 TRACE_SANITIZE (this); 453 return_trace (c->check_struct (this)); 454 } 455 extractOT::MathGlyphPartRecord456 inline void extract (hb_ot_math_glyph_part_t &out, 457 int scale, 458 hb_font_t *font) const 459 { 460 out.glyph = glyph; 461 462 out.start_connector_length = font->em_scale (startConnectorLength, scale); 463 out.end_connector_length = font->em_scale (endConnectorLength, scale); 464 out.full_advance = font->em_scale (fullAdvance, scale); 465 466 static_assert ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER == 467 (unsigned int) PartFlags::Extender, ""); 468 469 out.flags = (hb_ot_math_glyph_part_flags_t) 470 (unsigned int) 471 (partFlags & PartFlags::Defined); 472 } 473 474 protected: 475 GlyphID glyph; /* Glyph ID for the part. */ 476 UINT16 startConnectorLength; /* Advance width/ height of the straight bar 477 * connector material, in design units, is at 478 * the beginning of the glyph, in the 479 * direction of the extension. */ 480 UINT16 endConnectorLength; /* Advance width/ height of the straight bar 481 * connector material, in design units, is at 482 * the end of the glyph, in the direction of 483 * the extension. */ 484 UINT16 fullAdvance; /* Full advance width/height for this part, 485 * in the direction of the extension. 486 * In design units. */ 487 PartFlags partFlags; /* Part qualifiers. */ 488 489 public: 490 DEFINE_SIZE_STATIC (10); 491 }; 492 493 struct MathGlyphAssembly 494 { sanitizeOT::MathGlyphAssembly495 inline bool sanitize (hb_sanitize_context_t *c) const 496 { 497 TRACE_SANITIZE (this); 498 return_trace (c->check_struct (this) && 499 italicsCorrection.sanitize(c, this) && 500 partRecords.sanitize(c)); 501 } 502 get_partsOT::MathGlyphAssembly503 inline unsigned int get_parts (hb_direction_t direction, 504 hb_font_t *font, 505 unsigned int start_offset, 506 unsigned int *parts_count, /* IN/OUT */ 507 hb_ot_math_glyph_part_t *parts /* OUT */, 508 hb_position_t *italics_correction /* OUT */) const 509 { 510 if (parts_count) 511 { 512 int scale = font->dir_scale (direction); 513 const MathGlyphPartRecord *arr = 514 partRecords.sub_array (start_offset, parts_count); 515 unsigned int count = *parts_count; 516 for (unsigned int i = 0; i < count; i++) 517 arr[i].extract (parts[i], scale, font); 518 } 519 520 if (italics_correction) 521 *italics_correction = italicsCorrection.get_x_value (font, this); 522 523 return partRecords.len; 524 } 525 526 protected: 527 MathValueRecord italicsCorrection; /* Italics correction of this 528 * MathGlyphAssembly. Should not 529 * depend on the assembly size. */ 530 ArrayOf<MathGlyphPartRecord> partRecords; /* Array of part records, from 531 * left to right and bottom to 532 * top. */ 533 534 public: 535 DEFINE_SIZE_ARRAY (6, partRecords); 536 }; 537 538 struct MathGlyphConstruction 539 { sanitizeOT::MathGlyphConstruction540 inline bool sanitize (hb_sanitize_context_t *c) const 541 { 542 TRACE_SANITIZE (this); 543 return_trace (c->check_struct (this) && 544 glyphAssembly.sanitize(c, this) && 545 mathGlyphVariantRecord.sanitize(c)); 546 } 547 get_assemblyOT::MathGlyphConstruction548 inline const MathGlyphAssembly &get_assembly (void) const 549 { return this+glyphAssembly; } 550 get_variantsOT::MathGlyphConstruction551 inline unsigned int get_variants (hb_direction_t direction, 552 hb_font_t *font, 553 unsigned int start_offset, 554 unsigned int *variants_count, /* IN/OUT */ 555 hb_ot_math_glyph_variant_t *variants /* OUT */) const 556 { 557 if (variants_count) 558 { 559 int scale = font->dir_scale (direction); 560 const MathGlyphVariantRecord *arr = 561 mathGlyphVariantRecord.sub_array (start_offset, variants_count); 562 unsigned int count = *variants_count; 563 for (unsigned int i = 0; i < count; i++) 564 { 565 variants[i].glyph = arr[i].variantGlyph; 566 variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale); 567 } 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 nullptr. */ 575 OffsetTo<MathGlyphAssembly> glyphAssembly; 576 577 /* MathGlyphVariantRecords for alternative variants of the glyphs. */ 578 ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord; 579 580 public: 581 DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord); 582 }; 583 584 struct MathVariants 585 { sanitize_offsetsOT::MathVariants586 inline 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[i].sanitize (c, this)) return_trace (false); 592 return_trace (true); 593 } 594 sanitizeOT::MathVariants595 inline 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, 602 glyphConstruction[0].static_size, 603 vertGlyphCount + horizGlyphCount) && 604 sanitize_offsets (c)); 605 } 606 get_min_connector_overlapOT::MathVariants607 inline hb_position_t get_min_connector_overlap (hb_direction_t direction, 608 hb_font_t *font) const 609 { return font->em_scale_dir (minConnectorOverlap, direction); } 610 get_glyph_variantsOT::MathVariants611 inline unsigned int get_glyph_variants (hb_codepoint_t glyph, 612 hb_direction_t direction, 613 hb_font_t *font, 614 unsigned int start_offset, 615 unsigned int *variants_count, /* IN/OUT */ 616 hb_ot_math_glyph_variant_t *variants /* OUT */) const 617 { return get_glyph_construction (glyph, direction, font) 618 .get_variants (direction, font, start_offset, variants_count, variants); } 619 get_glyph_partsOT::MathVariants620 inline unsigned int get_glyph_parts (hb_codepoint_t glyph, 621 hb_direction_t direction, 622 hb_font_t *font, 623 unsigned int start_offset, 624 unsigned int *parts_count, /* IN/OUT */ 625 hb_ot_math_glyph_part_t *parts /* OUT */, 626 hb_position_t *italics_correction /* OUT */) const 627 { return get_glyph_construction (glyph, direction, font) 628 .get_assembly () 629 .get_parts (direction, font, 630 start_offset, parts_count, parts, 631 italics_correction); } 632 633 private: 634 inline const MathGlyphConstruction & get_glyph_constructionOT::MathVariants635 get_glyph_construction (hb_codepoint_t glyph, 636 hb_direction_t direction, 637 hb_font_t *font) const 638 { 639 bool vertical = HB_DIRECTION_IS_VERTICAL (direction); 640 unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; 641 const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage 642 : horizGlyphCoverage; 643 644 unsigned int index = (this+coverage).get_coverage (glyph); 645 if (unlikely (index >= count)) return Null(MathGlyphConstruction); 646 647 if (!vertical) 648 index += vertGlyphCount; 649 650 return this+glyphConstruction[index]; 651 } 652 653 protected: 654 UINT16 minConnectorOverlap; /* Minimum overlap of connecting 655 * glyphs during glyph construction, 656 * in design units. */ 657 OffsetTo<Coverage> vertGlyphCoverage; /* Offset to Coverage table - 658 * from the beginning of MathVariants 659 * table. */ 660 OffsetTo<Coverage> horizGlyphCoverage; /* Offset to Coverage table - 661 * from the beginning of MathVariants 662 * table. */ 663 UINT16 vertGlyphCount; /* Number of glyphs for which 664 * information is provided for 665 * vertically growing variants. */ 666 UINT16 horizGlyphCount; /* Number of glyphs for which 667 * information is provided for 668 * horizontally growing variants. */ 669 670 /* Array of offsets to MathGlyphConstruction tables - from the beginning of 671 the MathVariants table, for shapes growing in vertical/horizontal 672 direction. */ 673 OffsetTo<MathGlyphConstruction> glyphConstruction[VAR]; 674 675 public: 676 DEFINE_SIZE_ARRAY (10, glyphConstruction); 677 }; 678 679 680 /* 681 * MATH -- The MATH Table 682 */ 683 684 struct MATH 685 { 686 static const hb_tag_t tableTag = HB_OT_TAG_MATH; 687 sanitizeOT::MATH688 inline bool sanitize (hb_sanitize_context_t *c) const 689 { 690 TRACE_SANITIZE (this); 691 return_trace (version.sanitize (c) && 692 likely (version.major == 1) && 693 mathConstants.sanitize (c, this) && 694 mathGlyphInfo.sanitize (c, this) && 695 mathVariants.sanitize (c, this)); 696 } 697 get_constantOT::MATH698 inline hb_position_t get_constant (hb_ot_math_constant_t constant, 699 hb_font_t *font) const 700 { return (this+mathConstants).get_value (constant, font); } 701 get_math_glyph_infoOT::MATH702 inline const MathGlyphInfo &get_math_glyph_info (void) const 703 { return this+mathGlyphInfo; } 704 get_math_variantsOT::MATH705 inline const MathVariants &get_math_variants (void) const 706 { return this+mathVariants; } 707 708 protected: 709 FixedVersion<>version; /* Version of the MATH table 710 * initially set to 0x00010000u */ 711 OffsetTo<MathConstants> mathConstants;/* MathConstants table */ 712 OffsetTo<MathGlyphInfo> mathGlyphInfo;/* MathGlyphInfo table */ 713 OffsetTo<MathVariants> mathVariants; /* MathVariants table */ 714 715 public: 716 DEFINE_SIZE_STATIC (10); 717 }; 718 719 } /* namespace OT */ 720 721 722 #endif /* HB_OT_MATH_TABLE_HH */ 723