--- old/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-math-table.hh 2020-07-21 14:25:45.398861595 -0700 +++ /dev/null 2020-01-23 11:31:37.155195123 -0800 @@ -1,718 +0,0 @@ -/* - * Copyright © 2016 Igalia S.L. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Igalia Author(s): Frédéric Wang - */ - -#ifndef HB_OT_MATH_TABLE_HH -#define HB_OT_MATH_TABLE_HH - -#include "hb-open-type.hh" -#include "hb-ot-layout-common.hh" -#include "hb-ot-math.h" - -namespace OT { - - -struct MathValueRecord -{ - hb_position_t get_x_value (hb_font_t *font, const void *base) const - { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); } - hb_position_t get_y_value (hb_font_t *font, const void *base) const - { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); } - - bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && deviceTable.sanitize (c, base)); - } - - protected: - HBINT16 value; /* The X or Y value in design units */ - OffsetTo deviceTable; /* Offset to the device table - from the - * beginning of parent table. May be NULL. - * Suggested format for device table is 1. */ - - public: - DEFINE_SIZE_STATIC (4); -}; - -struct MathConstants -{ - bool sanitize_math_value_records (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - - unsigned int count = ARRAY_LENGTH (mathValueRecords); - for (unsigned int i = 0; i < count; i++) - if (!mathValueRecords[i].sanitize (c, this)) - return_trace (false); - - return_trace (true); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && sanitize_math_value_records (c)); - } - - hb_position_t get_value (hb_ot_math_constant_t constant, - hb_font_t *font) const - { - switch (constant) { - - case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN: - case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN: - return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN]; - - case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT: - case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT: - return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]); - - case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE: - case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE: - case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP: - case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT: - return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this); - - case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT: - case HB_OT_MATH_CONSTANT_AXIS_HEIGHT: - case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT: - case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN: - case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN: - case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN: - case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN: - case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP: - case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN: - case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP: - case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN: - case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS: - case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN: - case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN: - case HB_OT_MATH_CONSTANT_MATH_LEADING: - case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER: - case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS: - case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP: - case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP: - case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER: - case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS: - case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP: - case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP: - case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN: - case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN: - case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN: - case HB_OT_MATH_CONSTANT_STACK_GAP_MIN: - case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP: - case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP: - case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN: - case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN: - case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN: - case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP: - case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN: - case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN: - case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX: - case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN: - case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX: - case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT: - case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN: - case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP: - case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED: - case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER: - case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS: - case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP: - case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN: - case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN: - return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this); - - case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT: - return radicalDegreeBottomRaisePercent; - - default: - return 0; - } - } - - protected: - HBINT16 percentScaleDown[2]; - HBUINT16 minHeight[2]; - MathValueRecord mathValueRecords[51]; - HBINT16 radicalDegreeBottomRaisePercent; - - public: - DEFINE_SIZE_STATIC (214); -}; - -struct MathItalicsCorrectionInfo -{ - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - coverage.sanitize (c, this) && - italicsCorrection.sanitize (c, this)); - } - - hb_position_t get_value (hb_codepoint_t glyph, - hb_font_t *font) const - { - unsigned int index = (this+coverage).get_coverage (glyph); - return italicsCorrection[index].get_x_value (font, this); - } - - protected: - OffsetTo coverage; /* Offset to Coverage table - - * from the beginning of - * MathItalicsCorrectionInfo - * table. */ - ArrayOf italicsCorrection; /* Array of MathValueRecords - * defining italics correction - * values for each - * covered glyph. */ - - public: - DEFINE_SIZE_ARRAY (4, italicsCorrection); -}; - -struct MathTopAccentAttachment -{ - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - topAccentCoverage.sanitize (c, this) && - topAccentAttachment.sanitize (c, this)); - } - - hb_position_t get_value (hb_codepoint_t glyph, - hb_font_t *font) const - { - unsigned int index = (this+topAccentCoverage).get_coverage (glyph); - if (index == NOT_COVERED) - return font->get_glyph_h_advance (glyph) / 2; - return topAccentAttachment[index].get_x_value (font, this); - } - - protected: - OffsetTo topAccentCoverage; /* Offset to Coverage table - - * from the beginning of - * MathTopAccentAttachment - * table. */ - ArrayOf topAccentAttachment; /* Array of MathValueRecords - * defining top accent - * attachment points for each - * covered glyph. */ - - public: - DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment); -}; - -struct MathKern -{ - bool sanitize_math_value_records (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - unsigned int count = 2 * heightCount + 1; - for (unsigned int i = 0; i < count; i++) - if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false); - return_trace (true); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) && - sanitize_math_value_records (c)); - } - - hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const - { - const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; - const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; - int sign = font->y_scale < 0 ? -1 : +1; - - /* The description of the MathKern table is a ambiguous, but interpreting - * "between the two heights found at those indexes" for 0 < i < len as - * - * correctionHeight[i-1] < correction_height <= correctionHeight[i] - * - * makes the result consistent with the limit cases and we can just use the - * binary search algorithm of std::upper_bound: - */ - unsigned int i = 0; - unsigned int count = heightCount; - while (count > 0) - { - unsigned int half = count / 2; - hb_position_t height = correctionHeight[i + half].get_y_value (font, this); - if (sign * height < sign * correction_height) - { - i += half + 1; - count -= half + 1; - } else - count = half; - } - return kernValue[i].get_x_value (font, this); - } - - protected: - HBUINT16 heightCount; - UnsizedArrayOf - mathValueRecordsZ; /* Array of correction heights at - * which the kern value changes. - * Sorted by the height value in - * design units (heightCount entries), - * Followed by: - * Array of kern values corresponding - * to heights. (heightCount+1 entries). - */ - - public: - DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); -}; - -struct MathKernInfoRecord -{ - bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - - unsigned int count = ARRAY_LENGTH (mathKern); - for (unsigned int i = 0; i < count; i++) - if (unlikely (!mathKern[i].sanitize (c, base))) - return_trace (false); - - return_trace (true); - } - - hb_position_t get_kerning (hb_ot_math_kern_t kern, - hb_position_t correction_height, - hb_font_t *font, - const void *base) const - { - unsigned int idx = kern; - if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0; - return (base+mathKern[idx]).get_value (correction_height, font); - } - - protected: - /* Offset to MathKern table for each corner - - * from the beginning of MathKernInfo table. May be NULL. */ - OffsetTo mathKern[4]; - - public: - DEFINE_SIZE_STATIC (8); -}; - -struct MathKernInfo -{ - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - mathKernCoverage.sanitize (c, this) && - mathKernInfoRecords.sanitize (c, this)); - } - - hb_position_t get_kerning (hb_codepoint_t glyph, - hb_ot_math_kern_t kern, - hb_position_t correction_height, - hb_font_t *font) const - { - unsigned int index = (this+mathKernCoverage).get_coverage (glyph); - return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); - } - - protected: - OffsetTo mathKernCoverage; /* Offset to Coverage table - - * from the beginning of the - * MathKernInfo table. */ - ArrayOf mathKernInfoRecords; /* Array of - * MathKernInfoRecords, - * per-glyph information for - * mathematical positioning - * of subscripts and - * superscripts. */ - - public: - DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); -}; - -struct MathGlyphInfo -{ - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - mathItalicsCorrectionInfo.sanitize (c, this) && - mathTopAccentAttachment.sanitize (c, this) && - extendedShapeCoverage.sanitize (c, this) && - mathKernInfo.sanitize (c, this)); - } - - hb_position_t - get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const - { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } - - hb_position_t - get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const - { return (this+mathTopAccentAttachment).get_value (glyph, font); } - - bool is_extended_shape (hb_codepoint_t glyph) const - { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } - - hb_position_t get_kerning (hb_codepoint_t glyph, - hb_ot_math_kern_t kern, - hb_position_t correction_height, - hb_font_t *font) const - { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } - - protected: - /* Offset to MathItalicsCorrectionInfo table - - * from the beginning of MathGlyphInfo table. */ - OffsetTo mathItalicsCorrectionInfo; - - /* Offset to MathTopAccentAttachment table - - * from the beginning of MathGlyphInfo table. */ - OffsetTo mathTopAccentAttachment; - - /* Offset to coverage table for Extended Shape glyphs - - * from the beginning of MathGlyphInfo table. When the left or right glyph of - * a box is an extended shape variant, the (ink) box (and not the default - * position defined by values in MathConstants table) should be used for - * vertical positioning purposes. May be NULL.. */ - OffsetTo extendedShapeCoverage; - - /* Offset to MathKernInfo table - - * from the beginning of MathGlyphInfo table. */ - OffsetTo mathKernInfo; - - public: - DEFINE_SIZE_STATIC (8); -}; - -struct MathGlyphVariantRecord -{ - friend struct MathGlyphConstruction; - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - protected: - GlyphID variantGlyph; /* Glyph ID for the variant. */ - HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the - * variant, in the direction of requested - * glyph extension. */ - - public: - DEFINE_SIZE_STATIC (4); -}; - -struct PartFlags : HBUINT16 -{ - enum Flags { - Extender = 0x0001u, /* If set, the part can be skipped or repeated. */ - - Defined = 0x0001u, /* All defined flags. */ - }; - - public: - DEFINE_SIZE_STATIC (2); -}; - -struct MathGlyphPartRecord -{ - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - void extract (hb_ot_math_glyph_part_t &out, - int scale, - hb_font_t *font) const - { - out.glyph = glyph; - - out.start_connector_length = font->em_scale (startConnectorLength, scale); - out.end_connector_length = font->em_scale (endConnectorLength, scale); - out.full_advance = font->em_scale (fullAdvance, scale); - - static_assert ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER == - (unsigned int) PartFlags::Extender, ""); - - out.flags = (hb_ot_math_glyph_part_flags_t) - (unsigned int) - (partFlags & PartFlags::Defined); - } - - protected: - GlyphID glyph; /* Glyph ID for the part. */ - HBUINT16 startConnectorLength; /* Advance width/ height of the straight bar - * connector material, in design units, is at - * the beginning of the glyph, in the - * direction of the extension. */ - HBUINT16 endConnectorLength; /* Advance width/ height of the straight bar - * connector material, in design units, is at - * the end of the glyph, in the direction of - * the extension. */ - HBUINT16 fullAdvance; /* Full advance width/height for this part, - * in the direction of the extension. - * In design units. */ - PartFlags partFlags; /* Part qualifiers. */ - - public: - DEFINE_SIZE_STATIC (10); -}; - -struct MathGlyphAssembly -{ - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - italicsCorrection.sanitize (c, this) && - partRecords.sanitize (c)); - } - - unsigned int get_parts (hb_direction_t direction, - hb_font_t *font, - unsigned int start_offset, - unsigned int *parts_count, /* IN/OUT */ - hb_ot_math_glyph_part_t *parts /* OUT */, - hb_position_t *italics_correction /* OUT */) const - { - if (parts_count) - { - int scale = font->dir_scale (direction); - hb_array_t arr = partRecords.sub_array (start_offset, parts_count); - unsigned int count = arr.length; - for (unsigned int i = 0; i < count; i++) - arr[i].extract (parts[i], scale, font); - } - - if (italics_correction) - *italics_correction = italicsCorrection.get_x_value (font, this); - - return partRecords.len; - } - - protected: - MathValueRecord italicsCorrection; /* Italics correction of this - * MathGlyphAssembly. Should not - * depend on the assembly size. */ - ArrayOf partRecords; /* Array of part records, from - * left to right and bottom to - * top. */ - - public: - DEFINE_SIZE_ARRAY (6, partRecords); -}; - -struct MathGlyphConstruction -{ - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - glyphAssembly.sanitize (c, this) && - mathGlyphVariantRecord.sanitize (c)); - } - - const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; } - - unsigned int get_variants (hb_direction_t direction, - hb_font_t *font, - unsigned int start_offset, - unsigned int *variants_count, /* IN/OUT */ - hb_ot_math_glyph_variant_t *variants /* OUT */) const - { - if (variants_count) - { - int scale = font->dir_scale (direction); - hb_array_t arr = mathGlyphVariantRecord.sub_array (start_offset, variants_count); - unsigned int count = arr.length; - for (unsigned int i = 0; i < count; i++) - { - variants[i].glyph = arr[i].variantGlyph; - variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale); - } - } - return mathGlyphVariantRecord.len; - } - - protected: - /* Offset to MathGlyphAssembly table for this shape - from the beginning of - MathGlyphConstruction table. May be NULL. */ - OffsetTo glyphAssembly; - - /* MathGlyphVariantRecords for alternative variants of the glyphs. */ - ArrayOf mathGlyphVariantRecord; - - public: - DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord); -}; - -struct MathVariants -{ - bool sanitize_offsets (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - unsigned int count = vertGlyphCount + horizGlyphCount; - for (unsigned int i = 0; i < count; i++) - if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false); - return_trace (true); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - vertGlyphCoverage.sanitize (c, this) && - horizGlyphCoverage.sanitize (c, this) && - c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && - sanitize_offsets (c)); - } - - hb_position_t get_min_connector_overlap (hb_direction_t direction, - hb_font_t *font) const - { return font->em_scale_dir (minConnectorOverlap, direction); } - - unsigned int get_glyph_variants (hb_codepoint_t glyph, - hb_direction_t direction, - hb_font_t *font, - unsigned int start_offset, - unsigned int *variants_count, /* IN/OUT */ - hb_ot_math_glyph_variant_t *variants /* OUT */) const - { return get_glyph_construction (glyph, direction, font) - .get_variants (direction, font, start_offset, variants_count, variants); } - - unsigned int get_glyph_parts (hb_codepoint_t glyph, - hb_direction_t direction, - hb_font_t *font, - unsigned int start_offset, - unsigned int *parts_count, /* IN/OUT */ - hb_ot_math_glyph_part_t *parts /* OUT */, - hb_position_t *italics_correction /* OUT */) const - { return get_glyph_construction (glyph, direction, font) - .get_assembly () - .get_parts (direction, font, - start_offset, parts_count, parts, - italics_correction); } - - private: - const MathGlyphConstruction & - get_glyph_construction (hb_codepoint_t glyph, - hb_direction_t direction, - hb_font_t *font HB_UNUSED) const - { - bool vertical = HB_DIRECTION_IS_VERTICAL (direction); - unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; - const OffsetTo &coverage = vertical ? vertGlyphCoverage - : horizGlyphCoverage; - - unsigned int index = (this+coverage).get_coverage (glyph); - if (unlikely (index >= count)) return Null (MathGlyphConstruction); - - if (!vertical) - index += vertGlyphCount; - - return this+glyphConstruction[index]; - } - - protected: - HBUINT16 minConnectorOverlap; /* Minimum overlap of connecting - * glyphs during glyph construction, - * in design units. */ - OffsetTo vertGlyphCoverage; /* Offset to Coverage table - - * from the beginning of MathVariants - * table. */ - OffsetTo horizGlyphCoverage; /* Offset to Coverage table - - * from the beginning of MathVariants - * table. */ - HBUINT16 vertGlyphCount; /* Number of glyphs for which - * information is provided for - * vertically growing variants. */ - HBUINT16 horizGlyphCount; /* Number of glyphs for which - * information is provided for - * horizontally growing variants. */ - - /* Array of offsets to MathGlyphConstruction tables - from the beginning of - the MathVariants table, for shapes growing in vertical/horizontal - direction. */ - UnsizedArrayOf > - glyphConstruction; - - public: - DEFINE_SIZE_ARRAY (10, glyphConstruction); -}; - - -/* - * MATH -- Mathematical typesetting - * https://docs.microsoft.com/en-us/typography/opentype/spec/math - */ - -struct MATH -{ - static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH; - - bool has_data () const { return version.to_int (); } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (version.sanitize (c) && - likely (version.major == 1) && - mathConstants.sanitize (c, this) && - mathGlyphInfo.sanitize (c, this) && - mathVariants.sanitize (c, this)); - } - - hb_position_t get_constant (hb_ot_math_constant_t constant, - hb_font_t *font) const - { return (this+mathConstants).get_value (constant, font); } - - const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; } - - const MathVariants &get_variants () const { return this+mathVariants; } - - protected: - FixedVersion<>version; /* Version of the MATH table - * initially set to 0x00010000u */ - OffsetTo mathConstants;/* MathConstants table */ - OffsetTo mathGlyphInfo;/* MathGlyphInfo table */ - OffsetTo mathVariants; /* MathVariants table */ - - public: - DEFINE_SIZE_STATIC (10); -}; - -} /* namespace OT */ - - -#endif /* HB_OT_MATH_TABLE_HH */ --- /dev/null 2020-01-23 11:31:37.155195123 -0800 +++ new/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh 2020-07-21 14:25:45.042861601 -0700 @@ -0,0 +1,718 @@ +/* + * Copyright © 2016 Igalia S.L. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Igalia Author(s): Frédéric Wang + */ + +#ifndef HB_OT_MATH_TABLE_HH +#define HB_OT_MATH_TABLE_HH + +#include "hb-open-type.hh" +#include "hb-ot-layout-common.hh" +#include "hb-ot-math.h" + +namespace OT { + + +struct MathValueRecord +{ + hb_position_t get_x_value (hb_font_t *font, const void *base) const + { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); } + hb_position_t get_y_value (hb_font_t *font, const void *base) const + { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && deviceTable.sanitize (c, base)); + } + + protected: + HBINT16 value; /* The X or Y value in design units */ + OffsetTo deviceTable; /* Offset to the device table - from the + * beginning of parent table. May be NULL. + * Suggested format for device table is 1. */ + + public: + DEFINE_SIZE_STATIC (4); +}; + +struct MathConstants +{ + bool sanitize_math_value_records (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + + unsigned int count = ARRAY_LENGTH (mathValueRecords); + for (unsigned int i = 0; i < count; i++) + if (!mathValueRecords[i].sanitize (c, this)) + return_trace (false); + + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && sanitize_math_value_records (c)); + } + + hb_position_t get_value (hb_ot_math_constant_t constant, + hb_font_t *font) const + { + switch (constant) { + + case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN: + case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN: + return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN]; + + case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT: + case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT: + return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]); + + case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE: + case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE: + case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP: + case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT: + return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this); + + case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT: + case HB_OT_MATH_CONSTANT_AXIS_HEIGHT: + case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT: + case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN: + case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN: + case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN: + case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN: + case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP: + case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN: + case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP: + case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN: + case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS: + case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN: + case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN: + case HB_OT_MATH_CONSTANT_MATH_LEADING: + case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER: + case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS: + case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP: + case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP: + case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER: + case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS: + case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP: + case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP: + case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN: + case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN: + case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN: + case HB_OT_MATH_CONSTANT_STACK_GAP_MIN: + case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP: + case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP: + case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN: + case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN: + case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN: + case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP: + case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN: + case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN: + case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX: + case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN: + case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX: + case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT: + case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN: + case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP: + case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED: + case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER: + case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS: + case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP: + case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN: + case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN: + return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this); + + case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT: + return radicalDegreeBottomRaisePercent; + + default: + return 0; + } + } + + protected: + HBINT16 percentScaleDown[2]; + HBUINT16 minHeight[2]; + MathValueRecord mathValueRecords[51]; + HBINT16 radicalDegreeBottomRaisePercent; + + public: + DEFINE_SIZE_STATIC (214); +}; + +struct MathItalicsCorrectionInfo +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + coverage.sanitize (c, this) && + italicsCorrection.sanitize (c, this)); + } + + hb_position_t get_value (hb_codepoint_t glyph, + hb_font_t *font) const + { + unsigned int index = (this+coverage).get_coverage (glyph); + return italicsCorrection[index].get_x_value (font, this); + } + + protected: + OffsetTo coverage; /* Offset to Coverage table - + * from the beginning of + * MathItalicsCorrectionInfo + * table. */ + ArrayOf italicsCorrection; /* Array of MathValueRecords + * defining italics correction + * values for each + * covered glyph. */ + + public: + DEFINE_SIZE_ARRAY (4, italicsCorrection); +}; + +struct MathTopAccentAttachment +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + topAccentCoverage.sanitize (c, this) && + topAccentAttachment.sanitize (c, this)); + } + + hb_position_t get_value (hb_codepoint_t glyph, + hb_font_t *font) const + { + unsigned int index = (this+topAccentCoverage).get_coverage (glyph); + if (index == NOT_COVERED) + return font->get_glyph_h_advance (glyph) / 2; + return topAccentAttachment[index].get_x_value (font, this); + } + + protected: + OffsetTo topAccentCoverage; /* Offset to Coverage table - + * from the beginning of + * MathTopAccentAttachment + * table. */ + ArrayOf topAccentAttachment; /* Array of MathValueRecords + * defining top accent + * attachment points for each + * covered glyph. */ + + public: + DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment); +}; + +struct MathKern +{ + bool sanitize_math_value_records (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + unsigned int count = 2 * heightCount + 1; + for (unsigned int i = 0; i < count; i++) + if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false); + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) && + sanitize_math_value_records (c)); + } + + hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const + { + const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; + const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; + int sign = font->y_scale < 0 ? -1 : +1; + + /* The description of the MathKern table is a ambiguous, but interpreting + * "between the two heights found at those indexes" for 0 < i < len as + * + * correctionHeight[i-1] < correction_height <= correctionHeight[i] + * + * makes the result consistent with the limit cases and we can just use the + * binary search algorithm of std::upper_bound: + */ + unsigned int i = 0; + unsigned int count = heightCount; + while (count > 0) + { + unsigned int half = count / 2; + hb_position_t height = correctionHeight[i + half].get_y_value (font, this); + if (sign * height < sign * correction_height) + { + i += half + 1; + count -= half + 1; + } else + count = half; + } + return kernValue[i].get_x_value (font, this); + } + + protected: + HBUINT16 heightCount; + UnsizedArrayOf + mathValueRecordsZ; /* Array of correction heights at + * which the kern value changes. + * Sorted by the height value in + * design units (heightCount entries), + * Followed by: + * Array of kern values corresponding + * to heights. (heightCount+1 entries). + */ + + public: + DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); +}; + +struct MathKernInfoRecord +{ + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + + unsigned int count = ARRAY_LENGTH (mathKern); + for (unsigned int i = 0; i < count; i++) + if (unlikely (!mathKern[i].sanitize (c, base))) + return_trace (false); + + return_trace (true); + } + + hb_position_t get_kerning (hb_ot_math_kern_t kern, + hb_position_t correction_height, + hb_font_t *font, + const void *base) const + { + unsigned int idx = kern; + if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0; + return (base+mathKern[idx]).get_value (correction_height, font); + } + + protected: + /* Offset to MathKern table for each corner - + * from the beginning of MathKernInfo table. May be NULL. */ + OffsetTo mathKern[4]; + + public: + DEFINE_SIZE_STATIC (8); +}; + +struct MathKernInfo +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + mathKernCoverage.sanitize (c, this) && + mathKernInfoRecords.sanitize (c, this)); + } + + hb_position_t get_kerning (hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + hb_position_t correction_height, + hb_font_t *font) const + { + unsigned int index = (this+mathKernCoverage).get_coverage (glyph); + return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); + } + + protected: + OffsetTo mathKernCoverage; /* Offset to Coverage table - + * from the beginning of the + * MathKernInfo table. */ + ArrayOf mathKernInfoRecords; /* Array of + * MathKernInfoRecords, + * per-glyph information for + * mathematical positioning + * of subscripts and + * superscripts. */ + + public: + DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); +}; + +struct MathGlyphInfo +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + mathItalicsCorrectionInfo.sanitize (c, this) && + mathTopAccentAttachment.sanitize (c, this) && + extendedShapeCoverage.sanitize (c, this) && + mathKernInfo.sanitize (c, this)); + } + + hb_position_t + get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const + { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } + + hb_position_t + get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const + { return (this+mathTopAccentAttachment).get_value (glyph, font); } + + bool is_extended_shape (hb_codepoint_t glyph) const + { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } + + hb_position_t get_kerning (hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + hb_position_t correction_height, + hb_font_t *font) const + { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } + + protected: + /* Offset to MathItalicsCorrectionInfo table - + * from the beginning of MathGlyphInfo table. */ + OffsetTo mathItalicsCorrectionInfo; + + /* Offset to MathTopAccentAttachment table - + * from the beginning of MathGlyphInfo table. */ + OffsetTo mathTopAccentAttachment; + + /* Offset to coverage table for Extended Shape glyphs - + * from the beginning of MathGlyphInfo table. When the left or right glyph of + * a box is an extended shape variant, the (ink) box (and not the default + * position defined by values in MathConstants table) should be used for + * vertical positioning purposes. May be NULL.. */ + OffsetTo extendedShapeCoverage; + + /* Offset to MathKernInfo table - + * from the beginning of MathGlyphInfo table. */ + OffsetTo mathKernInfo; + + public: + DEFINE_SIZE_STATIC (8); +}; + +struct MathGlyphVariantRecord +{ + friend struct MathGlyphConstruction; + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + GlyphID variantGlyph; /* Glyph ID for the variant. */ + HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the + * variant, in the direction of requested + * glyph extension. */ + + public: + DEFINE_SIZE_STATIC (4); +}; + +struct PartFlags : HBUINT16 +{ + enum Flags { + Extender = 0x0001u, /* If set, the part can be skipped or repeated. */ + + Defined = 0x0001u, /* All defined flags. */ + }; + + public: + DEFINE_SIZE_STATIC (2); +}; + +struct MathGlyphPartRecord +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + void extract (hb_ot_math_glyph_part_t &out, + int scale, + hb_font_t *font) const + { + out.glyph = glyph; + + out.start_connector_length = font->em_scale (startConnectorLength, scale); + out.end_connector_length = font->em_scale (endConnectorLength, scale); + out.full_advance = font->em_scale (fullAdvance, scale); + + static_assert ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER == + (unsigned int) PartFlags::Extender, ""); + + out.flags = (hb_ot_math_glyph_part_flags_t) + (unsigned int) + (partFlags & PartFlags::Defined); + } + + protected: + GlyphID glyph; /* Glyph ID for the part. */ + HBUINT16 startConnectorLength; /* Advance width/ height of the straight bar + * connector material, in design units, is at + * the beginning of the glyph, in the + * direction of the extension. */ + HBUINT16 endConnectorLength; /* Advance width/ height of the straight bar + * connector material, in design units, is at + * the end of the glyph, in the direction of + * the extension. */ + HBUINT16 fullAdvance; /* Full advance width/height for this part, + * in the direction of the extension. + * In design units. */ + PartFlags partFlags; /* Part qualifiers. */ + + public: + DEFINE_SIZE_STATIC (10); +}; + +struct MathGlyphAssembly +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + italicsCorrection.sanitize (c, this) && + partRecords.sanitize (c)); + } + + unsigned int get_parts (hb_direction_t direction, + hb_font_t *font, + unsigned int start_offset, + unsigned int *parts_count, /* IN/OUT */ + hb_ot_math_glyph_part_t *parts /* OUT */, + hb_position_t *italics_correction /* OUT */) const + { + if (parts_count) + { + int scale = font->dir_scale (direction); + hb_array_t arr = partRecords.sub_array (start_offset, parts_count); + unsigned int count = arr.length; + for (unsigned int i = 0; i < count; i++) + arr[i].extract (parts[i], scale, font); + } + + if (italics_correction) + *italics_correction = italicsCorrection.get_x_value (font, this); + + return partRecords.len; + } + + protected: + MathValueRecord italicsCorrection; /* Italics correction of this + * MathGlyphAssembly. Should not + * depend on the assembly size. */ + ArrayOf partRecords; /* Array of part records, from + * left to right and bottom to + * top. */ + + public: + DEFINE_SIZE_ARRAY (6, partRecords); +}; + +struct MathGlyphConstruction +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + glyphAssembly.sanitize (c, this) && + mathGlyphVariantRecord.sanitize (c)); + } + + const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; } + + unsigned int get_variants (hb_direction_t direction, + hb_font_t *font, + unsigned int start_offset, + unsigned int *variants_count, /* IN/OUT */ + hb_ot_math_glyph_variant_t *variants /* OUT */) const + { + if (variants_count) + { + int scale = font->dir_scale (direction); + hb_array_t arr = mathGlyphVariantRecord.sub_array (start_offset, variants_count); + unsigned int count = arr.length; + for (unsigned int i = 0; i < count; i++) + { + variants[i].glyph = arr[i].variantGlyph; + variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale); + } + } + return mathGlyphVariantRecord.len; + } + + protected: + /* Offset to MathGlyphAssembly table for this shape - from the beginning of + MathGlyphConstruction table. May be NULL. */ + OffsetTo glyphAssembly; + + /* MathGlyphVariantRecords for alternative variants of the glyphs. */ + ArrayOf mathGlyphVariantRecord; + + public: + DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord); +}; + +struct MathVariants +{ + bool sanitize_offsets (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + unsigned int count = vertGlyphCount + horizGlyphCount; + for (unsigned int i = 0; i < count; i++) + if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false); + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + vertGlyphCoverage.sanitize (c, this) && + horizGlyphCoverage.sanitize (c, this) && + c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && + sanitize_offsets (c)); + } + + hb_position_t get_min_connector_overlap (hb_direction_t direction, + hb_font_t *font) const + { return font->em_scale_dir (minConnectorOverlap, direction); } + + unsigned int get_glyph_variants (hb_codepoint_t glyph, + hb_direction_t direction, + hb_font_t *font, + unsigned int start_offset, + unsigned int *variants_count, /* IN/OUT */ + hb_ot_math_glyph_variant_t *variants /* OUT */) const + { return get_glyph_construction (glyph, direction, font) + .get_variants (direction, font, start_offset, variants_count, variants); } + + unsigned int get_glyph_parts (hb_codepoint_t glyph, + hb_direction_t direction, + hb_font_t *font, + unsigned int start_offset, + unsigned int *parts_count, /* IN/OUT */ + hb_ot_math_glyph_part_t *parts /* OUT */, + hb_position_t *italics_correction /* OUT */) const + { return get_glyph_construction (glyph, direction, font) + .get_assembly () + .get_parts (direction, font, + start_offset, parts_count, parts, + italics_correction); } + + private: + const MathGlyphConstruction & + get_glyph_construction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_font_t *font HB_UNUSED) const + { + bool vertical = HB_DIRECTION_IS_VERTICAL (direction); + unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; + const OffsetTo &coverage = vertical ? vertGlyphCoverage + : horizGlyphCoverage; + + unsigned int index = (this+coverage).get_coverage (glyph); + if (unlikely (index >= count)) return Null (MathGlyphConstruction); + + if (!vertical) + index += vertGlyphCount; + + return this+glyphConstruction[index]; + } + + protected: + HBUINT16 minConnectorOverlap; /* Minimum overlap of connecting + * glyphs during glyph construction, + * in design units. */ + OffsetTo vertGlyphCoverage; /* Offset to Coverage table - + * from the beginning of MathVariants + * table. */ + OffsetTo horizGlyphCoverage; /* Offset to Coverage table - + * from the beginning of MathVariants + * table. */ + HBUINT16 vertGlyphCount; /* Number of glyphs for which + * information is provided for + * vertically growing variants. */ + HBUINT16 horizGlyphCount; /* Number of glyphs for which + * information is provided for + * horizontally growing variants. */ + + /* Array of offsets to MathGlyphConstruction tables - from the beginning of + the MathVariants table, for shapes growing in vertical/horizontal + direction. */ + UnsizedArrayOf > + glyphConstruction; + + public: + DEFINE_SIZE_ARRAY (10, glyphConstruction); +}; + + +/* + * MATH -- Mathematical typesetting + * https://docs.microsoft.com/en-us/typography/opentype/spec/math + */ + +struct MATH +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH; + + bool has_data () const { return version.to_int (); } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (version.sanitize (c) && + likely (version.major == 1) && + mathConstants.sanitize (c, this) && + mathGlyphInfo.sanitize (c, this) && + mathVariants.sanitize (c, this)); + } + + hb_position_t get_constant (hb_ot_math_constant_t constant, + hb_font_t *font) const + { return (this+mathConstants).get_value (constant, font); } + + const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; } + + const MathVariants &get_variants () const { return this+mathVariants; } + + protected: + FixedVersion<>version; /* Version of the MATH table + * initially set to 0x00010000u */ + OffsetTo mathConstants;/* MathConstants table */ + OffsetTo mathGlyphInfo;/* MathGlyphInfo table */ + OffsetTo mathVariants; /* MathVariants table */ + + public: + DEFINE_SIZE_STATIC (10); +}; + +} /* namespace OT */ + + +#endif /* HB_OT_MATH_TABLE_HH */