comparison 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
comparison
equal deleted inserted replaced
16151:6285d4ff3255 16152:8f4eccaaf2c0
83 typedef int CALLBACK; 83 typedef int CALLBACK;
84 typedef int COLORREF; 84 typedef int COLORREF;
85 typedef int CONSOLE_CURSOR_INFO; 85 typedef int CONSOLE_CURSOR_INFO;
86 typedef int COORD; 86 typedef int COORD;
87 typedef int DWORD; 87 typedef int DWORD;
88 typedef int ENUMLOGFONT; 88 typedef int ENUMLOGFONTW;
89 typedef int HANDLE; 89 typedef int HANDLE;
90 typedef int HDC; 90 typedef int HDC;
91 typedef int HFONT; 91 typedef int HFONT;
92 typedef int HICON; 92 typedef int HICON;
93 typedef int HWND; 93 typedef int HWND;
94 typedef int INPUT_RECORD; 94 typedef int INPUT_RECORD;
95 typedef int KEY_EVENT_RECORD; 95 typedef int KEY_EVENT_RECORD;
96 typedef int LOGFONT; 96 typedef int LOGFONTW;
97 typedef int LPARAM; 97 typedef int LPARAM;
98 typedef int LPBOOL; 98 typedef int LPBOOL;
99 typedef int LPCSTR; 99 typedef int LPCSTR;
100 typedef int LPCWSTR; 100 typedef int LPCWSTR;
101 typedef int LPSTR; 101 typedef int LPSTR;
102 typedef int LPTSTR; 102 typedef int LPTSTR;
103 typedef int LPWSTR; 103 typedef int LPWSTR;
104 typedef int LRESULT; 104 typedef int LRESULT;
105 typedef int MOUSE_EVENT_RECORD; 105 typedef int MOUSE_EVENT_RECORD;
106 typedef int NEWTEXTMETRIC; 106 typedef int NEWTEXTMETRICW;
107 typedef int PACL; 107 typedef int PACL;
108 typedef int PRINTDLG; 108 typedef int PRINTDLG;
109 typedef int PSECURITY_DESCRIPTOR; 109 typedef int PSECURITY_DESCRIPTOR;
110 typedef int PSID; 110 typedef int PSID;
111 typedef int SECURITY_INFORMATION; 111 typedef int SECURITY_INFORMATION;
1418 static HGLOBAL stored_dm = NULL; 1418 static HGLOBAL stored_dm = NULL;
1419 static HGLOBAL stored_devn = NULL; 1419 static HGLOBAL stored_devn = NULL;
1420 static int stored_nCopies = 1; 1420 static int stored_nCopies = 1;
1421 static int stored_nFlags = 0; 1421 static int stored_nFlags = 0;
1422 1422
1423 LOGFONT fLogFont; 1423 LOGFONTW fLogFont;
1424 int pifItalic; 1424 int pifItalic;
1425 int pifBold; 1425 int pifBold;
1426 int pifUnderline; 1426 int pifUnderline;
1427 1427
1428 DEVMODE *mem; 1428 DEVMODE *mem;
1575 { 1575 {
1576 fLogFont.lfWeight = boldface[pifBold]; 1576 fLogFont.lfWeight = boldface[pifBold];
1577 fLogFont.lfItalic = pifItalic; 1577 fLogFont.lfItalic = pifItalic;
1578 fLogFont.lfUnderline = pifUnderline; 1578 fLogFont.lfUnderline = pifUnderline;
1579 prt_font_handles[pifBold][pifItalic][pifUnderline] 1579 prt_font_handles[pifBold][pifItalic][pifUnderline]
1580 = CreateFontIndirect(&fLogFont); 1580 = CreateFontIndirectW(&fLogFont);
1581 } 1581 }
1582 1582
1583 SetBkMode(prt_dlg.hDC, OPAQUE); 1583 SetBkMode(prt_dlg.hDC, OPAQUE);
1584 SelectObject(prt_dlg.hDC, prt_font_handles[0][0][0]); 1584 SelectObject(prt_dlg.hDC, prt_font_handles[0][0][0]);
1585 1585
2913 if (id == qp->quality) 2913 if (id == qp->quality)
2914 break; 2914 break;
2915 return qp->name; 2915 return qp->name;
2916 } 2916 }
2917 2917
2918 static const LOGFONT s_lfDefault = 2918 static const LOGFONTW s_lfDefault =
2919 { 2919 {
2920 -12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, 2920 -12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
2921 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, 2921 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
2922 PROOF_QUALITY, FIXED_PITCH | FF_DONTCARE, 2922 PROOF_QUALITY, FIXED_PITCH | FF_DONTCARE,
2923 "Fixedsys" /* see _ReadVimIni */ 2923 L"Fixedsys" /* see _ReadVimIni */
2924 }; 2924 };
2925 2925
2926 /* Initialise the "current height" to -12 (same as s_lfDefault) just 2926 /* Initialise the "current height" to -12 (same as s_lfDefault) just
2927 * in case the user specifies a font in "guifont" with no size before a font 2927 * in case the user specifies a font in "guifont" with no size before a font
2928 * with an explicit size has been set. This defaults the size to this value 2928 * with an explicit size has been set. This defaults the size to this value
2935 * "10.5"). The pixel value is returned, and a pointer to the next unconverted 2935 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
2936 * character is stored in *end. The flag "vertical" says whether this 2936 * character is stored in *end. The flag "vertical" says whether this
2937 * calculation is for a vertical (height) size or a horizontal (width) one. 2937 * calculation is for a vertical (height) size or a horizontal (width) one.
2938 */ 2938 */
2939 static int 2939 static int
2940 points_to_pixels(char_u *str, char_u **end, int vertical, long_i pprinter_dc) 2940 points_to_pixels(WCHAR *str, WCHAR **end, int vertical, long_i pprinter_dc)
2941 { 2941 {
2942 int pixels; 2942 int pixels;
2943 int points = 0; 2943 int points = 0;
2944 int divisor = 0; 2944 int divisor = 0;
2945 HWND hwnd = (HWND)0; 2945 HWND hwnd = (HWND)0;
2946 HDC hdc; 2946 HDC hdc;
2947 HDC printer_dc = (HDC)pprinter_dc; 2947 HDC printer_dc = (HDC)pprinter_dc;
2948 2948
2949 while (*str != NUL) 2949 while (*str != NUL)
2950 { 2950 {
2951 if (*str == '.' && divisor == 0) 2951 if (*str == L'.' && divisor == 0)
2952 { 2952 {
2953 /* Start keeping a divisor, for later */ 2953 /* Start keeping a divisor, for later */
2954 divisor = 1; 2954 divisor = 1;
2955 } 2955 }
2956 else 2956 else
2957 { 2957 {
2958 if (!VIM_ISDIGIT(*str)) 2958 if (!VIM_ISDIGIT(*str))
2959 break; 2959 break;
2960 2960
2961 points *= 10; 2961 points *= 10;
2962 points += *str - '0'; 2962 points += *str - L'0';
2963 divisor *= 10; 2963 divisor *= 10;
2964 } 2964 }
2965 ++str; 2965 ++str;
2966 } 2966 }
2967 2967
2987 return pixels; 2987 return pixels;
2988 } 2988 }
2989 2989
2990 static int CALLBACK 2990 static int CALLBACK
2991 font_enumproc( 2991 font_enumproc(
2992 ENUMLOGFONT *elf, 2992 ENUMLOGFONTW *elf,
2993 NEWTEXTMETRIC *ntm UNUSED, 2993 NEWTEXTMETRICW *ntm UNUSED,
2994 int type UNUSED, 2994 DWORD type UNUSED,
2995 LPARAM lparam) 2995 LPARAM lparam)
2996 { 2996 {
2997 /* Return value: 2997 /* Return value:
2998 * 0 = terminate now (monospace & ANSI) 2998 * 0 = terminate now (monospace & ANSI)
2999 * 1 = continue, still no luck... 2999 * 1 = continue, still no luck...
3000 * 2 = continue, but we have an acceptable LOGFONT 3000 * 2 = continue, but we have an acceptable LOGFONTW
3001 * (monospace, not ANSI) 3001 * (monospace, not ANSI)
3002 * We use these values, as EnumFontFamilies returns 1 if the 3002 * We use these values, as EnumFontFamilies returns 1 if the
3003 * callback function is never called. So, we check the return as 3003 * callback function is never called. So, we check the return as
3004 * 0 = perfect, 2 = OK, 1 = no good... 3004 * 0 = perfect, 2 = OK, 1 = no good...
3005 * It's not pretty, but it works! 3005 * It's not pretty, but it works!
3006 */ 3006 */
3007 3007
3008 LOGFONT *lf = (LOGFONT *)(lparam); 3008 LOGFONTW *lf = (LOGFONTW *)(lparam);
3009 3009
3010 #ifndef FEAT_PROPORTIONAL_FONTS 3010 #ifndef FEAT_PROPORTIONAL_FONTS
3011 /* Ignore non-monospace fonts without further ado */ 3011 /* Ignore non-monospace fonts without further ado */
3012 if ((ntm->tmPitchAndFamily & 1) != 0) 3012 if ((ntm->tmPitchAndFamily & 1) != 0)
3013 return 1; 3013 return 1;
3014 #endif 3014 #endif
3015 3015
3016 /* Remember this LOGFONT as a "possible" */ 3016 /* Remember this LOGFONTW as a "possible" */
3017 *lf = elf->elfLogFont; 3017 *lf = elf->elfLogFont;
3018 3018
3019 /* Terminate the scan as soon as we find an ANSI font */ 3019 /* Terminate the scan as soon as we find an ANSI font */
3020 if (lf->lfCharSet == ANSI_CHARSET 3020 if (lf->lfCharSet == ANSI_CHARSET
3021 || lf->lfCharSet == OEM_CHARSET 3021 || lf->lfCharSet == OEM_CHARSET
3025 /* Continue the scan - we have a non-ANSI font */ 3025 /* Continue the scan - we have a non-ANSI font */
3026 return 2; 3026 return 2;
3027 } 3027 }
3028 3028
3029 static int 3029 static int
3030 init_logfont(LOGFONT *lf) 3030 init_logfont(LOGFONTW *lf)
3031 { 3031 {
3032 int n; 3032 int n;
3033 HWND hwnd = GetDesktopWindow(); 3033 HWND hwnd = GetDesktopWindow();
3034 HDC hdc = GetWindowDC(hwnd); 3034 HDC hdc = GetWindowDC(hwnd);
3035 3035
3036 n = EnumFontFamilies(hdc, 3036 n = EnumFontFamiliesW(hdc,
3037 (LPCSTR)lf->lfFaceName, 3037 lf->lfFaceName,
3038 (FONTENUMPROC)font_enumproc, 3038 (FONTENUMPROCW)font_enumproc,
3039 (LPARAM)lf); 3039 (LPARAM)lf);
3040 3040
3041 ReleaseDC(hwnd, hdc); 3041 ReleaseDC(hwnd, hdc);
3042 3042
3043 /* If we couldn't find a usable font, return failure */ 3043 /* If we couldn't find a usable font, return failure */
3044 if (n == 1) 3044 if (n == 1)
3045 return FAIL; 3045 return FAIL;
3046 3046
3047 /* Tidy up the rest of the LOGFONT structure. We set to a basic 3047 /* Tidy up the rest of the LOGFONTW structure. We set to a basic
3048 * font - get_logfont() sets bold, italic, etc based on the user's 3048 * font - get_logfont() sets bold, italic, etc based on the user's
3049 * input. 3049 * input.
3050 */ 3050 */
3051 lf->lfHeight = current_font_height; 3051 lf->lfHeight = current_font_height;
3052 lf->lfWidth = 0; 3052 lf->lfWidth = 0;
3058 /* Return success */ 3058 /* Return success */
3059 return OK; 3059 return OK;
3060 } 3060 }
3061 3061
3062 /* 3062 /*
3063 * Compare a UTF-16 string and an ASCII string literally.
3064 * Only works all the code points are inside ASCII range.
3065 */
3066 static int
3067 utf16ascncmp(const WCHAR *w, const char *p, size_t n)
3068 {
3069 size_t i;
3070
3071 for (i = 0; i < n; i++)
3072 {
3073 if (w[i] == 0 || w[i] != p[i])
3074 return w[i] - p[i];
3075 }
3076 return 0;
3077 }
3078
3079 /*
3063 * Get font info from "name" into logfont "lf". 3080 * Get font info from "name" into logfont "lf".
3064 * Return OK for a valid name, FAIL otherwise. 3081 * Return OK for a valid name, FAIL otherwise.
3065 */ 3082 */
3066 int 3083 int
3067 get_logfont( 3084 get_logfont(
3068 LOGFONT *lf, 3085 LOGFONTW *lf,
3069 char_u *name, 3086 char_u *name,
3070 HDC printer_dc, 3087 HDC printer_dc,
3071 int verbose) 3088 int verbose)
3072 { 3089 {
3073 char_u *p; 3090 WCHAR *p;
3074 int i; 3091 int i;
3075 int ret = FAIL; 3092 int ret = FAIL;
3076 static LOGFONT *lastlf = NULL; 3093 static LOGFONTW *lastlf = NULL;
3077 char_u *acpname = NULL; 3094 WCHAR *wname;
3078 3095
3079 *lf = s_lfDefault; 3096 *lf = s_lfDefault;
3080 if (name == NULL) 3097 if (name == NULL)
3081 return OK; 3098 return OK;
3082 3099
3083 /* Convert 'name' from 'encoding' to the current codepage, because 3100 wname = enc_to_utf16(name, NULL);
3084 * lf->lfFaceName uses the current codepage. 3101 if (wname == NULL)
3085 * TODO: Use Wide APIs instead of ANSI APIs. */ 3102 return FAIL;
3086 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) 3103
3087 { 3104 if (wcscmp(wname, L"*") == 0)
3088 int len;
3089 enc_to_acp(name, (int)STRLEN(name), &acpname, &len);
3090 name = acpname;
3091 }
3092 if (STRCMP(name, "*") == 0)
3093 { 3105 {
3094 #if defined(FEAT_GUI_MSWIN) 3106 #if defined(FEAT_GUI_MSWIN)
3095 CHOOSEFONT cf; 3107 CHOOSEFONTW cf;
3096 /* if name is "*", bring up std font dialog: */ 3108 /* if name is "*", bring up std font dialog: */
3097 vim_memset(&cf, 0, sizeof(cf)); 3109 vim_memset(&cf, 0, sizeof(cf));
3098 cf.lStructSize = sizeof(cf); 3110 cf.lStructSize = sizeof(cf);
3099 cf.hwndOwner = s_hwnd; 3111 cf.hwndOwner = s_hwnd;
3100 cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_INITTOLOGFONTSTRUCT; 3112 cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_INITTOLOGFONTSTRUCT;
3101 if (lastlf != NULL) 3113 if (lastlf != NULL)
3102 *lf = *lastlf; 3114 *lf = *lastlf;
3103 cf.lpLogFont = lf; 3115 cf.lpLogFont = lf;
3104 cf.nFontType = 0 ; //REGULAR_FONTTYPE; 3116 cf.nFontType = 0 ; //REGULAR_FONTTYPE;
3105 if (ChooseFont(&cf)) 3117 if (ChooseFontW(&cf))
3106 ret = OK; 3118 ret = OK;
3107 #endif 3119 #endif
3108 goto theend; 3120 goto theend;
3109 } 3121 }
3110 3122
3111 /* 3123 /*
3112 * Split name up, it could be <name>:h<height>:w<width> etc. 3124 * Split name up, it could be <name>:h<height>:w<width> etc.
3113 */ 3125 */
3114 for (p = name; *p && *p != ':'; p++) 3126 for (p = wname; *p && *p != L':'; p++)
3115 { 3127 {
3116 if (p - name + 1 >= LF_FACESIZE) 3128 if (p - wname + 1 >= LF_FACESIZE)
3117 goto theend; /* Name too long */ 3129 goto theend; /* Name too long */
3118 lf->lfFaceName[p - name] = *p; 3130 lf->lfFaceName[p - wname] = *p;
3119 } 3131 }
3120 if (p != name) 3132 if (p != wname)
3121 lf->lfFaceName[p - name] = NUL; 3133 lf->lfFaceName[p - wname] = NUL;
3122 3134
3123 /* First set defaults */ 3135 /* First set defaults */
3124 lf->lfHeight = -12; 3136 lf->lfHeight = -12;
3125 lf->lfWidth = 0; 3137 lf->lfWidth = 0;
3126 lf->lfWeight = FW_NORMAL; 3138 lf->lfWeight = FW_NORMAL;
3134 if (init_logfont(lf) == FAIL) 3146 if (init_logfont(lf) == FAIL)
3135 { 3147 {
3136 int did_replace = FALSE; 3148 int did_replace = FALSE;
3137 3149
3138 for (i = 0; lf->lfFaceName[i]; ++i) 3150 for (i = 0; lf->lfFaceName[i]; ++i)
3139 if (IsDBCSLeadByte(lf->lfFaceName[i])) 3151 if (lf->lfFaceName[i] == L'_')
3140 ++i;
3141 else if (lf->lfFaceName[i] == '_')
3142 { 3152 {
3143 lf->lfFaceName[i] = ' '; 3153 lf->lfFaceName[i] = L' ';
3144 did_replace = TRUE; 3154 did_replace = TRUE;
3145 } 3155 }
3146 if (!did_replace || init_logfont(lf) == FAIL) 3156 if (!did_replace || init_logfont(lf) == FAIL)
3147 goto theend; 3157 goto theend;
3148 } 3158 }
3149 3159
3150 while (*p == ':') 3160 while (*p == L':')
3151 p++; 3161 p++;
3152 3162
3153 /* Set the values found after ':' */ 3163 /* Set the values found after ':' */
3154 while (*p) 3164 while (*p)
3155 { 3165 {
3156 switch (*p++) 3166 switch (*p++)
3157 { 3167 {
3158 case 'h': 3168 case L'h':
3159 lf->lfHeight = - points_to_pixels(p, &p, TRUE, (long_i)printer_dc); 3169 lf->lfHeight = - points_to_pixels(p, &p, TRUE, (long_i)printer_dc);
3160 break; 3170 break;
3161 case 'w': 3171 case L'w':
3162 lf->lfWidth = points_to_pixels(p, &p, FALSE, (long_i)printer_dc); 3172 lf->lfWidth = points_to_pixels(p, &p, FALSE, (long_i)printer_dc);
3163 break; 3173 break;
3164 case 'b': 3174 case L'b':
3165 lf->lfWeight = FW_BOLD; 3175 lf->lfWeight = FW_BOLD;
3166 break; 3176 break;
3167 case 'i': 3177 case L'i':
3168 lf->lfItalic = TRUE; 3178 lf->lfItalic = TRUE;
3169 break; 3179 break;
3170 case 'u': 3180 case L'u':
3171 lf->lfUnderline = TRUE; 3181 lf->lfUnderline = TRUE;
3172 break; 3182 break;
3173 case 's': 3183 case L's':
3174 lf->lfStrikeOut = TRUE; 3184 lf->lfStrikeOut = TRUE;
3175 break; 3185 break;
3176 case 'c': 3186 case L'c':
3177 { 3187 {
3178 struct charset_pair *cp; 3188 struct charset_pair *cp;
3179 3189
3180 for (cp = charset_pairs; cp->name != NULL; ++cp) 3190 for (cp = charset_pairs; cp->name != NULL; ++cp)
3181 if (STRNCMP(p, cp->name, strlen(cp->name)) == 0) 3191 if (utf16ascncmp(p, cp->name, strlen(cp->name)) == 0)
3182 { 3192 {
3183 lf->lfCharSet = cp->charset; 3193 lf->lfCharSet = cp->charset;
3184 p += strlen(cp->name); 3194 p += strlen(cp->name);
3185 break; 3195 break;
3186 } 3196 }
3187 if (cp->name == NULL && verbose) 3197 if (cp->name == NULL && verbose)
3188 { 3198 {
3189 semsg(_("E244: Illegal charset name \"%s\" in font name \"%s\""), p, name); 3199 char_u *s = utf16_to_enc(p, NULL);
3200 semsg(_("E244: Illegal charset name \"%s\" in font name \"%s\""), s, name);
3201 vim_free(s);
3190 break; 3202 break;
3191 } 3203 }
3192 break; 3204 break;
3193 } 3205 }
3194 case 'q': 3206 case L'q':
3195 { 3207 {
3196 struct quality_pair *qp; 3208 struct quality_pair *qp;
3197 3209
3198 for (qp = quality_pairs; qp->name != NULL; ++qp) 3210 for (qp = quality_pairs; qp->name != NULL; ++qp)
3199 if (STRNCMP(p, qp->name, strlen(qp->name)) == 0) 3211 if (utf16ascncmp(p, qp->name, strlen(qp->name)) == 0)
3200 { 3212 {
3201 lf->lfQuality = qp->quality; 3213 lf->lfQuality = qp->quality;
3202 p += strlen(qp->name); 3214 p += strlen(qp->name);
3203 break; 3215 break;
3204 } 3216 }
3205 if (qp->name == NULL && verbose) 3217 if (qp->name == NULL && verbose)
3206 { 3218 {
3207 semsg(_("E244: Illegal quality name \"%s\" in font name \"%s\""), p, name); 3219 char_u *s = utf16_to_enc(p, NULL);
3220 semsg(_("E244: Illegal quality name \"%s\" in font name \"%s\""), s, name);
3221 vim_free(s);
3208 break; 3222 break;
3209 } 3223 }
3210 break; 3224 break;
3211 } 3225 }
3212 default: 3226 default:
3213 if (verbose) 3227 if (verbose)
3214 semsg(_("E245: Illegal char '%c' in font name \"%s\""), p[-1], name); 3228 semsg(_("E245: Illegal char '%c' in font name \"%s\""), p[-1], name);
3215 goto theend; 3229 goto theend;
3216 } 3230 }
3217 while (*p == ':') 3231 while (*p == L':')
3218 p++; 3232 p++;
3219 } 3233 }
3220 ret = OK; 3234 ret = OK;
3221 3235
3222 theend: 3236 theend:
3223 /* ron: init lastlf */ 3237 /* ron: init lastlf */
3224 if (ret == OK && printer_dc == NULL) 3238 if (ret == OK && printer_dc == NULL)
3225 { 3239 {
3226 vim_free(lastlf); 3240 vim_free(lastlf);
3227 lastlf = (LOGFONT *)alloc(sizeof(LOGFONT)); 3241 lastlf = (LOGFONTW *)alloc(sizeof(LOGFONTW));
3228 if (lastlf != NULL) 3242 if (lastlf != NULL)
3229 mch_memmove(lastlf, lf, sizeof(LOGFONT)); 3243 mch_memmove(lastlf, lf, sizeof(LOGFONTW));
3230 } 3244 }
3231 vim_free(acpname); 3245 vim_free(wname);
3232 3246
3233 return ret; 3247 return ret;
3234 } 3248 }
3235 3249
3236 #endif /* defined(FEAT_GUI) || defined(FEAT_PRINTER) */ 3250 #endif /* defined(FEAT_GUI) || defined(FEAT_PRINTER) */