diff src/os_mswin.c @ 16152:8f4eccaaf2c0 v8.1.1081

patch 8.1.1081: MS-Windows: cannot use some fonts commit https://github.com/vim/vim/commit/433a5eb9de861dd01ea3b3dfa3b8fe23527cab54 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Mar 30 16:24:16 2019 +0100 patch 8.1.1081: MS-Windows: cannot use some fonts Problem: MS-Windows: cannot use fonts whose name cannot be represented in the current code page. Solution: Use wide font functions. (Ken Takata, closes #4000)
author Bram Moolenaar <Bram@vim.org>
date Sat, 30 Mar 2019 16:30:04 +0100
parents 7fad90423bd2
children cd5c83115ec6
line wrap: on
line diff
--- a/src/os_mswin.c
+++ b/src/os_mswin.c
@@ -85,7 +85,7 @@ typedef int COLORREF;
 typedef int CONSOLE_CURSOR_INFO;
 typedef int COORD;
 typedef int DWORD;
-typedef int ENUMLOGFONT;
+typedef int ENUMLOGFONTW;
 typedef int HANDLE;
 typedef int HDC;
 typedef int HFONT;
@@ -93,7 +93,7 @@ typedef int HICON;
 typedef int HWND;
 typedef int INPUT_RECORD;
 typedef int KEY_EVENT_RECORD;
-typedef int LOGFONT;
+typedef int LOGFONTW;
 typedef int LPARAM;
 typedef int LPBOOL;
 typedef int LPCSTR;
@@ -103,7 +103,7 @@ typedef int LPTSTR;
 typedef int LPWSTR;
 typedef int LRESULT;
 typedef int MOUSE_EVENT_RECORD;
-typedef int NEWTEXTMETRIC;
+typedef int NEWTEXTMETRICW;
 typedef int PACL;
 typedef int PRINTDLG;
 typedef int PSECURITY_DESCRIPTOR;
@@ -1420,7 +1420,7 @@ mch_print_init(prt_settings_T *psettings
     static int		stored_nCopies = 1;
     static int		stored_nFlags = 0;
 
-    LOGFONT		fLogFont;
+    LOGFONTW		fLogFont;
     int			pifItalic;
     int			pifBold;
     int			pifUnderline;
@@ -1577,7 +1577,7 @@ mch_print_init(prt_settings_T *psettings
 		fLogFont.lfItalic = pifItalic;
 		fLogFont.lfUnderline = pifUnderline;
 		prt_font_handles[pifBold][pifItalic][pifUnderline]
-					      = CreateFontIndirect(&fLogFont);
+					      = CreateFontIndirectW(&fLogFont);
 	    }
 
     SetBkMode(prt_dlg.hDC, OPAQUE);
@@ -2915,12 +2915,12 @@ quality_id2name(DWORD id)
     return qp->name;
 }
 
-static const LOGFONT s_lfDefault =
+static const LOGFONTW s_lfDefault =
 {
     -12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
     OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
     PROOF_QUALITY, FIXED_PITCH | FF_DONTCARE,
-    "Fixedsys"	/* see _ReadVimIni */
+    L"Fixedsys"	/* see _ReadVimIni */
 };
 
 /* Initialise the "current height" to -12 (same as s_lfDefault) just
@@ -2937,7 +2937,7 @@ int current_font_height = -12;		/* also 
  * calculation is for a vertical (height) size or a horizontal (width) one.
  */
     static int
