Merge remote-tracking branch 'savannah/scratch/windows-98' into emacs-30

* 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.
This commit is contained in:
Po Lu 2024-06-30 10:08:22 +08:00
commit 38179f85f8
7 changed files with 205 additions and 69 deletions

View file

@ -3133,7 +3133,7 @@ if test "${HAVE_W32}" = "yes"; then
NATIVE_IMAGE_API="yes (w32)" NATIVE_IMAGE_API="yes (w32)"
W32_OBJ="$W32_OBJ w32image.o" W32_OBJ="$W32_OBJ w32image.o"
fi 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_LIBS="$W32_LIBS -lmpr -lwinspool -lole32 -lcomctl32"
W32_RES_LINK="\$(EMACSRES)" W32_RES_LINK="\$(EMACSRES)"
CLIENTRES="emacsclient.res" CLIENTRES="emacsclient.res"

View file

@ -1406,6 +1406,10 @@ main (int argc, char **argv)
the additional call here is harmless.) */ the additional call here is harmless.) */
cache_system_info (); cache_system_info ();
#ifdef WINDOWSNT #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, /* 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 to have non-stub implementations of APIs we need to convert file
names between UTF-8 and the system's ANSI codepage. */ names between UTF-8 and the system's ANSI codepage. */
@ -1517,11 +1521,10 @@ main (int argc, char **argv)
} }
} }
#endif #endif
emacs_wd = emacs_get_current_dir_name (); emacs_wd = emacs_get_current_dir_name ();
#ifdef WINDOWSNT #ifdef WINDOWSNT
initial_wd = emacs_wd; initial_wd = emacs_wd;
#endif #endif /* WINDOWSNT */
#ifdef HAVE_PDUMPER #ifdef HAVE_PDUMPER
if (dumped_with_pdumper_p ()) if (dumped_with_pdumper_p ())
pdumper_record_wd (emacs_wd); 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 (); init_atimer ();
#ifdef WINDOWSNT #ifdef WINDOWSNT
globals_of_w32 ();
#ifdef HAVE_W32NOTIFY #ifdef HAVE_W32NOTIFY
globals_of_w32notify (); globals_of_w32notify ();
#endif #endif

View file

@ -10624,6 +10624,7 @@ maybe_load_unicows_dll (void)
pWideCharToMultiByte = (WideCharToMultiByte_Proc) pWideCharToMultiByte = (WideCharToMultiByte_Proc)
get_proc_addr (ret, "WideCharToMultiByte"); get_proc_addr (ret, "WideCharToMultiByte");
multiByteToWideCharFlags = MB_ERR_INVALID_CHARS; multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
load_unicows_dll_for_w32fns (ret);
return ret; return ret;
} }
else else
@ -10658,6 +10659,7 @@ maybe_load_unicows_dll (void)
multiByteToWideCharFlags = 0; multiByteToWideCharFlags = 0;
else else
multiByteToWideCharFlags = MB_ERR_INVALID_CHARS; multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
load_unicows_dll_for_w32fns (NULL);
return LoadLibrary ("Gdi32.dll"); return LoadLibrary ("Gdi32.dll");
} }
} }

View file

@ -170,6 +170,7 @@ extern void release_listen_threads (void);
extern void init_ntproc (int); extern void init_ntproc (int);
extern void term_ntproc (int); extern void term_ntproc (int);
extern HANDLE maybe_load_unicows_dll (void); extern HANDLE maybe_load_unicows_dll (void);
extern void load_unicows_dll_for_w32fns (HMODULE);
extern void globals_of_w32 (void); extern void globals_of_w32 (void);
extern void term_timers (void); extern void term_timers (void);

View file

