1 /* 2 * Copyright © 2016 Igalia S.L. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Igalia Author(s): Frédéric Wang 25 */ 26 27 #ifndef HB_OT_MATH_TABLE_HH 28 #define HB_OT_MATH_TABLE_HH 29 30 #include "hb-open-type.hh" 31 #include "hb-ot-layout-common.hh" 32 #include "hb-ot-math.h" 33 34 namespace OT { 35 36 37 struct MathValueRecord 38 { get_x_valueOT::MathValueRecord39 hb_position_t get_x_value (hb_font_t *font, const void *base) const 40 { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); } get_y_valueOT::MathValueRecord41 hb_position_t get_y_value (hb_font_t *font, const void *base) const 42 { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); } 43 copyOT::MathValueRecord44 MathValueRecord* copy (hb_serialize_context_t *c, const void *base) const 45 { 46 TRACE_SERIALIZE (this); 47 auto *out = c->embed (this); 48 if (unlikely (!out)) return_trace (nullptr); 49 out->deviceTable.serialize_copy (c, deviceTable, base, 0, hb_serialize_context_t::Head); 50 51 return_trace (out); 52 } 53 sanitizeOT::MathValueRecord54 bool sanitize (hb_sanitize_context_t *c, const void *base) const 55 { 56 TRACE_SANITIZE (this); 57 return_trace (c->check_struct (this) && deviceTable.sanitize (c, base)); 58 } 59 60 protected: 61 HBINT16 value; /* The X or Y value in design units */ 62 Offset16To<Device> deviceTable; /* Offset to the device table - from the 63 * beginning of parent table. May be NULL. 64 * Suggested format for device table is 1. */ 65 66 public: 67 DEFINE_SIZE_STATIC (4); 68 }; 69 70 struct MathConstants 71 { copyOT::MathConstants72 MathConstants* copy (hb_serialize_context_t *c) const 73 { 74 TRACE_SERIALIZE (this); 75 auto *out = c->start_embed (this); 76 if (unlikely (!out)) return_trace (nullptr); 77 78 HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2); 79 if (unlikely (!p)) return_trace (nullptr); 80 memcpy (p, percentScaleDown, HBINT16::static_size * 2); 81 82 HBUINT16 *m = c->allocate_size<HBUINT16> (HBUINT16::static_size * 2); 83 if (unlikely (!m)) return_trace (nullptr); 84 memcpy (m, minHeight, HBUINT16::static_size * 2); 85 86 unsigned count = ARRAY_LENGTH (mathValueRecords); 87 for (unsigned i = 0; i < count; i++) 88 if (!c->copy (mathValueRecords[i], this)) 89 return_trace (nullptr); 90 91 if (!c->embed (radicalDegreeBottomRaisePercent)) return_trace (nullptr); 92 return_trace (out); 93 } 94 sanitize_math_value_recordsOT::MathConstants95 bool sanitize_math_value_records (hb_sanitize_context_t *c) const 96 { 97 TRACE_SANITIZE (this); 98 99 unsigned int count = ARRAY_LENGTH (mathValueRecords); 100 for (unsigned int i = 0; i < count; i++) 101 if (!mathValueRecords[i].sanitize (c, this)) 102 return_trace (false); 103 104 return_trace (true); 105 } 106 sanitizeOT::MathConstants107 bool sanitize (hb_sanitize_context_t *c) const 108 { 109 TRACE_SANITIZE (this); 110 return_trace (c->check_struct (this) && sanitize_math_value_records (c)); 111 } 112 get_valueOT::MathConstants113 hb_position_t get_value (hb_ot_math_constant_t constant, 114 hb_font_t *font) const 115 { 116 switch (constant) { 117 118 case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN: 119 case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN: 120 return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN]; 121 122 case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT: 123 case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT: 124 return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]); 125 126 case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE: 127 case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE: 128 case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP: 129 case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT: 130 return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this); 131 132 case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT: 133 case HB_OT_MATH_CONSTANT_AXIS_HEIGHT: 134 case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT: 135 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN: 136 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN: 137 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN: 138 case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN: 139 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP: 140 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN: 141 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP: 142 case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN: 143 case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS: 144 case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN: 145 case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN: 146 case HB_OT_MATH_CONSTANT_MATH_LEADING: 147 case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER: 148 case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS: 149 case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP: 150 case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP: 151 case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER: 152 case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS: 153 case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP: 154 case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP: 155 case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN: 156 case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN: 157 case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN: 158 case HB_OT_MATH_CONSTANT_STACK_GAP_MIN: 159 case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP: 160 case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP: 161 case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN: 162 case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN: 163 case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN: 164 case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP: 165 case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN: 166 case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN: 167 case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX: 168 case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN: 169 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX: 170 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT: 171 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN: 172 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP: 173 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED: 174 case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER: 175 case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS: 176 case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP: 177 case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN: 178 case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN: 179 return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this); 180 181 case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT: 182 return radicalDegreeBottomRaisePercent; 183 184 default: 185 return 0; 186 } 187 } 188 189 protected: 190 HBINT16 percentScaleDown[2]; 191 HBUINT16 minHeight[2]; 192 MathValueRecord mathValueRecords[51]; 193 HBINT16 radicalDegreeBottomRaisePercent; 194 195 public: 196 DEFINE_SIZE_STATIC (214); 197 }; 198 199 struct MathItalicsCorrectionInfo 200 { subsetOT::MathItalicsCorrectionInfo201 bool subset (hb_subset_context_t *c) const 202 { 203 TRACE_SUBSET (this); 204 const hb_set_t &glyphset = *c->plan->_glyphset_mathed; 205 const hb_map_t &glyph_map = *c->plan->glyph_map; 206 207 auto *out = c->serializer->start_embed (*this); 208 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 209 210 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 211 + hb_zip (this+coverage, italicsCorrection) 212 | hb_filter (glyphset, hb_first) 213 | hb_filter (serialize_math_record_array (c->serializer, out->italicsCorrection, this), hb_second) 214 | hb_map (hb_first) 215 | hb_map (glyph_map) 216 | hb_sink (new_coverage) 217 ; 218 219 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); 220 return_trace (true); 221 } 222 sanitizeOT::MathItalicsCorrectionInfo223 bool sanitize (hb_sanitize_context_t *c) const 224 { 225 TRACE_SANITIZE (this); 226 return_trace (c->check_struct (this) && 227 coverage.sanitize (c, this) && 228 italicsCorrection.sanitize (c, this)); 229 } 230 get_valueOT::MathItalicsCorrectionInfo231 hb_position_t get_value (hb_codepoint_t glyph, 232 hb_font_t *font) const 233 { 234 unsigned int index = (this+coverage).get_coverage (glyph); 235 return italicsCorrection[index].get_x_value (font, this); 236 } 237 238 protected: 239 Offset16To<Coverage> coverage; /* Offset to Coverage table - 240 * from the beginning of 241 * MathItalicsCorrectionInfo 242 * table. */ 243 Array16Of<MathValueRecord> italicsCorrection; /* Array of MathValueRecords 244 * defining italics correction 245 * values for each 246 * covered glyph. */ 247 248 public: 249 DEFINE_SIZE_ARRAY (4, italicsCorrection); 250 }; 251 252 struct MathTopAccentAttachment 253 { subsetOT::MathTopAccentAttachment254 bool subset (hb_subset_context_t *c) const 255 { 256 TRACE_SUBSET (this); 257 const hb_set_t &glyphset = *c->plan->_glyphset_mathed; 258 const hb_map_t &glyph_map = *c->plan->glyph_map; 259 260 auto *out = c->serializer->start_embed (*this); 261 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 262 263 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 264 + hb_zip (this+topAccentCoverage, topAccentAttachment) 265 | hb_filter (glyphset, hb_first) 266 | hb_filter (serialize_math_record_array (c->serializer, out->topAccentAttachment, this), hb_second) 267 | hb_map (hb_first) 268 | hb_map (glyph_map) 269 | hb_sink (new_coverage) 270 ; 271 272 out->topAccentCoverage.serialize_serialize (c->serializer, new_coverage.iter ()); 273 return_trace (true); 274 } 275 sanitizeOT::MathTopAccentAttachment276 bool sanitize (hb_sanitize_context_t *c) const 277 { 278 TRACE_SANITIZE (this); 279 return_trace (c->check_struct (this) && 280 topAccentCoverage.sanitize (c, this) && 281 topAccentAttachment.sanitize (c, this)); 282 } 283 get_valueOT::MathTopAccentAttachment284 hb_position_t get_value (hb_codepoint_t glyph, 285 hb_font_t *font) const 286 { 287 unsigned int index = (this+topAccentCoverage).get_coverage (glyph); 288 if (index == NOT_COVERED) 289 return font->get_glyph_h_advance (glyph) / 2; 290 return topAccentAttachment[index].get_x_value (font, this); 291 } 292 293 protected: 294 Offset16To<Coverage> topAccentCoverage; /* Offset to Coverage table - 295 * from the beginning of 296 * MathTopAccentAttachment 297 * table. */ 298 Array16Of<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords 299 * defining top accent 300 * attachment points for each 301 * covered glyph. */ 302 303 public: 304 DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment); 305 }; 306 307 struct MathKern 308 { copyOT::MathKern309 MathKern* copy (hb_serialize_context_t *c) const 310 { 311 TRACE_SERIALIZE (this); 312 auto *out = c->start_embed (this); 313 if (unlikely (!out)) return_trace (nullptr); 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 sanitize_math_value_recordsOT::MathKern325 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 sanitizeOT::MathKern334 bool sanitize (hb_sanitize_context_t *c) const 335 { 336 TRACE_SANITIZE (this); 337 return_trace (c->check_struct (this) && 338 c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) && 339 sanitize_math_value_records (c)); 340 } 341 get_valueOT::MathKern342 hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const 343 { 344 const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; 345 const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; 346 int sign = font->y_scale < 0 ? -1 : +1; 347 348 /* The description of the MathKern table is a ambiguous, but interpreting 349 * "between the two heights found at those indexes" for 0 < i < len as 350 * 351 * correctionHeight[i-1] < correction_height <= correctionHeight[i] 352 * 353 * makes the result consistent with the limit cases and we can just use the 354 * binary search algorithm of std::upper_bound: 355 */ 356 unsigned int i = 0; 357 unsigned int count = heightCount; 358 while (count > 0) 359 { 360 unsigned int half = count / 2; 361 hb_position_t height = correctionHeight[i + half].get_y_value (font, this); 362 if (sign * height < sign * correction_height) 363 { 364 i += half + 1; 365 count -= half + 1; 366 } else 367 count = half; 368 } 369 return kernValue[i].get_x_value (font, this); 370 } 371 372 protected: 373 HBUINT16 heightCount; 374 UnsizedArrayOf<MathValueRecord> 375 mathValueRecordsZ; 376 /* Array of correction heights at 377 * which the kern value changes. 378 * Sorted by the height value in 379 * design units (heightCount entries), 380 * Followed by: 381 * Array of kern values corresponding 382 * to heights. (heightCount+1 entries). 383 */ 384 385 public: 386 DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); 387 }; 388 389 struct MathKernInfoRecord 390 { copyOT::MathKernInfoRecord391 MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const 392 { 393 TRACE_SERIALIZE (this); 394 auto *out = c->embed (this); 395 if (unlikely (!out)) return_trace (nullptr); 396 397 unsigned count = ARRAY_LENGTH (mathKern); 398 for (unsigned i = 0; i < count; i++) 399 out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head); 400 401 return_trace (out); 402 } 403 sanitizeOT::MathKernInfoRecord404 bool sanitize (hb_sanitize_context_t *c, const void *base) const 405 { 406 TRACE_SANITIZE (this); 407 408 unsigned int count = ARRAY_LENGTH (mathKern); 409 for (unsigned int i = 0; i < count; i++) 410 if (unlikely (!mathKern[i].sanitize (c, base))) 411 return_trace (false); 412 413 return_trace (true); 414 } 415 get_kerningOT::MathKernInfoRecord416 hb_position_t get_kerning (hb_ot_math_kern_t kern, 417 hb_position_t correction_height, 418 hb_font_t *font, 419 const void *base) const 420 { 421 unsigned int idx = kern; 422 if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0; 423 return (base+mathKern[idx]).get_value (correction_height, font); 424 } 425 426 protected: 427 /* Offset to MathKern table for each corner - 428 * from the beginning of MathKernInfo table. May be NULL. */ 429 Offset16To<MathKern> mathKern[4]; 430 431 public: 432 DEFINE_SIZE_STATIC (8); 433 }; 434 435 struct MathKernInfo 436 { subsetOT::MathKernInfo437 bool subset (hb_subset_context_t *c) const 438 { 439 TRACE_SUBSET (this); 440 const hb_set_t &glyphset = *c->plan->_glyphset_mathed; 441 const hb_map_t &glyph_map = *c->plan->glyph_map; 442 443 auto *out = c->serializer->start_embed (*this); 444 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 445 446 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 447 + hb_zip (this+mathKernCoverage, mathKernInfoRecords) 448 | hb_filter (glyphset, hb_first) 449 | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second) 450 | hb_map (hb_first) 451 | hb_map (glyph_map) 452 | hb_sink (new_coverage) 453 ; 454 455 out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ()); 456 return_trace (true); 457 } 458 sanitizeOT::MathKernInfo459 bool sanitize (hb_sanitize_context_t *c) const 460 { 461 TRACE_SANITIZE (this); 462 return_trace (c->check_struct (this) && 463 mathKernCoverage.sanitize (c, this) && 464 mathKernInfoRecords.sanitize (c, this)); 465 } 466 get_kerningOT::MathKernInfo467 hb_position_t get_kerning (hb_codepoint_t glyph, 468 hb_ot_math_kern_t kern, 469 hb_position_t correction_height, 470 hb_font_t *font) const 471 { 472 unsigned int index = (this+mathKernCoverage).get_coverage (glyph); 473 return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); 474 } 475 476 protected: 477 Offset16To<Coverage> 478 mathKernCoverage; 479 /* Offset to Coverage table - 480 * from the beginning of the 481 * MathKernInfo table. */ 482 Array16Of<MathKernInfoRecord> 483 mathKernInfoRecords; 484 /* Array of MathKernInfoRecords, 485 * per-glyph information for 486 * mathematical positioning 487 * of subscripts and 488 * superscripts. */ 489 490 public: 491 DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); 492 }; 493 494 struct MathGlyphInfo 495 { subsetOT::MathGlyphInfo496 bool subset (hb_subset_context_t *c) const 497 { 498 TRACE_SUBSET (this); 499 auto *out = c->serializer->embed (*this); 500 if (unlikely (!out)) return_trace (false); 501 502 out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this); 503 out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this); 504 505 const hb_set_t &glyphset = *c->plan->_glyphset_mathed; 506 const hb_map_t &glyph_map = *c->plan->glyph_map; 507 508 auto it = 509 + hb_iter (this+extendedShapeCoverage) 510 | hb_filter (glyphset) 511 | hb_map_retains_sorting (glyph_map) 512 ; 513 514 out->extendedShapeCoverage.serialize_serialize (c->serializer, it); 515 516 out->mathKernInfo.serialize_subset (c, mathKernInfo, this); 517 return_trace (true); 518 } 519 sanitizeOT::MathGlyphInfo520 bool sanitize (hb_sanitize_context_t *c) const 521 { 522 TRACE_SANITIZE (this); 523 return_trace (c->check_struct (this) && 524 mathItalicsCorrectionInfo.sanitize (c, this) && 525 mathTopAccentAttachment.sanitize (c, this) && 526 extendedShapeCoverage.sanitize (c, this) && 527 mathKernInfo.sanitize (c, this)); 528 } 529 530 hb_position_t get_italics_correctionOT::MathGlyphInfo531 get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const 532 { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } 533 534 hb_position_t get_top_accent_attachmentOT::MathGlyphInfo535 get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const 536 { return (this+mathTopAccentAttachment).get_value (glyph, font); } 537 is_extended_shapeOT::MathGlyphInfo538 bool is_extended_shape (hb_codepoint_t glyph) const 539 { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } 540 get_kerningOT::MathGlyphInfo541 hb_position_t get_kerning (hb_codepoint_t glyph, 542 hb_ot_math_kern_t kern, 543 hb_position_t correction_height, 544 hb_font_t *font) const 545 { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } 546 547 protected: 548 /* Offset to MathItalicsCorrectionInfo table - 549 * from the beginning of MathGlyphInfo table. */ 550 Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo; 551 552 /* Offset to MathTopAccentAttachment table - 553 * from the beginning of MathGlyphInfo table. */ 554 Offset16To<MathTopAccentAttachment> mathTopAccentAttachment; 555 556 /* Offset to coverage table for Extended Shape glyphs - 557 * from the beginning of MathGlyphInfo table. When the left or right glyph of 558 * a box is an extended shape variant, the (ink) box (and not the default 559 * position defined by values in MathConstants table) should be used for 560 * vertical positioning purposes. May be NULL.. */ 561 Offset16To<Coverage> extendedShapeCoverage; 562 563 /* Offset to MathKernInfo table - 564 * from the beginning of MathGlyphInfo table. */ 565 Offset16To<MathKernInfo> mathKernInfo; 566 567 public: 568 DEFINE_SIZE_STATIC (8); 569 }; 570 571 struct MathGlyphVariantRecord 572 { 573 friend struct MathGlyphConstruction; 574 subsetOT::MathGlyphVariantRecord575 bool subset (hb_subset_context_t *c) const 576 { 577 TRACE_SUBSET (this); 578 auto *out = c->serializer->embed (this); 579 if (unlikely (!out)) return_trace (false); 580 581 const hb_map_t& glyph_map = *c->plan->glyph_map; 582 return_trace (c->serializer->check_assign (out->variantGlyph, glyph_map.get (variantGlyph), HB_SERIALIZE_ERROR_INT_OVERFLOW)); 583 } 584 sanitizeOT::MathGlyphVariantRecord585 bool sanitize (hb_sanitize_context_t *c) const 586 { 587 TRACE_SANITIZE (this); 588 return_trace (c->check_struct (this)); 589 } 590 closure_glyphsOT::MathGlyphVariantRecord591 void closure_glyphs (hb_set_t *variant_glyphs) const 592 { variant_glyphs->add (variantGlyph); } 593 594 protected: 595 HBGlyphID16 variantGlyph; /* Glyph ID for the variant. */ 596 HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the 597 * variant, in the direction of requested 598 * glyph extension. */ 599 600 public: 601 DEFINE_SIZE_STATIC (4); 602 }; 603 604 struct PartFlags : HBUINT16 605 { 606 enum Flags { 607 Extender = 0x0001u, /* If set, the part can be skipped or repeated. */ 608 609 Defined = 0x0001u, /* All defined flags. */ 610 }; 611 612 public: 613 DEFINE_SIZE_STATIC (2); 614 }; 615 616 struct MathGlyphPartRecord 617 { subsetOT::MathGlyphPartRecord618 bool subset (hb_subset_context_t *c) const 619 { 620 TRACE_SUBSET (this); 621 auto *out = c->serializer->embed (this); 622 if (unlikely (!out)) return_trace (false); 623 624 const hb_map_t& glyph_map = *c->plan->glyph_map; 625 return_trace (c->serializer->check_assign (out->glyph, glyph_map.get (glyph), HB_SERIALIZE_ERROR_INT_OVERFLOW)); 626 } 627 sanitizeOT::MathGlyphPartRecord628 bool sanitize (hb_sanitize_context_t *c) const 629 { 630 TRACE_SANITIZE (this); 631 return_trace (c->check_struct (this)); 632 } 633 extractOT::MathGlyphPartRecord634 void extract (hb_ot_math_glyph_part_t &out, 635 int64_t mult, 636 hb_font_t *font) const 637 { 638 out.glyph = glyph; 639 640 out.start_connector_length = font->em_mult (startConnectorLength, mult); 641 out.end_connector_length = font->em_mult (endConnectorLength, mult); 642 out.full_advance = font->em_mult (fullAdvance, mult); 643 644 static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER == 645 (unsigned int) PartFlags::Extender, ""); 646 647 out.flags = (hb_ot_math_glyph_part_flags_t) 648 (unsigned int) 649 (partFlags & PartFlags::Defined); 650 } 651 closure_glyphsOT::MathGlyphPartRecord652 void closure_glyphs (hb_set_t *variant_glyphs) const 653 { variant_glyphs->add (glyph); } 654 655 protected: 656 HBGlyphID16 glyph; /* Glyph ID for the part. */ 657 HBUINT16 startConnectorLength; 658 /* Advance width/ height of the straight bar 659 * connector material, in design units, is at 660 * the beginning of the glyph, in the 661 * direction of the extension. */ 662 HBUINT16 endConnectorLength; 663 /* Advance width/ height of the straight bar 664 * connector material, in design units, is at 665 * the end of the glyph, in the direction of 666 * the extension. */ 667 HBUINT16 fullAdvance; /* Full advance width/height for this part, 668 * in the direction of the extension. 669 * In design units. */ 670 PartFlags partFlags; /* Part qualifiers. */ 671 672 public: 673 DEFINE_SIZE_STATIC (10); 674 }; 675 676 struct MathGlyphAssembly 677 { subsetOT::MathGlyphAssembly678 bool subset (hb_subset_context_t *c) const 679 { 680 TRACE_SUBSET (this); 681 auto *out = c->serializer->start_embed (*this); 682 if (unlikely (!out)) return_trace (false); 683 684 if (!c->serializer->copy (italicsCorrection, this)) return_trace (false); 685 if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false); 686 687 for (const auto& record : partRecords.iter ()) 688 if (!record.subset (c)) return_trace (false); 689 return_trace (true); 690 } 691 sanitizeOT::MathGlyphAssembly692 bool sanitize (hb_sanitize_context_t *c) const 693 { 694 TRACE_SANITIZE (this); 695 return_trace (c->check_struct (this) && 696 italicsCorrection.sanitize (c, this) && 697 partRecords.sanitize (c)); 698 } 699 get_partsOT::MathGlyphAssembly700 unsigned int get_parts (hb_direction_t direction, 701 hb_font_t *font, 702 unsigned int start_offset, 703 unsigned int *parts_count, /* IN/OUT */ 704 hb_ot_math_glyph_part_t *parts /* OUT */, 705 hb_position_t *italics_correction /* OUT */) const 706 { 707 if (parts_count) 708 { 709 int64_t mult = font->dir_mult (direction); 710 for (auto _ : hb_zip (partRecords.sub_array (start_offset, parts_count), 711 hb_array (parts, *parts_count))) 712 _.first.extract (_.second, mult, font); 713 } 714 715 if (italics_correction) 716 *italics_correction = italicsCorrection.get_x_value (font, this); 717 718 return partRecords.len; 719 } 720 closure_glyphsOT::MathGlyphAssembly721 void closure_glyphs (hb_set_t *variant_glyphs) const 722 { 723 for (const auto& _ : partRecords.iter ()) 724 _.closure_glyphs (variant_glyphs); 725 } 726 727 protected: 728 MathValueRecord 729 italicsCorrection; 730 /* Italics correction of this 731 * MathGlyphAssembly. Should not 732 * depend on the assembly size. */ 733 Array16Of<MathGlyphPartRecord> 734 partRecords; /* Array of part records, from 735 * left to right and bottom to 736 * top. */ 737 738 public: 739 DEFINE_SIZE_ARRAY (6, partRecords); 740 }; 741 742 struct MathGlyphConstruction 743 { subsetOT::MathGlyphConstruction744 bool subset (hb_subset_context_t *c) const 745 { 746 TRACE_SUBSET (this); 747 auto *out = c->serializer->start_embed (*this); 748 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 749 750 out->glyphAssembly.serialize_subset (c, glyphAssembly, this); 751 752 if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 753 return_trace (false); 754 for (const auto& record : mathGlyphVariantRecord.iter ()) 755 if (!record.subset (c)) return_trace (false); 756 757 return_trace (true); 758 } 759 sanitizeOT::MathGlyphConstruction760 bool sanitize (hb_sanitize_context_t *c) const 761 { 762 TRACE_SANITIZE (this); 763 return_trace (c->check_struct (this) && 764 glyphAssembly.sanitize (c, this) && 765 mathGlyphVariantRecord.sanitize (c)); 766 } 767 get_assemblyOT::MathGlyphConstruction768 const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; } 769 get_variantsOT::MathGlyphConstruction770 unsigned int get_variants (hb_direction_t direction, 771 hb_font_t *font, 772 unsigned int start_offset, 773 unsigned int *variants_count, /* IN/OUT */ 774 hb_ot_math_glyph_variant_t *variants /* OUT */) const 775 { 776 if (variants_count) 777 { 778 int64_t mult = font->dir_mult (direction); 779 for (auto _ : hb_zip (mathGlyphVariantRecord.sub_array (start_offset, variants_count), 780 hb_array (variants, *variants_count))) 781 _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)}; 782 } 783 return mathGlyphVariantRecord.len; 784 } 785 closure_glyphsOT::MathGlyphConstruction786 void closure_glyphs (hb_set_t *variant_glyphs) const 787 { 788 (this+glyphAssembly).closure_glyphs (variant_glyphs); 789 790 for (const auto& _ : mathGlyphVariantRecord.iter ()) 791 _.closure_glyphs (variant_glyphs); 792 } 793 794 protected: 795 /* Offset to MathGlyphAssembly table for this shape - from the beginning of 796 MathGlyphConstruction table. May be NULL. */ 797 Offset16To<MathGlyphAssembly> glyphAssembly; 798 799 /* MathGlyphVariantRecords for alternative variants of the glyphs. */ 800 Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord; 801 802 public: 803 DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord); 804 }; 805 806 struct MathVariants 807 { closure_glyphsOT::MathVariants808 void closure_glyphs (const hb_set_t *glyph_set, 809 hb_set_t *variant_glyphs) const 810 { 811 const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount); 812 813 if (vertGlyphCoverage) 814 { 815 const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount); 816 + hb_zip (this+vertGlyphCoverage, vert_offsets) 817 | hb_filter (glyph_set, hb_first) 818 | hb_map (hb_second) 819 | hb_map (hb_add (this)) 820 | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); }) 821 ; 822 } 823 824 if (horizGlyphCoverage) 825 { 826 const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount); 827 + hb_zip (this+horizGlyphCoverage, hori_offsets) 828 | hb_filter (glyph_set, hb_first) 829 | hb_map (hb_second) 830 | hb_map (hb_add (this)) 831 | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); }) 832 ; 833 } 834 } 835 collect_coverage_and_indicesOT::MathVariants836 void collect_coverage_and_indices (hb_sorted_vector_t<hb_codepoint_t>& new_coverage, 837 const Offset16To<Coverage>& coverage, 838 unsigned i, 839 unsigned end_index, 840 hb_set_t& indices, 841 const hb_set_t& glyphset, 842 const hb_map_t& glyph_map) const 843 { 844 if (!coverage) return; 845 846 for (const auto _ : (this+coverage).iter ()) 847 { 848 if (i >= end_index) return; 849 if (glyphset.has (_)) 850 { 851 unsigned new_gid = glyph_map.get (_); 852 new_coverage.push (new_gid); 853 indices.add (i); 854 } 855 i++; 856 } 857 } 858 subsetOT::MathVariants859 bool subset (hb_subset_context_t *c) const 860 { 861 TRACE_SUBSET (this); 862 const hb_set_t &glyphset = *c->plan->_glyphset_mathed; 863 const hb_map_t &glyph_map = *c->plan->glyph_map; 864 865 auto *out = c->serializer->start_embed (*this); 866 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 867 if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 868 return_trace (false); 869 870 hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage; 871 hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage; 872 hb_set_t indices; 873 collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map); 874 collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map); 875 876 if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 877 return_trace (false); 878 if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 879 return_trace (false); 880 881 for (unsigned i : indices.iter ()) 882 { 883 auto *o = c->serializer->embed (glyphConstruction[i]); 884 if (!o) return_trace (false); 885 o->serialize_subset (c, glyphConstruction[i], this); 886 } 887 888 out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ()); 889 out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ()); 890 return_trace (true); 891 } 892 sanitize_offsetsOT::MathVariants893 bool sanitize_offsets (hb_sanitize_context_t *c) const 894 { 895 TRACE_SANITIZE (this); 896 unsigned int count = vertGlyphCount + horizGlyphCount; 897 for (unsigned int i = 0; i < count; i++) 898 if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false); 899 return_trace (true); 900 } 901 sanitizeOT::MathVariants902 bool sanitize (hb_sanitize_context_t *c) const 903 { 904 TRACE_SANITIZE (this); 905 return_trace (c->check_struct (this) && 906 vertGlyphCoverage.sanitize (c, this) && 907 horizGlyphCoverage.sanitize (c, this) && 908 c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && 909 sanitize_offsets (c)); 910 } 911 get_min_connector_overlapOT::MathVariants912 hb_position_t get_min_connector_overlap (hb_direction_t direction, 913 hb_font_t *font) const 914 { return font->em_scale_dir (minConnectorOverlap, direction); } 915 get_glyph_variantsOT::MathVariants916 unsigned int get_glyph_variants (hb_codepoint_t glyph, 917 hb_direction_t direction, 918 hb_font_t *font, 919 unsigned int start_offset, 920 unsigned int *variants_count, /* IN/OUT */ 921 hb_ot_math_glyph_variant_t *variants /* OUT */) const 922 { return get_glyph_construction (glyph, direction, font) 923 .get_variants (direction, font, start_offset, variants_count, variants); } 924 get_glyph_partsOT::MathVariants925 unsigned int get_glyph_parts (hb_codepoint_t glyph, 926 hb_direction_t direction, 927 hb_font_t *font, 928 unsigned int start_offset, 929 unsigned int *parts_count, /* IN/OUT */ 930 hb_ot_math_glyph_part_t *parts /* OUT */, 931 hb_position_t *italics_correction /* OUT */) const 932 { return get_glyph_construction (glyph, direction, font) 933 .get_assembly () 934 .get_parts (direction, font, 935 start_offset, parts_count, parts, 936 italics_correction); } 937 938 private: 939 const MathGlyphConstruction & get_glyph_constructionOT::MathVariants940 get_glyph_construction (hb_codepoint_t glyph, 941 hb_direction_t direction, 942 hb_font_t *font HB_UNUSED) const 943 { 944 bool vertical = HB_DIRECTION_IS_VERTICAL (direction); 945 unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; 946 const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage 947 : horizGlyphCoverage; 948 949 unsigned int index = (this+coverage).get_coverage (glyph); 950 if (unlikely (index >= count)) return Null (MathGlyphConstruction); 951 952 if (!vertical) 953 index += vertGlyphCount; 954 955 return this+glyphConstruction[index]; 956 } 957 958 protected: 959 HBUINT16 minConnectorOverlap; 960 /* Minimum overlap of connecting 961 * glyphs during glyph construction, 962 * in design units. */ 963 Offset16To<Coverage> vertGlyphCoverage; 964 /* Offset to Coverage table - 965 * from the beginning of MathVariants 966 * table. */ 967 Offset16To<Coverage> horizGlyphCoverage; 968 /* Offset to Coverage table - 969 * from the beginning of MathVariants 970 * table. */ 971 HBUINT16 vertGlyphCount; /* Number of glyphs for which 972 * information is provided for 973 * vertically growing variants. */ 974 HBUINT16 horizGlyphCount;/* Number of glyphs for which 975 * information is provided for 976 * horizontally growing variants. */ 977 978 /* Array of offsets to MathGlyphConstruction tables - from the beginning of 979 the MathVariants table, for shapes growing in vertical/horizontal 980 direction. */ 981 UnsizedArrayOf<Offset16To<MathGlyphConstruction>> 982 glyphConstruction; 983 984 public: 985 DEFINE_SIZE_ARRAY (10, glyphConstruction); 986 }; 987 988 989 /* 990 * MATH -- Mathematical typesetting 991 * https://docs.microsoft.com/en-us/typography/opentype/spec/math 992 */ 993 994 struct MATH 995 { 996 static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH; 997 has_dataOT::MATH998 bool has_data () const { return version.to_int (); } 999 closure_glyphsOT::MATH1000 void closure_glyphs (hb_set_t *glyph_set) const 1001 { 1002 if (mathVariants) 1003 { 1004 hb_set_t variant_glyphs; 1005 (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs); 1006 hb_set_union (glyph_set, &variant_glyphs); 1007 } 1008 } 1009 subsetOT::MATH1010 bool subset (hb_subset_context_t *c) const 1011 { 1012 TRACE_SUBSET (this); 1013 auto *out = c->serializer->embed (*this); 1014 if (unlikely (!out)) return_trace (false); 1015 1016 out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head); 1017 out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this); 1018 out->mathVariants.serialize_subset (c, mathVariants, this); 1019 return_trace (true); 1020 } 1021 sanitizeOT::MATH1022 bool sanitize (hb_sanitize_context_t *c) const 1023 { 1024 TRACE_SANITIZE (this); 1025 return_trace (version.sanitize (c) && 1026 likely (version.major == 1) && 1027 mathConstants.sanitize (c, this) && 1028 mathGlyphInfo.sanitize (c, this) && 1029 mathVariants.sanitize (c, this)); 1030 } 1031 get_constantOT::MATH1032 hb_position_t get_constant (hb_ot_math_constant_t constant, 1033 hb_font_t *font) const 1034 { return (this+mathConstants).get_value (constant, font); } 1035 get_glyph_infoOT::MATH1036 const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; } 1037 get_variantsOT::MATH1038 const MathVariants &get_variants () const { return this+mathVariants; } 1039 1040 protected: 1041 FixedVersion<>version; /* Version of the MATH table 1042 * initially set to 0x00010000u */ 1043 Offset16To<MathConstants> 1044 mathConstants; /* MathConstants table */ 1045 Offset16To<MathGlyphInfo> 1046 mathGlyphInfo; /* MathGlyphInfo table */ 1047 Offset16To<MathVariants> 1048 mathVariants; /* MathVariants table */ 1049 1050 public: 1051 DEFINE_SIZE_STATIC (10); 1052 }; 1053 1054 } /* namespace OT */ 1055 1056 1057 #endif /* HB_OT_MATH_TABLE_HH */ 1058