From 81754a5a962ebefef848237ee218c019f85ef316 Mon Sep 17 00:00:00 2001 From: Alexis King Date: Wed, 9 Feb 2022 12:00:47 -0600 Subject: [PATCH] [ot-math] Add hb_ot_math_get_glyph_kernings closes #3396 --- docs/harfbuzz-sections.txt | 2 + src/hb-ot-math-table.hh | 78 ++++++++++++++++++++++++++++++++++++ src/hb-ot-math.cc | 45 +++++++++++++++++++++ src/hb-ot-math.h | 22 ++++++++++ test/api/test-ot-face.c | 1 + test/api/test-ot-math.c | 82 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 230 insertions(+) diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index a114a6bff..8f21edf3c 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -546,6 +546,7 @@ HB_OT_TAG_MATH HB_OT_TAG_MATH_SCRIPT hb_ot_math_constant_t hb_ot_math_kern_t +hb_ot_math_kern_entry_t hb_ot_math_glyph_variant_t hb_ot_math_glyph_part_flags_t hb_ot_math_glyph_part_t @@ -554,6 +555,7 @@ hb_ot_math_get_constant hb_ot_math_get_glyph_italics_correction hb_ot_math_get_glyph_top_accent_attachment hb_ot_math_get_glyph_kerning +hb_ot_math_get_glyph_kernings hb_ot_math_is_glyph_extended_shape hb_ot_math_get_glyph_variants hb_ot_math_get_min_connector_overlap diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh index 8d0b4317c..d834d9437 100644 --- a/src/hb-ot-math-table.hh +++ b/src/hb-ot-math-table.hh @@ -369,6 +369,37 @@ struct MathKern return kernValue[i].get_x_value (font, this); } + unsigned int get_entries (unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries, /* OUT */ + hb_font_t *font) const + { + const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; + const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; + const unsigned int entriesCount = heightCount + 1; + + if (entries_count) + { + unsigned int start = hb_min (start_offset, entriesCount); + unsigned int end = hb_min (start + *entries_count, entriesCount); + *entries_count = end - start; + + for (unsigned int i = 0; i < *entries_count; i++) { + unsigned int j = start + i; + + hb_position_t max_height; + if (j == heightCount) { + max_height = INT32_MAX; + } else { + max_height = correctionHeight[j].get_y_value (font, this); + } + + kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)}; + } + } + return entriesCount; + } + protected: HBUINT16 heightCount; UnsizedArrayOf @@ -423,6 +454,24 @@ struct MathKernInfoRecord return (base+mathKern[idx]).get_value (correction_height, font); } + unsigned int get_kernings (hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries, /* OUT */ + hb_font_t *font, + const void *base) const + { + unsigned int idx = kern; + if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) { + if (entries_count) *entries_count = 0; + return 0; + } + return (base+mathKern[idx]).get_entries (start_offset, + entries_count, + kern_entries, + font); + } + protected: /* Offset to MathKern table for each corner - * from the beginning of MathKernInfo table. May be NULL. */ @@ -473,6 +522,22 @@ struct MathKernInfo return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); } + unsigned int get_kernings (hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries, /* OUT */ + hb_font_t *font) const + { + unsigned int index = (this+mathKernCoverage).get_coverage (glyph); + return mathKernInfoRecords[index].get_kernings (kern, + start_offset, + entries_count, + kern_entries, + font, + this); + } + protected: Offset16To mathKernCoverage; @@ -545,6 +610,19 @@ struct MathGlyphInfo hb_font_t *font) const { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } + hb_position_t get_kernings (hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries, /* OUT */ + hb_font_t *font) const + { return (this+mathKernInfo).get_kernings (glyph, + kern, + start_offset, + entries_count, + kern_entries, + font); } + protected: /* Offset to MathItalicsCorrectionInfo table - * from the beginning of MathGlyphInfo table. */ diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc index 5781d25f2..b1ffc27b6 100644 --- a/src/hb-ot-math.cc +++ b/src/hb-ot-math.cc @@ -184,6 +184,51 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font, font); } +/** + * hb_ot_math_get_glyph_kernings: + * @font: #hb_font_t to work upon + * @glyph: The glyph index from which to retrieve the kernings + * @kern: The #hb_ot_math_kern_t from which to retrieve the kernings + * @start_offset: offset of the first kern entry to retrieve + * @entries_count: (inout) (optional): Input = the maximum number of kern entries to return; + * Output = the actual number of kern entries returned + * @kern_entries: (out caller-allocates) (array length=entries_count): array of kern entries returned + * + * Fetches the raw MathKern (cut-in) data for the specified font, glyph index, + * and @kern. The corresponding list of kern values and correction heights is + * returned as a list of #hb_ot_math_kern_entry_t structs. + * + * See also #hb_ot_math_get_glyph_kerning, which handles selecting the + * appropriate kern value for a given correction height. + * + * For a glyph with @n defined kern values (where @n > 0), there are only + * @n−1 defined correction heights, as each correction height defines a boundary + * past which the next kern value should be selected. Therefore, only the + * #hb_ot_math_kern_entry_t.kern_value of the uppermost #hb_ot_math_kern_entry_t + * actually comes from the font; its corresponding + * #hb_ot_math_kern_entry_t.max_correction_height is always set to + * INT32_MAX. + * + * Return value: the total number of kern values available or zero + * + * Since: REPLACEME + **/ +unsigned int +hb_ot_math_get_glyph_kernings (hb_font_t *font, + hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries /* OUT */) +{ + return font->face->table.MATH->get_glyph_info().get_kernings (glyph, + kern, + start_offset, + entries_count, + kern_entries, + font); +} + /** * hb_ot_math_get_glyph_variants: * @font: #hb_font_t to work upon diff --git a/src/hb-ot-math.h b/src/hb-ot-math.h index d4ea517e4..b9e55bab7 100644 --- a/src/hb-ot-math.h +++ b/src/hb-ot-math.h @@ -208,6 +208,20 @@ typedef enum { HB_OT_MATH_KERN_BOTTOM_LEFT = 3 } hb_ot_math_kern_t; +/** + * hb_ot_math_kern_entry_t: + * @max_correction_height: The maximum height at which this entry should be used + * @kern_value: The kern value of the entry + * + * Data type to hold math kerning (cut-in) information for a glyph. + * + * Since: REPLACEME + */ +typedef struct { + hb_position_t max_correction_height; + hb_position_t kern_value; +} hb_ot_math_kern_entry_t; + /** * hb_ot_math_glyph_variant_t: * @glyph: The glyph index of the variant @@ -284,6 +298,14 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font, hb_ot_math_kern_t kern, hb_position_t correction_height); +HB_EXTERN unsigned int +hb_ot_math_get_glyph_kernings (hb_font_t *font, + hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries /* OUT */); + HB_EXTERN unsigned int hb_ot_math_get_glyph_variants (hb_font_t *font, hb_codepoint_t glyph, diff --git a/test/api/test-ot-face.c b/test/api/test-ot-face.c index 6a8ebcdf3..e5c9b861a 100644 --- a/test/api/test-ot-face.c +++ b/test/api/test-ot-face.c @@ -131,6 +131,7 @@ test_font (hb_font_t *font, hb_codepoint_t cp) hb_ot_math_get_glyph_top_accent_attachment (font, cp); hb_ot_math_is_glyph_extended_shape (face, cp); hb_ot_math_get_glyph_kerning (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0); + hb_ot_math_get_glyph_kernings (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, NULL, NULL); hb_ot_math_get_glyph_variants (font, cp, HB_DIRECTION_TTB, 0, NULL, NULL); hb_ot_math_get_min_connector_overlap (font, HB_DIRECTION_RTL); hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_BTT, 0, NULL, NULL, NULL); diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c index 3434700ee..6d87396e1 100644 --- a/test/api/test-ot-math.c +++ b/test/api/test-ot-math.c @@ -332,6 +332,87 @@ test_get_glyph_kerning (void) cleanupFreeType(); } +static void +test_get_glyph_kernings (void) +{ + hb_codepoint_t glyph; + hb_ot_math_kern_entry_t entries[20]; + const unsigned entries_size = sizeof (entries) / sizeof (entries[0]); + unsigned int count; + + initFreeType(); + + openFont("fonts/MathTestFontEmpty.otf"); + g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph)); + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0, NULL, NULL), ==, 0); // MathGlyphInfo not available + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0, NULL, NULL), ==, 0); // MathGlyphInfo not available + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, NULL, NULL), ==, 0); // MathGlyphInfo not available + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0, NULL, NULL), ==, 0); // MathGlyphInfo not available + closeFont(); + + openFont("fonts/MathTestFontPartial2.otf"); + g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph)); + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0, NULL, NULL), ==, 0); // MathKernInfo empty + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0, NULL, NULL), ==, 0); // MathKernInfo empty + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, NULL, NULL), ==, 0); // MathKernInfo empty + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0, NULL, NULL), ==, 0); // MathKernInfo empty + closeFont(); + + openFont("fonts/MathTestFontPartial3.otf"); + g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph)); + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0, NULL, NULL), ==, 0); // MathKernInfoRecords empty + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0, NULL, NULL), ==, 0); // MathKernInfoRecords empty + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, NULL, NULL), ==, 0); // MathKernInfoRecords empty + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0, NULL, NULL), ==, 0); // MathKernInfoRecords empty + closeFont(); + + openFont("fonts/MathTestFontFull.otf"); + g_assert(hb_font_get_glyph_from_name (hb_font, "I", -1, &glyph)); + + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0, NULL, NULL), ==, 10); + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0, NULL, NULL), ==, 3); + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0, NULL, NULL), ==, 9); + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0, NULL, NULL), ==, 7); + + count = entries_size; + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0, &count, entries), ==, 10); + g_assert_cmpint(count, ==, 10); + g_assert_cmpint(entries[0].max_correction_height, ==, 14); + g_assert_cmpint(entries[0].kern_value, ==, 62); + g_assert_cmpint(entries[1].max_correction_height, ==, 23); + g_assert_cmpint(entries[1].kern_value, ==, 104); + g_assert_cmpint(entries[2].max_correction_height, ==, 32); + g_assert_cmpint(entries[2].kern_value, ==, 146); + g_assert_cmpint(entries[3].max_correction_height, ==, 41); + g_assert_cmpint(entries[3].kern_value, ==, 188); + g_assert_cmpint(entries[4].max_correction_height, ==, 50); + g_assert_cmpint(entries[4].kern_value, ==, 230); + g_assert_cmpint(entries[5].max_correction_height, ==, 59); + g_assert_cmpint(entries[5].kern_value, ==, 272); + g_assert_cmpint(entries[6].max_correction_height, ==, 68); + g_assert_cmpint(entries[6].kern_value, ==, 314); + g_assert_cmpint(entries[7].max_correction_height, ==, 77); + g_assert_cmpint(entries[7].kern_value, ==, 356); + g_assert_cmpint(entries[8].max_correction_height, ==, 86); + g_assert_cmpint(entries[8].kern_value, ==, 398); + g_assert_cmpint(entries[9].max_correction_height, ==, INT32_MAX); + g_assert_cmpint(entries[9].kern_value, ==, 440); + + count = entries_size; + g_assert_cmpint(hb_ot_math_get_glyph_kernings (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0, &count, entries), ==, 3); + g_assert_cmpint(count, ==, 3); + g_assert_cmpint(entries[0].max_correction_height, ==, 20); + g_assert_cmpint(entries[0].kern_value, ==, 50); + g_assert_cmpint(entries[1].max_correction_height, ==, 35); + g_assert_cmpint(entries[1].kern_value, ==, 80); + g_assert_cmpint(entries[2].max_correction_height, ==, INT32_MAX); + g_assert_cmpint(entries[2].kern_value, ==, 110); + + closeFont(); + + cleanupFreeType(); +} + static hb_position_t get_glyph_assembly_italics_correction (hb_font_t *font, @@ -707,6 +788,7 @@ main (int argc, char **argv) hb_test_add (test_get_glyph_top_accent_attachment); hb_test_add (test_is_glyph_extended_shape); hb_test_add (test_get_glyph_kerning); + hb_test_add (test_get_glyph_kernings); hb_test_add (test_get_glyph_assembly_italics_correction); hb_test_add (test_get_min_connector_overlap); hb_test_add (test_get_glyph_variants);