diff --git a/src/uharfbuzz/_harfbuzz.pyx b/src/uharfbuzz/_harfbuzz.pyx index de2b0f9..33d796d 100644 --- a/src/uharfbuzz/_harfbuzz.pyx +++ b/src/uharfbuzz/_harfbuzz.pyx @@ -374,6 +374,23 @@ cdef class Font: finally: free(hb_variations) + def get_glyph_name(self, gid: int): + cdef char name[64] + cdef bytes packed + success = hb_font_get_glyph_name(self._hb_font, gid, name, 64) + if success: + packed = name + return packed.decode() + else: + return None + + def glyph_to_string(self, gid: int): + cdef char name[64] + cdef bytes packed + hb_font_glyph_to_string(self._hb_font, gid, name, 64) + packed = name + return packed.decode() + cdef hb_position_t _glyph_h_advance_func(hb_font_t* font, void* font_data, hb_codepoint_t glyph, diff --git a/src/uharfbuzz/charfbuzz.pxd b/src/uharfbuzz/charfbuzz.pxd index 75c59ea..9a814cb 100644 --- a/src/uharfbuzz/charfbuzz.pxd +++ b/src/uharfbuzz/charfbuzz.pxd @@ -212,6 +212,16 @@ cdef extern from "hb.h": hb_font_t* font, const hb_variation_t* variations, unsigned int variations_length) + hb_bool_t hb_font_get_glyph_name( + hb_font_t* font, + hb_codepoint_t glyph, + char* name, + unsigned int size) + void hb_font_glyph_to_string( + hb_font_t* font, + hb_codepoint_t glyph, + char* name, + unsigned int size) void hb_font_destroy(hb_font_t* font) # hb-shape.h diff --git a/tests/data/AdobeBlank.subset.ttf b/tests/data/AdobeBlank.subset.ttf index 75da7a2..0c89e20 100644 Binary files a/tests/data/AdobeBlank.subset.ttf and b/tests/data/AdobeBlank.subset.ttf differ diff --git a/tests/test_uharfbuzz.py b/tests/test_uharfbuzz.py index 3943511..e58e00e 100644 --- a/tests/test_uharfbuzz.py +++ b/tests/test_uharfbuzz.py @@ -112,6 +112,32 @@ def test_gid_and_cluster_no_features(self, blankfont, string, expected): infos = [(g.codepoint, g.cluster) for g in buf.glyph_infos] assert infos == expected + @pytest.mark.parametrize( + "string, expected", + [ + ("abcde", ["a", "b", "c", "d", "e"]), + ("abçde", ["a", "b", "ccedilla", "d", "e"]), + ("aбcde", ["a", "uni0431", "c", "d", "e"]), + ("abc💩e", ["a", "b", "c", "u1F4A9", "e"]), + ], + ids=["ascii", "latin1", "ucs2", "ucs4"], + ) + def test_glyh_name_no_features(self, blankfont, string, expected): + buf = hb.Buffer() + buf.add_str(string) + buf.guess_segment_properties() + hb.shape(blankfont, buf) + # font.get_glyph_name() returns None if the font does not contain glyph names + # or if the glyph ID does not exist. + glyph_names = [blankfont.get_glyph_name(g.codepoint) for g in buf.glyph_infos] + assert glyph_names == expected + assert blankfont.get_glyph_name(1000) is None + # font.glyph_to_string() return "gidN" if the font does not contain glyph names + # or if the glyph ID does not exist. + glyph_names = [blankfont.glyph_to_string(g.codepoint) for g in buf.glyph_infos] + assert glyph_names == expected + assert blankfont.glyph_to_string(1000) == 'gid1000' + class TestCallbacks: def test_nominal_glyph_func(self, blankfont):