aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2019-05-31 11:30:36 +0300
committerEli Zaretskii2019-05-31 11:30:36 +0300
commitfba3687db414306da780d1faeb13fe947d2e6da6 (patch)
tree5518fa631be611f8534bc67ed0a9140788a39650 /src
parentb40dde705af4d53853de6185a2468153b442dc9a (diff)
downloademacs-fba3687db414306da780d1faeb13fe947d2e6da6.tar.gz
emacs-fba3687db414306da780d1faeb13fe947d2e6da6.zip
Add HarfBuzz font backend for MS-Windows
* src/w32uniscribe.c [HAVE_HARFBUZZ]: Include math.h and hb.h. (bswap_32): Define for GCC 4.3.0 and later; else include <byteswap.h> from Gnulib. (struct uniscribe_font_info): Extend for HarfBuzz; 'cache' is now a 'void *' (all users changed). [HAVE_HARFBUZZ]: Define typedefs for HarfBuzz functions to be loaded dynamically from the HarfBuzz DLL. Define macros to call those functions via function pointers. (uniscribe_open) [HAVE_HARFBUZZ]: Use the HarfBuzz font driver if the type of the font entity is 'harfbuzz'. (uniscribe_close) [HAVE_HARFBUZZ]: For fonts using the HarfBuzz backend, call hb_font_destroy to free memory used for the cached hb_font data. (uniscribe_shape): Fix assignment of character codepoints to glyphs from a single cluster. (w32hb_list, w32hb_match, free_cb, w32hb_get_font_table) (w32hb_get_font, w32hb_encode_char, w32hb_begin_font) (w32uni_combining, w32uni_general, w32uni_mirroring) (get_hb_unicode_funcs, w32hb_shape) (w32hb_combining_capability, load_harfbuzz_funcs) [HAVE_HARFBUZZ]: New functions. (syms_of_w32uniscribe_for_pdumper) [HAVE_HARFBUZZ]: Load the HarfBuzz DLL and register the HarfBuzz backend with its functions. * src/w32font.c (syms_of_w32font) <Qharfbuzz>: New DEFSYM. * src/w32fns.c (Fx_create_frame, w32_create_tip_frame) [HAVE_HARFBUZZ]: Register the harfbuzz font backend. * src/lisp.h (get_unicode_property): Declare prototype. * src/font.h (harfbuzz_font_driver) [HAVE_NTGUI]: Declare. * src/chartab.c (get_unicode_property): New function, body taken from get-unicode-property-internal. (Fget_unicode_property_internal): Call get_unicode_property after validating input. * doc/lispref/frames.texi (Font and Color Parameters): * doc/emacs/msdos.texi (Windows Fonts): Document support for HarfBuzz text shaping on MS-Windows. * configure.ac (HAVE_HARFBUZZ): Move out of the X-specific part, and consider HarfBuzz also for HAVE_W32 systems. Require HarfBuzz v1.2.3 for w32.
Diffstat (limited to 'src')
-rw-r--r--src/chartab.c15
-rw-r--r--src/font.h3
-rw-r--r--src/lisp.h1
-rw-r--r--src/w32fns.c9
-rw-r--r--src/w32font.c1
-rw-r--r--src/w32uniscribe.c742
6 files changed, 740 insertions, 31 deletions
diff --git a/src/chartab.c b/src/chartab.c
index 16017f4a49a..bf8e34b2529 100644
--- a/src/chartab.c
+++ b/src/chartab.c
@@ -1321,22 +1321,25 @@ and put an element value. */)
1321 return Fcdr (Fassq (prop, Vchar_code_property_alist)); 1321 return Fcdr (Fassq (prop, Vchar_code_property_alist));
1322} 1322}
1323 1323
1324Lisp_Object
1325get_unicode_property (Lisp_Object char_table, int ch)
1326{
1327 Lisp_Object val = CHAR_TABLE_REF (char_table, ch);
1328 uniprop_decoder_t decoder = uniprop_get_decoder (char_table);
1329 return (decoder ? decoder (char_table, val) : val);
1330}
1331
1324DEFUN ("get-unicode-property-internal", Fget_unicode_property_internal, 1332DEFUN ("get-unicode-property-internal", Fget_unicode_property_internal,
1325 Sget_unicode_property_internal, 2, 2, 0, 1333 Sget_unicode_property_internal, 2, 2, 0,
1326 doc: /* Return an element of CHAR-TABLE for character CH. 1334 doc: /* Return an element of CHAR-TABLE for character CH.
1327CHAR-TABLE must be what returned by `unicode-property-table-internal'. */) 1335CHAR-TABLE must be what returned by `unicode-property-table-internal'. */)
1328 (Lisp_Object char_table, Lisp_Object ch) 1336 (Lisp_Object char_table, Lisp_Object ch)
1329{ 1337{
1330 Lisp_Object val;
1331 uniprop_decoder_t decoder;
1332
1333 CHECK_CHAR_TABLE (char_table); 1338 CHECK_CHAR_TABLE (char_table);
1334 CHECK_CHARACTER (ch); 1339 CHECK_CHARACTER (ch);
1335 if (! UNIPROP_TABLE_P (char_table)) 1340 if (! UNIPROP_TABLE_P (char_table))
1336 error ("Invalid Unicode property table"); 1341 error ("Invalid Unicode property table");
1337 val = CHAR_TABLE_REF (char_table, XFIXNUM (ch)); 1342 return get_unicode_property (char_table, XFIXNUM (ch));
1338 decoder = uniprop_get_decoder (char_table);
1339 return (decoder ? decoder (char_table, val) : val);
1340} 1343}
1341 1344
1342DEFUN ("put-unicode-property-internal", Fput_unicode_property_internal, 1345DEFUN ("put-unicode-property-internal", Fput_unicode_property_internal,
diff --git a/src/font.h b/src/font.h
index a590bda3db4..4d1341a0db8 100644
--- a/src/font.h
+++ b/src/font.h
@@ -951,6 +951,9 @@ extern void syms_of_bdffont (void);
951#ifdef HAVE_NTGUI 951#ifdef HAVE_NTGUI
952extern struct font_driver w32font_driver; 952extern struct font_driver w32font_driver;
953extern struct font_driver uniscribe_font_driver; 953extern struct font_driver uniscribe_font_driver;
954#ifdef HAVE_HARFBUZZ
955extern struct font_driver harfbuzz_font_driver;
956#endif
954extern void syms_of_w32font (void); 957extern void syms_of_w32font (void);
955#endif /* HAVE_NTGUI */ 958#endif /* HAVE_NTGUI */
956#ifdef HAVE_NS 959#ifdef HAVE_NS
diff --git a/src/lisp.h b/src/lisp.h
index 6db90596899..5bd88f32e6e 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3994,6 +3994,7 @@ extern void map_char_table_for_charset (void (*c_function) (Lisp_Object, Lisp_Ob
3994 Lisp_Object, struct charset *, 3994 Lisp_Object, struct charset *,
3995 unsigned, unsigned); 3995 unsigned, unsigned);
3996extern Lisp_Object uniprop_table (Lisp_Object); 3996extern Lisp_Object uniprop_table (Lisp_Object);
3997extern Lisp_Object get_unicode_property (Lisp_Object, int);
3997extern void syms_of_chartab (void); 3998extern void syms_of_chartab (void);
3998 3999
3999/* Defined in print.c. */ 4000/* Defined in print.c. */
diff --git a/src/w32fns.c b/src/w32fns.c
index bb74fcc1640..25fa1ac6ea0 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -221,6 +221,7 @@ int menubar_in_use = 0;
221/* From w32uniscribe.c */ 221/* From w32uniscribe.c */
222extern void syms_of_w32uniscribe (void); 222extern void syms_of_w32uniscribe (void);
223extern int uniscribe_available; 223extern int uniscribe_available;
224extern int harfbuzz_available;
224 225
225#ifdef WINDOWSNT 226#ifdef WINDOWSNT
226/* From w32inevt.c */ 227/* From w32inevt.c */
@@ -5843,6 +5844,10 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5843 specbind (Qx_resource_name, name); 5844 specbind (Qx_resource_name, name);
5844 } 5845 }
5845 5846
5847#ifdef HAVE_HARFBUZZ
5848 if (harfbuzz_available)
5849 register_font_driver (&harfbuzz_font_driver, f);
5850#endif
5846 if (uniscribe_available) 5851 if (uniscribe_available)
5847 register_font_driver (&uniscribe_font_driver, f); 5852 register_font_driver (&uniscribe_font_driver, f);
5848 register_font_driver (&w32font_driver, f); 5853 register_font_driver (&w32font_driver, f);
@@ -6896,6 +6901,10 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
6896 specbind (Qx_resource_name, name); 6901 specbind (Qx_resource_name, name);
6897 } 6902 }
6898 6903
6904#ifdef HAVE_HARFBUZZ
6905 if (harfbuzz_available)
6906 register_font_driver (&harfbuzz_font_driver, f);
6907#endif
6899 if (uniscribe_available) 6908 if (uniscribe_available)
6900 register_font_driver (&uniscribe_font_driver, f); 6909 register_font_driver (&uniscribe_font_driver, f);
6901 register_font_driver (&w32font_driver, f); 6910 register_font_driver (&w32font_driver, f);
diff --git a/src/w32font.c b/src/w32font.c
index bd68e22cc90..2576df64b6f 100644
--- a/src/w32font.c
+++ b/src/w32font.c
@@ -2634,6 +2634,7 @@ syms_of_w32font (void)
2634{ 2634{
2635 DEFSYM (Qgdi, "gdi"); 2635 DEFSYM (Qgdi, "gdi");
2636 DEFSYM (Quniscribe, "uniscribe"); 2636 DEFSYM (Quniscribe, "uniscribe");
2637 DEFSYM (Qharfbuzz, "harfbuzz");
2637 DEFSYM (QCformat, ":format"); 2638 DEFSYM (QCformat, ":format");
2638 2639
2639 /* Generic font families. */ 2640 /* Generic font families. */
diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c
index 693e4a4b1b3..f1e69452160 100644
--- a/src/w32uniscribe.c
+++ b/src/w32uniscribe.c
@@ -29,6 +29,15 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
29#define _WIN32_WINNT 0x0600 29#define _WIN32_WINNT 0x0600
30#include <windows.h> 30#include <windows.h>
31#include <usp10.h> 31#include <usp10.h>
32#ifdef HAVE_HARFBUZZ
33# include <math.h> /* for lround */
34# include <hb.h>
35# if GNUC_PREREQ (4, 3, 0)
36# define bswap_32(v) __builtin_bswap32(v)
37# else
38# include <byteswap.h>
39# endif
40#endif
32 41
33#include "lisp.h" 42#include "lisp.h"
34#include "w32term.h" 43#include "w32term.h"
@@ -39,10 +48,16 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
39#include "pdumper.h" 48#include "pdumper.h"
40#include "w32common.h" 49#include "w32common.h"
41 50
51/* Extension of w32font_info used by Uniscribe and HarfBuzz backends. */
42struct uniscribe_font_info 52struct uniscribe_font_info
43{ 53{
44 struct w32font_info w32_font; 54 struct w32font_info w32_font;
45 SCRIPT_CACHE cache; 55 /* This is used by the Uniscribe backend as a pointer to the script
56 cache, and by the HarfBuzz backend as a pointer to a hb_font_t
57 object. */
58 void *cache;
59 /* This is used by the HarfBuzz backend to store the font scale. */
60 double scale;
46}; 61};
47 62
48int uniscribe_available = 0; 63int uniscribe_available = 0;
@@ -51,6 +66,94 @@ int uniscribe_available = 0;
51static int CALLBACK ALIGN_STACK add_opentype_font_name_to_list (ENUMLOGFONTEX *, 66static int CALLBACK ALIGN_STACK add_opentype_font_name_to_list (ENUMLOGFONTEX *,
52 NEWTEXTMETRICEX *, 67 NEWTEXTMETRICEX *,
53 DWORD, LPARAM); 68 DWORD, LPARAM);
69#ifdef HAVE_HARFBUZZ
70
71struct font_driver harfbuzz_font_driver;
72int harfbuzz_available = 0;
73
74/* Typedefs for HarfBuzz functions which we call through function
75 pointers initialized after we load the HarfBuzz DLL. */
76DEF_DLL_FN (hb_blob_t *, hb_blob_create,
77 (const char *, unsigned int, hb_memory_mode_t, void *,
78 hb_destroy_func_t));
79DEF_DLL_FN (hb_face_t *, hb_face_create_for_tables,
80 (hb_reference_table_func_t, void *, hb_destroy_func_t));
81DEF_DLL_FN (unsigned, hb_face_get_glyph_count, (const hb_face_t *));
82DEF_DLL_FN (hb_font_t *, hb_font_create, (hb_face_t *));
83DEF_DLL_FN (void, hb_font_destroy, (hb_font_t *));
84DEF_DLL_FN (void, hb_face_destroy, (hb_face_t *));
85DEF_DLL_FN (unsigned int, hb_face_get_upem, (hb_face_t *));
86DEF_DLL_FN (hb_bool_t, hb_font_get_nominal_glyph,
87 (hb_font_t *, hb_codepoint_t, hb_codepoint_t *));
88DEF_DLL_FN (hb_unicode_funcs_t *, hb_unicode_funcs_create,
89 (hb_unicode_funcs_t *));
90DEF_DLL_FN (hb_unicode_funcs_t *, hb_unicode_funcs_get_default, (void));
91DEF_DLL_FN (void, hb_unicode_funcs_set_combining_class_func,
92 (hb_unicode_funcs_t *, hb_unicode_combining_class_func_t,
93 void *, hb_destroy_func_t));
94DEF_DLL_FN (void, hb_unicode_funcs_set_general_category_func,
95 (hb_unicode_funcs_t *, hb_unicode_general_category_func_t,
96 void *, hb_destroy_func_t));
97DEF_DLL_FN (void, hb_unicode_funcs_set_mirroring_func,
98 (hb_unicode_funcs_t *, hb_unicode_mirroring_func_t,
99 void *, hb_destroy_func_t));
100DEF_DLL_FN (hb_buffer_t *, hb_buffer_create, (void));
101DEF_DLL_FN (void, hb_buffer_set_unicode_funcs,
102 (hb_buffer_t *, hb_unicode_funcs_t *));
103DEF_DLL_FN (void, hb_buffer_clear_contents, (hb_buffer_t *));
104DEF_DLL_FN (hb_bool_t, hb_buffer_pre_allocate, (hb_buffer_t *, unsigned int));
105DEF_DLL_FN (void, hb_buffer_add, (hb_buffer_t *, hb_codepoint_t, unsigned int));
106DEF_DLL_FN (void, hb_buffer_set_content_type,
107 (hb_buffer_t *, hb_buffer_content_type_t));
108DEF_DLL_FN (void, hb_buffer_set_cluster_level,
109 (hb_buffer_t *, hb_buffer_cluster_level_t));
110DEF_DLL_FN (void, hb_buffer_set_direction, (hb_buffer_t *, hb_direction_t));
111DEF_DLL_FN (void, hb_buffer_set_language, (hb_buffer_t *, hb_language_t));
112DEF_DLL_FN (hb_language_t, hb_language_from_string, (const char *, int));
113DEF_DLL_FN (void, hb_buffer_guess_segment_properties, (hb_buffer_t *));
114DEF_DLL_FN (hb_bool_t, hb_shape_full,
115 (hb_font_t *, hb_buffer_t *, const hb_feature_t *,
116 unsigned int, const char * const *));
117DEF_DLL_FN (unsigned int, hb_buffer_get_length, (hb_buffer_t *));
118DEF_DLL_FN (hb_direction_t, hb_buffer_get_direction, (hb_buffer_t *));
119DEF_DLL_FN (void, hb_buffer_reverse_clusters, (hb_buffer_t *));
120DEF_DLL_FN (hb_glyph_info_t *, hb_buffer_get_glyph_infos,
121 (hb_buffer_t *, unsigned int *));
122DEF_DLL_FN (hb_glyph_position_t *, hb_buffer_get_glyph_positions,
123 (hb_buffer_t *, unsigned int *));
124
125#define hb_blob_create fn_hb_blob_create
126#define hb_face_create_for_tables fn_hb_face_create_for_tables
127#define hb_face_get_glyph_count fn_hb_face_get_glyph_count
128#define hb_font_create fn_hb_font_create
129#define hb_font_destroy fn_hb_font_destroy
130#define hb_face_destroy fn_hb_face_destroy
131#define hb_face_get_upem fn_hb_face_get_upem
132#define hb_font_get_nominal_glyph fn_hb_font_get_nominal_glyph
133#define hb_unicode_funcs_create fn_hb_unicode_funcs_create
134#define hb_unicode_funcs_get_default fn_hb_unicode_funcs_get_default
135#define hb_unicode_funcs_set_combining_class_func fn_hb_unicode_funcs_set_combining_class_func
136#define hb_unicode_funcs_set_general_category_func fn_hb_unicode_funcs_set_general_category_func
137#define hb_unicode_funcs_set_mirroring_func fn_hb_unicode_funcs_set_mirroring_func
138#define hb_buffer_create fn_hb_buffer_create
139#define hb_buffer_set_unicode_funcs fn_hb_buffer_set_unicode_funcs
140#define hb_buffer_clear_contents fn_hb_buffer_clear_contents
141#define hb_buffer_pre_allocate fn_hb_buffer_pre_allocate
142#define hb_buffer_add fn_hb_buffer_add
143#define hb_buffer_set_content_type fn_hb_buffer_set_content_type
144#define hb_buffer_set_cluster_level fn_hb_buffer_set_cluster_level
145#define hb_buffer_set_direction fn_hb_buffer_set_direction
146#define hb_buffer_set_language fn_hb_buffer_set_language
147#define hb_language_from_string fn_hb_language_from_string
148#define hb_buffer_guess_segment_properties fn_hb_buffer_guess_segment_properties
149#define hb_shape_full fn_hb_shape_full
150#define hb_buffer_get_length fn_hb_buffer_get_length
151#define hb_buffer_get_direction fn_hb_buffer_get_direction
152#define hb_buffer_reverse_clusters fn_hb_buffer_reverse_clusters
153#define hb_buffer_get_glyph_infos fn_hb_buffer_get_glyph_infos
154#define hb_buffer_get_glyph_positions fn_hb_buffer_get_glyph_positions
155#endif
156
54/* Used by uniscribe_otf_capability. */ 157/* Used by uniscribe_otf_capability. */
55static Lisp_Object otf_features (HDC context, const char *table); 158static Lisp_Object otf_features (HDC context, const char *table);
56 159
@@ -117,7 +220,10 @@ uniscribe_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
117 struct uniscribe_font_info *uniscribe_font 220 struct uniscribe_font_info *uniscribe_font
118 = (struct uniscribe_font_info *) XFONT_OBJECT (font_object); 221 = (struct uniscribe_font_info *) XFONT_OBJECT (font_object);
119 222
120 ASET (font_object, FONT_TYPE_INDEX, Quniscribe); 223 if (!NILP (AREF (font_entity, FONT_TYPE_INDEX)))
224 ASET (font_object, FONT_TYPE_INDEX, AREF (font_entity, FONT_TYPE_INDEX));
225 else /* paranoia: this should never happen */
226 ASET (font_object, FONT_TYPE_INDEX, Quniscribe);
121 227
122 if (!w32font_open_internal (f, font_entity, pixel_size, font_object)) 228 if (!w32font_open_internal (f, font_entity, pixel_size, font_object))
123 { 229 {
@@ -127,10 +233,15 @@ uniscribe_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
127 /* Initialize the cache for this font. */ 233 /* Initialize the cache for this font. */
128 uniscribe_font->cache = NULL; 234 uniscribe_font->cache = NULL;
129 235
130 /* Uniscribe backend uses glyph indices. */ 236 /* Uniscribe and HarfBuzz backends use glyph indices. */
131 uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX; 237 uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX;
132 238
133 uniscribe_font->w32_font.font.driver = &uniscribe_font_driver; 239#ifdef HAVE_HARFBUZZ
240 if (EQ (AREF (font_object, FONT_TYPE_INDEX), Qharfbuzz))
241 uniscribe_font->w32_font.font.driver = &harfbuzz_font_driver;
242 else
243#endif /* HAVE_HARFBUZZ */
244 uniscribe_font->w32_font.font.driver = &uniscribe_font_driver;
134 245
135 return font_object; 246 return font_object;
136} 247}
@@ -141,8 +252,16 @@ uniscribe_close (struct font *font)
141 struct uniscribe_font_info *uniscribe_font 252 struct uniscribe_font_info *uniscribe_font
142 = (struct uniscribe_font_info *) font; 253 = (struct uniscribe_font_info *) font;
143 254
255#ifdef HAVE_HARFBUZZ
256 if (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver
257 && uniscribe_font->cache)
258 hb_font_destroy ((hb_font_t *) uniscribe_font->cache);
259 else
260#endif
144 if (uniscribe_font->cache) 261 if (uniscribe_font->cache)
145 ScriptFreeCache (&(uniscribe_font->cache)); 262 ScriptFreeCache ((SCRIPT_CACHE) &(uniscribe_font->cache));
263
264 uniscribe_font->cache = NULL;
146 265
147 w32font_close (font); 266 w32font_close (font);
148} 267}
@@ -290,7 +409,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
290 409
291 /* Context may be NULL here, in which case the cache should be 410 /* Context may be NULL here, in which case the cache should be
292 used without needing to select the font. */ 411 used without needing to select the font. */
293 result = ScriptShape (context, &(uniscribe_font->cache), 412 result = ScriptShape (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
294 chars + items[i].iCharPos, nchars_in_run, 413 chars + items[i].iCharPos, nchars_in_run,
295 max_glyphs - done_glyphs, &(items[i].a), 414 max_glyphs - done_glyphs, &(items[i].a),
296 glyphs, clusters, attributes, &nglyphs); 415 glyphs, clusters, attributes, &nglyphs);
@@ -304,7 +423,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
304 context = get_frame_dc (f); 423 context = get_frame_dc (f);
305 old_font = SelectObject (context, FONT_HANDLE (font)); 424 old_font = SelectObject (context, FONT_HANDLE (font));
306 425
307 result = ScriptShape (context, &(uniscribe_font->cache), 426 result = ScriptShape (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
308 chars + items[i].iCharPos, nchars_in_run, 427 chars + items[i].iCharPos, nchars_in_run,
309 max_glyphs - done_glyphs, &(items[i].a), 428 max_glyphs - done_glyphs, &(items[i].a),
310 glyphs, clusters, attributes, &nglyphs); 429 glyphs, clusters, attributes, &nglyphs);
@@ -329,7 +448,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
329 } 448 }
330 else 449 else
331 { 450 {
332 result = ScriptPlace (context, &(uniscribe_font->cache), 451 result = ScriptPlace (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
333 glyphs, nglyphs, attributes, &(items[i].a), 452 glyphs, nglyphs, attributes, &(items[i].a),
334 advances, offsets, &overall_metrics); 453 advances, offsets, &overall_metrics);
335 if (result == E_PENDING && !context) 454 if (result == E_PENDING && !context)
@@ -339,13 +458,15 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
339 context = get_frame_dc (f); 458 context = get_frame_dc (f);
340 old_font = SelectObject (context, FONT_HANDLE (font)); 459 old_font = SelectObject (context, FONT_HANDLE (font));
341 460
342 result = ScriptPlace (context, &(uniscribe_font->cache), 461 result = ScriptPlace (context,
462 (SCRIPT_CACHE) &(uniscribe_font->cache),
343 glyphs, nglyphs, attributes, &(items[i].a), 463 glyphs, nglyphs, attributes, &(items[i].a),
344 advances, offsets, &overall_metrics); 464 advances, offsets, &overall_metrics);
345 } 465 }
346 if (SUCCEEDED (result)) 466 if (SUCCEEDED (result))
347 { 467 {
348 int j, from, to, adj_offset = 0; 468 int j, from, to, adj_offset = 0;
469 int cluster_offset = 0;
349 470
350 from = 0; 471 from = 0;
351 to = from; 472 to = from;
@@ -389,6 +510,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
389 } 510 }
390 } 511 }
391 } 512 }
513 cluster_offset = 0;
392 514
393 /* For RTL text, the Uniscribe shaper prepares 515 /* For RTL text, the Uniscribe shaper prepares
394 the values in ADVANCES array for layout in 516 the values in ADVANCES array for layout in
@@ -419,8 +541,11 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
419 } 541 }
420 } 542 }
421 543
422 LGLYPH_SET_CHAR (lglyph, chars[items[i].iCharPos 544 int char_idx = items[i].iCharPos + from + cluster_offset;
423 + from]); 545 if (from + cluster_offset > to)
546 char_idx = items[i].iCharPos + to;
547 cluster_offset++;
548 LGLYPH_SET_CHAR (lglyph, chars[char_idx]);
424 LGLYPH_SET_FROM (lglyph, items[i].iCharPos + from); 549 LGLYPH_SET_FROM (lglyph, items[i].iCharPos + from);
425 LGLYPH_SET_TO (lglyph, items[i].iCharPos + to); 550 LGLYPH_SET_TO (lglyph, items[i].iCharPos + to);
426 551
@@ -429,18 +554,18 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
429 LGLYPH_SET_ASCENT (lglyph, font->ascent); 554 LGLYPH_SET_ASCENT (lglyph, font->ascent);
430 LGLYPH_SET_DESCENT (lglyph, font->descent); 555 LGLYPH_SET_DESCENT (lglyph, font->descent);
431 556
432 result = ScriptGetGlyphABCWidth (context, 557 result = ScriptGetGlyphABCWidth
433 &(uniscribe_font->cache), 558 (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
434 glyphs[j], &char_metric); 559 glyphs[j], &char_metric);
435 if (result == E_PENDING && !context) 560 if (result == E_PENDING && !context)
436 { 561 {
437 /* Cache incomplete... */ 562 /* Cache incomplete... */
438 f = XFRAME (selected_frame); 563 f = XFRAME (selected_frame);
439 context = get_frame_dc (f); 564 context = get_frame_dc (f);
440 old_font = SelectObject (context, FONT_HANDLE (font)); 565 old_font = SelectObject (context, FONT_HANDLE (font));
441 result = ScriptGetGlyphABCWidth (context, 566 result = ScriptGetGlyphABCWidth
442 &(uniscribe_font->cache), 567 (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
443 glyphs[j], &char_metric); 568 glyphs[j], &char_metric);
444 } 569 }
445 570
446 if (SUCCEEDED (result)) 571 if (SUCCEEDED (result))
@@ -572,7 +697,8 @@ uniscribe_encode_char (struct font *font, int c)
572 order. */ 697 order. */
573 items[0].a.fLogicalOrder = 1; 698 items[0].a.fLogicalOrder = 1;
574 699
575 result = ScriptShape (context, &(uniscribe_font->cache), 700 result = ScriptShape (context,
701 (SCRIPT_CACHE) &(uniscribe_font->cache),
576 ch, len, 2, &(items[0].a), 702 ch, len, 2, &(items[0].a),
577 glyphs, clusters, attrs, &nglyphs); 703 glyphs, clusters, attrs, &nglyphs);
578 704
@@ -583,7 +709,8 @@ uniscribe_encode_char (struct font *font, int c)
583 f = XFRAME (selected_frame); 709 f = XFRAME (selected_frame);
584 context = get_frame_dc (f); 710 context = get_frame_dc (f);
585 old_font = SelectObject (context, FONT_HANDLE (font)); 711 old_font = SelectObject (context, FONT_HANDLE (font));
586 result = ScriptShape (context, &(uniscribe_font->cache), 712 result = ScriptShape (context,
713 (SCRIPT_CACHE) &(uniscribe_font->cache),
587 ch, len, 2, &(items[0].a), 714 ch, len, 2, &(items[0].a),
588 glyphs, clusters, attrs, &nglyphs); 715 glyphs, clusters, attrs, &nglyphs);
589 } 716 }
@@ -601,7 +728,8 @@ uniscribe_encode_char (struct font *font, int c)
601 when shaped. But we still need the return from here 728 when shaped. But we still need the return from here
602 to be valid for the shaping engine to be invoked 729 to be valid for the shaping engine to be invoked
603 later. */ 730 later. */
604 result = ScriptGetCMap (context, &(uniscribe_font->cache), 731 result = ScriptGetCMap (context,
732 (SCRIPT_CACHE) &(uniscribe_font->cache),
605 ch, len, 0, glyphs); 733 ch, len, 0, glyphs);
606 if (SUCCEEDED (result) && glyphs[0]) 734 if (SUCCEEDED (result) && glyphs[0])
607 code = glyphs[0]; 735 code = glyphs[0];
@@ -1148,6 +1276,508 @@ font_table_error:
1148 return Qnil; 1276 return Qnil;
1149} 1277}
1150 1278
1279#ifdef HAVE_HARFBUZZ
1280
1281/* W32 implementation of the 'list' method for HarfBuzz backend. */
1282static Lisp_Object
1283w32hb_list (struct frame *f, Lisp_Object font_spec)
1284{
1285 Lisp_Object fonts = w32font_list_internal (f, font_spec, true);
1286 FONT_ADD_LOG ("harfbuzz-list", font_spec, fonts);
1287
1288 for (Lisp_Object tail = fonts; CONSP (tail); tail = XCDR (tail))
1289 ASET (XCAR (tail), FONT_TYPE_INDEX, Qharfbuzz);
1290
1291 return fonts;
1292}
1293
1294/* W32 implementation of the 'match' method for HarfBuzz backend. */
1295static Lisp_Object
1296w32hb_match (struct frame *f, Lisp_Object font_spec)
1297{
1298 Lisp_Object entity = w32font_match_internal (f, font_spec, true);
1299 FONT_ADD_LOG ("harfbuzz-match", font_spec, entity);
1300
1301 if (! NILP (entity))
1302 ASET (entity, FONT_TYPE_INDEX, Qharfbuzz);
1303 return entity;
1304}
1305
1306/* Callback function to free memory. We need this so we could pass it
1307 to HarfBuzz as the function to call to destroy objects for which we
1308 allocated data by calling our 'malloc' (as opposed to 'malloc' from
1309 the MS CRT, against which HarfBuzz was linked). */
1310static void
1311free_cb (void *ptr)
1312{
1313 free (ptr);
1314}
1315
1316/* A function used as reference_table_func for HarfBuzz. It returns
1317 the data of a specified table of a font as a blob. */
1318static hb_blob_t *
1319w32hb_get_font_table (hb_face_t *face, hb_tag_t tag, void *data)
1320{
1321 struct frame *f = XFRAME (selected_frame);
1322 HDC context = get_frame_dc (f);
1323 HFONT old_font = SelectObject (context, (HFONT) data);
1324 char *font_data = NULL;
1325 DWORD font_data_size = 0, val;
1326 DWORD table = bswap_32 (tag);
1327 hb_blob_t *blob = NULL;
1328
1329 val = GetFontData (context, table, 0, font_data, font_data_size);
1330 if (val != GDI_ERROR)
1331 {
1332 font_data_size = val;
1333 /* Don't call xmalloc, because it can signal an error, while
1334 we are inside a critical section established by get_frame_dc. */
1335 font_data = malloc (font_data_size);
1336 if (font_data)
1337 {
1338 val = GetFontData (context, table, 0, font_data, font_data_size);
1339 if (val != GDI_ERROR)
1340 blob = hb_blob_create (font_data, font_data_size,
1341 HB_MEMORY_MODE_READONLY, font_data, free_cb);
1342 }
1343 }
1344
1345 /* Restore graphics context. */
1346 SelectObject (context, old_font);
1347 release_frame_dc (f, context);
1348
1349 return blob;
1350}
1351
1352/* Helper function used by the HarfBuzz implementations of the
1353 encode_char, has_char, and begin_hb_font methods. It creates an
1354 hb_font_t object for a given Emacs font. */
1355static hb_font_t *
1356w32hb_get_font (struct font *font, double *scale)
1357{
1358 hb_font_t *hb_font = NULL;
1359 HFONT font_handle = FONT_HANDLE (font);
1360 hb_face_t *hb_face =
1361 hb_face_create_for_tables (w32hb_get_font_table, font_handle, NULL);
1362 if (hb_face_get_glyph_count (hb_face) > 0)
1363 hb_font = hb_font_create (hb_face);
1364
1365 struct uniscribe_font_info *uniscribe_font =
1366 (struct uniscribe_font_info *) font;
1367 unsigned upem = hb_face_get_upem (hb_face);
1368 eassert (upem > 0);
1369 /* https://support.microsoft.com/en-sg/help/74299/info-calculating-the-logical-height-and-point-size-of-a-font. */
1370 LONG font_point_size =
1371 uniscribe_font->w32_font.metrics.tmHeight
1372 - uniscribe_font->w32_font.metrics.tmInternalLeading;
1373 /* https://docs.microsoft.com/en-us/typography/opentype/spec/ttch01,
1374 under "Converting FUnits to pixels". */
1375 *scale = font_point_size * 1.0 / upem;
1376
1377 hb_face_destroy (hb_face);
1378
1379 /* FIXME: Can hb_font be non-NULL and yet invalid? Compare to get_empty? */
1380 return hb_font;
1381}
1382
1383/* W32 implementation of encode_char method for HarfBuzz backend. */
1384static unsigned
1385w32hb_encode_char (struct font *font, int c)
1386{
1387 struct uniscribe_font_info *uniscribe_font
1388 = (struct uniscribe_font_info *) font;
1389 eassert (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver);
1390 hb_font_t *hb_font = uniscribe_font->cache;
1391
1392 /* First time we use this font with HarfBuzz, create the hb_font_t
1393 object and cache it. */
1394 if (!hb_font)
1395 {
1396 double scale;
1397 hb_font = w32hb_get_font (font, &scale);
1398 if (!hb_font)
1399 return FONT_INVALID_CODE;
1400
1401 uniscribe_font->cache = hb_font;
1402 eassert (scale > 0.0);
1403 uniscribe_font->scale = scale;
1404 }
1405 hb_codepoint_t glyph;
1406 if (hb_font_get_nominal_glyph (hb_font, c, &glyph))
1407 return glyph;
1408 return FONT_INVALID_CODE;
1409}
1410
1411/* W32 implementation of HarfBuzz begin_hb_font and end_hb_font
1412 methods. */
1413
1414/* Return a HarfBuzz font object for FONT and store in POSITION_UNIT
1415 the scale factor to convert a hb_position_t value to the number of
1416 pixels. Return NULL if HarfBuzz font object is not available for
1417 FONT. */
1418static hb_font_t *
1419w32hb_begin_font (struct font *font, double *position_unit)
1420{
1421 struct uniscribe_font_info *uniscribe_font
1422 = (struct uniscribe_font_info *) font;
1423 eassert (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver);
1424
1425 /* First time we use this font with HarfBuzz, create the hb_font_t
1426 object and cache it. */
1427 if (!uniscribe_font->cache)
1428 {
1429 double scale;
1430 uniscribe_font->cache = w32hb_get_font (font, &scale);
1431 eassert (scale > 0.0);
1432 uniscribe_font->scale = scale;
1433 }
1434 *position_unit = uniscribe_font->scale;
1435 return (hb_font_t *) uniscribe_font->cache;
1436}
1437
1438static bool combining_class_loaded = false;
1439static Lisp_Object canonical_combining_class_table;
1440
1441static hb_unicode_combining_class_t
1442w32uni_combining (hb_unicode_funcs_t *funcs, hb_codepoint_t ch, void *user_data)
1443{
1444 /* Load the Unicode table first time it is needed. */
1445 if (!combining_class_loaded)
1446 {
1447 canonical_combining_class_table =
1448 uniprop_table (intern ("canonical-combining-class"));
1449 if (NILP (canonical_combining_class_table))
1450 emacs_abort ();
1451 staticpro (&canonical_combining_class_table);
1452 combining_class_loaded = true;
1453 }
1454
1455 Lisp_Object combining =
1456 get_unicode_property (canonical_combining_class_table, ch);
1457 if (FIXNUMP (combining))
1458 return (hb_unicode_combining_class_t) XFIXNUM (combining);
1459
1460 return HB_UNICODE_COMBINING_CLASS_NOT_REORDERED;
1461}
1462
1463static hb_unicode_general_category_t
1464w32uni_general (hb_unicode_funcs_t *funcs, hb_codepoint_t ch, void *user_data)
1465{
1466 Lisp_Object category = CHAR_TABLE_REF (Vunicode_category_table, ch);
1467
1468 if (INTEGERP (category))
1469 {
1470 switch (XFIXNUM (category))
1471 {
1472 case UNICODE_CATEGORY_Cc:
1473 return HB_UNICODE_GENERAL_CATEGORY_CONTROL;
1474 case UNICODE_CATEGORY_Cf:
1475 return HB_UNICODE_GENERAL_CATEGORY_FORMAT;
1476 case UNICODE_CATEGORY_Cn:
1477 return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
1478 case UNICODE_CATEGORY_Co:
1479 return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;
1480 case UNICODE_CATEGORY_Cs:
1481 return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;
1482 case UNICODE_CATEGORY_Ll:
1483 return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;
1484 case UNICODE_CATEGORY_Lm:
1485 return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;
1486 case UNICODE_CATEGORY_Lo:
1487 return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
1488 case UNICODE_CATEGORY_Lt:
1489 return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;
1490 case UNICODE_CATEGORY_Lu:
1491 return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;
1492 case UNICODE_CATEGORY_Mc:
1493 return HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK;
1494 case UNICODE_CATEGORY_Me:
1495 return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
1496 case UNICODE_CATEGORY_Mn:
1497 return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;
1498 case UNICODE_CATEGORY_Nd:
1499 return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;
1500 case UNICODE_CATEGORY_Nl:
1501 return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;
1502 case UNICODE_CATEGORY_No:
1503 return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;
1504 case UNICODE_CATEGORY_Pc:
1505 return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;
1506 case UNICODE_CATEGORY_Pd:
1507 return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;
1508 case UNICODE_CATEGORY_Pe:
1509 return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;
1510 case UNICODE_CATEGORY_Pf:
1511 return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;
1512 case UNICODE_CATEGORY_Pi:
1513 return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;
1514 case UNICODE_CATEGORY_Po:
1515 return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;
1516 case UNICODE_CATEGORY_Ps:
1517 return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;
1518 case UNICODE_CATEGORY_Sc:
1519 return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;
1520 case UNICODE_CATEGORY_Sk:
1521 return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;
1522 case UNICODE_CATEGORY_Sm:
1523 return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;
1524 case UNICODE_CATEGORY_So:
1525 return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;
1526 case UNICODE_CATEGORY_Zl:
1527 return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;
1528 case UNICODE_CATEGORY_Zp:
1529 return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;
1530 case UNICODE_CATEGORY_Zs:
1531 return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
1532 case UNICODE_CATEGORY_UNKNOWN:
1533 return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
1534 }
1535 }
1536
1537 return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
1538}
1539
1540static hb_codepoint_t
1541w32uni_mirroring (hb_unicode_funcs_t *funcs, hb_codepoint_t ch, void *user_data)
1542{
1543 return bidi_mirror_char (ch);
1544}
1545
1546static hb_unicode_funcs_t *
1547get_hb_unicode_funcs (void)
1548{
1549 /* Subclass HarfBuzz's default Unicode functions and override functions that
1550 * use data Emacs can provide. This way changing Emacs data is reflected in
1551 * the shaped output. */
1552 hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (hb_unicode_funcs_get_default ());
1553
1554 hb_unicode_funcs_set_combining_class_func (funcs, w32uni_combining, NULL, NULL);
1555 hb_unicode_funcs_set_general_category_func (funcs, w32uni_general, NULL, NULL);
1556 hb_unicode_funcs_set_mirroring_func (funcs, w32uni_mirroring, NULL, NULL);
1557
1558 /* Use default implmentation for Unicode composition/decomposition, we might
1559 * want to revisit this later.
1560 hb_unicode_funcs_set_compose_func (funcs, uni_compose, NULL, NULL);
1561 hb_unicode_funcs_set_decompose_func (funcs, uni_decompose, NULL, NULL);
1562 */
1563
1564 /* Emacs own script mapping for characters differs from Unicode, so we want
1565 * to keep the default HarfBuzz's implementation here.
1566 hb_unicode_funcs_set_script_func (funcs, uni_script, NULL, NULL);
1567 */
1568
1569 return funcs;
1570}
1571
1572/* HarfBuzz implementation of shape for font backend. See the
1573 commentary before uniscribe_shape for the meaning of the
1574 arguments. */
1575static Lisp_Object
1576w32hb_shape (Lisp_Object lgstring, Lisp_Object direction)
1577{
1578 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
1579 ptrdiff_t glyph_len = 0, text_len = LGSTRING_GLYPH_LEN (lgstring);
1580 ptrdiff_t i;
1581
1582 hb_glyph_info_t *info;
1583 hb_glyph_position_t *pos;
1584
1585 /* Cache the HarfBuzz buffer for better performance and less allocations.
1586 * We intentionally never destroy the buffer. */
1587 static hb_buffer_t *hb_buffer = NULL;
1588 if (! hb_buffer)
1589 {
1590 hb_buffer = hb_buffer_create ();
1591 hb_unicode_funcs_t* ufuncs = get_hb_unicode_funcs();
1592 hb_buffer_set_unicode_funcs(hb_buffer, ufuncs);
1593 }
1594
1595 hb_buffer_clear_contents (hb_buffer);
1596 hb_buffer_pre_allocate (hb_buffer, text_len);
1597
1598 /* Copy the characters in their original logical order, so we can
1599 assign them to glyphs correctly after shaping. */
1600 int *chars = alloca (text_len * sizeof (int));
1601 for (i = 0; i < text_len; i++)
1602 {
1603 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
1604 int c;
1605
1606 if (NILP (g))
1607 break;
1608 c = LGLYPH_CHAR (g);
1609 hb_buffer_add (hb_buffer, c, i);
1610 chars[i] = c;
1611 }
1612
1613 text_len = i;
1614 if (!text_len)
1615 return Qnil;
1616
1617 hb_buffer_set_content_type (hb_buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
1618 hb_buffer_set_cluster_level (hb_buffer,
1619 HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES);
1620
1621 /* If the caller didn't provide a meaningful DIRECTION, let HarfBuzz
1622 guess it. */
1623 if (!NILP (direction))
1624 {
1625 hb_direction_t dir = HB_DIRECTION_LTR;
1626 if (EQ (direction, QL2R))
1627 dir = HB_DIRECTION_LTR;
1628 else if (EQ (direction, QR2L))
1629 dir = HB_DIRECTION_RTL;
1630 hb_buffer_set_direction (hb_buffer, dir);
1631 }
1632
1633 /* Leave the script determination to HarfBuzz, until Emacs has a
1634 better idea of the script of LGSTRING. FIXME. */
1635#if 0
1636 hb_buffer_set_script (hb_buffer, XXX);
1637#endif
1638
1639 /* FIXME: This can only handle the single global language, which
1640 normally comes from the locale. In addition, if
1641 current-iso639-language is a list, we arbitrarily use the first
1642 one. We should instead have a notion of the language of the text
1643 being shaped. */
1644 Lisp_Object lang = Vcurrent_iso639_language;
1645 if (CONSP (Vcurrent_iso639_language))
1646 lang = XCAR (Vcurrent_iso639_language);
1647 if (SYMBOLP (lang))
1648 {
1649 Lisp_Object lang_str = SYMBOL_NAME (lang);
1650 hb_buffer_set_language (hb_buffer,
1651 hb_language_from_string (SSDATA (lang_str),
1652 SBYTES (lang_str)));
1653 }
1654
1655 /* Guess the default properties for when they cannot be determined above.
1656
1657 FIXME: maybe drop this guessing once script and language handling
1658 is fixed above; but then will need to guess the direction by
1659 ourselves, perhaps by looking at the the characters using
1660 bidi_get_type or somesuch. */
1661 hb_buffer_guess_segment_properties (hb_buffer);
1662
1663 double position_unit;
1664 hb_font_t *hb_font
1665 = font->driver->begin_hb_font
1666 ? font->driver->begin_hb_font (font, &position_unit)
1667 : NULL;
1668 if (!hb_font)
1669 return make_fixnum (0);
1670
1671 hb_bool_t success = hb_shape_full (hb_font, hb_buffer, NULL, 0, NULL);
1672 if (font->driver->end_hb_font)
1673 font->driver->end_hb_font (font, hb_font);
1674 if (!success)
1675 return Qnil;
1676
1677 glyph_len = hb_buffer_get_length (hb_buffer);
1678 /* FIXME: can't we just grow the lgstring in this case? Giving up is an
1679 * overly heavy handed solution. */
1680 if (glyph_len > LGSTRING_GLYPH_LEN (lgstring))
1681 return Qnil;
1682
1683 /* We need the clusters in logical order. */
1684 bool buf_reversed = false;
1685 if (HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (hb_buffer)))
1686 {
1687 buf_reversed = true;
1688 hb_buffer_reverse_clusters (hb_buffer);
1689 }
1690 info = hb_buffer_get_glyph_infos (hb_buffer, NULL);
1691 pos = hb_buffer_get_glyph_positions (hb_buffer, NULL);
1692 int from = -1, to, cluster_offset = 0;
1693 int char_idx, incr = buf_reversed ? -1 : 1;
1694 for (i = 0; i < glyph_len; i++)
1695 {
1696 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
1697 struct font_metrics metrics = {.width = 0};
1698 int xoff, yoff, wadjust;
1699
1700 if (NILP (lglyph))
1701 {
1702 lglyph = LGLYPH_NEW ();
1703 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
1704 }
1705
1706 if (info[i].cluster != from)
1707 {
1708 int j;
1709 /* Found a new cluster. Determine its FROM and TO, and the
1710 offset to the first character of the cluster. */
1711 /* FROM is the index of the first character that contributed
1712 to this cluster. */
1713 from = info[i].cluster;
1714 /* TO is the index of the last character that contributed to
1715 this cluster. */
1716 for (j = i; j < glyph_len && info[j].cluster == from; j++)
1717 ;
1718 to = (j == glyph_len) ? text_len - 1 : info[j].cluster - 1;
1719 cluster_offset = 0;
1720 /* For RTL buffers, HarfBuzz produces glyphs in a cluster in
1721 reverse order, so we need to account for that to record
1722 the correct character in each glyph.
1723
1724 Implementation note: the character codepoint recorded in
1725 each glyph is not really used, except when we display the
1726 glyphs in descr-text.el. So this is just an aeasthetic
1727 issue. */
1728 if (buf_reversed)
1729 cluster_offset = to - from;
1730 }
1731
1732 /* All the glyphs in a cluster have the same values of FROM and TO. */
1733 LGLYPH_SET_FROM (lglyph, from);
1734 LGLYPH_SET_TO (lglyph, to);
1735
1736 /* Not every glyph in a cluster maps directly to a single
1737 character; in general, N characters can yield M glyphs, where
1738 M could be smaller or greater than N. However, in many cases
1739 there is a one-to-one correspondence, and it would be a pity
1740 to lose that information, even if it's sometimes inaccurate. */
1741 char_idx = from + cluster_offset;
1742 cluster_offset += incr;
1743 if (char_idx > to)
1744 char_idx = to;
1745 if (char_idx < from)
1746 char_idx = from;
1747 LGLYPH_SET_CHAR (lglyph, chars[char_idx]);
1748 LGLYPH_SET_CODE (lglyph, info[i].codepoint);
1749
1750 unsigned code = info[i].codepoint;
1751 font->driver->text_extents (font, &code, 1, &metrics);
1752 LGLYPH_SET_WIDTH (lglyph, metrics.width);
1753 LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
1754 LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
1755 LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
1756 LGLYPH_SET_DESCENT (lglyph, metrics.descent);
1757
1758 xoff = lround (pos[i].x_offset * position_unit);
1759 yoff = - lround (pos[i].y_offset * position_unit);
1760 wadjust = lround (pos[i].x_advance * position_unit);
1761 if (xoff || yoff || wadjust != metrics.width)
1762 {
1763 Lisp_Object vec = make_uninit_vector (3);
1764 ASET (vec, 0, make_fixnum (xoff));
1765 ASET (vec, 1, make_fixnum (yoff));
1766 ASET (vec, 2, make_fixnum (wadjust));
1767 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
1768 }
1769 }
1770
1771 return make_fixnum (glyph_len);
1772}
1773
1774static Lisp_Object
1775w32hb_combining_capability (struct font *font)
1776{
1777 return Qt;
1778}
1779#endif /* HAVE_HARFBUZZ */
1780
1151#undef OTF_INT16_VAL 1781#undef OTF_INT16_VAL
1152#undef OTF_TAG_VAL 1782#undef OTF_TAG_VAL
1153#undef OTF_TAG 1783#undef OTF_TAG
@@ -1196,17 +1826,53 @@ syms_of_w32uniscribe (void)
1196 pdumper_do_now_and_after_load (syms_of_w32uniscribe_for_pdumper); 1826 pdumper_do_now_and_after_load (syms_of_w32uniscribe_for_pdumper);
1197} 1827}
1198 1828
1829#ifdef HAVE_HARFBUZZ
1830static bool
1831load_harfbuzz_funcs (HMODULE library)
1832{
1833 LOAD_DLL_FN (library, hb_blob_create);
1834 LOAD_DLL_FN (library, hb_face_create_for_tables);
1835 LOAD_DLL_FN (library, hb_face_get_glyph_count);
1836 LOAD_DLL_FN (library, hb_font_create);
1837 LOAD_DLL_FN (library, hb_font_destroy);
1838 LOAD_DLL_FN (library, hb_face_get_upem);
1839 LOAD_DLL_FN (library, hb_face_destroy);
1840 LOAD_DLL_FN (library, hb_font_get_nominal_glyph);
1841 LOAD_DLL_FN (library, hb_unicode_funcs_create);
1842 LOAD_DLL_FN (library, hb_unicode_funcs_get_default);
1843 LOAD_DLL_FN (library, hb_unicode_funcs_set_combining_class_func);
1844 LOAD_DLL_FN (library, hb_unicode_funcs_set_general_category_func);
1845 LOAD_DLL_FN (library, hb_unicode_funcs_set_mirroring_func);
1846 LOAD_DLL_FN (library, hb_buffer_create);
1847 LOAD_DLL_FN (library, hb_buffer_set_unicode_funcs);
1848 LOAD_DLL_FN (library, hb_buffer_clear_contents);
1849 LOAD_DLL_FN (library, hb_buffer_pre_allocate);
1850 LOAD_DLL_FN (library, hb_buffer_add);
1851 LOAD_DLL_FN (library, hb_buffer_set_content_type);
1852 LOAD_DLL_FN (library, hb_buffer_set_cluster_level);
1853 LOAD_DLL_FN (library, hb_buffer_set_direction);
1854 LOAD_DLL_FN (library, hb_buffer_set_language);
1855 LOAD_DLL_FN (library, hb_language_from_string);
1856 LOAD_DLL_FN (library, hb_buffer_guess_segment_properties);
1857 LOAD_DLL_FN (library, hb_shape_full);
1858 LOAD_DLL_FN (library, hb_buffer_get_length);
1859 LOAD_DLL_FN (library, hb_buffer_get_direction);
1860 LOAD_DLL_FN (library, hb_buffer_reverse_clusters);
1861 LOAD_DLL_FN (library, hb_buffer_get_glyph_infos);
1862 LOAD_DLL_FN (library, hb_buffer_get_glyph_positions);
1863 return true;
1864}
1865#endif /* HAVE_HARFBUZZ */
1866
1199static void 1867static void
1200syms_of_w32uniscribe_for_pdumper (void) 1868syms_of_w32uniscribe_for_pdumper (void)
1201{ 1869{
1202 HMODULE uniscribe; 1870 /* Don't init Uniscribe and HarfBuzz when dumping */
1203
1204 /* Don't init uniscribe when dumping */
1205 if (!initialized) 1871 if (!initialized)
1206 return; 1872 return;
1207 1873
1208 /* Don't register if uniscribe is not available. */ 1874 /* Don't register if Uniscribe is not available. */
1209 uniscribe = GetModuleHandle ("usp10"); 1875 HMODULE uniscribe = GetModuleHandle ("usp10");
1210 if (!uniscribe) 1876 if (!uniscribe)
1211 return; 1877 return;
1212 1878
@@ -1226,4 +1892,30 @@ syms_of_w32uniscribe_for_pdumper (void)
1226 uniscribe_new_apis = true; 1892 uniscribe_new_apis = true;
1227 else 1893 else
1228 uniscribe_new_apis = false; 1894 uniscribe_new_apis = false;
1895
1896#ifdef HAVE_HARFBUZZ
1897 /* Currently, HarfBuzz DLLs are always named libharfbuzz-0.dll, as
1898 the project keeps the ABI backeard-compatible. So we can
1899 hard-code the name of the library here, for now. If they ever
1900 break ABI compatibility, we may need to load the DLL that
1901 corresponds to the HarfBuzz version for which Emacs was built. */
1902 HMODULE harfbuzz = LoadLibrary ("libharfbuzz-0.dll");
1903 /* Don't register if HarfBuzz is not available. */
1904 if (!harfbuzz)
1905 return;
1906
1907 if (!load_harfbuzz_funcs (harfbuzz))
1908 return;
1909
1910 harfbuzz_available = 1;
1911 harfbuzz_font_driver = uniscribe_font_driver;
1912 harfbuzz_font_driver.type = Qharfbuzz;
1913 harfbuzz_font_driver.list = w32hb_list;
1914 harfbuzz_font_driver.match = w32hb_match;
1915 harfbuzz_font_driver.encode_char = w32hb_encode_char;
1916 harfbuzz_font_driver.shape = w32hb_shape;
1917 harfbuzz_font_driver.combining_capability = w32hb_combining_capability;
1918 harfbuzz_font_driver.begin_hb_font = w32hb_begin_font;
1919 register_font_driver (&harfbuzz_font_driver, NULL);
1920#endif /* HAVE_HARFBUZZ */
1229} 1921}