From 6843e3677ca8972d13d29f35fadc26ddc9f3723a Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 23 Jun 2024 16:28:22 +0800 Subject: [PATCH] Restore functionality on Windows 98 * configure.ac (W32_LIBS): Don't link with -lusp10 on non-Cygwin systems. * src/emacs.c (main): Call globals_of_w32 before the startup directory is initialized. * src/w32.c (maybe_load_unicows_dll): Call load_unicows_dll_for_w32fns. * src/w32.h: Update prototypes. * src/w32fns.c (Fx_create_frame, w32_create_tip_frame): Do not register the Uniscribe font driver when unavailable. (pfnSHFileOperationW): New function pointer. (Fsystem_move_file_to_trash): Load UNICOWS.DLL if not yet loaded. Call SHFileOperationW through said function pointer. (pfnShellExecuteExW): New function pointer. (Fw32_shell_execute) [!CYGWIN]: Load UNICOWS.DLL if not yet loaded. Call ShellExecuteExW through said function pointer. (pfnShell_NotifyIconW): New function pointer. (add_tray_notification, delete_tray_notification): Call Shell_NotifyIconW through said function pointer. (Fw32_notification_notify): Load UNICOWS.DLL. (Fw32_notification_close): Return if Shell_NotifyIconW is unavailable, as when UNICOWS.DLL has yet to be loaded. (load_unicows_dll_for_w32fns): New function. * src/w32notify.c (pfnReadDirectoryChangesW): New function pointer. (watch_completion, remove_watch, Fw32notify_add_watch) (Fw32notify_rm_watch, Fw32notify_valid_p): Call ReadDirectoryChangesW through said function pointer, and assert its presence. (globals_of_w32notify): Load ReadDirectoryChangesW from KERNEL32.DLL. * src/w32uniscribe.c (pfnScriptItemize, pfnScriptShape) (pfnScriptPlace, pfnScriptGetGlyphABCWidth, pfnScriptFreeCache) (pfnScriptGetCMap): New function pointers. (uniscribe_close, uniscribe_shape, uniscribe_encode_char) (uniscribe_check_otf_1): Call Uniscribe functions through the same. (syms_of_w32uniscribe_for_pdumper): Load Uniscribe library and required functions from the same, and if unavailable, return while leaving uniscribe_available intact. On Cygwin, simply assign USP10.DLL functions to the said new function pointers. (cherry picked from commit 18e7a9f3d0c27385f8efeb2b1ef80b3446dca288) --- configure.ac | 2 +- src/emacs.c | 8 ++- src/w32.c | 2 + src/w32.h | 1 + src/w32fns.c | 79 +++++++++++++++++++++----- src/w32notify.c | 42 +++++++++----- src/w32uniscribe.c | 134 ++++++++++++++++++++++++++++++++------------- 7 files changed, 199 insertions(+), 69 deletions(-) diff --git a/configure.ac b/configure.ac index 2162cf5f578..1bc67a846b6 100644 --- a/configure.ac +++ b/configure.ac @@ -3133,7 +3133,7 @@ if test "${HAVE_W32}" = "yes"; then NATIVE_IMAGE_API="yes (w32)" W32_OBJ="$W32_OBJ w32image.o" fi - W32_LIBS="$W32_LIBS -lwinmm -lusp10 -lgdi32 -lcomdlg32" + W32_LIBS="$W32_LIBS -lwinmm -lgdi32 -lcomdlg32" W32_LIBS="$W32_LIBS -lmpr -lwinspool -lole32 -lcomctl32" W32_RES_LINK="\$(EMACSRES)" CLIENTRES="emacsclient.res" diff --git a/src/emacs.c b/src/emacs.c index d786bc65141..74a46468933 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1406,6 +1406,10 @@ main (int argc, char **argv) the additional call here is harmless.) */ cache_system_info (); #ifdef WINDOWSNT + /* This must be called to initialize w32_unicode_filenames and + is_windows_9x prior to w32_init_current_directory. */ + globals_of_w32 (); + /* On Windows 9X, we have to load UNICOWS.DLL as early as possible, to have non-stub implementations of APIs we need to convert file names between UTF-8 and the system's ANSI codepage. */ @@ -1517,11 +1521,10 @@ main (int argc, char **argv) } } #endif - emacs_wd = emacs_get_current_dir_name (); #ifdef WINDOWSNT initial_wd = emacs_wd; -#endif +#endif /* WINDOWSNT */ #ifdef HAVE_PDUMPER if (dumped_with_pdumper_p ()) pdumper_record_wd (emacs_wd); @@ -2176,7 +2179,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem init_atimer (); #ifdef WINDOWSNT - globals_of_w32 (); #ifdef HAVE_W32NOTIFY globals_of_w32notify (); #endif diff --git a/src/w32.c b/src/w32.c index 1c6a56bcbd9..4986d4c6676 100644 --- a/src/w32.c +++ b/src/w32.c @@ -10624,6 +10624,7 @@ maybe_load_unicows_dll (void) pWideCharToMultiByte = (WideCharToMultiByte_Proc) get_proc_addr (ret, "WideCharToMultiByte"); multiByteToWideCharFlags = MB_ERR_INVALID_CHARS; + load_unicows_dll_for_w32fns (ret); return ret; } else @@ -10658,6 +10659,7 @@ maybe_load_unicows_dll (void) multiByteToWideCharFlags = 0; else multiByteToWideCharFlags = MB_ERR_INVALID_CHARS; + load_unicows_dll_for_w32fns (NULL); return LoadLibrary ("Gdi32.dll"); } } diff --git a/src/w32.h b/src/w32.h index cf470ae9901..3dc79dabf4b 100644 --- a/src/w32.h +++ b/src/w32.h @@ -170,6 +170,7 @@ extern void release_listen_threads (void); extern void init_ntproc (int); extern void term_ntproc (int); extern HANDLE maybe_load_unicows_dll (void); +extern void load_unicows_dll_for_w32fns (HMODULE); extern void globals_of_w32 (void); extern void term_timers (void); diff --git a/src/w32fns.c b/src/w32fns.c index 4c2f18abd08..6090eb34e82 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -2612,6 +2612,7 @@ my_post_msg (W32Msg * wmsg, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } #ifdef WINDOWSNT + /* The Windows keyboard hook callback. */ static LRESULT CALLBACK funhook (int code, WPARAM w, LPARAM l) @@ -2688,8 +2689,8 @@ funhook (int code, WPARAM w, LPARAM l) can prevent this by setting the w32-pass-[lr]window-to-system variable to NIL. */ - if ((hs->vkCode == VK_LWIN && !NILP (Vw32_pass_lwindow_to_system)) || - (hs->vkCode == VK_RWIN && !NILP (Vw32_pass_rwindow_to_system))) + if ((hs->vkCode == VK_LWIN && !NILP (Vw32_pass_lwindow_to_system)) + || (hs->vkCode == VK_RWIN && !NILP (Vw32_pass_rwindow_to_system))) { /* Not prevented - Simulate the keypress to the system. */ memset (inputs, 0, sizeof (inputs)); @@ -2704,7 +2705,6 @@ funhook (int code, WPARAM w, LPARAM l) inputs[1].ki.dwFlags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP; inputs[1].ki.time = 0; - SendInput (2, inputs, sizeof (INPUT)); } else if (focus != NULL) { @@ -6150,7 +6150,8 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, if (harfbuzz_available) register_font_driver (&harfbuzz_font_driver, f); #endif - register_font_driver (&uniscribe_font_driver, f); + if (uniscribe_available) + register_font_driver (&uniscribe_font_driver, f); register_font_driver (&w32font_driver, f); gui_default_parameter (f, parameters, Qfont_backend, Qnil, @@ -7227,7 +7228,8 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms) if (harfbuzz_available) register_font_driver (&harfbuzz_font_driver, f); #endif - register_font_driver (&uniscribe_font_driver, f); + if (uniscribe_available) + register_font_driver (&uniscribe_font_driver, f); register_font_driver (&w32font_driver, f); gui_default_parameter (f, parms, Qfont_backend, Qnil, @@ -8265,6 +8267,8 @@ DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0, #ifdef WINDOWSNT +static int (WINAPI *pfnSHFileOperationW) (LPSHFILEOPSTRUCTW); + /* Moving files to the system recycle bin. Used by `move-file-to-trash' instead of the default moving to ~/.Trash */ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash, @@ -8276,6 +8280,9 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash, Lisp_Object encoded_file; Lisp_Object operation; + /* Required on Windows 9X. */ + maybe_load_unicows_dll (); + operation = Qdelete_file; if (!NILP (Ffile_directory_p (filename)) && NILP (Ffile_symlink_p (filename))) @@ -8324,7 +8331,10 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash, | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS; file_op_w.fAnyOperationsAborted = FALSE; - result = SHFileOperationW (&file_op_w); + /* This is stated to exist on all versions of Windows NT Emacs + supports. */ + eassert (pfnSHFileOperationW); + result = (*pfnSHFileOperationW) (&file_op_w); } else { @@ -8389,6 +8399,10 @@ If optional parameter FRAME is not specified, use selected frame. */) return Qnil; } +#ifndef CYGWIN +static BOOL (WINAPI *pfnShellExecuteExW) (LPSHELLEXECUTEINFOW); +#endif /* !CYGWIN */ + DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0, doc: /* Get Windows to perform OPERATION on DOCUMENT. This is a wrapper around the ShellExecute system function, which @@ -8539,6 +8553,9 @@ a ShowWindow flag: const int file_url_len = sizeof (file_url_str) - 1; int doclen; + /* Required on Windows 9X. */ + maybe_load_unicows_dll (); + if (strncmp (SSDATA (document), file_url_str, file_url_len) == 0) { /* Passing "file:///" URLs to ShellExecute causes shlwapi.dll to @@ -8598,7 +8615,7 @@ a ShowWindow flag: doc_w = xmalloc (doclen * sizeof (wchar_t)); pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, SSDATA (document), -1, doc_w, doclen); - if (use_unicode) + if (use_unicode && pfnShellExecuteExW) { wchar_t current_dir_w[MAX_PATH]; SHELLEXECUTEINFOW shexinfo_w; @@ -8650,7 +8667,7 @@ a ShowWindow flag: shexinfo_w.lpDirectory = current_dir_w; shexinfo_w.nShow = (FIXNUMP (show_flag) ? XFIXNUM (show_flag) : SW_SHOWDEFAULT); - success = ShellExecuteExW (&shexinfo_w); + success = (*pfnShellExecuteExW) (&shexinfo_w); xfree (doc_w); } else @@ -9121,6 +9138,7 @@ and width values are in pixels. menu_bar.cbSize = sizeof (menu_bar); menu_bar.rcBar.right = menu_bar.rcBar.left = 0; menu_bar.rcBar.top = menu_bar.rcBar.bottom = 0; + GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &menu_bar); single_menu_bar_height = GetSystemMetrics (SM_CYMENU); wrapped_menu_bar_height = GetSystemMetrics (SM_CYMENUSIZE); @@ -10007,6 +10025,8 @@ Internal use only. */) #if defined WINDOWSNT && !defined HAVE_DBUS +static BOOL (WINAPI *pfnShell_NotifyIconW) (DWORD, PNOTIFYICONDATAW); + /*********************************************************************** Tray notifications ***********************************************************************/ @@ -10273,7 +10293,7 @@ add_tray_notification (struct frame *f, const char *icon, const char *tip, } } - if (!Shell_NotifyIconW (NIM_ADD, (PNOTIFYICONDATAW)&nidw)) + if (!(*pfnShell_NotifyIconW) (NIM_ADD, (PNOTIFYICONDATAW)&nidw)) { /* GetLastError returns meaningless results when Shell_NotifyIcon fails. */ @@ -10305,7 +10325,7 @@ delete_tray_notification (struct frame *f, int id) nidw.hWnd = FRAME_W32_WINDOW (f); nidw.uID = id; - if (!Shell_NotifyIconW (NIM_DELETE, (PNOTIFYICONDATAW)&nidw)) + if (!(*pfnShell_NotifyIconW) (NIM_DELETE, (PNOTIFYICONDATAW)&nidw)) { /* GetLastError returns meaningless results when Shell_NotifyIcon fails. */ @@ -10372,8 +10392,8 @@ The following parameters are supported: characters long, and will be truncated if it's longer. Note that versions of Windows before W2K support only `:icon' and `:tip'. -You can pass the other parameters, but they will be ignored on those -old systems. +You can pass the other parameters, but they will be ignored on +those old systems. There can be at most one active notification at any given time. An active notification must be removed by calling `w32-notification-close' @@ -10389,7 +10409,10 @@ usage: (w32-notification-notify &rest PARAMS) */) enum NI_Severity severity; unsigned timeout = 0; - if (nargs == 0) + /* Required on Windows 9X. */ + maybe_load_unicows_dll (); + + if (nargs == 0 || !pfnShell_NotifyIconW) return Qnil; arg_plist = Flist (nargs, args); @@ -10448,7 +10471,7 @@ DEFUN ("w32-notification-close", { struct frame *f = SELECTED_FRAME (); - if (FIXNUMP (id)) + if (FIXNUMP (id) && !pfnShell_NotifyIconW) delete_tray_notification (f, XFIXNUM (id)); return Qnil; @@ -11499,7 +11522,7 @@ globals_of_w32fns (void) get_proc_addr (wtsapi32_lib, "WTSRegisterSessionNotification"); WTSUnRegisterSessionNotification_fn = (WTSUnRegisterSessionNotification_Proc) get_proc_addr (wtsapi32_lib, "WTSUnRegisterSessionNotification"); -#endif +#endif /* WINDOWSNT */ /* Support OS dark mode on Windows 10 version 1809 and higher. See `w32_applytheme' which uses appropriate APIs per version of Windows. @@ -11580,6 +11603,32 @@ Changing the value takes effect only for frames created after the change. */); syms_of_w32uniscribe (); } +#ifdef WINDOWSNT + +/* Initialize pointers to functions whose real implementations exist in + UNICOWS.DLL on Windows 9X. UNICOWS should be a pointer to a loaded + handle referencing UNICOWS.DLL, or NULL on Windows NT systems. */ + +void +load_unicows_dll_for_w32fns (HMODULE unicows) +{ + if (!unicows) + /* The functions following are defined by SHELL32.DLL onw Windows + NT. */ + unicows = GetModuleHandle ("shell32"); + + pfnSHFileOperationW + = (void *) get_proc_addr (unicows, "SHFileOperationW"); + pfnShellExecuteExW + = (void *) get_proc_addr (unicows, "ShellExecuteExW"); +#ifndef HAVE_DBUS + pfnShell_NotifyIconW + = (void *) get_proc_addr (unicows, "Shell_NotifyIconW"); +#endif /* !HAVE_DBUS */ +} + +#endif /* WINDOWSNT */ + #ifdef NTGUI_UNICODE Lisp_Object diff --git a/src/w32notify.c b/src/w32notify.c index c93e8796fe2..1001c85fdbe 100644 --- a/src/w32notify.c +++ b/src/w32notify.c @@ -120,6 +120,10 @@ struct notification { /* Used for communicating notifications to the main thread. */ struct notifications_set *notifications_set_head; +/* Function pointers. */ +static BOOL (WINAPI *pfnReadDirectoryChangesW) (HANDLE, PVOID, DWORD, BOOL, + DWORD, PDWORD, LPOVERLAPPED, + LPOVERLAPPED_COMPLETION_ROUTINE); static Lisp_Object watch_list; /* Signal to the main thread that we have file notifications for it to @@ -252,10 +256,10 @@ watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info) /* Calling ReadDirectoryChangesW quickly to watch again for new notifications. */ - if (!ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf, - DIRWATCH_BUFFER_SIZE, dirwatch->subtree, - dirwatch->filter, &_bytes, dirwatch->io_info, - watch_completion)) + if (!(*pfnReadDirectoryChangesW) (dirwatch->dir, dirwatch->buf, + DIRWATCH_BUFFER_SIZE, dirwatch->subtree, + dirwatch->filter, &_bytes, + dirwatch->io_info, watch_completion)) { DebPrint (("ReadDirectoryChangesW error: %lu\n", GetLastError ())); /* If this call fails, it means that the directory is not @@ -270,7 +274,7 @@ watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info) /* If we were asked to terminate the thread, then fire the event. */ if (terminate) - SetEvent(dirwatch->terminate); + SetEvent (dirwatch->terminate); } /* Worker routine for the watch thread. */ @@ -284,10 +288,10 @@ watch_worker (LPVOID arg) if (dirwatch->dir) { - bErr = ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf, - DIRWATCH_BUFFER_SIZE, dirwatch->subtree, - dirwatch->filter, &_bytes, - dirwatch->io_info, watch_completion); + bErr = (*pfnReadDirectoryChangesW) (dirwatch->dir, dirwatch->buf, + DIRWATCH_BUFFER_SIZE, dirwatch->subtree, + dirwatch->filter, &_bytes, + dirwatch->io_info, watch_completion); if (!bErr) { DebPrint (("ReadDirectoryChangesW: %lu\n", GetLastError ())); @@ -436,7 +440,7 @@ remove_watch (struct notification *dirwatch) DebPrint (("QueueUserAPC failed (%lu)!\n", GetLastError ())); /* We also signal the thread that it can terminate. */ - SetEvent(dirwatch->terminate); + SetEvent (dirwatch->terminate); /* Wait for the thread to exit. FIXME: is there a better method that is not overly complex? */ @@ -466,7 +470,7 @@ remove_watch (struct notification *dirwatch) CloseHandle (dirwatch->thr); dirwatch->thr = NULL; } - CloseHandle(dirwatch->terminate); + CloseHandle (dirwatch->terminate); xfree (dirwatch->buf); xfree (dirwatch->io_info); xfree (dirwatch->watchee); @@ -575,6 +579,8 @@ generate notifications correctly, though. */) report_file_notify_error ("Watching filesystem events is not supported", Qnil); } + else + eassert (pfnReadDirectoryChangesW); /* filenotify.el always passes us a directory, either the parent directory of a file to be watched, or the directory to be @@ -649,7 +655,7 @@ WATCH-DESCRIPTOR should be an object returned by `w32notify-add-watch'. */) if (!NILP (watch_object)) { watch_list = Fdelete (watch_object, watch_list); - dirwatch = (struct notification *)xmint_pointer (watch_descriptor); + dirwatch = (struct notification *) xmint_pointer (watch_descriptor); if (w32_valid_pointer_p (dirwatch, sizeof(struct notification))) status = remove_watch (dirwatch); } @@ -687,7 +693,7 @@ watch by calling `w32notify-rm-watch' also makes it invalid. */) if (!NILP (watch_object)) { struct notification *dirwatch = - (struct notification *)xmint_pointer (watch_descriptor); + (struct notification *) xmint_pointer (watch_descriptor); if (w32_valid_pointer_p (dirwatch, sizeof(struct notification)) && dirwatch->dir != NULL) return Qt; @@ -699,6 +705,16 @@ watch by calling `w32notify-rm-watch' also makes it invalid. */) void globals_of_w32notify (void) { + HANDLE kernel32 = GetModuleHandle ("kernel32"); + + /* Initialize pointers to IO functions that provide file + notifications. In the event that these are absent, no harm will be + done, since their absence indicates that Emacs is running on + Windows 9X, where file notifications are unavailable at the + outset. */ + pfnReadDirectoryChangesW + = (void *) get_proc_addr (kernel32, "ReadDirectoryChangesW"); + watch_list = Qnil; } diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c index dacd6dd766e..e840e14541e 100644 --- a/src/w32uniscribe.c +++ b/src/w32uniscribe.c @@ -108,6 +108,31 @@ memq_no_quit (Lisp_Object elt, Lisp_Object list) return (CONSP (list)); } + +/* Uniscribe function pointers. */ +static HRESULT (WINAPI * pfnScriptItemize) (const WCHAR *, + int, + int, + const SCRIPT_CONTROL *, + const SCRIPT_STATE *, + SCRIPT_ITEM *, int *); +static HRESULT (WINAPI * pfnScriptShape) (HDC, SCRIPT_CACHE *, + const WCHAR *, + int, int, SCRIPT_ANALYSIS *, + WORD *, WORD *, SCRIPT_VISATTR *, + int *); +static HRESULT (WINAPI * pfnScriptPlace) (HDC, SCRIPT_CACHE *, + const WORD *, int, + const SCRIPT_VISATTR *, + SCRIPT_ANALYSIS *, + int *, GOFFSET *, ABC *); +static HRESULT (WINAPI * pfnScriptGetGlyphABCWidth) (HDC, SCRIPT_CACHE *, + WORD, ABC *); +static HRESULT (WINAPI * pfnScriptFreeCache) (SCRIPT_CACHE *); +static HRESULT (WINAPI * pfnScriptGetCMap) (HDC, SCRIPT_CACHE *, + const WCHAR *, + int, DWORD, WORD *); + /* Font backend interface implementation. */ static Lisp_Object @@ -202,7 +227,7 @@ uniscribe_close (struct font *font) else #endif if (uniscribe_font->cache) - ScriptFreeCache ((SCRIPT_CACHE) &(uniscribe_font->cache)); + (*pfnScriptFreeCache) ((SCRIPT_CACHE) &(uniscribe_font->cache)); uniscribe_font->cache = NULL; @@ -320,8 +345,8 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction) max_items = 2; items = xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1); - while ((result = ScriptItemize (chars, nchars, max_items, NULL, NULL, - items, &nitems)) == E_OUTOFMEMORY) + while ((result = (*pfnScriptItemize) (chars, nchars, max_items, NULL, NULL, + items, &nitems)) == E_OUTOFMEMORY) { /* If that wasn't enough, keep trying with one more run. */ max_items++; @@ -344,17 +369,18 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction) { int nglyphs, nchars_in_run; nchars_in_run = items[i+1].iCharPos - items[i].iCharPos; - /* Force ScriptShape to generate glyphs in the same order as + /* Force (*pfnScriptShape) to generate glyphs in the same order as they are in the input LGSTRING, which is in the logical order. */ items[i].a.fLogicalOrder = 1; /* Context may be NULL here, in which case the cache should be used without needing to select the font. */ - result = ScriptShape (context, (SCRIPT_CACHE) &(uniscribe_font->cache), - chars + items[i].iCharPos, nchars_in_run, - max_glyphs - done_glyphs, &(items[i].a), - glyphs, clusters, attributes, &nglyphs); + result + = (*pfnScriptShape) (context, (SCRIPT_CACHE) &(uniscribe_font->cache), + chars + items[i].iCharPos, nchars_in_run, + max_glyphs - done_glyphs, &(items[i].a), + glyphs, clusters, attributes, &nglyphs); if (result == E_PENDING && !context) { @@ -365,10 +391,12 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction) context = get_frame_dc (f); old_font = SelectObject (context, FONT_HANDLE (font)); - result = ScriptShape (context, (SCRIPT_CACHE) &(uniscribe_font->cache), - chars + items[i].iCharPos, nchars_in_run, - max_glyphs - done_glyphs, &(items[i].a), - glyphs, clusters, attributes, &nglyphs); + result + = (*pfnScriptShape) (context, + (SCRIPT_CACHE) &(uniscribe_font->cache), + chars + items[i].iCharPos, nchars_in_run, + max_glyphs - done_glyphs, &(items[i].a), + glyphs, clusters, attributes, &nglyphs); } if (result == E_OUTOFMEMORY) @@ -390,9 +418,11 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction) } else { - result = ScriptPlace (context, (SCRIPT_CACHE) &(uniscribe_font->cache), - glyphs, nglyphs, attributes, &(items[i].a), - advances, offsets, &overall_metrics); + result + = (*pfnScriptPlace) (context, + (SCRIPT_CACHE) &(uniscribe_font->cache), + glyphs, nglyphs, attributes, &(items[i].a), + advances, offsets, &overall_metrics); if (result == E_PENDING && !context) { /* Cache not complete... */ @@ -400,10 +430,11 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction) context = get_frame_dc (f); old_font = SelectObject (context, FONT_HANDLE (font)); - result = ScriptPlace (context, - (SCRIPT_CACHE) &(uniscribe_font->cache), - glyphs, nglyphs, attributes, &(items[i].a), - advances, offsets, &overall_metrics); + result + = (*pfnScriptPlace) (context, + (SCRIPT_CACHE) &(uniscribe_font->cache), + glyphs, nglyphs, attributes, &(items[i].a), + advances, offsets, &overall_metrics); } if (SUCCEEDED (result)) { @@ -469,7 +500,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction) then updated for each successive glyph in the grapheme cluster. */ /* FIXME: Should we use DIRECTION here instead - of what ScriptItemize guessed? */ + of what (*pfnScriptItemize) guessed? */ if (items[i].a.fRTL) { int j1 = j; @@ -496,7 +527,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction) LGLYPH_SET_ASCENT (lglyph, font->ascent); LGLYPH_SET_DESCENT (lglyph, font->descent); - result = ScriptGetGlyphABCWidth + result = (*pfnScriptGetGlyphABCWidth) (context, (SCRIPT_CACHE) &(uniscribe_font->cache), glyphs[j], &char_metric); if (result == E_PENDING && !context) @@ -505,7 +536,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction) f = XFRAME (selected_frame); context = get_frame_dc (f); old_font = SelectObject (context, FONT_HANDLE (font)); - result = ScriptGetGlyphABCWidth + result = (*pfnScriptGetGlyphABCWidth) (context, (SCRIPT_CACHE) &(uniscribe_font->cache), glyphs[j], &char_metric); } @@ -624,7 +655,8 @@ uniscribe_encode_char (struct font *font, int c) convert surrogate pairs to glyph indexes correctly. */ { items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1); - if (SUCCEEDED (ScriptItemize (ch, len, 2, NULL, NULL, items, &nitems))) + if (SUCCEEDED ((*pfnScriptItemize) (ch, len, 2, NULL, NULL, items, + &nitems))) { HRESULT result; /* Surrogates seem to need 2 here, even though only one glyph is @@ -635,14 +667,14 @@ uniscribe_encode_char (struct font *font, int c) SCRIPT_VISATTR attrs[2]; int nglyphs; - /* Force ScriptShape to generate glyphs in the logical + /* Force (*pfnScriptShape) to generate glyphs in the logical order. */ items[0].a.fLogicalOrder = 1; - result = ScriptShape (context, - (SCRIPT_CACHE) &(uniscribe_font->cache), - ch, len, 2, &(items[0].a), - glyphs, clusters, attrs, &nglyphs); + result = (*pfnScriptShape) (context, + (SCRIPT_CACHE) &(uniscribe_font->cache), + ch, len, 2, &(items[0].a), + glyphs, clusters, attrs, &nglyphs); if (result == E_PENDING) { @@ -651,10 +683,11 @@ uniscribe_encode_char (struct font *font, int c) f = XFRAME (selected_frame); context = get_frame_dc (f); old_font = SelectObject (context, FONT_HANDLE (font)); - result = ScriptShape (context, - (SCRIPT_CACHE) &(uniscribe_font->cache), - ch, len, 2, &(items[0].a), - glyphs, clusters, attrs, &nglyphs); + result + = (*pfnScriptShape) (context, + (SCRIPT_CACHE) &(uniscribe_font->cache), + ch, len, 2, &(items[0].a), + glyphs, clusters, attrs, &nglyphs); } if (SUCCEEDED (result) && nglyphs == 1) @@ -670,9 +703,10 @@ uniscribe_encode_char (struct font *font, int c) when shaped. But we still need the return from here to be valid for the shaping engine to be invoked later. */ - result = ScriptGetCMap (context, - (SCRIPT_CACHE) &(uniscribe_font->cache), - ch, len, 0, glyphs); + result + = (*pfnScriptGetCMap) (context, + (SCRIPT_CACHE) &(uniscribe_font->cache), + ch, len, 0, glyphs); if (SUCCEEDED (result) && glyphs[0]) code = glyphs[0]; } @@ -942,7 +976,7 @@ uniscribe_check_otf_1 (HDC context, Lisp_Object script, Lisp_Object lang, no_support: if (cache) - ScriptFreeCache (&cache); + (*pfnScriptFreeCache) (&cache); return ret; } @@ -1504,11 +1538,37 @@ syms_of_w32uniscribe_for_pdumper (void) if (!initialized) return; +#ifdef WINDOWSNT /* Don't register if Uniscribe is not available. */ - HMODULE uniscribe = GetModuleHandle ("usp10"); + HMODULE uniscribe = LoadLibrary ("usp10.dll"); if (!uniscribe) return; + pfnScriptItemize = (void *) get_proc_addr (uniscribe, "ScriptItemize"); + pfnScriptShape = (void *) get_proc_addr (uniscribe, "ScriptShape"); + pfnScriptPlace = (void *) get_proc_addr (uniscribe, "ScriptPlace"); + pfnScriptGetGlyphABCWidth + = (void *) get_proc_addr (uniscribe, "ScriptGetGlyphABCWidth"); + pfnScriptFreeCache + = (void *) get_proc_addr (uniscribe, "ScriptFreeCache"); + pfnScriptGetCMap + = (void *) get_proc_addr (uniscribe, "ScriptGetCMap"); + if (!pfnScriptItemize || !pfnScriptShape || !pfnScriptPlace + || !pfnScriptGetGlyphABCWidth || !pfnScriptFreeCache + || !pfnScriptGetCMap) + { + FreeLibrary (uniscribe); + return; + } +#else /* Cygwin */ + pfnScriptItemize = &ScriptItemize; + pfnScriptShape = &ScriptShape; + pfnScriptPlace = &ScriptPlace; + pfnScriptGetGlyphABCWidth = &ScriptGetGlyphABCWidth; + pfnScriptFreeCache = &ScriptFreeCache; + pfnScriptGetCMap = &ScriptGetCMap; +#endif /* Cygwin */ + uniscribe_available = 1; register_font_driver (&uniscribe_font_driver, NULL); -- 2.39.2