@ -2612,6 +2612,7 @@ my_post_msg (W32Msg * wmsg, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
} }
#ifdef WINDOWSNT #ifdef WINDOWSNT
/* The Windows keyboard hook callback. */ /* The Windows keyboard hook callback. */
static LRESULT CALLBACK static LRESULT CALLBACK
funhook (int code, WPARAM w, LPARAM l) funhook (int code, WPARAM w, LPARAM l)
@ -2688,8 +2689,8 @@ funhook (int code, WPARAM w, LPARAM l)
can prevent this by setting the can prevent this by setting the
w32-pass-[lr]window-to-system variable to w32-pass-[lr]window-to-system variable to
NIL. */ NIL. */
if ((hs->vkCode == VK_LWIN && !NILP (Vw32_pass_lwindow_to_system)) || if ((hs->vkCode == VK_LWIN && !NILP (Vw32_pass_lwindow_to_system))
(hs->vkCode == VK_RWIN && !NILP (Vw32_pass_rwindow_to_system))) || (hs->vkCode == VK_RWIN && !NILP (Vw32_pass_rwindow_to_system)))
{ {
/* Not prevented - Simulate the keypress to the system. */ /* Not prevented - Simulate the keypress to the system. */
memset (inputs, 0, sizeof (inputs)); memset (inputs, 0, sizeof (inputs));
@ -2704,7 +2705,6 @@ funhook (int code, WPARAM w, LPARAM l)
inputs[1].ki.dwFlags inputs[1].ki.dwFlags
= KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP; = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP;
inputs[1].ki.time = 0; inputs[1].ki.time = 0;
SendInput (2, inputs, sizeof (INPUT));
} }
else if (focus != NULL) else if (focus != NULL)
{ {
@ -6150,6 +6150,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
if (harfbuzz_available) if (harfbuzz_available)
register_font_driver (&harfbuzz_font_driver, f); register_font_driver (&harfbuzz_font_driver, f);
#endif #endif
if (uniscribe_available)
register_font_driver (&uniscribe_font_driver, f); register_font_driver (&uniscribe_font_driver, f);
register_font_driver (&w32font_driver, f); register_font_driver (&w32font_driver, f);
@ -7227,6 +7228,7 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
if (harfbuzz_available) if (harfbuzz_available)
register_font_driver (&harfbuzz_font_driver, f); register_font_driver (&harfbuzz_font_driver, f);
#endif #endif
if (uniscribe_available)
register_font_driver (&uniscribe_font_driver, f); register_font_driver (&uniscribe_font_driver, f);
register_font_driver (&w32font_driver, f); register_font_driver (&w32font_driver, f);
@ -8265,6 +8267,8 @@ DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0,
#ifdef WINDOWSNT #ifdef WINDOWSNT
static int (WINAPI *pfnSHFileOperationW) (LPSHFILEOPSTRUCTW);
/* Moving files to the system recycle bin. /* Moving files to the system recycle bin.
Used by `move-file-to-trash' instead of the default moving to ~/.Trash */ Used by `move-file-to-trash' instead of the default moving to ~/.Trash */
DEFUN ("system-move-file-to-trash", Fsystem_move_file_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 encoded_file;
Lisp_Object operation; Lisp_Object operation;
/* Required on Windows 9X. */
maybe_load_unicows_dll ();
operation = Qdelete_file; operation = Qdelete_file;
if (!NILP (Ffile_directory_p (filename)) if (!NILP (Ffile_directory_p (filename))
&& NILP (Ffile_symlink_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; | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
file_op_w.fAnyOperationsAborted = FALSE; 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 else
{ {
@ -8389,6 +8399,10 @@ If optional parameter FRAME is not specified, use selected frame. */)
return Qnil; return Qnil;
} }
#ifndef CYGWIN
static BOOL (WINAPI *pfnShellExecuteExW) (LPSHELLEXECUTEINFOW);
#endif /* !CYGWIN */
DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0, DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
doc: /* Get Windows to perform OPERATION on DOCUMENT. doc: /* Get Windows to perform OPERATION on DOCUMENT.
This is a wrapper around the ShellExecute system function, which 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; const int file_url_len = sizeof (file_url_str) - 1;
int doclen; int doclen;
/* Required on Windows 9X. */
maybe_load_unicows_dll ();
if (strncmp (SSDATA (document), file_url_str, file_url_len) == 0) if (strncmp (SSDATA (document), file_url_str, file_url_len) == 0)
{ {
/* Passing "file:///" URLs to ShellExecute causes shlwapi.dll to /* Passing "file:///" URLs to ShellExecute causes shlwapi.dll to
@ -8598,7 +8615,7 @@ a ShowWindow flag:
doc_w = xmalloc (doclen * sizeof (wchar_t)); doc_w = xmalloc (doclen * sizeof (wchar_t));
pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
SSDATA (document), -1, doc_w, doclen); SSDATA (document), -1, doc_w, doclen);
if (use_unicode) if (use_unicode && pfnShellExecuteExW)
{ {
wchar_t current_dir_w[MAX_PATH]; wchar_t current_dir_w[MAX_PATH];
SHELLEXECUTEINFOW shexinfo_w; SHELLEXECUTEINFOW shexinfo_w;
@ -8650,7 +8667,7 @@ a ShowWindow flag:
shexinfo_w.lpDirectory = current_dir_w; shexinfo_w.lpDirectory = current_dir_w;
shexinfo_w.nShow = shexinfo_w.nShow =
(FIXNUMP (show_flag) ? XFIXNUM (show_flag) : SW_SHOWDEFAULT); (FIXNUMP (show_flag) ? XFIXNUM (show_flag) : SW_SHOWDEFAULT);
success = ShellExecuteExW (&shexinfo_w); success = (*pfnShellExecuteExW) (&shexinfo_w);
xfree (doc_w); xfree (doc_w);
} }
else else
@ -9121,6 +9138,7 @@ and width values are in pixels.
menu_bar.cbSize = sizeof (menu_bar); menu_bar.cbSize = sizeof (menu_bar);
menu_bar.rcBar.right = menu_bar.rcBar.left = 0; menu_bar.rcBar.right = menu_bar.rcBar.left = 0;
menu_bar.rcBar.top = menu_bar.rcBar.bottom = 0; menu_bar.rcBar.top = menu_bar.rcBar.bottom = 0;
GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &menu_bar); GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &menu_bar);
single_menu_bar_height = GetSystemMetrics (SM_CYMENU); single_menu_bar_height = GetSystemMetrics (SM_CYMENU);
wrapped_menu_bar_height = GetSystemMetrics (SM_CYMENUSIZE); wrapped_menu_bar_height = GetSystemMetrics (SM_CYMENUSIZE);
@ -10007,6 +10025,8 @@ Internal use only. */)
#if defined WINDOWSNT && !defined HAVE_DBUS #if defined WINDOWSNT && !defined HAVE_DBUS
static BOOL (WINAPI *pfnShell_NotifyIconW) (DWORD, PNOTIFYICONDATAW);
/*********************************************************************** /***********************************************************************
Tray notifications 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 /* GetLastError returns meaningless results when
Shell_NotifyIcon fails. */ Shell_NotifyIcon fails. */
@ -10305,7 +10325,7 @@ delete_tray_notification (struct frame *f, int id)
nidw.hWnd = FRAME_W32_WINDOW (f); nidw.hWnd = FRAME_W32_WINDOW (f);
nidw.uID = id; nidw.uID = id;
if (!Shell_NotifyIconW (NIM_DELETE, (PNOTIFYICONDATAW)&nidw)) if (!(*pfnShell_NotifyIconW) (NIM_DELETE, (PNOTIFYICONDATAW)&nidw))
{ {
/* GetLastError returns meaningless results when /* GetLastError returns meaningless results when
Shell_NotifyIcon fails. */ Shell_NotifyIcon fails. */
@ -10372,8 +10392,8 @@ The following parameters are supported:
characters long, and will be truncated if it's longer. characters long, and will be truncated if it's longer.
Note that versions of Windows before W2K support only `:icon' and `:tip'. 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 You can pass the other parameters, but they will be ignored on
old systems. those old systems.
There can be at most one active notification at any given time. An There can be at most one active notification at any given time. An
active notification must be removed by calling `w32-notification-close' active notification must be removed by calling `w32-notification-close'
@ -10389,7 +10409,10 @@ usage: (w32-notification-notify &rest PARAMS) */)
enum NI_Severity severity; enum NI_Severity severity;
unsigned timeout = 0; unsigned timeout = 0;
if (nargs == 0) /* Required on Windows 9X. */
maybe_load_unicows_dll ();
if (nargs == 0 || !pfnShell_NotifyIconW)
return Qnil; return Qnil;
arg_plist = Flist (nargs, args); arg_plist = Flist (nargs, args);
@ -10448,7 +10471,7 @@ DEFUN ("w32-notification-close",
{ {
struct frame *f = SELECTED_FRAME (); struct frame *f = SELECTED_FRAME ();
if (FIXNUMP (id)) if (FIXNUMP (id) && !pfnShell_NotifyIconW)
delete_tray_notification (f, XFIXNUM (id)); delete_tray_notification (f, XFIXNUM (id));
return Qnil; return Qnil;
@ -11499,7 +11522,7 @@ globals_of_w32fns (void)
get_proc_addr (wtsapi32_lib, "WTSRegisterSessionNotification"); get_proc_addr (wtsapi32_lib, "WTSRegisterSessionNotification");
WTSUnRegisterSessionNotification_fn = (WTSUnRegisterSessionNotification_Proc) WTSUnRegisterSessionNotification_fn = (WTSUnRegisterSessionNotification_Proc)
get_proc_addr (wtsapi32_lib, "WTSUnRegisterSessionNotification"); get_proc_addr (wtsapi32_lib, "WTSUnRegisterSessionNotification");
#endif #endif /* WINDOWSNT */
/* Support OS dark mode on Windows 10 version 1809 and higher. /* Support OS dark mode on Windows 10 version 1809 and higher.
See `w32_applytheme' which uses appropriate APIs per version of Windows. 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 (); 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 #ifdef NTGUI_UNICODE
Lisp_Object Lisp_Object

View file

@ -120,6 +120,10 @@ struct notification {
/* Used for communicating notifications to the main thread. */ /* Used for communicating notifications to the main thread. */
struct notifications_set *notifications_set_head; 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; static Lisp_Object watch_list;
/* Signal to the main thread that we have file notifications for it to /* 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 /* Calling ReadDirectoryChangesW quickly to watch again for new
notifications. */ notifications. */
if (!ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf, if (!(*pfnReadDirectoryChangesW) (dirwatch->dir, dirwatch->buf,
DIRWATCH_BUFFER_SIZE, dirwatch->subtree, DIRWATCH_BUFFER_SIZE, dirwatch->subtree,
dirwatch->filter, &_bytes, dirwatch->io_info, dirwatch->filter, &_bytes,
watch_completion)) dirwatch->io_info, watch_completion))
{ {
DebPrint (("ReadDirectoryChangesW error: %lu\n", GetLastError ())); DebPrint (("ReadDirectoryChangesW error: %lu\n", GetLastError ()));
/* If this call fails, it means that the directory is not /* If this call fails, it means that the directory is not
@ -284,7 +288,7 @@ watch_worker (LPVOID arg)
if (dirwatch->dir) if (dirwatch->dir)
{ {
bErr = ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf, bErr = (*pfnReadDirectoryChangesW) (dirwatch->dir, dirwatch->buf,
DIRWATCH_BUFFER_SIZE, dirwatch->subtree, DIRWATCH_BUFFER_SIZE, dirwatch->subtree,
dirwatch->filter, &_bytes, dirwatch->filter, &_bytes,
dirwatch->io_info, watch_completion); dirwatch->io_info, watch_completion);
@ -575,6 +579,8 @@ generate notifications correctly, though. */)
report_file_notify_error ("Watching filesystem events is not supported", report_file_notify_error ("Watching filesystem events is not supported",
Qnil); Qnil);
} }
else
eassert (pfnReadDirectoryChangesW);
/* filenotify.el always passes us a directory, either the parent /* filenotify.el always passes us a directory, either the parent
directory of a file to be watched, or the directory to be directory of a file to be watched, or the directory to be
@ -699,6 +705,16 @@ watch by calling `w32notify-rm-watch' also makes it invalid. */)
void void
globals_of_w32notify (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; watch_list = Qnil;
} }

