diff options
Diffstat (limited to 'src/w32uniscribe.c')
-rw-r--r-- | src/w32uniscribe.c | 421 |
1 files changed, 386 insertions, 35 deletions
diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c index ca030ad5ae6..7c772b68f6e 100644 --- a/src/w32uniscribe.c +++ b/src/w32uniscribe.c @@ -1,5 +1,6 @@ /* Font backend for the Microsoft W32 Uniscribe API. - Copyright (C) 2008-2017 Free Software Foundation, Inc. + Windows-specific parts of the HarfBuzz font backend. + Copyright (C) 2008-2022 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -29,6 +30,15 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #define _WIN32_WINNT 0x0600 #include <windows.h> #include <usp10.h> +#ifdef HAVE_HARFBUZZ +# include <hb.h> +# include <hb-ot.h> /* for hb_ot_font_set_funcs */ +# if GNUC_PREREQ (4, 3, 0) +# define bswap_32(v) __builtin_bswap32(v) +# else +# include <byteswap.h> +# endif +#endif #include "lisp.h" #include "w32term.h" @@ -36,11 +46,19 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "composite.h" #include "font.h" #include "w32font.h" +#include "pdumper.h" +#include "w32common.h" +/* Extension of w32font_info used by Uniscribe and HarfBuzz backends. */ struct uniscribe_font_info { struct w32font_info w32_font; - SCRIPT_CACHE cache; + /* This is used by the Uniscribe backend as a pointer to the script + cache, and by the HarfBuzz backend as a pointer to a hb_font_t + object. */ + void *cache; + /* This is used by the HarfBuzz backend to store the font scale. */ + double scale; }; int uniscribe_available = 0; @@ -49,6 +67,41 @@ int uniscribe_available = 0; static int CALLBACK ALIGN_STACK add_opentype_font_name_to_list (ENUMLOGFONTEX *, NEWTEXTMETRICEX *, DWORD, LPARAM); +#ifdef HAVE_HARFBUZZ + +struct font_driver harfbuzz_font_driver; +int harfbuzz_available = 0; + +/* Typedefs for HarfBuzz functions which we call through function + pointers initialized after we load the HarfBuzz DLL. */ +DEF_DLL_FN (hb_blob_t *, hb_blob_create, + (const char *, unsigned int, hb_memory_mode_t, void *, + hb_destroy_func_t)); +DEF_DLL_FN (hb_face_t *, hb_face_create_for_tables, + (hb_reference_table_func_t, void *, hb_destroy_func_t)); +DEF_DLL_FN (unsigned, hb_face_get_glyph_count, (const hb_face_t *)); +DEF_DLL_FN (hb_font_t *, hb_font_create, (hb_face_t *)); +DEF_DLL_FN (void, hb_font_destroy, (hb_font_t *)); +DEF_DLL_FN (void, hb_face_destroy, (hb_face_t *)); +DEF_DLL_FN (unsigned int, hb_face_get_upem, (hb_face_t *)); +DEF_DLL_FN (hb_bool_t, hb_font_get_nominal_glyph, + (hb_font_t *, hb_codepoint_t, hb_codepoint_t *)); +DEF_DLL_FN (hb_bool_t, hb_font_get_variation_glyph, + (hb_font_t *, hb_codepoint_t, hb_codepoint_t, hb_codepoint_t *)); +DEF_DLL_FN (void, hb_ot_font_set_funcs, (hb_font_t *)); + +#define hb_blob_create fn_hb_blob_create +#define hb_face_create_for_tables fn_hb_face_create_for_tables +#define hb_face_get_glyph_count fn_hb_face_get_glyph_count +#define hb_font_create fn_hb_font_create +#define hb_font_destroy fn_hb_font_destroy +#define hb_face_destroy fn_hb_face_destroy +#define hb_face_get_upem fn_hb_face_get_upem +#define hb_font_get_nominal_glyph fn_hb_font_get_nominal_glyph +#define hb_font_get_variation_glyph fn_hb_font_get_variation_glyph +#define hb_ot_font_set_funcs fn_hb_ot_font_set_funcs +#endif + /* Used by uniscribe_otf_capability. */ static Lisp_Object otf_features (HDC context, const char *table); @@ -115,7 +168,10 @@ uniscribe_open (struct frame *f, Lisp_Object font_entity, int pixel_size) struct uniscribe_font_info *uniscribe_font = (struct uniscribe_font_info *) XFONT_OBJECT (font_object); - ASET (font_object, FONT_TYPE_INDEX, Quniscribe); + if (!NILP (AREF (font_entity, FONT_TYPE_INDEX))) + ASET (font_object, FONT_TYPE_INDEX, AREF (font_entity, FONT_TYPE_INDEX)); + else /* paranoia: this should never happen */ + ASET (font_object, FONT_TYPE_INDEX, Quniscribe); if (!w32font_open_internal (f, font_entity, pixel_size, font_object)) { @@ -125,10 +181,15 @@ uniscribe_open (struct frame *f, Lisp_Object font_entity, int pixel_size) /* Initialize the cache for this font. */ uniscribe_font->cache = NULL; - /* Uniscribe backend uses glyph indices. */ + /* Uniscribe and HarfBuzz backends use glyph indices. */ uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX; - uniscribe_font->w32_font.font.driver = &uniscribe_font_driver; +#ifdef HAVE_HARFBUZZ + if (EQ (AREF (font_object, FONT_TYPE_INDEX), Qharfbuzz)) + uniscribe_font->w32_font.font.driver = &harfbuzz_font_driver; + else +#endif /* HAVE_HARFBUZZ */ + uniscribe_font->w32_font.font.driver = &uniscribe_font_driver; return font_object; } @@ -139,8 +200,16 @@ uniscribe_close (struct font *font) struct uniscribe_font_info *uniscribe_font = (struct uniscribe_font_info *) font; +#ifdef HAVE_HARFBUZZ + if (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver + && uniscribe_font->cache) + hb_font_destroy ((hb_font_t *) uniscribe_font->cache); + else +#endif if (uniscribe_font->cache) - ScriptFreeCache (&(uniscribe_font->cache)); + ScriptFreeCache ((SCRIPT_CACHE) &(uniscribe_font->cache)); + + uniscribe_font->cache = NULL; w32font_close (font); } @@ -176,6 +245,11 @@ uniscribe_otf_capability (struct font *font) Lisp_Object features; f = XFRAME (selected_frame); + /* Prevent quitting while we cons the lists in otf_features. + That's because get_frame_dc acquires the critical section, so we + cannot quit before we release it in release_frame_dc. */ + Lisp_Object prev_quit = Vinhibit_quit; + Vinhibit_quit = Qt; context = get_frame_dc (f); old_font = SelectObject (context, FONT_HANDLE (font)); @@ -186,6 +260,7 @@ uniscribe_otf_capability (struct font *font) SelectObject (context, old_font); release_frame_dc (f, context); + Vinhibit_quit = prev_quit; return capability; } @@ -197,6 +272,9 @@ uniscribe_otf_capability (struct font *font) (N+1)th element of LGSTRING is nil, input of shaping is from the 1st to (N)th elements. In each input glyph, FROM, TO, CHAR, and CODE are already set. + DIRECTION is either L2R or R2L, or nil if unknown. During + redisplay, this comes from applying the UBA, is passed from + composition_reseat_it, and is used by the HarfBuzz shaper. This function updates all fields of the input glyphs. If the output glyphs (M) are more than the input glyphs (N), (N+1)th @@ -205,7 +283,7 @@ uniscribe_otf_capability (struct font *font) than the length of LGSTRING, nil should be returned. In that case, this function is called again with a larger LGSTRING. */ static Lisp_Object -uniscribe_shape (Lisp_Object lgstring) +uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction) { struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring)); struct uniscribe_font_info *uniscribe_font @@ -279,7 +357,7 @@ uniscribe_shape (Lisp_Object lgstring) /* Context may be NULL here, in which case the cache should be used without needing to select the font. */ - result = ScriptShape (context, &(uniscribe_font->cache), + result = ScriptShape (context, (SCRIPT_CACHE) &(uniscribe_font->cache), chars + items[i].iCharPos, nchars_in_run, max_glyphs - done_glyphs, &(items[i].a), glyphs, clusters, attributes, &nglyphs); @@ -293,7 +371,7 @@ uniscribe_shape (Lisp_Object lgstring) context = get_frame_dc (f); old_font = SelectObject (context, FONT_HANDLE (font)); - result = ScriptShape (context, &(uniscribe_font->cache), + result = ScriptShape (context, (SCRIPT_CACHE) &(uniscribe_font->cache), chars + items[i].iCharPos, nchars_in_run, max_glyphs - done_glyphs, &(items[i].a), glyphs, clusters, attributes, &nglyphs); @@ -318,7 +396,7 @@ uniscribe_shape (Lisp_Object lgstring) } else { - result = ScriptPlace (context, &(uniscribe_font->cache), + result = ScriptPlace (context, (SCRIPT_CACHE) &(uniscribe_font->cache), glyphs, nglyphs, attributes, &(items[i].a), advances, offsets, &overall_metrics); if (result == E_PENDING && !context) @@ -328,13 +406,15 @@ uniscribe_shape (Lisp_Object lgstring) context = get_frame_dc (f); old_font = SelectObject (context, FONT_HANDLE (font)); - result = ScriptPlace (context, &(uniscribe_font->cache), + result = ScriptPlace (context, + (SCRIPT_CACHE) &(uniscribe_font->cache), glyphs, nglyphs, attributes, &(items[i].a), advances, offsets, &overall_metrics); } if (SUCCEEDED (result)) { int j, from, to, adj_offset = 0; + int cluster_offset = 0; from = 0; to = from; @@ -378,6 +458,7 @@ uniscribe_shape (Lisp_Object lgstring) } } } + cluster_offset = 0; /* For RTL text, the Uniscribe shaper prepares the values in ADVANCES array for layout in @@ -393,6 +474,8 @@ uniscribe_shape (Lisp_Object lgstring) adjustment for the base character, which is then updated for each successive glyph in the grapheme cluster. */ + /* FIXME: Should we use DIRECTION here instead + of what ScriptItemize guessed? */ if (items[i].a.fRTL) { int j1 = j; @@ -406,8 +489,11 @@ uniscribe_shape (Lisp_Object lgstring) } } - LGLYPH_SET_CHAR (lglyph, chars[items[i].iCharPos - + from]); + int char_idx = items[i].iCharPos + from + cluster_offset; + if (from + cluster_offset > to) + char_idx = items[i].iCharPos + to; + cluster_offset++; + LGLYPH_SET_CHAR (lglyph, chars[char_idx]); LGLYPH_SET_FROM (lglyph, items[i].iCharPos + from); LGLYPH_SET_TO (lglyph, items[i].iCharPos + to); @@ -416,18 +502,18 @@ uniscribe_shape (Lisp_Object lgstring) LGLYPH_SET_ASCENT (lglyph, font->ascent); LGLYPH_SET_DESCENT (lglyph, font->descent); - result = ScriptGetGlyphABCWidth (context, - &(uniscribe_font->cache), - glyphs[j], &char_metric); + result = ScriptGetGlyphABCWidth + (context, (SCRIPT_CACHE) &(uniscribe_font->cache), + glyphs[j], &char_metric); if (result == E_PENDING && !context) { /* Cache incomplete... */ f = XFRAME (selected_frame); context = get_frame_dc (f); old_font = SelectObject (context, FONT_HANDLE (font)); - result = ScriptGetGlyphABCWidth (context, - &(uniscribe_font->cache), - glyphs[j], &char_metric); + result = ScriptGetGlyphABCWidth + (context, (SCRIPT_CACHE) &(uniscribe_font->cache), + glyphs[j], &char_metric); } if (SUCCEEDED (result)) @@ -460,21 +546,21 @@ uniscribe_shape (Lisp_Object lgstring) the direction, the Hebrew point HOLAM is drawn above the right edge of the base consonant, instead of above the left edge. */ - ASET (vec, 0, make_number (-offsets[j].du + ASET (vec, 0, make_fixnum (-offsets[j].du + adj_offset)); /* Update the adjustment value for the width advance of the glyph we just emitted. */ adj_offset -= 2 * advances[j]; } else - ASET (vec, 0, make_number (offsets[j].du + adj_offset)); + ASET (vec, 0, make_fixnum (offsets[j].du + adj_offset)); /* In the font definition coordinate system, the Y coordinate points up, while in our screen coordinates Y grows downwards. So we need to reverse the sign of Y-OFFSET here. */ - ASET (vec, 1, make_number (-offsets[j].dv)); + ASET (vec, 1, make_fixnum (-offsets[j].dv)); /* Based on what ftfont.c does... */ - ASET (vec, 2, make_number (advances[j])); + ASET (vec, 2, make_fixnum (advances[j])); LGLYPH_SET_ADJUSTMENT (lglyph, vec); } else @@ -502,7 +588,7 @@ uniscribe_shape (Lisp_Object lgstring) if (NILP (lgstring)) return Qnil; else - return make_number (done_glyphs); + return make_fixnum (done_glyphs); } /* Uniscribe implementation of encode_char for font backend. @@ -559,7 +645,8 @@ uniscribe_encode_char (struct font *font, int c) order. */ items[0].a.fLogicalOrder = 1; - result = ScriptShape (context, &(uniscribe_font->cache), + result = ScriptShape (context, + (SCRIPT_CACHE) &(uniscribe_font->cache), ch, len, 2, &(items[0].a), glyphs, clusters, attrs, &nglyphs); @@ -570,7 +657,8 @@ uniscribe_encode_char (struct font *font, int c) f = XFRAME (selected_frame); context = get_frame_dc (f); old_font = SelectObject (context, FONT_HANDLE (font)); - result = ScriptShape (context, &(uniscribe_font->cache), + result = ScriptShape (context, + (SCRIPT_CACHE) &(uniscribe_font->cache), ch, len, 2, &(items[0].a), glyphs, clusters, attrs, &nglyphs); } @@ -588,7 +676,8 @@ uniscribe_encode_char (struct font *font, int c) when shaped. But we still need the return from here to be valid for the shaping engine to be invoked later. */ - result = ScriptGetCMap (context, &(uniscribe_font->cache), + result = ScriptGetCMap (context, + (SCRIPT_CACHE) &(uniscribe_font->cache), ch, len, 0, glyphs); if (SUCCEEDED (result) && glyphs[0]) code = glyphs[0]; @@ -879,7 +968,7 @@ uniscribe_check_otf (LOGFONT *font, Lisp_Object otf_spec) int i, retval = 0; /* Check the spec is in the right format. */ - if (!CONSP (otf_spec) || XINT (Flength (otf_spec)) < 3) + if (!CONSP (otf_spec) || XFIXNUM (Flength (otf_spec)) < 3) return 0; /* Break otf_spec into its components. */ @@ -1135,6 +1224,215 @@ font_table_error: return Qnil; } +#ifdef HAVE_HARFBUZZ + +/* W32 implementation of the 'list' method for HarfBuzz backend. */ +static Lisp_Object +w32hb_list (struct frame *f, Lisp_Object font_spec) +{ + Lisp_Object fonts = w32font_list_internal (f, font_spec, true); + FONT_ADD_LOG ("harfbuzz-list", font_spec, fonts); + + for (Lisp_Object tail = fonts; CONSP (tail); tail = XCDR (tail)) + ASET (XCAR (tail), FONT_TYPE_INDEX, Qharfbuzz); + + return fonts; +} + +/* W32 implementation of the 'match' method for HarfBuzz backend. */ +static Lisp_Object +w32hb_match (struct frame *f, Lisp_Object font_spec) +{ + Lisp_Object entity = w32font_match_internal (f, font_spec, true); + FONT_ADD_LOG ("harfbuzz-match", font_spec, entity); + + if (! NILP (entity)) + ASET (entity, FONT_TYPE_INDEX, Qharfbuzz); + return entity; +} + +/* Callback function to free memory. We need this so we could pass it + to HarfBuzz as the function to call to destroy objects for which we + allocated data by calling our 'malloc' (as opposed to 'malloc' from + the MS CRT, against which HarfBuzz was linked). */ +static void +free_cb (void *ptr) +{ + free (ptr); +} + +/* A function used as reference_table_func for HarfBuzz. It returns + the data of a specified table of a font as a blob. */ +static hb_blob_t * +w32hb_get_font_table (hb_face_t *face, hb_tag_t tag, void *data) +{ + struct frame *f = XFRAME (selected_frame); + HDC context = get_frame_dc (f); + HFONT old_font = SelectObject (context, (HFONT) data); + char *font_data = NULL; + DWORD font_data_size = 0, val; + DWORD table = bswap_32 (tag); + hb_blob_t *blob = NULL; + + val = GetFontData (context, table, 0, font_data, font_data_size); + if (val != GDI_ERROR) + { + font_data_size = val; + /* Don't call xmalloc, because it can signal an error, while + we are inside a critical section established by get_frame_dc. */ + font_data = malloc (font_data_size); + if (font_data) + { + val = GetFontData (context, table, 0, font_data, font_data_size); + if (val != GDI_ERROR) + blob = hb_blob_create (font_data, font_data_size, + HB_MEMORY_MODE_READONLY, font_data, free_cb); + } + } + + /* Restore graphics context. */ + SelectObject (context, old_font); + release_frame_dc (f, context); + + return blob; +} + +/* Helper function used by the HarfBuzz implementations of the + encode_char, has_char, and begin_hb_font methods. It creates an + hb_font_t object for a given Emacs font. */ +static hb_font_t * +w32hb_get_font (struct font *font, double *scale) +{ + hb_font_t *hb_font = NULL; + HFONT font_handle = FONT_HANDLE (font); + hb_face_t *hb_face = + hb_face_create_for_tables (w32hb_get_font_table, font_handle, NULL); + if (hb_face_get_glyph_count (hb_face) > 0) + { + hb_font = hb_font_create (hb_face); + /* This is needed for HarfBuzz before 2.0.0; it is the default + in later versions. */ + hb_ot_font_set_funcs (hb_font); + } + + struct uniscribe_font_info *uniscribe_font = + (struct uniscribe_font_info *) font; + unsigned upem = hb_face_get_upem (hb_face); + eassert (upem > 0); + /* https://support.microsoft.com/en-sg/help/74299/info-calculating-the-logical-height-and-point-size-of-a-font. */ + LONG font_point_size = + uniscribe_font->w32_font.metrics.tmHeight + - uniscribe_font->w32_font.metrics.tmInternalLeading; + /* https://docs.microsoft.com/en-us/typography/opentype/spec/ttch01, + under "Converting FUnits to pixels". */ + *scale = font_point_size * 1.0 / upem; + + hb_face_destroy (hb_face); + + /* FIXME: Can hb_font be non-NULL and yet invalid? Compare to get_empty? */ + return hb_font; +} + +/* W32 implementation of encode_char method for HarfBuzz backend. */ +static unsigned +w32hb_encode_char (struct font *font, int c) +{ + struct uniscribe_font_info *uniscribe_font + = (struct uniscribe_font_info *) font; + eassert (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver); + hb_font_t *hb_font = uniscribe_font->cache; + + /* First time we use this font with HarfBuzz, create the hb_font_t + object and cache it. */ + if (!hb_font) + { + double scale; + hb_font = w32hb_get_font (font, &scale); + if (!hb_font) + return FONT_INVALID_CODE; + + uniscribe_font->cache = hb_font; + eassert (scale > 0.0); + uniscribe_font->scale = scale; + } + hb_codepoint_t glyph; + if (hb_font_get_nominal_glyph (hb_font, c, &glyph)) + return glyph; + return FONT_INVALID_CODE; +} + +/* W32 implementation of HarfBuzz begin_hb_font and end_hb_font + methods. */ + +/* Return a HarfBuzz font object for FONT and store in POSITION_UNIT + the scale factor to convert a hb_position_t value to the number of + pixels. Return NULL if HarfBuzz font object is not available for + FONT. */ +static hb_font_t * +w32hb_begin_font (struct font *font, double *position_unit) +{ + struct uniscribe_font_info *uniscribe_font + = (struct uniscribe_font_info *) font; + eassert (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver); + + /* First time we use this font with HarfBuzz, create the hb_font_t + object and cache it. */ + if (!uniscribe_font->cache) + { + double scale; + uniscribe_font->cache = w32hb_get_font (font, &scale); + eassert (scale > 0.0); + uniscribe_font->scale = scale; + } + *position_unit = uniscribe_font->scale; + return (hb_font_t *) uniscribe_font->cache; +} + +/* W32 implementation of get_variation_glyphs method for HarfBuzz. + + Return the number of variation glyphs of character C supported by + FONT. VARIATIONS is an array of 256 elements. If the variation + selector N (1..256) defines a glyph, that glyph code is stored in + the (N-1)th element of VARIATIONS. */ +static int +w32hb_get_variation_glyphs (struct font *font, int c, unsigned variations[256]) +{ + struct uniscribe_font_info *uniscribe_font + = (struct uniscribe_font_info *) font; + eassert (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver); + + /* First time we use this font with HarfBuzz, create the hb_font_t + object and cache it. */ + if (!uniscribe_font->cache) + { + double scale; + uniscribe_font->cache = w32hb_get_font (font, &scale); + eassert (scale > 0.0); + uniscribe_font->scale = scale; + } + + int i, n = 0; + hb_font_t *hb_font = uniscribe_font->cache; + for (i = 0; i < 16; i++) + { + if (hb_font_get_variation_glyph (hb_font, c, 0xFE00 + i, &variations[i])) + n++; + else + variations[i] = 0; + } + for ( ; i < 256; i++) + { + if (hb_font_get_variation_glyph (hb_font, c, 0xE0100 + (i - 16), + &variations[i])) + n++; + else + variations[i] = 0; + } + + return n; +} +#endif /* HAVE_HARFBUZZ */ + #undef OTF_INT16_VAL #undef OTF_TAG_VAL #undef OTF_TAG @@ -1175,17 +1473,41 @@ struct font_driver uniscribe_font_driver = as it needs to test for the existence of the Uniscribe library. */ void syms_of_w32uniscribe (void); +static void syms_of_w32uniscribe_for_pdumper (void); + void syms_of_w32uniscribe (void) { - HMODULE uniscribe; + pdumper_do_now_and_after_load (syms_of_w32uniscribe_for_pdumper); +} + +#ifdef HAVE_HARFBUZZ +static bool +load_harfbuzz_funcs (HMODULE library) +{ + LOAD_DLL_FN (library, hb_blob_create); + LOAD_DLL_FN (library, hb_face_create_for_tables); + LOAD_DLL_FN (library, hb_face_get_glyph_count); + LOAD_DLL_FN (library, hb_font_create); + LOAD_DLL_FN (library, hb_font_destroy); + LOAD_DLL_FN (library, hb_face_get_upem); + LOAD_DLL_FN (library, hb_face_destroy); + LOAD_DLL_FN (library, hb_font_get_nominal_glyph); + LOAD_DLL_FN (library, hb_font_get_variation_glyph); + LOAD_DLL_FN (library, hb_ot_font_set_funcs); + return hbfont_init_w32_funcs (library); +} +#endif /* HAVE_HARFBUZZ */ - /* Don't init uniscribe when dumping */ +static void +syms_of_w32uniscribe_for_pdumper (void) +{ + /* Don't init Uniscribe and HarfBuzz when dumping */ if (!initialized) return; - /* Don't register if uniscribe is not available. */ - uniscribe = GetModuleHandle ("usp10"); + /* Don't register if Uniscribe is not available. */ + HMODULE uniscribe = GetModuleHandle ("usp10"); if (!uniscribe) return; @@ -1194,15 +1516,44 @@ syms_of_w32uniscribe (void) register_font_driver (&uniscribe_font_driver, NULL); script_get_font_scripts_fn = (ScriptGetFontScriptTags_Proc) - GetProcAddress (uniscribe, "ScriptGetFontScriptTags"); + get_proc_addr (uniscribe, "ScriptGetFontScriptTags"); script_get_font_languages_fn = (ScriptGetFontLanguageTags_Proc) - GetProcAddress (uniscribe, "ScriptGetFontLanguageTags"); + get_proc_addr (uniscribe, "ScriptGetFontLanguageTags"); script_get_font_features_fn = (ScriptGetFontFeatureTags_Proc) - GetProcAddress (uniscribe, "ScriptGetFontFeatureTags"); + get_proc_addr (uniscribe, "ScriptGetFontFeatureTags"); if (script_get_font_scripts_fn && script_get_font_languages_fn && script_get_font_features_fn) uniscribe_new_apis = true; else uniscribe_new_apis = false; + +#ifdef HAVE_HARFBUZZ + /* Currently, HarfBuzz DLLs are always named libharfbuzz-0.dll, as + the project keeps the ABI backward-compatible. So we can + hard-code the name of the library here, for now. If they ever + break ABI compatibility, we may need to load the DLL that + corresponds to the HarfBuzz version for which Emacs was built. */ + HMODULE harfbuzz = LoadLibrary ("libharfbuzz-0.dll"); + /* Don't register if HarfBuzz is not available. */ + if (!harfbuzz) + return; + + if (!load_harfbuzz_funcs (harfbuzz)) + return; + + Fput (Quniscribe, Qfont_driver_superseded_by, Qharfbuzz); + harfbuzz_available = 1; + harfbuzz_font_driver = uniscribe_font_driver; + harfbuzz_font_driver.type = Qharfbuzz; + harfbuzz_font_driver.list = w32hb_list; + harfbuzz_font_driver.match = w32hb_match; + harfbuzz_font_driver.encode_char = w32hb_encode_char; + harfbuzz_font_driver.otf_capability = hbfont_otf_capability; + harfbuzz_font_driver.shape = hbfont_shape; + harfbuzz_font_driver.get_variation_glyphs = w32hb_get_variation_glyphs; + harfbuzz_font_driver.combining_capability = hbfont_combining_capability; + harfbuzz_font_driver.begin_hb_font = w32hb_begin_font; + register_font_driver (&harfbuzz_font_driver, NULL); +#endif /* HAVE_HARFBUZZ */ } |