- Fix compilation with GCC 4.0-20041219.
[reactos.git] / reactos / lib / gdi32 / objects / font.c
1 /* $Id: font.c,v 1.10 2004/12/25 11:18:50 navaraf 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 #include "precomp.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 #define INITIAL_FAMILY_COUNT 64
17
18 static BOOL FASTCALL
19 MetricsCharConvert(WCHAR w, UCHAR *b)
20 {
21 UNICODE_STRING WString;
22 WCHAR WBuf[2];
23 ANSI_STRING AString;
24 CHAR ABuf[2];
25 NTSTATUS Status;
26
27 if (L'\0' == w)
28 {
29 *b = '\0';
30 }
31 else
32 {
33 WBuf[0] = w;
34 WBuf[1] = L'\0';
35 RtlInitUnicodeString(&WString, WBuf);
36 ABuf[0] = '*';
37 ABuf[1] = L'\0';
38 RtlInitAnsiString(&AString, ABuf);
39
40 Status = RtlUnicodeStringToAnsiString(&AString, &WString, FALSE);
41 if (! NT_SUCCESS(Status))
42 {
43 SetLastError(RtlNtStatusToDosError(Status));
44 return FALSE;
45 }
46 *b = ABuf[0];
47 }
48
49 return TRUE;
50 }
51
52 BOOL FASTCALL
53 TextMetricW2A(TEXTMETRICA *tma, TEXTMETRICW *tmw)
54 {
55 UNICODE_STRING WString;
56 WCHAR WBuf[256];
57 ANSI_STRING AString;
58 CHAR ABuf[256];
59 UINT Letter;
60 NTSTATUS Status;
61
62 tma->tmHeight = tmw->tmHeight;
63 tma->tmAscent = tmw->tmAscent;
64 tma->tmDescent = tmw->tmDescent;
65 tma->tmInternalLeading = tmw->tmInternalLeading;
66 tma->tmExternalLeading = tmw->tmExternalLeading;
67 tma->tmAveCharWidth = tmw->tmAveCharWidth;
68 tma->tmMaxCharWidth = tmw->tmMaxCharWidth;
69 tma->tmWeight = tmw->tmWeight;
70 tma->tmOverhang = tmw->tmOverhang;
71 tma->tmDigitizedAspectX = tmw->tmDigitizedAspectX;
72 tma->tmDigitizedAspectY = tmw->tmDigitizedAspectY;
73
74 /* The Unicode FirstChar/LastChar need not correspond to the ANSI
75 FirstChar/LastChar. For example, if the font contains glyphs for
76 letters A-Z and an accented version of the letter e, the Unicode
77 FirstChar would be A and the Unicode LastChar would be the accented
78 e. If you just translate those to ANSI, the range would become
79 letters A-E instead of A-Z.
80 We translate all possible ANSI chars to Unicode and find the first
81 and last translated character which fall into the Unicode FirstChar/
82 LastChar range and return the corresponding ANSI char. */
83
84 /* Setup an Ansi string containing all possible letters (note: skip '\0' at
85 the beginning since that would be interpreted as end-of-string, handle
86 '\0' special later */
87 for (Letter = 1; Letter < 256; Letter++)
88 {
89 ABuf[Letter - 1] = (CHAR) Letter;
90 WBuf[Letter - 1] = L' ';
91 }
92 ABuf[255] = '\0';
93 WBuf[255] = L'\0';
94 RtlInitAnsiString(&AString, ABuf);
95 RtlInitUnicodeString(&WString, WBuf);
96
97 /* Find the corresponding Unicode characters */
98 Status = RtlAnsiStringToUnicodeString(&WString, &AString, FALSE);
99 if (! NT_SUCCESS(Status))
100 {
101 SetLastError(RtlNtStatusToDosError(Status));
102 return FALSE;
103 }
104
105 /* Scan for the first ANSI character which maps to an Unicode character
106 in the range */
107 tma->tmFirstChar = '\0';
108 if (L'\0' != tmw->tmFirstChar)
109 {
110 for (Letter = 1; Letter < 256; Letter++)
111 {
112 if (tmw->tmFirstChar <= WBuf[Letter - 1] &&
113 WBuf[Letter - 1] <= tmw->tmLastChar)
114 {
115 tma->tmFirstChar = (CHAR) Letter;
116 break;
117 }
118 }
119 }
120
121 /* Scan for the last ANSI character which maps to an Unicode character
122 in the range */
123 tma->tmLastChar = '\0';
124 if (L'\0' != tmw->tmLastChar)
125 {
126 for (Letter = 255; 0 < Letter; Letter--)
127 {
128 if (tmw->tmFirstChar <= WBuf[Letter - 1] &&
129 WBuf[Letter - 1] <= tmw->tmLastChar)
130 {
131 tma->tmLastChar = (CHAR) Letter;
132 break;
133 }
134 }
135 }
136
137 if (! MetricsCharConvert(tmw->tmDefaultChar, &tma->tmDefaultChar) ||
138 ! MetricsCharConvert(tmw->tmBreakChar, &tma->tmBreakChar))
139 {
140 return FALSE;
141 }
142
143 tma->tmItalic = tmw->tmItalic;
144 tma->tmUnderlined = tmw->tmUnderlined;
145 tma->tmStruckOut = tmw->tmStruckOut;
146 tma->tmPitchAndFamily = tmw->tmPitchAndFamily;
147 tma->tmCharSet = tmw->tmCharSet;
148
149 return TRUE;
150 }
151
152 BOOL FASTCALL
153 NewTextMetricW2A(NEWTEXTMETRICA *tma, NEWTEXTMETRICW *tmw)
154 {
155 if (! TextMetricW2A((TEXTMETRICA *) tma, (TEXTMETRICW *) tmw))
156 {
157 return FALSE;
158 }
159
160 tma->ntmFlags = tmw->ntmFlags;
161 tma->ntmSizeEM = tmw->ntmSizeEM;
162 tma->ntmCellHeight = tmw->ntmCellHeight;
163 tma->ntmAvgWidth = tmw->ntmAvgWidth;
164
165 return TRUE;
166 }
167
168 BOOL FASTCALL
169 NewTextMetricExW2A(NEWTEXTMETRICEXA *tma, NEWTEXTMETRICEXW *tmw)
170 {
171 if (! NewTextMetricW2A(&tma->ntmTm, &tmw->ntmTm))
172 {
173 return FALSE;
174 }
175
176 tma->ntmFontSig = tmw->ntmFontSig;
177
178 return TRUE;
179 }
180
181 /*
182 * @implemented
183 */
184 BOOL
185 STDCALL
186 TranslateCharsetInfo(DWORD *pSrc, LPCHARSETINFO lpCs, DWORD dwFlags)
187 {
188 return NtGdiTranslateCharsetInfo(pSrc, lpCs, dwFlags);
189 }
190
191 static int FASTCALL
192 IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam,
193 BOOL Unicode)
194 {
195 int FontFamilyCount;
196 unsigned FontFamilySize;
197 PFONTFAMILYINFO Info;
198 int Ret = 0;
199 unsigned i;
200 ENUMLOGFONTEXA EnumLogFontExA;
201 NEWTEXTMETRICEXA NewTextMetricExA;
202
203 Info = RtlAllocateHeap(GetProcessHeap(), 0,
204 INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO));
205 if (NULL == Info)
206 {
207 return 0;
208 }
209 FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, INITIAL_FAMILY_COUNT);
210 if (FontFamilyCount < 0)
211 {
212 RtlFreeHeap(GetProcessHeap(), 0, Info);
213 return 0;
214 }
215 if (INITIAL_FAMILY_COUNT < FontFamilyCount)
216 {
217 FontFamilySize = FontFamilyCount;
218 RtlFreeHeap(GetProcessHeap(), 0, Info);
219 Info = RtlAllocateHeap(GetProcessHeap(), 0,
220 FontFamilyCount * sizeof(FONTFAMILYINFO));
221 if (NULL == Info)
222 {
223 return 0;
224 }
225 FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, FontFamilySize);
226 if (FontFamilyCount < 0 || FontFamilySize < FontFamilyCount)
227 {
228 RtlFreeHeap(GetProcessHeap(), 0, Info);
229 return 0;
230 }
231 }
232
233 for (i = 0; i < FontFamilyCount; i++)
234 {
235 if (Unicode)
236 {
237 Ret = ((FONTENUMPROCW) EnumProc)(
238 (LPLOGFONTW)&Info[i].EnumLogFontEx,
239 (LPTEXTMETRICW)&Info[i].NewTextMetricEx,
240 Info[i].FontType, lParam);
241 }
242 else
243 {
244 RosRtlLogFontW2A(&EnumLogFontExA.elfLogFont, &Info[i].EnumLogFontEx.elfLogFont);
245 WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfFullName, -1,
246 (LPSTR)EnumLogFontExA.elfFullName, LF_FULLFACESIZE, NULL, NULL);
247 WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfStyle, -1,
248 (LPSTR)EnumLogFontExA.elfStyle, LF_FACESIZE, NULL, NULL);
249 WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfScript, -1,
250 (LPSTR)EnumLogFontExA.elfScript, LF_FACESIZE, NULL, NULL);
251 NewTextMetricExW2A(&NewTextMetricExA,
252 &Info[i].NewTextMetricEx);
253 Ret = ((FONTENUMPROCA) EnumProc)(
254 (LPLOGFONTA)&EnumLogFontExA,
255 (LPTEXTMETRICA)&NewTextMetricExA,
256 Info[i].FontType, lParam);
257 }
258 }
259
260 RtlFreeHeap(GetProcessHeap(), 0, Info);
261
262 return Ret;
263 }
264
265 /*
266 * @implemented
267 */
268 int STDCALL
269 EnumFontFamiliesExW(HDC hdc, LPLOGFONTW lpLogfont, FONTENUMPROCW lpEnumFontFamExProc,
270 LPARAM lParam, DWORD dwFlags)
271 {
272 return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam, TRUE);
273 }
274
275
276 /*
277 * @implemented
278 */
279 int STDCALL
280 EnumFontFamiliesW(HDC hdc, LPCWSTR lpszFamily, FONTENUMPROCW lpEnumFontFamProc,
281 LPARAM lParam)
282 {
283 LOGFONTW LogFont;
284
285 ZeroMemory(&LogFont, sizeof(LOGFONTW));
286 LogFont.lfCharSet = DEFAULT_CHARSET;
287 if (NULL != lpszFamily)
288 {
289 lstrcpynW(LogFont.lfFaceName, lpszFamily, LF_FACESIZE);
290 }
291
292 return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, TRUE);
293 }
294
295
296 /*
297 * @implemented
298 */
299 int STDCALL
300 EnumFontFamiliesExA (HDC hdc, LPLOGFONTA lpLogfont, FONTENUMPROCA lpEnumFontFamExProc,
301 LPARAM lParam, DWORD dwFlags)
302 {
303 LOGFONTW LogFontW;
304
305 RosRtlLogFontA2W(&LogFontW, lpLogfont);
306
307 /* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */
308 return IntEnumFontFamilies(hdc, &LogFontW, lpEnumFontFamExProc, lParam, FALSE);
309 }
310
311
312 /*
313 * @implemented
314 */
315 int STDCALL
316 EnumFontFamiliesA(HDC hdc, LPCSTR lpszFamily, FONTENUMPROCA lpEnumFontFamProc,
317 LPARAM lParam)
318 {
319 LOGFONTW LogFont;
320
321 ZeroMemory(&LogFont, sizeof(LOGFONTW));
322 LogFont.lfCharSet = DEFAULT_CHARSET;
323 if (NULL != lpszFamily)
324 {
325 MultiByteToWideChar(CP_THREAD_ACP, 0, lpszFamily, -1, LogFont.lfFaceName, LF_FACESIZE);
326 }
327
328 return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, FALSE);
329 }
330
331
332 /*
333 * @implemented
334 */
335 BOOL
336 STDCALL
337 GetCharWidthA (
338 HDC hdc,
339 UINT iFirstChar,
340 UINT iLastChar,
341 LPINT lpBuffer
342 )
343 {
344 /* FIXME what to do with iFirstChar and iLastChar ??? */
345 return NtGdiGetCharWidth32 ( hdc, iFirstChar, iLastChar, lpBuffer );
346 }
347
348
349 /*
350 * @implemented
351 */
352 BOOL
353 STDCALL
354 GetCharWidth32A(
355 HDC hdc,
356 UINT iFirstChar,
357 UINT iLastChar,
358 LPINT lpBuffer
359 )
360 {
361 /* FIXME what to do with iFirstChar and iLastChar ??? */
362 return NtGdiGetCharWidth32 ( hdc, iFirstChar, iLastChar, lpBuffer );
363 }
364
365
366 /*
367 * @implemented
368 */
369 BOOL
370 STDCALL
371 GetCharWidthW (
372 HDC hdc,
373 UINT iFirstChar,
374 UINT iLastChar,
375 LPINT lpBuffer
376 )
377 {
378 return NtGdiGetCharWidth32 ( hdc, iFirstChar, iLastChar, lpBuffer );
379 }
380
381
382 /*
383 * @implemented
384 */
385 BOOL
386 STDCALL
387 GetCharWidth32W(
388 HDC hdc,
389 UINT iFirstChar,
390 UINT iLastChar,
391 LPINT lpBuffer
392 )
393 {
394 return NtGdiGetCharWidth32 ( hdc, iFirstChar, iLastChar, lpBuffer );
395 }
396
397
398 /*
399 * @implemented
400 */
401 DWORD
402 STDCALL
403 GetFontData(
404 HDC a0,
405 DWORD a1,
406 DWORD a2,
407 LPVOID a3,
408 DWORD a4
409 )
410 {
411 return NtGdiGetFontData(a0, a1, a2, a3, a4);
412 }
413
414
415 /*
416 * @implemented
417 */
418 DWORD
419 STDCALL
420 GetCharacterPlacementW(
421 HDC hdc,
422 LPCWSTR lpString,
423 INT uCount,
424 INT nMaxExtent,
425 GCP_RESULTSW *lpResults,
426 DWORD dwFlags
427 )
428 {
429 DWORD ret=0;
430 SIZE size;
431 UINT i, nSet;
432
433 if(dwFlags&(~GCP_REORDER)) DPRINT("flags 0x%08lx ignored\n", dwFlags);
434 if(lpResults->lpClass) DPRINT("classes not implemented\n");
435 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
436 DPRINT("Caret positions for complex scripts not implemented\n");
437
438 nSet = (UINT)uCount;
439 if(nSet > lpResults->nGlyphs)
440 nSet = lpResults->nGlyphs;
441
442 /* return number of initialized fields */
443 lpResults->nGlyphs = nSet;
444
445 /*if((dwFlags&GCP_REORDER)==0 || !BidiAvail)
446 {*/
447 /* Treat the case where no special handling was requested in a fastpath way */
448 /* copy will do if the GCP_REORDER flag is not set */
449 if(lpResults->lpOutString)
450 strncpyW( lpResults->lpOutString, lpString, nSet );
451
452 if(lpResults->lpGlyphs)
453 strncpyW( lpResults->lpGlyphs, lpString, nSet );
454
455 if(lpResults->lpOrder)
456 {
457 for(i = 0; i < nSet; i++)
458 lpResults->lpOrder[i] = i;
459 }
460 /*} else
461 {
462 BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
463 nSet, lpResults->lpOrder );
464 }*/
465
466 /* FIXME: Will use the placement chars */
467 if (lpResults->lpDx)
468 {
469 int c;
470 for (i = 0; i < nSet; i++)
471 {
472 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
473 lpResults->lpDx[i]= c;
474 }
475 }
476
477 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
478 {
479 int pos = 0;
480
481 lpResults->lpCaretPos[0] = 0;
482 for (i = 1; i < nSet; i++)
483 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
484 lpResults->lpCaretPos[i] = (pos += size.cx);
485 }
486
487 /*if(lpResults->lpGlyphs)
488 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);*/
489
490 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
491 ret = MAKELONG(size.cx, size.cy);
492
493 return ret;
494 }