View file

@ -108,6 +108,31 @@ memq_no_quit (Lisp_Object elt, Lisp_Object list)
return (CONSP (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. */ /* Font backend interface implementation. */
static Lisp_Object static Lisp_Object
@ -202,7 +227,7 @@ uniscribe_close (struct font *font)
else else
#endif #endif
if (uniscribe_font->cache) if (uniscribe_font->cache)
ScriptFreeCache ((SCRIPT_CACHE) &(uniscribe_font->cache)); (*pfnScriptFreeCache) ((SCRIPT_CACHE) &(uniscribe_font->cache));
uniscribe_font->cache = NULL; uniscribe_font->cache = NULL;
@ -320,7 +345,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
max_items = 2; max_items = 2;
items = xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1); items = xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1);
while ((result = ScriptItemize (chars, nchars, max_items, NULL, NULL, while ((result = (*pfnScriptItemize) (chars, nchars, max_items, NULL, NULL,
items, &nitems)) == E_OUTOFMEMORY) items, &nitems)) == E_OUTOFMEMORY)
{ {
/* If that wasn't enough, keep trying with one more run. */ /* If that wasn't enough, keep trying with one more run. */
@ -344,14 +369,15 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
{ {
int nglyphs, nchars_in_run; int nglyphs, nchars_in_run;
nchars_in_run = items[i+1].iCharPos - items[i].iCharPos; 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 they are in the input LGSTRING, which is in the logical
order. */ order. */
items[i].a.fLogicalOrder = 1; items[i].a.fLogicalOrder = 1;
/* Context may be NULL here, in which case the cache should be /* Context may be NULL here, in which case the cache should be
used without needing to select the font. */ used without needing to select the font. */
result = ScriptShape (context, (SCRIPT_CACHE) &(uniscribe_font->cache), result
= (*pfnScriptShape) (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
chars + items[i].iCharPos, nchars_in_run, chars + items[i].iCharPos, nchars_in_run,
max_glyphs - done_glyphs, &(items[i].a), max_glyphs - done_glyphs, &(items[i].a),
glyphs, clusters, attributes, &nglyphs); glyphs, clusters, attributes, &nglyphs);
@ -365,7 +391,9 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
context = get_frame_dc (f); context = get_frame_dc (f);
old_font = SelectObject (context, FONT_HANDLE (font)); old_font = SelectObject (context, FONT_HANDLE (font));
result = ScriptShape (context, (SCRIPT_CACHE) &(uniscribe_font->cache), result
= (*pfnScriptShape) (context,
(SCRIPT_CACHE) &(uniscribe_font->cache),
chars + items[i].iCharPos, nchars_in_run, chars + items[i].iCharPos, nchars_in_run,
max_glyphs - done_glyphs, &(items[i].a), max_glyphs - done_glyphs, &(items[i].a),
glyphs, clusters, attributes, &nglyphs); glyphs, clusters, attributes, &nglyphs);
@ -390,7 +418,9 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
} }
else else
{ {
result = ScriptPlace (context, (SCRIPT_CACHE) &(uniscribe_font->cache), result
= (*pfnScriptPlace) (context,
(SCRIPT_CACHE) &(uniscribe_font->cache),
glyphs, nglyphs, attributes, &(items[i].a), glyphs, nglyphs, attributes, &(items[i].a),
advances, offsets, &overall_metrics); advances, offsets, &overall_metrics);
if (result == E_PENDING && !context) if (result == E_PENDING && !context)
@ -400,7 +430,8 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
context = get_frame_dc (f); context = get_frame_dc (f);
old_font = SelectObject (context, FONT_HANDLE (font)); old_font = SelectObject (context, FONT_HANDLE (font));
result = ScriptPlace (context, result
= (*pfnScriptPlace) (context,
(SCRIPT_CACHE) &(uniscribe_font->cache), (SCRIPT_CACHE) &(uniscribe_font->cache),
glyphs, nglyphs, attributes, &(items[i].a), glyphs, nglyphs, attributes, &(items[i].a),
advances, offsets, &overall_metrics); advances, offsets, &overall_metrics);
@ -469,7 +500,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
then updated for each successive glyph in the then updated for each successive glyph in the
grapheme cluster. */ grapheme cluster. */
/* FIXME: Should we use DIRECTION here instead /* FIXME: Should we use DIRECTION here instead
of what ScriptItemize guessed? */ of what (*pfnScriptItemize) guessed? */
if (items[i].a.fRTL) if (items[i].a.fRTL)
{ {
int j1 = j; int j1 = j;
@ -496,7 +527,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
LGLYPH_SET_ASCENT (lglyph, font->ascent); LGLYPH_SET_ASCENT (lglyph, font->ascent);
LGLYPH_SET_DESCENT (lglyph, font->descent); LGLYPH_SET_DESCENT (lglyph, font->descent);
result = ScriptGetGlyphABCWidth result = (*pfnScriptGetGlyphABCWidth)
(context, (SCRIPT_CACHE) &(uniscribe_font->cache), (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
glyphs[j], &char_metric); glyphs[j], &char_metric);
if (result == E_PENDING && !context) if (result == E_PENDING && !context)
@ -505,7 +536,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
f = XFRAME (selected_frame); f = XFRAME (selected_frame);
context = get_frame_dc (f); context = get_frame_dc (f);
old_font = SelectObject (context, FONT_HANDLE (font)); old_font = SelectObject (context, FONT_HANDLE (font));
result = ScriptGetGlyphABCWidth result = (*pfnScriptGetGlyphABCWidth)
(context, (SCRIPT_CACHE) &(uniscribe_font->cache), (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
glyphs[j], &char_metric); glyphs[j], &char_metric);
} }
@ -624,7 +655,8 @@ uniscribe_encode_char (struct font *font, int c)
convert surrogate pairs to glyph indexes correctly. */ convert surrogate pairs to glyph indexes correctly. */
{ {
items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1); 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; HRESULT result;
/* Surrogates seem to need 2 here, even though only one glyph is /* Surrogates seem to need 2 here, even though only one glyph is
@ -635,11 +667,11 @@ uniscribe_encode_char (struct font *font, int c)
SCRIPT_VISATTR attrs[2]; SCRIPT_VISATTR attrs[2];
int nglyphs; int nglyphs;
/* Force ScriptShape to generate glyphs in the logical /* Force (*pfnScriptShape) to generate glyphs in the logical
order. */ order. */
items[0].a.fLogicalOrder = 1; items[0].a.fLogicalOrder = 1;
result = ScriptShape (context, result = (*pfnScriptShape) (context,
(SCRIPT_CACHE) &(uniscribe_font->cache), (SCRIPT_CACHE) &(uniscribe_font->cache),
ch, len, 2, &(items[0].a), ch, len, 2, &(items[0].a),
glyphs, clusters, attrs, &nglyphs); glyphs, clusters, attrs, &nglyphs);
@ -651,7 +683,8 @@ uniscribe_encode_char (struct font *font, int c)
f = XFRAME (selected_frame); f = XFRAME (selected_frame);
context = get_frame_dc (f); context = get_frame_dc (f);
old_font = SelectObject (context, FONT_HANDLE (font)); old_font = SelectObject (context, FONT_HANDLE (font));
result = ScriptShape (context, result
= (*pfnScriptShape) (context,
(SCRIPT_CACHE) &(uniscribe_font->cache), (SCRIPT_CACHE) &(uniscribe_font->cache),
ch, len, 2, &(items[0].a), ch, len, 2, &(items[0].a),
glyphs, clusters, attrs, &nglyphs); glyphs, clusters, attrs, &nglyphs);
@ -670,7 +703,8 @@ uniscribe_encode_char (struct font *font, int c)
when shaped. But we still need the return from here when shaped. But we still need the return from here
to be valid for the shaping engine to be invoked to be valid for the shaping engine to be invoked
later. */ later. */
result = ScriptGetCMap (context, result
= (*pfnScriptGetCMap) (context,
(SCRIPT_CACHE) &(uniscribe_font->cache), (SCRIPT_CACHE) &(uniscribe_font->cache),
ch, len, 0, glyphs); ch, len, 0, glyphs);
if (SUCCEEDED (result) && glyphs[0]) if (SUCCEEDED (result) && glyphs[0])
@ -942,7 +976,7 @@ uniscribe_check_otf_1 (HDC context, Lisp_Object script, Lisp_Object lang,
no_support: no_support:
if (cache) if (cache)
ScriptFreeCache (&cache); (*pfnScriptFreeCache) (&cache);
return ret; return ret;
} }
@ -1505,11 +1539,43 @@ syms_of_w32uniscribe_for_pdumper (void)
return; return;
/* Don't register if Uniscribe is not available. */ /* Don't register if Uniscribe is not available. */
HMODULE uniscribe = GetModuleHandle ("usp10"); HMODULE uniscribe;
#ifdef WINDOWSNT
uniscribe = LoadLibrary ("usp10.dll");
if (!uniscribe) if (!uniscribe)
return; 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 */
uniscribe = GetModuleHandle ("usp10.dll");
if (!uniscribe)
return;
pfnScriptItemize = &ScriptItemize;
pfnScriptShape = &ScriptShape;
pfnScriptPlace = &ScriptPlace;
pfnScriptGetGlyphABCWidth = &ScriptGetGlyphABCWidth;
pfnScriptFreeCache = &ScriptFreeCache;
pfnScriptGetCMap = &ScriptGetCMap;
uniscribe_available = 1; uniscribe_available = 1;
#endif /* Cygwin */
register_font_driver (&uniscribe_font_driver, NULL); register_font_driver (&uniscribe_font_driver, NULL);