1 /* NetHack 3.7 mhfont.c $NHDT-Date: 1596498349 2020/08/03 23:45:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.29 $ */
2 /* Copyright (C) 2001 by Alex Kompel */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 /* font management and such */
6
7 #include "win10.h"
8 #include "winos.h"
9 #include "mhfont.h"
10
11 /* font table - 64 fonts ought to be enough */
12 #define MAXFONTS 64
13
14 static cached_font font_table[MAXFONTS];
15 static int font_table_size = 0;
16
17 #define NHFONT_CODE(win, attr) (((attr & 0xFF) << 8) | (win_type & 0xFF))
18
19 static void __cdecl font_table_cleanup(void);
20
21 HFONT
mswin_create_splashfont(HWND hWnd)22 mswin_create_splashfont(HWND hWnd)
23 {
24 HDC hdc = GetDC(hWnd);
25 double scale = win10_monitor_scale(hWnd);
26 LOGFONT lgfnt;
27 ZeroMemory(&lgfnt, sizeof(lgfnt));
28 lgfnt.lfHeight = -(int)(80 * scale); // height of font
29 lgfnt.lfWidth = 0; // average character width
30 lgfnt.lfEscapement = 0; // angle of escapement
31 lgfnt.lfOrientation = 0; // base-line orientation angle
32 lgfnt.lfWeight = FW_BOLD; // font weight
33 lgfnt.lfItalic = FALSE; // italic attribute option
34 lgfnt.lfUnderline = FALSE; // underline attribute option
35 lgfnt.lfStrikeOut = FALSE; // strikeout attribute option
36 lgfnt.lfCharSet = ANSI_CHARSET; // character set identifier
37 lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision
38 lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision
39 lgfnt.lfQuality = DEFAULT_QUALITY; // output quality
40 lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family
41 NH_A2W("Times New Roman", lgfnt.lfFaceName, LF_FACESIZE);
42 HFONT font = CreateFontIndirect(&lgfnt);
43 ReleaseDC(hWnd, hdc);
44
45 return font;
46 }
47
48 BOOL
mswin_font_supports_unicode(HFONT hFont)49 mswin_font_supports_unicode(HFONT hFont)
50 {
51 for (int i = 0; i < font_table_size; i++)
52 if (font_table[i].hFont == hFont)
53 return font_table[i].supportsUnicode;
54
55 return FALSE;
56 }
57
58 /* create font based on window type, charater attributes and
59 window device context */
60 cached_font *
mswin_get_font(int win_type,int attr,HDC hdc,BOOL replace)61 mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace)
62 {
63 HFONT fnt = NULL;
64 LOGFONT lgfnt;
65 int font_size;
66 int font_index;
67 static BOOL once = FALSE;
68
69 if (!once) {
70 once = TRUE;
71 atexit(font_table_cleanup);
72 }
73
74 ZeroMemory(&lgfnt, sizeof(lgfnt));
75
76 /* try find font in the table */
77 for (font_index = 0; font_index < font_table_size; font_index++)
78 if (NHFONT_CODE(win_type, attr) == font_table[font_index].code)
79 break;
80
81 if (!replace && font_index < font_table_size)
82 return &font_table[font_index];
83
84 switch (win_type) {
85 case NHW_STATUS:
86 font_size = (attr == ATR_BOLD) ? iflags.wc_fontsiz_status + 1
87 : iflags.wc_fontsiz_status;
88 lgfnt.lfHeight = -font_size * GetDeviceCaps(hdc, LOGPIXELSY)
89 / 72; // height of font
90 lgfnt.lfWidth = 0; // average character width
91 lgfnt.lfEscapement = 0; // angle of escapement
92 lgfnt.lfOrientation = 0; // base-line orientation angle
93 lgfnt.lfWeight =
94 (attr == ATR_BOLD) ? FW_BOLD : FW_NORMAL; // font weight
95 lgfnt.lfItalic = FALSE; // italic attribute option
96 lgfnt.lfUnderline = (attr == ATR_ULINE); // underline attribute option
97 lgfnt.lfStrikeOut = FALSE; // strikeout attribute option
98 lgfnt.lfCharSet = mswin_charset(); // character set identifier
99 lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision
100 lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision
101 lgfnt.lfQuality = DEFAULT_QUALITY; // output quality
102 if (iflags.wc_font_status && *iflags.wc_font_status) {
103 lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family
104 NH_A2W(iflags.wc_font_status, lgfnt.lfFaceName, LF_FACESIZE);
105 } else {
106 lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family
107 }
108 break;
109
110 case NHW_MENU:
111 lgfnt.lfHeight = -iflags.wc_fontsiz_menu
112 * GetDeviceCaps(hdc, LOGPIXELSY)
113 / 72; // height of font
114 lgfnt.lfWidth = 0; // average character width
115 lgfnt.lfEscapement = 0; // angle of escapement
116 lgfnt.lfOrientation = 0; // base-line orientation angle
117 lgfnt.lfWeight = (attr == ATR_BOLD || attr == ATR_INVERSE)
118 ? FW_BOLD
119 : FW_NORMAL; // font weight
120 lgfnt.lfItalic =
121 (attr == ATR_BLINK) ? TRUE : FALSE; // italic attribute option
122 lgfnt.lfUnderline =
123 (attr == ATR_ULINE) ? TRUE : FALSE; // underline attribute option
124 lgfnt.lfStrikeOut = FALSE; // strikeout attribute option
125 lgfnt.lfCharSet = mswin_charset(); // character set identifier
126 lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision
127 lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision
128 lgfnt.lfQuality = DEFAULT_QUALITY; // output quality
129 if (iflags.wc_font_menu && *iflags.wc_font_menu) {
130 lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family
131 NH_A2W(iflags.wc_font_menu, lgfnt.lfFaceName, LF_FACESIZE);
132 } else {
133 lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family
134 }
135 break;
136
137 case NHW_MESSAGE:
138 font_size = (attr == ATR_INVERSE) ? iflags.wc_fontsiz_message + 1
139 : iflags.wc_fontsiz_message;
140 lgfnt.lfHeight = -font_size * GetDeviceCaps(hdc, LOGPIXELSY)
141 / 72; // height of font
142 lgfnt.lfWidth = 0; // average character width
143 lgfnt.lfEscapement = 0; // angle of escapement
144 lgfnt.lfOrientation = 0; // base-line orientation angle
145 lgfnt.lfWeight = (attr == ATR_BOLD || attr == ATR_INVERSE)
146 ? FW_BOLD
147 : FW_NORMAL; // font weight
148 lgfnt.lfItalic =
149 (attr == ATR_BLINK) ? TRUE : FALSE; // italic attribute option
150 lgfnt.lfUnderline =
151 (attr == ATR_ULINE) ? TRUE : FALSE; // underline attribute option
152 lgfnt.lfStrikeOut = FALSE; // strikeout attribute option
153 lgfnt.lfCharSet = mswin_charset(); // character set identifier
154 lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision
155 lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision
156 lgfnt.lfQuality = DEFAULT_QUALITY; // output quality
157 if (iflags.wc_font_message && *iflags.wc_font_message) {
158 lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family
159 NH_A2W(iflags.wc_font_message, lgfnt.lfFaceName, LF_FACESIZE);
160 } else {
161 lgfnt.lfPitchAndFamily = VARIABLE_PITCH; // pitch and family
162 }
163 break;
164
165 case NHW_TEXT:
166 lgfnt.lfHeight = -iflags.wc_fontsiz_text
167 * GetDeviceCaps(hdc, LOGPIXELSY)
168 / 72; // height of font
169 lgfnt.lfWidth = 0; // average character width
170 lgfnt.lfEscapement = 0; // angle of escapement
171 lgfnt.lfOrientation = 0; // base-line orientation angle
172 lgfnt.lfWeight = (attr == ATR_BOLD || attr == ATR_INVERSE)
173 ? FW_BOLD
174 : FW_NORMAL; // font weight
175 lgfnt.lfItalic =
176 (attr == ATR_BLINK) ? TRUE : FALSE; // italic attribute option
177 lgfnt.lfUnderline =
178 (attr == ATR_ULINE) ? TRUE : FALSE; // underline attribute option
179 lgfnt.lfStrikeOut = FALSE; // strikeout attribute option
180 lgfnt.lfCharSet = mswin_charset(); // character set identifier
181 lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision
182 lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision
183 lgfnt.lfQuality = DEFAULT_QUALITY; // output quality
184 if (iflags.wc_font_text && *iflags.wc_font_text) {
185 lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family
186 NH_A2W(iflags.wc_font_text, lgfnt.lfFaceName, LF_FACESIZE);
187 } else {
188 lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family
189 }
190 break;
191 }
192
193 fnt = CreateFontIndirect(&lgfnt);
194
195 /* add font to the table */
196 if (font_index == font_table_size) {
197 if (font_table_size >= MAXFONTS)
198 panic("font table overflow!");
199 font_table_size++;
200 } else {
201 DeleteObject(font_table[font_index].hFont);
202 }
203
204 font_table[font_index].code = NHFONT_CODE(win_type, attr);
205 font_table[font_index].hFont = fnt;
206 font_table[font_index].supportsUnicode = winos_font_support_cp437(fnt);
207
208 HGDIOBJ savedFont = SelectObject(hdc, fnt);
209 SIZE size;
210 GetTextExtentPoint32A(hdc, " ", 1, &size);
211 SelectObject(hdc, savedFont);
212
213 font_table[font_index].height = size.cy;
214 font_table[font_index].width = size.cx;
215
216 return &font_table[font_index];
217 }
218
219 UINT
mswin_charset(void)220 mswin_charset(void)
221 {
222 CHARSETINFO cis;
223 if (SYMHANDLING(H_IBM))
224 if (TranslateCharsetInfo((DWORD *) (uintptr_t) GetOEMCP(), &cis, TCI_SRCCODEPAGE))
225 return cis.ciCharset;
226 else
227 return OEM_CHARSET;
228 else if (TranslateCharsetInfo((DWORD *) (uintptr_t) GetACP(), &cis, TCI_SRCCODEPAGE))
229 return cis.ciCharset;
230 else
231 return ANSI_CHARSET;
232 }
233
font_table_cleanup(void)234 void __cdecl font_table_cleanup(void)
235 {
236 int i;
237 for (i = 0; i < font_table_size; i++) {
238 DeleteObject(font_table[i].hFont);
239 }
240 font_table_size = 0;
241 }
242