-points_to_pixels(char_u *str, char_u **end, int vertical, long_i pprinter_dc)
+points_to_pixels(WCHAR *str, WCHAR **end, int vertical, long_i pprinter_dc)
 {
     int		pixels;
     int		points = 0;
@@ -2948,7 +2948,7 @@ points_to_pixels(char_u *str, char_u **e
 
     while (*str != NUL)
     {
-	if (*str == '.' && divisor == 0)
+	if (*str == L'.' && divisor == 0)
 	{
 	    /* Start keeping a divisor, for later */
 	    divisor = 1;
@@ -2959,7 +2959,7 @@ points_to_pixels(char_u *str, char_u **e
 		break;
 
 	    points *= 10;
-	    points += *str - '0';
+	    points += *str - L'0';
 	    divisor *= 10;
 	}
 	++str;
@@ -2989,15 +2989,15 @@ points_to_pixels(char_u *str, char_u **e
 
     static int CALLBACK
 font_enumproc(
-    ENUMLOGFONT	    *elf,
-    NEWTEXTMETRIC   *ntm UNUSED,
-    int		    type UNUSED,
+    ENUMLOGFONTW    *elf,
+    NEWTEXTMETRICW  *ntm UNUSED,
+    DWORD	    type UNUSED,
     LPARAM	    lparam)
 {
     /* Return value:
      *	  0 = terminate now (monospace & ANSI)
      *	  1 = continue, still no luck...
-     *	  2 = continue, but we have an acceptable LOGFONT
+     *	  2 = continue, but we have an acceptable LOGFONTW
      *	      (monospace, not ANSI)
      * We use these values, as EnumFontFamilies returns 1 if the
      * callback function is never called. So, we check the return as
@@ -3005,7 +3005,7 @@ font_enumproc(
      * It's not pretty, but it works!
      */
 
-    LOGFONT *lf = (LOGFONT *)(lparam);
+    LOGFONTW *lf = (LOGFONTW *)(lparam);
 
 #ifndef FEAT_PROPORTIONAL_FONTS
     /* Ignore non-monospace fonts without further ado */
@@ -3013,7 +3013,7 @@ font_enumproc(
 	return 1;
 #endif
 
-    /* Remember this LOGFONT as a "possible" */
+    /* Remember this LOGFONTW as a "possible" */
     *lf = elf->elfLogFont;
 
     /* Terminate the scan as soon as we find an ANSI font */
@@ -3027,15 +3027,15 @@ font_enumproc(
 }
 
     static int
-init_logfont(LOGFONT *lf)
+init_logfont(LOGFONTW *lf)
 {
     int		n;
     HWND	hwnd = GetDesktopWindow();
     HDC		hdc = GetWindowDC(hwnd);
 
-    n = EnumFontFamilies(hdc,
-			 (LPCSTR)lf->lfFaceName,
-			 (FONTENUMPROC)font_enumproc,
+    n = EnumFontFamiliesW(hdc,
+			 lf->lfFaceName,
+			 (FONTENUMPROCW)font_enumproc,
 			 (LPARAM)lf);
 
     ReleaseDC(hwnd, hdc);
@@ -3044,7 +3044,7 @@ init_logfont(LOGFONT *lf)
     if (n == 1)
 	return FAIL;
 
-    /* Tidy up the rest of the LOGFONT structure. We set to a basic
+    /* Tidy up the rest of the LOGFONTW structure. We set to a basic
      * font - get_logfont() sets bold, italic, etc based on the user's
      * input.
      */
@@ -3060,39 +3060,51 @@ init_logfont(LOGFONT *lf)
 }
 
 /*
+ * Compare a UTF-16 string and an ASCII string literally.
+ * Only works all the code points are inside ASCII range.
+ */
+    static int
+utf16ascncmp(const WCHAR *w, const char *p, size_t n)
+{
+    size_t i;
+
+    for (i = 0; i < n; i++)
+    {
+	if (w[i] == 0 || w[i] != p[i])
+	    return w[i] - p[i];
+    }
+    return 0;
+}
+
+/*
  * Get font info from "name" into logfont "lf".
  * Return OK for a valid name, FAIL otherwise.
  */
     int
 get_logfont(
-    LOGFONT	*lf,
+    LOGFONTW	*lf,
     char_u	*name,
     HDC		printer_dc,
     int		verbose)
 {
-    char_u	*p;
+    WCHAR	*p;
     int		i;
     int		ret = FAIL;
-    static LOGFONT *lastlf = NULL;
-    char_u	*acpname = NULL;
+    static LOGFONTW *lastlf = NULL;
+    WCHAR	*wname;
 
     *lf = s_lfDefault;
     if (name == NULL)
 	return OK;
 
-    /* Convert 'name' from 'encoding' to the current codepage, because
-     * lf->lfFaceName uses the current codepage.
-     * TODO: Use Wide APIs instead of ANSI APIs. */
-    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
-    {
-	int	len;
-	enc_to_acp(name, (int)STRLEN(name), &acpname, &len);
-	name = acpname;
-    }
-    if (STRCMP(name, "*") == 0)
+    wname = enc_to_utf16(name, NULL);
+    if (wname == NULL)
+	return FAIL;
+
+    if (wcscmp(wname, L"*") == 0)
     {
 #if defined(FEAT_GUI_MSWIN)
-	CHOOSEFONT	cf;
+	CHOOSEFONTW	cf;
 	/* if name is "*", bring up std font dialog: */
 	vim_memset(&cf, 0, sizeof(cf));
 	cf.lStructSize = sizeof(cf);
@@ -3102,7 +3114,7 @@ get_logfont(
 	    *lf = *lastlf;
 	cf.lpLogFont = lf;
 	cf.nFontType = 0 ; //REGULAR_FONTTYPE;
-	if (ChooseFont(&cf))
+	if (ChooseFontW(&cf))
 	    ret = OK;
 #endif
 	goto theend;
@@ -3111,14 +3123,14 @@ get_logfont(
     /*
      * Split name up, it could be <name>:h<height>:w<width> etc.
      */
-    for (p = name; *p && *p != ':'; p++)
+    for (p = wname; *p && *p != L':'; p++)
     {
-	if (p - name + 1 >= LF_FACESIZE)
+	if (p - wname + 1 >= LF_FACESIZE)
 	    goto theend;			/* Name too long */
-	lf->lfFaceName[p - name] = *p;
+	lf->lfFaceName[p - wname] = *p;
     }
-    if (p != name)
-	lf->lfFaceName[p - name] = NUL;
+    if (p != wname)
+	lf->lfFaceName[p - wname] = NUL;
 
     /* First set defaults */
     lf->lfHeight = -12;
@@ -3136,18 +3148,16 @@ get_logfont(
 	int	did_replace = FALSE;
 
 	for (i = 0; lf->lfFaceName[i]; ++i)
-	    if (IsDBCSLeadByte(lf->lfFaceName[i]))
-		++i;
-	    else if (lf->lfFaceName[i] == '_')
+	    if (lf->lfFaceName[i] == L'_')
 	    {
-		lf->lfFaceName[i] = ' ';
+		lf->lfFaceName[i] = L' ';
 		did_replace = TRUE;
 	    }
 	if (!did_replace || init_logfont(lf) == FAIL)
 	    goto theend;
     }
 
-    while (*p == ':')
+    while (*p == L':')
 	p++;
 
     /* Set the values found after ':' */
@@ -3155,30 +3165,30 @@ get_logfont(
     {
 	switch (*p++)
 	{
-	    case 'h':
+	    case L'h':
 		lf->lfHeight = - points_to_pixels(p, &p, TRUE, (long_i)printer_dc);
 		break;
-	    case 'w':
+	    case L'w':
 		lf->lfWidth = points_to_pixels(p, &p, FALSE, (long_i)printer_dc);
 		break;
-	    case 'b':
+	    case L'b':
 		lf->lfWeight = FW_BOLD;
 		break;
-	    case 'i':
+	    case L'i':
 		lf->lfItalic = TRUE;
 		break;
-	    case 'u':
+	    case L'u':
 		lf->lfUnderline = TRUE;
 		break;
-	    case 's':
+	    case L's':
 		lf->lfStrikeOut = TRUE;
 		break;
-	    case 'c':
+	    case L'c':
 		{
 		    struct charset_pair *cp;
 
 		    for (cp = charset_pairs; cp->name != NULL; ++cp)
-			if (STRNCMP(p, cp->name, strlen(cp->name)) == 0)
+			if (utf16ascncmp(p, cp->name, strlen(cp->name)) == 0)
 			{
 			    lf->lfCharSet = cp->charset;
 			    p += strlen(cp->name);
@@ -3186,17 +3196,19 @@ get_logfont(
 			}
 		    if (cp->name == NULL && verbose)
 		    {
-			semsg(_("E244: Illegal charset name \"%s\" in font name \"%s\""), p, name);
+			char_u *s = utf16_to_enc(p, NULL);
+			semsg(_("E244: Illegal charset name \"%s\" in font name \"%s\""), s, name);
+			vim_free(s);
 			break;
 		    }
 		    break;
 		}
-	    case 'q':
+	    case L'q':
 		{
 		    struct quality_pair *qp;
 
 		    for (qp = quality_pairs; qp->name != NULL; ++qp)
-			if (STRNCMP(p, qp->name, strlen(qp->name)) == 0)
+			if (utf16ascncmp(p, qp->name, strlen(qp->name)) == 0)
 			{
 			    lf->lfQuality = qp->quality;
 			    p += strlen(qp->name);
@@ -3204,7 +3216,9 @@ get_logfont(
 			}
 		    if (qp->name == NULL && verbose)
 		    {
-			semsg(_("E244: Illegal quality name \"%s\" in font name \"%s\""), p, name);
+			char_u *s = utf16_to_enc(p, NULL);
+			semsg(_("E244: Illegal quality name \"%s\" in font name \"%s\""), s, name);
+			vim_free(s);
 			break;
 		    }
 		    break;
@@ -3214,7 +3228,7 @@ get_logfont(
 		    semsg(_("E245: Illegal char '%c' in font name \"%s\""), p[-1], name);
 		goto theend;
 	}
-	while (*p == ':')
+	while (*p == L':')
 	    p++;
     }
     ret = OK;
@@ -3224,11 +3238,11 @@ theend:
     if (ret == OK && printer_dc == NULL)
     {
 	vim_free(lastlf);
-	lastlf = (LOGFONT *)alloc(sizeof(LOGFONT));
+	lastlf = (LOGFONTW *)alloc(sizeof(LOGFONTW));
 	if (lastlf != NULL)
-	    mch_memmove(lastlf, lf, sizeof(LOGFONT));
+	    mch_memmove(lastlf, lf, sizeof(LOGFONTW));
     }
-    vim_free(acpname);
+    vim_free(wname);
 
     return ret;
 }