diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/chartab.c | 15 | ||||
| -rw-r--r-- | src/font.h | 3 | ||||
| -rw-r--r-- | src/lisp.h | 1 | ||||
| -rw-r--r-- | src/w32fns.c | 9 | ||||
| -rw-r--r-- | src/w32font.c | 1 | ||||
| -rw-r--r-- | src/w32uniscribe.c | 742 |
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 | ||
| 1324 | Lisp_Object | ||
| 1325 | get_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 | |||
| 1324 | DEFUN ("get-unicode-property-internal", Fget_unicode_property_internal, | 1332 | DEFUN ("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. |
| 1327 | CHAR-TABLE must be what returned by `unicode-property-table-internal'. */) | 1335 | CHAR-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 | ||
| 1342 | DEFUN ("put-unicode-property-internal", Fput_unicode_property_internal, | 1345 | DEFUN ("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 |
| 952 | extern struct font_driver w32font_driver; | 952 | extern struct font_driver w32font_driver; |
| 953 | extern struct font_driver uniscribe_font_driver; | 953 | extern struct font_driver uniscribe_font_driver; |
| 954 | #ifdef HAVE_HARFBUZZ | ||
| 955 | extern struct font_driver harfbuzz_font_driver; | ||
| 956 | #endif | ||
| 954 | extern void syms_of_w32font (void); | 957 | extern 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); |
| 3996 | extern Lisp_Object uniprop_table (Lisp_Object); | 3996 | extern Lisp_Object uniprop_table (Lisp_Object); |
| 3997 | extern Lisp_Object get_unicode_property (Lisp_Object, int); | ||
| 3997 | extern void syms_of_chartab (void); | 3998 | extern 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 */ |
| 222 | extern void syms_of_w32uniscribe (void); | 222 | extern void syms_of_w32uniscribe (void); |
| 223 | extern int uniscribe_available; | 223 | extern int uniscribe_available; |
| 224 | extern 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. */ | ||
| 42 | struct uniscribe_font_info | 52 | struct 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 | ||
| 48 | int uniscribe_available = 0; | 63 | int uniscribe_available = 0; |
| @@ -51,6 +66,94 @@ int uniscribe_available = 0; | |||
| 51 | static int CALLBACK ALIGN_STACK add_opentype_font_name_to_list (ENUMLOGFONTEX *, | 66 | static 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 | |||
| 71 | struct font_driver harfbuzz_font_driver; | ||
| 72 | int harfbuzz_available = 0; | ||
| 73 | |||
| 74 | /* Typedefs for HarfBuzz functions which we call through function | ||
| 75 | pointers initialized after we load the HarfBuzz DLL. */ | ||
| 76 | DEF_DLL_FN (hb_blob_t *, hb_blob_create, | ||
| 77 | (const char *, unsigned int, hb_memory_mode_t, void *, | ||
| 78 | hb_destroy_func_t)); | ||
| 79 | DEF_DLL_FN (hb_face_t *, hb_face_create_for_tables, | ||
| 80 | (hb_reference_table_func_t, void *, hb_destroy_func_t)); | ||
| 81 | DEF_DLL_FN (unsigned, hb_face_get_glyph_count, (const hb_face_t *)); | ||
| 82 | DEF_DLL_FN (hb_font_t *, hb_font_create, (hb_face_t *)); | ||
| 83 | DEF_DLL_FN (void, hb_font_destroy, (hb_font_t *)); | ||
| 84 | DEF_DLL_FN (void, hb_face_destroy, (hb_face_t *)); | ||
| 85 | DEF_DLL_FN (unsigned int, hb_face_get_upem, (hb_face_t *)); | ||
| 86 | DEF_DLL_FN (hb_bool_t, hb_font_get_nominal_glyph, | ||
| 87 | (hb_font_t *, hb_codepoint_t, hb_codepoint_t *)); | ||
| 88 | DEF_DLL_FN (hb_unicode_funcs_t *, hb_unicode_funcs_create, | ||
| 89 | (hb_unicode_funcs_t *)); | ||
| 90 | DEF_DLL_FN (hb_unicode_funcs_t *, hb_unicode_funcs_get_default, (void)); | ||
| 91 | DEF_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)); | ||
| 94 | DEF_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)); | ||
| 97 | DEF_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)); | ||
| 100 | DEF_DLL_FN (hb_buffer_t *, hb_buffer_create, (void)); | ||
| 101 | DEF_DLL_FN (void, hb_buffer_set_unicode_funcs, | ||
| 102 | (hb_buffer_t *, hb_unicode_funcs_t *)); | ||
| 103 | DEF_DLL_FN (void, hb_buffer_clear_contents, (hb_buffer_t *)); | ||
| 104 | DEF_DLL_FN (hb_bool_t, hb_buffer_pre_allocate, (hb_buffer_t *, unsigned int)); | ||
| 105 | DEF_DLL_FN (void, hb_buffer_add, (hb_buffer_t *, hb_codepoint_t, unsigned int)); | ||
| 106 | DEF_DLL_FN (void, hb_buffer_set_content_type, | ||
| 107 | (hb_buffer_t *, hb_buffer_content_type_t)); | ||
| 108 | DEF_DLL_FN (void, hb_buffer_set_cluster_level, | ||
| 109 | (hb_buffer_t *, hb_buffer_cluster_level_t)); | ||
| 110 | DEF_DLL_FN (void, hb_buffer_set_direction, (hb_buffer_t *, hb_direction_t)); | ||
| 111 | DEF_DLL_FN (void, hb_buffer_set_language, (hb_buffer_t *, hb_language_t)); | ||
| 112 | DEF_DLL_FN (hb_language_t, hb_language_from_string, (const char *, int)); | ||
| 113 | DEF_DLL_FN (void, hb_buffer_guess_segment_properties, (hb_buffer_t *)); | ||
| 114 | DEF_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 *)); | ||
| 117 | DEF_DLL_FN (unsigned int, hb_buffer_get_length, (hb_buffer_t *)); | ||
| 118 | DEF_DLL_FN (hb_direction_t, hb_buffer_get_direction, (hb_buffer_t *)); | ||
| 119 | DEF_DLL_FN (void, hb_buffer_reverse_clusters, (hb_buffer_t *)); | ||
| 120 | DEF_DLL_FN (hb_glyph_info_t *, hb_buffer_get_glyph_infos, | ||
| 121 | (hb_buffer_t *, unsigned int *)); | ||
| 122 | DEF_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. */ |
| 55 | static Lisp_Object otf_features (HDC context, const char *table); | 158 | static 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. */ | ||
| 1282 | static Lisp_Object | ||
| 1283 | w32hb_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. */ | ||
| 1295 | static Lisp_Object | ||
| 1296 | w32hb_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). */ | ||
| 1310 | static void | ||
| 1311 | free_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. */ | ||
| 1318 | static hb_blob_t * | ||
| 1319 | w32hb_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. */ | ||
| 1355 | static hb_font_t * | ||
| 1356 | w32hb_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. */ | ||
| 1384 | static unsigned | ||
| 1385 | w32hb_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. */ | ||
| 1418 | static hb_font_t * | ||
| 1419 | w32hb_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 | |||
| 1438 | static bool combining_class_loaded = false; | ||
| 1439 | static Lisp_Object canonical_combining_class_table; | ||
| 1440 | |||
| 1441 | static hb_unicode_combining_class_t | ||
| 1442 | w32uni_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 | |||
| 1463 | static hb_unicode_general_category_t | ||
| 1464 | w32uni_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 | |||
| 1540 | static hb_codepoint_t | ||
| 1541 | w32uni_mirroring (hb_unicode_funcs_t *funcs, hb_codepoint_t ch, void *user_data) | ||
| 1542 | { | ||
| 1543 | return bidi_mirror_char (ch); | ||
| 1544 | } | ||
| 1545 | |||
| 1546 | static hb_unicode_funcs_t * | ||
| 1547 | get_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. */ | ||
| 1575 | static Lisp_Object | ||
| 1576 | w32hb_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 | |||
| 1774 | static Lisp_Object | ||
| 1775 | w32hb_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 | ||
| 1830 | static bool | ||
| 1831 | load_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 | |||
| 1199 | static void | 1867 | static void |
| 1200 | syms_of_w32uniscribe_for_pdumper (void) | 1868 | syms_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 | } |