Win32/Gdi32:
[reactos.git] / reactos / dll / win32 / gdi32 / objects / font.c
1 /* $Id$
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 /***********************************************************************
19 * TEXTMETRIC conversion functions.
20 */
21 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
22 {
23 ptmA->tmHeight = ptmW->tmHeight;
24 ptmA->tmAscent = ptmW->tmAscent;
25 ptmA->tmDescent = ptmW->tmDescent;
26 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
27 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
28 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
29 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
30 ptmA->tmWeight = ptmW->tmWeight;
31 ptmA->tmOverhang = ptmW->tmOverhang;
32 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
33 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
34 ptmA->tmFirstChar = ptmW->tmFirstChar > 255 ? 255 : ptmW->tmFirstChar;
35 ptmA->tmLastChar = ptmW->tmLastChar > 255 ? 255 : ptmW->tmLastChar;
36 ptmA->tmDefaultChar = ptmW->tmDefaultChar > 255 ? 255 : ptmW->tmDefaultChar;
37 ptmA->tmBreakChar = ptmW->tmBreakChar > 255 ? 255 : ptmW->tmBreakChar;
38 ptmA->tmItalic = ptmW->tmItalic;
39 ptmA->tmUnderlined = ptmW->tmUnderlined;
40 ptmA->tmStruckOut = ptmW->tmStruckOut;
41 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
42 ptmA->tmCharSet = ptmW->tmCharSet;
43 }
44
45 /***********************************************************************
46 * FONT_mbtowc
47 *
48 * Returns a Unicode translation of str. If count is -1 then str is
49 * assumed to be '\0' terminated, otherwise it contains the number of
50 * bytes to convert. If plenW is non-NULL, on return it will point to
51 * the number of WCHARs that have been written. The caller should free
52 * the returned LPWSTR from the process heap itself.
53 */
54 static LPWSTR FONT_mbtowc(LPCSTR str, INT count, INT *plenW)
55 {
56 UINT cp = CP_ACP;
57 INT lenW;
58 LPWSTR strW;
59
60 if(count == -1) count = strlen(str);
61 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
62 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
63 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
64 DPRINT1("mapped %s -> %s \n", str, strW);
65 if(plenW) *plenW = lenW;
66 return strW;
67 }
68
69
70 static BOOL FASTCALL
71 MetricsCharConvert(WCHAR w, UCHAR *b)
72 {
73 UNICODE_STRING WString;
74 WCHAR WBuf[2];
75 ANSI_STRING AString;
76 CHAR ABuf[2];
77 NTSTATUS Status;
78
79 if (L'\0' == w)
80 {
81 *b = '\0';
82 }
83 else
84 {
85 WBuf[0] = w;
86 WBuf[1] = L'\0';
87 RtlInitUnicodeString(&WString, WBuf);
88 ABuf[0] = '*';
89 ABuf[1] = L'\0';
90 RtlInitAnsiString(&AString, ABuf);
91
92 Status = RtlUnicodeStringToAnsiString(&AString, &WString, FALSE);
93 if (! NT_SUCCESS(Status))
94 {
95 SetLastError(RtlNtStatusToDosError(Status));
96 return FALSE;
97 }
98 *b = ABuf[0];
99 }
100
101 return TRUE;
102 }
103
104 BOOL FASTCALL
105 TextMetricW2A(TEXTMETRICA *tma, TEXTMETRICW *tmw)
106 {
107 UNICODE_STRING WString;
108 WCHAR WBuf[256];
109 ANSI_STRING AString;
110 CHAR ABuf[256];
111 UINT Letter;
112 NTSTATUS Status;
113
114 tma->tmHeight = tmw->tmHeight;
115 tma->tmAscent = tmw->tmAscent;
116 tma->tmDescent = tmw->tmDescent;
117 tma->tmInternalLeading = tmw->tmInternalLeading;
118 tma->tmExternalLeading = tmw->tmExternalLeading;
119 tma->tmAveCharWidth = tmw->tmAveCharWidth;
120 tma->tmMaxCharWidth = tmw->tmMaxCharWidth;
121 tma->tmWeight = tmw->tmWeight;
122 tma->tmOverhang = tmw->tmOverhang;
123 tma->tmDigitizedAspectX = tmw->tmDigitizedAspectX;
124 tma->tmDigitizedAspectY = tmw->tmDigitizedAspectY;
125
126 /* The Unicode FirstChar/LastChar need not correspond to the ANSI
127 FirstChar/LastChar. For example, if the font contains glyphs for
128 letters A-Z and an accented version of the letter e, the Unicode
129 FirstChar would be A and the Unicode LastChar would be the accented
130 e. If you just translate those to ANSI, the range would become
131 letters A-E instead of A-Z.
132 We translate all possible ANSI chars to Unicode and find the first
133 and last translated character which fall into the Unicode FirstChar/
134 LastChar range and return the corresponding ANSI char. */
135
136 /* Setup an Ansi string containing all possible letters (note: skip '\0' at
137 the beginning since that would be interpreted as end-of-string, handle
138 '\0' special later */
139 for (Letter = 1; Letter < 256; Letter++)
140 {
141 ABuf[Letter - 1] = (CHAR) Letter;
142 WBuf[Letter - 1] = L' ';
143 }
144 ABuf[255] = '\0';
145 WBuf[255] = L'\0';
146 RtlInitAnsiString(&AString, ABuf);
147 RtlInitUnicodeString(&WString, WBuf);
148
149 /* Find the corresponding Unicode characters */
150 Status = RtlAnsiStringToUnicodeString(&WString, &AString, FALSE);
151 if (! NT_SUCCESS(Status))
152 {
153 SetLastError(RtlNtStatusToDosError(Status));
154 return FALSE;
155 }
156
157 /* Scan for the first ANSI character which maps to an Unicode character
158 in the range */
159 tma->tmFirstChar = '\0';
160 if (L'\0' != tmw->tmFirstChar)
161 {
162 for (Letter = 1; Letter < 256; Letter++)
163 {
164 if (tmw->tmFirstChar <= WBuf[Letter - 1] &&
165 WBuf[Letter - 1] <= tmw->tmLastChar)
166 {
167 tma->tmFirstChar = (CHAR) Letter;
168 break;
169 }
170 }
171 }
172
173 /* Scan for the last ANSI character which maps to an Unicode character
174 in the range */
175 tma->tmLastChar = '\0';
176 if (L'\0' != tmw->tmLastChar)
177 {
178 for (Letter = 255; 0 < Letter; Letter--)
179 {
180 if (tmw->tmFirstChar <= WBuf[Letter - 1] &&
181 WBuf[Letter - 1] <= tmw->tmLastChar)
182 {
183 tma->tmLastChar = (CHAR) Letter;
184 break;
185 }
186 }
187 }
188
189 if (! MetricsCharConvert(tmw->tmDefaultChar, &tma->tmDefaultChar) ||
190 ! MetricsCharConvert(tmw->tmBreakChar, &tma->tmBreakChar))
191 {
192 return FALSE;
193 }
194
195 tma->tmItalic = tmw->tmItalic;
196 tma->tmUnderlined = tmw->tmUnderlined;
197 tma->tmStruckOut = tmw->tmStruckOut;
198 tma->tmPitchAndFamily = tmw->tmPitchAndFamily;
199 tma->tmCharSet = tmw->tmCharSet;
200
201 return TRUE;
202 }
203
204 BOOL FASTCALL
205 NewTextMetricW2A(NEWTEXTMETRICA *tma, NEWTEXTMETRICW *tmw)
206 {
207 if (! TextMetricW2A((TEXTMETRICA *) tma, (TEXTMETRICW *) tmw))
208 {
209 return FALSE;
210 }
211
212 tma->ntmFlags = tmw->ntmFlags;
213 tma->ntmSizeEM = tmw->ntmSizeEM;
214 tma->ntmCellHeight = tmw->ntmCellHeight;
215 tma->ntmAvgWidth = tmw->ntmAvgWidth;
216
217 return TRUE;
218 }
219
220 BOOL FASTCALL
221 NewTextMetricExW2A(NEWTEXTMETRICEXA *tma, NEWTEXTMETRICEXW *tmw)
222 {
223 if (! NewTextMetricW2A(&tma->ntmTm, &tmw->ntmTm))
224 {
225 return FALSE;
226 }
227
228 tma->ntmFontSig = tmw->ntmFontSig;
229
230 return TRUE;
231 }
232
233 static int FASTCALL
234 IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam,
235 BOOL Unicode)
236 {
237 int FontFamilyCount;
238 int FontFamilySize;
239 PFONTFAMILYINFO Info;
240 int Ret = 0;
241 int i;
242 ENUMLOGFONTEXA EnumLogFontExA;
243 NEWTEXTMETRICEXA NewTextMetricExA;
244
245 Info = RtlAllocateHeap(GetProcessHeap(), 0,
246 INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO));
247 if (NULL == Info)
248 {
249 return 0;
250 }
251 FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, INITIAL_FAMILY_COUNT);
252 if (FontFamilyCount < 0)
253 {
254 RtlFreeHeap(GetProcessHeap(), 0, Info);
255 return 0;
256 }
257 if (INITIAL_FAMILY_COUNT < FontFamilyCount)
258 {
259 FontFamilySize = FontFamilyCount;
260 RtlFreeHeap(GetProcessHeap(), 0, Info);
261 Info = RtlAllocateHeap(GetProcessHeap(), 0,
262 FontFamilyCount * sizeof(FONTFAMILYINFO));
263 if (NULL == Info)
264 {
265 return 0;
266 }
267 FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, FontFamilySize);
268 if (FontFamilyCount < 0 || FontFamilySize < FontFamilyCount)
269 {
270 RtlFreeHeap(GetProcessHeap(), 0, Info);
271 return 0;
272 }
273 }
274
275 for (i = 0; i < FontFamilyCount; i++)
276 {
277 if (Unicode)
278 {
279 Ret = ((FONTENUMPROCW) EnumProc)(
280 &Info[i].EnumLogFontEx,
281 &Info[i].NewTextMetricEx,
282 Info[i].FontType, lParam);
283 }
284 else
285 { // Could use EnumLogFontExW2A here?
286 LogFontW2A(&EnumLogFontExA.elfLogFont, &Info[i].EnumLogFontEx.elfLogFont);
287 WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfFullName, -1,
288 (LPSTR)EnumLogFontExA.elfFullName, LF_FULLFACESIZE, NULL, NULL);
289 WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfStyle, -1,
290 (LPSTR)EnumLogFontExA.elfStyle, LF_FACESIZE, NULL, NULL);
291 WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfScript, -1,
292 (LPSTR)EnumLogFontExA.elfScript, LF_FACESIZE, NULL, NULL);
293 NewTextMetricExW2A(&NewTextMetricExA,
294 &Info[i].NewTextMetricEx);
295 Ret = ((FONTENUMPROCA) EnumProc)(
296 &EnumLogFontExA,
297 &NewTextMetricExA,
298 Info[i].FontType, lParam);
299 }
300 }
301
302 RtlFreeHeap(GetProcessHeap(), 0, Info);
303
304 return Ret;
305 }
306
307 /*
308 * @implemented
309 */
310 int STDCALL
311 EnumFontFamiliesExW(HDC hdc, LPLOGFONTW lpLogfont, FONTENUMPROCW lpEnumFontFamExProc,
312 LPARAM lParam, DWORD dwFlags)
313 {
314 return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam, TRUE);
315 }
316
317
318 /*
319 * @implemented
320 */
321 int STDCALL
322 EnumFontFamiliesW(HDC hdc, LPCWSTR lpszFamily, FONTENUMPROCW lpEnumFontFamProc,
323 LPARAM lParam)
324 {
325 LOGFONTW LogFont;
326
327 ZeroMemory(&LogFont, sizeof(LOGFONTW));
328 LogFont.lfCharSet = DEFAULT_CHARSET;
329 if (NULL != lpszFamily)
330 {
331 lstrcpynW(LogFont.lfFaceName, lpszFamily, LF_FACESIZE);
332 }
333
334 return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, TRUE);
335 }
336
337
338 /*
339 * @implemented
340 */
341 int STDCALL
342 EnumFontFamiliesExA (HDC hdc, LPLOGFONTA lpLogfont, FONTENUMPROCA lpEnumFontFamExProc,
343 LPARAM lParam, DWORD dwFlags)
344 {
345 LOGFONTW LogFontW;
346
347 LogFontA2W(&LogFontW, lpLogfont);
348
349 /* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */
350 return IntEnumFontFamilies(hdc, &LogFontW, lpEnumFontFamExProc, lParam, FALSE);
351 }
352
353
354 /*
355 * @implemented
356 */
357 int STDCALL
358 EnumFontFamiliesA(HDC hdc, LPCSTR lpszFamily, FONTENUMPROCA lpEnumFontFamProc,
359 LPARAM lParam)
360 {
361 LOGFONTW LogFont;
362
363 ZeroMemory(&LogFont, sizeof(LOGFONTW));
364 LogFont.lfCharSet = DEFAULT_CHARSET;
365 if (NULL != lpszFamily)
366 {
367 MultiByteToWideChar(CP_THREAD_ACP, 0, lpszFamily, -1, LogFont.lfFaceName, LF_FACESIZE);
368 }
369
370 return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, FALSE);
371 }
372
373
374 /*
375 * @implemented
376 */
377 BOOL
378 STDCALL
379 GetCharWidthA (
380 HDC hdc,
381 UINT iFirstChar,
382 UINT iLastChar,
383 LPINT lpBuffer
384 )
385 {
386 DPRINT1("GCWA iFirstChar %x\n",iFirstChar);
387
388 return GetCharWidth32A ( hdc, iFirstChar, iLastChar, lpBuffer );
389 }
390
391
392 /*
393 * @implemented
394 */
395 BOOL
396 STDCALL
397 GetCharWidth32A(
398 HDC hdc,
399 UINT iFirstChar,
400 UINT iLastChar,
401 LPINT lpBuffer
402 )
403 {
404 INT i, wlen, count = (INT)(iLastChar - iFirstChar + 1);
405 LPSTR str;
406 LPWSTR wstr;
407 BOOL ret = TRUE;
408 DPRINT1("GCW32A iFirstChar %x\n",iFirstChar);
409
410 if(count <= 0) return FALSE;
411
412 str = HeapAlloc(GetProcessHeap(), 0, count);
413 for(i = 0; i < count; i++)
414 str[i] = (BYTE)(iFirstChar + i);
415
416 wstr = FONT_mbtowc(str, count, &wlen);
417
418 for(i = 0; i < wlen; i++)
419 {
420 /* FIXME should be NtGdiGetCharWidthW */
421 if(!NtGdiGetCharWidth32 (hdc, wstr[i], wstr[i], lpBuffer))
422 {
423 ret = FALSE;
424 break;
425 }
426 lpBuffer++;
427 }
428
429 HeapFree(GetProcessHeap(), 0, str);
430 HeapFree(GetProcessHeap(), 0, wstr);
431
432 return ret;
433 }
434
435
436 /*
437 * @implemented
438 */
439 BOOL
440 STDCALL
441 GetCharWidthW (
442 HDC hdc,
443 UINT iFirstChar,
444 UINT iLastChar,
445 LPINT lpBuffer
446 )
447 {
448 DPRINT1("GCW32w uFirstChar %x\n",iFirstChar);
449
450 /* FIXME should be NtGdiGetCharWidthW */
451 return NtGdiGetCharWidth32 ( hdc, iFirstChar, iLastChar, lpBuffer );
452 }
453
454
455 /*
456 * @implemented
457 */
458 DWORD
459 STDCALL
460 GetCharacterPlacementW(
461 HDC hdc,
462 LPCWSTR lpString,
463 INT uCount,
464 INT nMaxExtent,
465 GCP_RESULTSW *lpResults,
466 DWORD dwFlags
467 )
468 {
469 DWORD ret=0;
470 SIZE size;
471 UINT i, nSet;
472
473 if(dwFlags&(~GCP_REORDER)) DPRINT("flags 0x%08lx ignored\n", dwFlags);
474 if(lpResults->lpClass) DPRINT("classes not implemented\n");
475 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
476 DPRINT("Caret positions for complex scripts not implemented\n");
477
478 nSet = (UINT)uCount;
479 if(nSet > lpResults->nGlyphs)
480 nSet = lpResults->nGlyphs;
481
482 /* return number of initialized fields */
483 lpResults->nGlyphs = nSet;
484
485 /*if((dwFlags&GCP_REORDER)==0 || !BidiAvail)
486 {*/
487 /* Treat the case where no special handling was requested in a fastpath way */
488 /* copy will do if the GCP_REORDER flag is not set */
489 if(lpResults->lpOutString)
490 lstrcpynW( lpResults->lpOutString, lpString, nSet );
491
492 if(lpResults->lpGlyphs)
493 lstrcpynW( lpResults->lpGlyphs, lpString, nSet );
494
495 if(lpResults->lpOrder)
496 {
497 for(i = 0; i < nSet; i++)
498 lpResults->lpOrder[i] = i;
499 }
500 /*} else
501 {
502 BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
503 nSet, lpResults->lpOrder );
504 }*/
505
506 /* FIXME: Will use the placement chars */
507 if (lpResults->lpDx)
508 {
509 int c;
510 for (i = 0; i < nSet; i++)
511 {
512 if (NtGdiGetCharWidth32(hdc, lpString[i], lpString[i], &c))
513 lpResults->lpDx[i]= c;
514 }
515 }
516
517 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
518 {
519 int pos = 0;
520
521 lpResults->lpCaretPos[0] = 0;
522 for (i = 1; i < nSet; i++)
523 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
524 lpResults->lpCaretPos[i] = (pos += size.cx);
525 }
526
527 /*if(lpResults->lpGlyphs)
528 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);*/
529
530 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
531 ret = MAKELONG(size.cx, size.cy);
532
533 return ret;
534 }
535
536
537 /*
538 * @unimplemented
539 */
540 BOOL
541 APIENTRY
542 GetCharWidthFloatA(
543 HDC hdc,
544 UINT iFirstChar,
545 UINT iLastChar,
546 PFLOAT pxBuffer
547 )
548 {
549 /* FIXME what to do with iFirstChar and iLastChar ??? */
550 return NtGdiGetCharWidthFloat ( hdc, iFirstChar, iLastChar, pxBuffer );
551 }
552
553
554 /*
555 * @implemented
556 */
557 BOOL
558 APIENTRY
559 GetCharABCWidthsA(
560 HDC hdc,
561 UINT uFirstChar,
562 UINT uLastChar,
563 LPABC lpabc
564 )
565 {
566 DPRINT1("GCABCWA uFirstChar %x\n",uFirstChar);
567
568 return NtGdiGetCharABCWidths(hdc, uFirstChar, uLastChar, lpabc);
569 }
570
571
572 /*
573 * @unimplemented
574 */
575 BOOL
576 APIENTRY
577 GetCharABCWidthsFloatA(
578 HDC hdc,
579 UINT iFirstChar,
580 UINT iLastChar,
581 LPABCFLOAT lpABCF
582 )
583 {
584 DPRINT1("GCABCWFA iFirstChar %x\n",iFirstChar);
585
586 /* FIXME what to do with iFirstChar and iLastChar ??? */
587 return NtGdiGetCharABCWidthsFloat ( hdc, iFirstChar, iLastChar, lpABCF );
588 }
589
590
591 /*
592 * @implemented
593 */
594 DWORD
595 STDCALL
596 GetGlyphOutlineA(
597 HDC hdc,
598 UINT uChar,
599 UINT uFormat,
600 LPGLYPHMETRICS lpgm,
601 DWORD cbBuffer,
602 LPVOID lpvBuffer,
603 CONST MAT2 *lpmat2
604 )
605 {
606
607 LPWSTR p = NULL;
608 DWORD ret;
609 UINT c;
610 DPRINT1("GetGlyphOutlineA uChar %x\n", uChar);
611 if(!(uFormat & GGO_GLYPH_INDEX)) {
612 int len;
613 char mbchs[2];
614 if(uChar > 0xff) { /* but, 2 bytes character only */
615 len = 2;
616 mbchs[0] = (uChar & 0xff00) >> 8;
617 mbchs[1] = (uChar & 0xff);
618 } else {
619 len = 1;
620 mbchs[0] = (uChar & 0xff);
621 }
622 p = FONT_mbtowc(mbchs, len, NULL);
623 c = p[0];
624 } else
625 c = uChar;
626 ret = NtGdiGetGlyphOutline(hdc, c, uFormat, lpgm, cbBuffer, lpvBuffer, (CONST LPMAT2)lpmat2, TRUE);
627 HeapFree(GetProcessHeap(), 0, p);
628 return ret;
629 }
630
631
632 /*
633 * @implemented
634 */
635 DWORD
636 STDCALL
637 GetGlyphOutlineW(
638 HDC hdc,
639 UINT uChar,
640 UINT uFormat,
641 LPGLYPHMETRICS lpgm,
642 DWORD cbBuffer,
643 LPVOID lpvBuffer,
644 CONST MAT2 *lpmat2
645 )
646 {
647 DPRINT1("GetGlyphOutlineW uChar %x\n", uChar);
648 return NtGdiGetGlyphOutline ( hdc, uChar, uFormat, lpgm, cbBuffer, lpvBuffer, (CONST LPMAT2)lpmat2, TRUE);
649 }
650
651
652 /*
653 * @implemented
654 */
655 UINT
656 APIENTRY
657 GetOutlineTextMetricsA(
658 HDC hdc,
659 UINT cbData,
660 LPOUTLINETEXTMETRICA lpOTM
661 )
662 {
663 char buf[512], *ptr;
664 UINT ret, needed;
665 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
666 OUTLINETEXTMETRICA *output = lpOTM;
667 INT left, len;
668
669 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
670 return 0;
671 if(ret > sizeof(buf))
672 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
673 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
674
675 needed = sizeof(OUTLINETEXTMETRICA);
676 if(lpOTMW->otmpFamilyName)
677 needed += WideCharToMultiByte(CP_ACP, 0,
678 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFamilyName), -1,
679 NULL, 0, NULL, NULL);
680 if(lpOTMW->otmpFaceName)
681 needed += WideCharToMultiByte(CP_ACP, 0,
682 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFaceName), -1,
683 NULL, 0, NULL, NULL);
684 if(lpOTMW->otmpStyleName)
685 needed += WideCharToMultiByte(CP_ACP, 0,
686 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpStyleName), -1,
687 NULL, 0, NULL, NULL);
688 if(lpOTMW->otmpFullName)
689 needed += WideCharToMultiByte(CP_ACP, 0,
690 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFullName), -1,
691 NULL, 0, NULL, NULL);
692
693 if(!lpOTM) {
694 ret = needed;
695 goto end;
696 }
697
698 DPRINT("needed = %d\n", needed);
699 if(needed > cbData)
700 /* Since the supplied buffer isn't big enough, we'll alloc one
701 that is and memcpy the first cbData bytes into the lpOTM at
702 the end. */
703 output = HeapAlloc(GetProcessHeap(), 0, needed);
704
705 ret = output->otmSize = min(needed, cbData);
706 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
707 output->otmFiller = 0;
708 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
709 output->otmfsSelection = lpOTMW->otmfsSelection;
710 output->otmfsType = lpOTMW->otmfsType;
711 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
712 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
713 output->otmItalicAngle = lpOTMW->otmItalicAngle;
714 output->otmEMSquare = lpOTMW->otmEMSquare;
715 output->otmAscent = lpOTMW->otmAscent;
716 output->otmDescent = lpOTMW->otmDescent;
717 output->otmLineGap = lpOTMW->otmLineGap;
718 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
719 output->otmsXHeight = lpOTMW->otmsXHeight;
720 output->otmrcFontBox = lpOTMW->otmrcFontBox;
721 output->otmMacAscent = lpOTMW->otmMacAscent;
722 output->otmMacDescent = lpOTMW->otmMacDescent;
723 output->otmMacLineGap = lpOTMW->otmMacLineGap;
724 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
725 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
726 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
727 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
728 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
729 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
730 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
731 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
732 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
733
734
735 ptr = (char*)(output + 1);
736 left = needed - sizeof(*output);
737
738 if(lpOTMW->otmpFamilyName) {
739 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
740 len = WideCharToMultiByte(CP_ACP, 0,
741 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFamilyName), -1,
742 ptr, left, NULL, NULL);
743 left -= len;
744 ptr += len;
745 } else
746 output->otmpFamilyName = 0;
747
748 if(lpOTMW->otmpFaceName) {
749 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
750 len = WideCharToMultiByte(CP_ACP, 0,
751 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFaceName), -1,
752 ptr, left, NULL, NULL);
753 left -= len;
754 ptr += len;
755 } else
756 output->otmpFaceName = 0;
757
758 if(lpOTMW->otmpStyleName) {
759 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
760 len = WideCharToMultiByte(CP_ACP, 0,
761 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpStyleName), -1,
762 ptr, left, NULL, NULL);
763 left -= len;
764 ptr += len;
765 } else
766 output->otmpStyleName = 0;
767
768 if(lpOTMW->otmpFullName) {
769 output->otmpFullName = (LPSTR)(ptr - (char*)output);
770 len = WideCharToMultiByte(CP_ACP, 0,
771 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFullName), -1,
772 ptr, left, NULL, NULL);
773 left -= len;
774 } else
775 output->otmpFullName = 0;
776
777 assert(left == 0);
778
779 if(output != lpOTM) {
780 memcpy(lpOTM, output, cbData);
781 HeapFree(GetProcessHeap(), 0, output);
782
783 /* check if the string offsets really fit into the provided size */
784 /* FIXME: should we check string length as well? */
785 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
786 lpOTM->otmpFamilyName = 0; /* doesn't fit */
787
788 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
789 lpOTM->otmpFaceName = 0; /* doesn't fit */
790
791 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
792 lpOTM->otmpStyleName = 0; /* doesn't fit */
793
794 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
795 lpOTM->otmpFullName = 0; /* doesn't fit */
796 }
797
798 end:
799 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
800 HeapFree(GetProcessHeap(), 0, lpOTMW);
801
802 return ret;
803 }
804
805
806 /*
807 * @implemented
808 */
809 UINT
810 APIENTRY
811 GetOutlineTextMetricsW(
812 HDC hdc,
813 UINT cbData,
814 LPOUTLINETEXTMETRICW lpOTM
815 )
816 {
817 TMDIFF Tmd; // Should not be zero.
818
819 return NtGdiGetOutlineTextMetricsInternalW(hdc, cbData, lpOTM, &Tmd);
820 }
821
822
823 /*
824 * @implemented
825 */
826 HFONT
827 STDCALL
828 CreateFontIndirectA(
829 CONST LOGFONTA *lplf
830 )
831 {
832 if (lplf)
833 {
834 LOGFONTW tlf;
835
836 LogFontA2W(&tlf, lplf);
837 return CreateFontIndirectW(&tlf);
838 }
839 else return NULL;
840 }
841
842
843 /*
844 * @implemented
845 */
846 HFONT
847 STDCALL
848 CreateFontIndirectW(
849 CONST LOGFONTW *lplf
850 )
851 {
852 if (lplf)
853 {
854 ENUMLOGFONTEXDVW Logfont;
855
856 RtlCopyMemory( &Logfont.elfEnumLogfontEx.elfLogFont, lplf, sizeof(LOGFONTW));
857 // Need something other than just cleaning memory here.
858 // Guess? Use caller data to determine the rest.
859 RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfFullName,
860 sizeof(Logfont.elfEnumLogfontEx.elfFullName));
861 RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfStyle,
862 sizeof(Logfont.elfEnumLogfontEx.elfStyle));
863 RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfScript,
864 sizeof(Logfont.elfEnumLogfontEx.elfScript));
865
866 RtlZeroMemory( &Logfont.elfDesignVector, sizeof(DESIGNVECTOR));
867
868 return CreateFontIndirectExW(&Logfont);
869 }
870 else return NULL;
871 }
872
873
874 /*
875 * @implemented
876 */
877 HFONT
878 STDCALL
879 CreateFontA(
880 int nHeight,
881 int nWidth,
882 int nEscapement,
883 int nOrientation,
884 int fnWeight,
885 DWORD fdwItalic,
886 DWORD fdwUnderline,
887 DWORD fdwStrikeOut,
888 DWORD fdwCharSet,
889 DWORD fdwOutputPrecision,
890 DWORD fdwClipPrecision,
891 DWORD fdwQuality,
892 DWORD fdwPitchAndFamily,
893 LPCSTR lpszFace
894 )
895 {
896 ANSI_STRING StringA;
897 UNICODE_STRING StringU;
898 HFONT ret;
899
900 RtlInitAnsiString(&StringA, (LPSTR)lpszFace);
901 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
902
903 ret = CreateFontW(nHeight,
904 nWidth,
905 nEscapement,
906 nOrientation,
907 fnWeight,
908 fdwItalic,
909 fdwUnderline,
910 fdwStrikeOut,
911 fdwCharSet,
912 fdwOutputPrecision,
913 fdwClipPrecision,
914 fdwQuality,
915 fdwPitchAndFamily,
916 StringU.Buffer);
917
918 RtlFreeUnicodeString(&StringU);
919
920 return ret;
921 }
922
923
924 /*
925 * @implemented
926 */
927 HFONT
928 STDCALL
929 CreateFontW(
930 int nHeight,
931 int nWidth,
932 int nEscapement,
933 int nOrientation,
934 int nWeight,
935 DWORD fnItalic,
936 DWORD fdwUnderline,
937 DWORD fdwStrikeOut,
938 DWORD fdwCharSet,
939 DWORD fdwOutputPrecision,
940 DWORD fdwClipPrecision,
941 DWORD fdwQuality,
942 DWORD fdwPitchAndFamily,
943 LPCWSTR lpszFace
944 )
945 {
946 LOGFONTW logfont;
947
948 logfont.lfHeight = nHeight;
949 logfont.lfWidth = nWidth;
950 logfont.lfEscapement = nEscapement;
951 logfont.lfOrientation = nOrientation;
952 logfont.lfWeight = nWeight;
953 logfont.lfItalic = fnItalic;
954 logfont.lfUnderline = fdwUnderline;
955 logfont.lfStrikeOut = fdwStrikeOut;
956 logfont.lfCharSet = fdwCharSet;
957 logfont.lfOutPrecision = fdwOutputPrecision;
958 logfont.lfClipPrecision = fdwClipPrecision;
959 logfont.lfQuality = fdwQuality;
960 logfont.lfPitchAndFamily = fdwPitchAndFamily;
961
962 if (NULL != lpszFace)
963 {
964 int Size = sizeof(logfont.lfFaceName) / sizeof(WCHAR);
965 wcsncpy((wchar_t *)logfont.lfFaceName, lpszFace, Size - 1);
966 /* Be 101% sure to have '\0' at end of string */
967 logfont.lfFaceName[Size - 1] = '\0';
968 }
969 else
970 {
971 logfont.lfFaceName[0] = L'\0';
972 }
973
974 return CreateFontIndirectW(&logfont);
975 }
976
977
978 /*
979 * @implemented
980 */
981 BOOL
982 STDCALL
983 CreateScalableFontResourceW(
984 DWORD fdwHidden,
985 LPCWSTR lpszFontRes,
986 LPCWSTR lpszFontFile,
987 LPCWSTR lpszCurrentPath
988 )
989 {
990 return NtGdiCreateScalableFontResource ( fdwHidden,
991 lpszFontRes,
992 lpszFontFile,
993 lpszCurrentPath );
994 }
995
996
997 /*
998 * @implemented
999 */
1000 BOOL
1001 STDCALL
1002 CreateScalableFontResourceA(
1003 DWORD fdwHidden,
1004 LPCSTR lpszFontRes,
1005 LPCSTR lpszFontFile,
1006 LPCSTR lpszCurrentPath
1007 )
1008 {
1009 NTSTATUS Status;
1010 LPWSTR lpszFontResW, lpszFontFileW, lpszCurrentPathW;
1011 BOOL rc = FALSE;
1012
1013 Status = HEAP_strdupA2W ( &lpszFontResW, lpszFontRes );
1014 if (!NT_SUCCESS (Status))
1015 SetLastError (RtlNtStatusToDosError(Status));
1016 else
1017 {
1018 Status = HEAP_strdupA2W ( &lpszFontFileW, lpszFontFile );
1019 if (!NT_SUCCESS (Status))
1020 SetLastError (RtlNtStatusToDosError(Status));
1021 else
1022 {
1023 Status = HEAP_strdupA2W ( &lpszCurrentPathW, lpszCurrentPath );
1024 if (!NT_SUCCESS (Status))
1025 SetLastError (RtlNtStatusToDosError(Status));
1026 else
1027 {
1028 rc = NtGdiCreateScalableFontResource ( fdwHidden,
1029 lpszFontResW,
1030 lpszFontFileW,
1031 lpszCurrentPathW );
1032
1033 HEAP_free ( lpszCurrentPathW );
1034 }
1035
1036 HEAP_free ( lpszFontFileW );
1037 }
1038
1039 HEAP_free ( lpszFontResW );
1040 }
1041 return rc;
1042 }
1043
1044
1045 /*
1046 * @implemented
1047 */
1048 int
1049 STDCALL
1050 AddFontResourceExW ( LPCWSTR lpszFilename, DWORD fl, PVOID pvReserved )
1051 {
1052 UNICODE_STRING Filename;
1053
1054 /* FIXME handle fl parameter */
1055 RtlInitUnicodeString(&Filename, lpszFilename);
1056 return NtGdiAddFontResource ( &Filename, fl );
1057 }
1058
1059
1060 /*
1061 * @implemented
1062 */
1063 int
1064 STDCALL
1065 AddFontResourceExA ( LPCSTR lpszFilename, DWORD fl, PVOID pvReserved )
1066 {
1067 NTSTATUS Status;
1068 PWSTR FilenameW;
1069 int rc = 0;
1070
1071 Status = HEAP_strdupA2W ( &FilenameW, lpszFilename );
1072 if ( !NT_SUCCESS (Status) )
1073 SetLastError (RtlNtStatusToDosError(Status));
1074 else
1075 {
1076 rc = AddFontResourceExW ( FilenameW, fl, pvReserved );
1077
1078 HEAP_free ( FilenameW );
1079 }
1080 return rc;
1081 }
1082
1083
1084 /*
1085 * @implemented
1086 */
1087 int
1088 STDCALL
1089 AddFontResourceA ( LPCSTR lpszFilename )
1090 {
1091 return AddFontResourceExA ( lpszFilename, 0, 0 );
1092 }
1093
1094
1095 /*
1096 * @implemented
1097 */
1098 int
1099 STDCALL
1100 AddFontResourceW ( LPCWSTR lpszFilename )
1101 {
1102 return AddFontResourceExW ( lpszFilename, 0, 0 );
1103 }
1104
1105
1106 /*
1107 * @implemented
1108 */
1109 BOOL
1110 STDCALL
1111 RemoveFontResourceW(
1112 LPCWSTR lpFileName
1113 )
1114 {
1115 return NtGdiRemoveFontResource ( lpFileName );
1116 }
1117
1118
1119 /*
1120 * @implemented
1121 */
1122 BOOL
1123 STDCALL
1124 RemoveFontResourceA(
1125 LPCSTR lpFileName
1126 )
1127 {
1128 NTSTATUS Status;
1129 LPWSTR lpFileNameW;
1130 BOOL rc = 0;
1131
1132 Status = HEAP_strdupA2W ( &lpFileNameW, lpFileName );
1133 if (!NT_SUCCESS (Status))
1134 SetLastError (RtlNtStatusToDosError(Status));
1135 else
1136 {
1137 rc = NtGdiRemoveFontResource ( lpFileNameW );
1138
1139 HEAP_free ( lpFileNameW );
1140 }
1141
1142 return rc;
1143 }
1144
1145 /***********************************************************************
1146 * GdiGetCharDimensions
1147 *
1148 * Gets the average width of the characters in the English alphabet.
1149 *
1150 * PARAMS
1151 * hdc [I] Handle to the device context to measure on.
1152 * lptm [O] Pointer to memory to store the text metrics into.
1153 * height [O] On exit, the maximum height of characters in the English alphabet.
1154 *
1155 * RETURNS
1156 * The average width of characters in the English alphabet.
1157 *
1158 * NOTES
1159 * This function is used by the dialog manager to get the size of a dialog
1160 * unit. It should also be used by other pieces of code that need to know
1161 * the size of a dialog unit in logical units without having access to the
1162 * window handle of the dialog.
1163 * Windows caches the font metrics from this function, but we don't and
1164 * there doesn't appear to be an immediate advantage to do so.
1165 *
1166 * SEE ALSO
1167 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
1168 *
1169 * Despite most of MSDN insisting that the horizontal base unit is
1170 * tmAveCharWidth it isn't. Knowledge base article Q145994
1171 * "HOWTO: Calculate Dialog Units When Not Using the System Font",
1172 * says that we should take the average of the 52 English upper and lower
1173 * case characters.
1174 */
1175 /*
1176 * @implemented
1177 */
1178 DWORD
1179 STDCALL
1180 GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
1181 {
1182 SIZE sz;
1183 static const WCHAR alphabet[] = {
1184 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
1185 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
1186 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
1187
1188 if(lptm && !GetTextMetricsW(hdc, lptm)) return 0;
1189
1190 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
1191
1192 if (height) *height = sz.cy;
1193 return (sz.cx / 26 + 1) / 2;
1194 }
1195
1196
1197 /*
1198 * @unimplemented
1199 */
1200 int
1201 STDCALL
1202 EnumFontsW(
1203 HDC hDC,
1204 LPCWSTR lpFaceName,
1205 FONTENUMPROCW FontFunc,
1206 LPARAM lParam
1207 )
1208 {
1209 #if 0
1210 return NtGdiEnumFonts ( hDC, lpFaceName, FontFunc, lParam );
1211 #else
1212 return EnumFontFamiliesW( hDC, lpFaceName, FontFunc, lParam );
1213 #endif
1214 }
1215
1216 /*
1217 * @unimplemented
1218 */
1219 int
1220 STDCALL
1221 EnumFontsA (
1222 HDC hDC,
1223 LPCSTR lpFaceName,
1224 FONTENUMPROCA FontFunc,
1225 LPARAM lParam
1226 )
1227 {
1228 #if 0
1229 NTSTATUS Status;
1230 LPWSTR lpFaceNameW;
1231 int rc = 0;
1232
1233 Status = HEAP_strdupA2W ( &lpFaceNameW, lpFaceName );
1234 if (!NT_SUCCESS (Status))
1235 SetLastError (RtlNtStatusToDosError(Status));
1236 else
1237 {
1238 rc = NtGdiEnumFonts ( hDC, lpFaceNameW, FontFunc, lParam );
1239
1240 HEAP_free ( lpFaceNameW );
1241 }
1242 return rc;
1243 #else
1244 return EnumFontFamiliesA( hDC, lpFaceName, FontFunc, lParam );
1245 #endif
1246 }
1247
1248
1249
1250