Implement EnumFontFamilies(Ex)A/W() and TranslateCharsetInfo()
[reactos.git] / reactos / lib / gdi32 / objects / font.c
1 /* $Id: font.c,v 1.1 2004/03/23 00:18:54 gvg Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/gdi32/object/font.c
6 * PURPOSE:
7 * PROGRAMMER:
8 *
9 */
10
11 #ifdef UNICODE
12 #undef UNICODE
13 #endif
14
15 #include <windows.h>
16 #include <rosrtl/logfont.h>
17 #include <win32k/font.h>
18 #include <internal/font.h>
19
20 #define NDEBUG
21 #include <debug.h>
22
23 #define INITIAL_FAMILY_COUNT 64
24
25 static BOOL FASTCALL
26 MetricsCharConvert(WCHAR w, CHAR *b)
27 {
28 UNICODE_STRING WString;
29 WCHAR WBuf[2];
30 ANSI_STRING AString;
31 CHAR ABuf[2];
32 NTSTATUS Status;
33
34 if (L'\0' == w)
35 {
36 *b = '\0';
37 }
38 else
39 {
40 WBuf[0] = w;
41 WBuf[1] = L'\0';
42 RtlInitUnicodeString(&WString, WBuf);
43 ABuf[0] = '*';
44 ABuf[1] = L'\0';
45 RtlInitAnsiString(&AString, ABuf);
46
47 Status = RtlUnicodeStringToAnsiString(&AString, &WString, FALSE);
48 if (! NT_SUCCESS(Status))
49 {
50 SetLastError(RtlNtStatusToDosError(Status));
51 return FALSE;
52 }
53 *b = ABuf[0];
54 }
55
56 return TRUE;
57 }
58
59 BOOL FASTCALL
60 TextMetricW2A(TEXTMETRICA *tma, TEXTMETRICW *tmw)
61 {
62 UNICODE_STRING WString;
63 WCHAR WBuf[256];
64 ANSI_STRING AString;
65 CHAR ABuf[256];
66 UINT Letter;
67 NTSTATUS Status;
68
69 tma->tmHeight = tmw->tmHeight;
70 tma->tmAscent = tmw->tmAscent;
71 tma->tmDescent = tmw->tmDescent;
72 tma->tmInternalLeading = tmw->tmInternalLeading;
73 tma->tmExternalLeading = tmw->tmExternalLeading;
74 tma->tmAveCharWidth = tmw->tmAveCharWidth;
75 tma->tmMaxCharWidth = tmw->tmMaxCharWidth;
76 tma->tmWeight = tmw->tmWeight;
77 tma->tmOverhang = tmw->tmOverhang;
78 tma->tmDigitizedAspectX = tmw->tmDigitizedAspectX;
79 tma->tmDigitizedAspectY = tmw->tmDigitizedAspectY;
80
81 /* The Unicode FirstChar/LastChar need not correspond to the ANSI
82 FirstChar/LastChar. For example, if the font contains glyphs for
83 letters A-Z and an accented version of the letter e, the Unicode
84 FirstChar would be A and the Unicode LastChar would be the accented
85 e. If you just translate those to ANSI, the range would become
86 letters A-E instead of A-Z.
87 We translate all possible ANSI chars to Unicode and find the first
88 and last translated character which fall into the Unicode FirstChar/
89 LastChar range and return the corresponding ANSI char. */
90
91 /* Setup an Ansi string containing all possible letters (note: skip '\0' at
92 the beginning since that would be interpreted as end-of-string, handle
93 '\0' special later */
94 for (Letter = 1; Letter < 256; Letter++)
95 {
96 ABuf[Letter - 1] = (CHAR) Letter;
97 WBuf[Letter - 1] = L' ';
98 }
99 ABuf[255] = '\0';
100 WBuf[255] = L'\0';
101 RtlInitAnsiString(&AString, ABuf);
102 RtlInitUnicodeString(&WString, WBuf);
103
104 /* Find the corresponding Unicode characters */
105 Status = RtlAnsiStringToUnicodeString(&WString, &AString, FALSE);
106 if (! NT_SUCCESS(Status))
107 {
108 SetLastError(RtlNtStatusToDosError(Status));
109 return FALSE;
110 }
111
112 /* Scan for the first ANSI character which maps to an Unicode character
113 in the range */
114 tma->tmFirstChar = '\0';
115 if (L'\0' != tmw->tmFirstChar)
116 {
117 for (Letter = 1; Letter < 256; Letter++)
118 {
119 if (tmw->tmFirstChar <= WBuf[Letter - 1] &&
120 WBuf[Letter - 1] <= tmw->tmLastChar)
121 {
122 tma->tmFirstChar = (CHAR) Letter;
123 break;
124 }
125 }
126 }
127
128 /* Scan for the last ANSI character which maps to an Unicode character
129 in the range */
130 tma->tmLastChar = '\0';
131 if (L'\0' != tmw->tmLastChar)
132 {
133 for (Letter = 255; 0 < Letter; Letter--)
134 {
135 if (tmw->tmFirstChar <= WBuf[Letter - 1] &&
136 WBuf[Letter - 1] <= tmw->tmLastChar)
137 {
138 tma->tmLastChar = (CHAR) Letter;
139 break;
140 }
141 }
142 }
143
144 if (! MetricsCharConvert(tmw->tmDefaultChar, &tma->tmDefaultChar) ||
145 ! MetricsCharConvert(tmw->tmBreakChar, &tma->tmBreakChar))
146 {
147 return FALSE;
148 }
149
150 tma->tmItalic = tmw->tmItalic;
151 tma->tmUnderlined = tmw->tmUnderlined;
152 tma->tmStruckOut = tmw->tmStruckOut;
153 tma->tmPitchAndFamily = tmw->tmPitchAndFamily;
154 tma->tmCharSet = tmw->tmCharSet;
155
156 return TRUE;
157 }
158
159 BOOL FASTCALL
160 NewTextMetricW2A(NEWTEXTMETRICA *tma, NEWTEXTMETRICW *tmw)
161 {
162 if (! TextMetricW2A((TEXTMETRICA *) tma, (TEXTMETRICW *) tmw))
163 {
164 return FALSE;
165 }
166
167 tma->ntmFlags = tmw->ntmFlags;
168 tma->ntmSizeEM = tmw->ntmSizeEM;
169 tma->ntmCellHeight = tmw->ntmCellHeight;
170 tma->ntmAvgWidth = tmw->ntmAvgWidth;
171
172 return TRUE;
173 }
174
175 BOOL FASTCALL
176 NewTextMetricExW2A(NEWTEXTMETRICEXA *tma, NEWTEXTMETRICEXW *tmw)
177 {
178 if (! NewTextMetricW2A(&tma->ntmTm, &tmw->ntmTm))
179 {
180 return FALSE;
181 }
182
183 tma->ntmFontSig = tmw->ntmFontSig;
184
185 return TRUE;
186 }
187
188 /*
189 * @implemented
190 */
191 BOOL
192 STDCALL
193 TranslateCharsetInfo(DWORD *Src, LPCHARSETINFO Cs, DWORD Flags)
194 {
195 return NtGdiTranslateCharsetInfo(Src, Cs, Flags);
196 }
197
198 static int FASTCALL
199 IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam,
200 BOOL Unicode)
201 {
202 int FontFamilyCount;
203 unsigned FontFamilySize;
204 PFONTFAMILYINFO Info;
205 int Ret;
206 unsigned i;
207 ENUMLOGFONTEXA EnumLogFontExA;
208 NEWTEXTMETRICEXA NewTextMetricExA;
209
210 Info = RtlAllocateHeap(GetProcessHeap(), 0,
211 INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO));
212 if (NULL == Info)
213 {
214 return 0;
215 }
216 FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, INITIAL_FAMILY_COUNT);
217 if (FontFamilyCount < 0)
218 {
219 RtlFreeHeap(GetProcessHeap(), 0, Info);
220 return 0;
221 }
222 if (INITIAL_FAMILY_COUNT < FontFamilyCount)
223 {
224 FontFamilySize = FontFamilyCount;
225 RtlFreeHeap(GetProcessHeap(), 0, Info);
226 Info = RtlAllocateHeap(GetProcessHeap(), 0,
227 FontFamilyCount * sizeof(FONTFAMILYINFO));
228 if (NULL == Info)
229 {
230 return 0;
231 }
232 FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, FontFamilySize);
233 if (FontFamilyCount < 0 || FontFamilySize < FontFamilyCount)
234 {
235 RtlFreeHeap(GetProcessHeap(), 0, Info);
236 return 0;
237 }
238 }
239
240 for (i = 0; i < FontFamilyCount; i++)
241 {
242 if (Unicode)
243 {
244 Ret = ((FONTENUMEXPROCW) EnumProc)(&Info[i].EnumLogFontEx, &Info[i].NewTextMetricEx,
245 Info[i].FontType, lParam);
246 }
247 else
248 {
249 RosRtlLogFontW2A(&EnumLogFontExA.elfLogFont, &Info[i].EnumLogFontEx.elfLogFont);
250 WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfFullName, -1,
251 EnumLogFontExA.elfFullName, LF_FULLFACESIZE, NULL, NULL);
252 WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfStyle, -1,
253 EnumLogFontExA.elfStyle, LF_FACESIZE, NULL, NULL);
254 WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfScript, -1,
255 EnumLogFontExA.elfScript, LF_FACESIZE, NULL, NULL);
256 NewTextMetricExW2A(&NewTextMetricExA,
257 &Info[i].NewTextMetricEx);
258 Ret = ((FONTENUMEXPROCA) EnumProc)(&EnumLogFontExA, &NewTextMetricExA,
259 Info[i].FontType, lParam);
260 }
261 }
262
263 RtlFreeHeap(GetProcessHeap(), 0, Info);
264
265 return Ret;
266 }
267
268 /*
269 * @implemented
270 */
271 int STDCALL
272 EnumFontFamiliesExW(HDC Dc, LPLOGFONTW LogFont, FONTENUMEXPROCW EnumFontFamProc,
273 LPARAM lParam, DWORD Flags)
274 {
275 return IntEnumFontFamilies(Dc, LogFont, EnumFontFamProc, lParam, TRUE);
276 }
277
278
279 /*
280 * @implemented
281 */
282 int STDCALL
283 EnumFontFamiliesW(HDC Dc, LPCWSTR Family, FONTENUMPROCW EnumFontFamProc,
284 LPARAM lParam)
285 {
286 LOGFONTW LogFont;
287
288 ZeroMemory(&LogFont, sizeof(LOGFONTW));
289 LogFont.lfCharSet = DEFAULT_CHARSET;
290 if (NULL != Family)
291 {
292 lstrcpynW(LogFont.lfFaceName, Family, LF_FACESIZE);
293 }
294
295 return IntEnumFontFamilies(Dc, &LogFont, EnumFontFamProc, lParam, TRUE);
296 }
297
298
299 /*
300 * @implemented
301 */
302 int STDCALL
303 EnumFontFamiliesExA (HDC Dc, LPLOGFONTA LogFont, FONTENUMEXPROCA EnumFontFamProc,
304 LPARAM lParam, DWORD dwFlags)
305 {
306 LOGFONTW LogFontW;
307
308 RosRtlLogFontA2W(&LogFontW, LogFont);
309
310 /* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */
311 return IntEnumFontFamilies(Dc, &LogFontW, EnumFontFamProc, lParam, FALSE);
312 }
313
314
315 /*
316 * @implemented
317 */
318 int STDCALL
319 EnumFontFamiliesA(HDC Dc, LPCSTR Family, FONTENUMPROCA EnumFontFamProc,
320 LPARAM lParam)
321 {
322 LOGFONTW LogFont;
323
324 ZeroMemory(&LogFont, sizeof(LOGFONTW));
325 LogFont.lfCharSet = DEFAULT_CHARSET;
326 if (NULL != Family)
327 {
328 MultiByteToWideChar(CP_THREAD_ACP, 0, Family, -1, LogFont.lfFaceName, LF_FACESIZE);
329 }
330
331 return IntEnumFontFamilies(Dc, &LogFont, EnumFontFamProc, lParam, FALSE);
332 }