3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/gdi32/object/font.c
16 #define INITIAL_FAMILY_COUNT 64
19 MetricsCharConvert(WCHAR w
, UCHAR
*b
)
21 UNICODE_STRING WString
;
35 RtlInitUnicodeString(&WString
, WBuf
);
38 RtlInitAnsiString(&AString
, ABuf
);
40 Status
= RtlUnicodeStringToAnsiString(&AString
, &WString
, FALSE
);
41 if (! NT_SUCCESS(Status
))
43 SetLastError(RtlNtStatusToDosError(Status
));
53 TextMetricW2A(TEXTMETRICA
*tma
, TEXTMETRICW
*tmw
)
55 UNICODE_STRING WString
;
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
;
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. */
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
87 for (Letter
= 1; Letter
< 256; Letter
++)
89 ABuf
[Letter
- 1] = (CHAR
) Letter
;
90 WBuf
[Letter
- 1] = L
' ';
94 RtlInitAnsiString(&AString
, ABuf
);
95 RtlInitUnicodeString(&WString
, WBuf
);
97 /* Find the corresponding Unicode characters */
98 Status
= RtlAnsiStringToUnicodeString(&WString
, &AString
, FALSE
);
99 if (! NT_SUCCESS(Status
))
101 SetLastError(RtlNtStatusToDosError(Status
));
105 /* Scan for the first ANSI character which maps to an Unicode character
107 tma
->tmFirstChar
= '\0';
108 if (L
'\0' != tmw
->tmFirstChar
)
110 for (Letter
= 1; Letter
< 256; Letter
++)
112 if (tmw
->tmFirstChar
<= WBuf
[Letter
- 1] &&
113 WBuf
[Letter
- 1] <= tmw
->tmLastChar
)
115 tma
->tmFirstChar
= (CHAR
) Letter
;
121 /* Scan for the last ANSI character which maps to an Unicode character
123 tma
->tmLastChar
= '\0';
124 if (L
'\0' != tmw
->tmLastChar
)
126 for (Letter
= 255; 0 < Letter
; Letter
--)
128 if (tmw
->tmFirstChar
<= WBuf
[Letter
- 1] &&
129 WBuf
[Letter
- 1] <= tmw
->tmLastChar
)
131 tma
->tmLastChar
= (CHAR
) Letter
;
137 if (! MetricsCharConvert(tmw
->tmDefaultChar
, &tma
->tmDefaultChar
) ||
138 ! MetricsCharConvert(tmw
->tmBreakChar
, &tma
->tmBreakChar
))
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
;
153 NewTextMetricW2A(NEWTEXTMETRICA
*tma
, NEWTEXTMETRICW
*tmw
)
155 if (! TextMetricW2A((TEXTMETRICA
*) tma
, (TEXTMETRICW
*) tmw
))
160 tma
->ntmFlags
= tmw
->ntmFlags
;
161 tma
->ntmSizeEM
= tmw
->ntmSizeEM
;
162 tma
->ntmCellHeight
= tmw
->ntmCellHeight
;
163 tma
->ntmAvgWidth
= tmw
->ntmAvgWidth
;
169 NewTextMetricExW2A(NEWTEXTMETRICEXA
*tma
, NEWTEXTMETRICEXW
*tmw
)
171 if (! NewTextMetricW2A(&tma
->ntmTm
, &tmw
->ntmTm
))
176 tma
->ntmFontSig
= tmw
->ntmFontSig
;
182 IntEnumFontFamilies(HDC Dc
, LPLOGFONTW LogFont
, PVOID EnumProc
, LPARAM lParam
,
187 PFONTFAMILYINFO Info
;
190 ENUMLOGFONTEXA EnumLogFontExA
;
191 NEWTEXTMETRICEXA NewTextMetricExA
;
193 Info
= RtlAllocateHeap(GetProcessHeap(), 0,
194 INITIAL_FAMILY_COUNT
* sizeof(FONTFAMILYINFO
));
199 FontFamilyCount
= NtGdiGetFontFamilyInfo(Dc
, LogFont
, Info
, INITIAL_FAMILY_COUNT
);
200 if (FontFamilyCount
< 0)
202 RtlFreeHeap(GetProcessHeap(), 0, Info
);
205 if (INITIAL_FAMILY_COUNT
< FontFamilyCount
)
207 FontFamilySize
= FontFamilyCount
;
208 RtlFreeHeap(GetProcessHeap(), 0, Info
);
209 Info
= RtlAllocateHeap(GetProcessHeap(), 0,
210 FontFamilyCount
* sizeof(FONTFAMILYINFO
));
215 FontFamilyCount
= NtGdiGetFontFamilyInfo(Dc
, LogFont
, Info
, FontFamilySize
);
216 if (FontFamilyCount
< 0 || FontFamilySize
< FontFamilyCount
)
218 RtlFreeHeap(GetProcessHeap(), 0, Info
);
223 for (i
= 0; i
< FontFamilyCount
; i
++)
227 Ret
= ((FONTENUMPROCW
) EnumProc
)(
228 (LPLOGFONTW
)&Info
[i
].EnumLogFontEx
,
229 (LPTEXTMETRICW
)&Info
[i
].NewTextMetricEx
,
230 Info
[i
].FontType
, lParam
);
234 LogFontW2A(&EnumLogFontExA
.elfLogFont
, &Info
[i
].EnumLogFontEx
.elfLogFont
);
235 WideCharToMultiByte(CP_THREAD_ACP
, 0, Info
[i
].EnumLogFontEx
.elfFullName
, -1,
236 (LPSTR
)EnumLogFontExA
.elfFullName
, LF_FULLFACESIZE
, NULL
, NULL
);
237 WideCharToMultiByte(CP_THREAD_ACP
, 0, Info
[i
].EnumLogFontEx
.elfStyle
, -1,
238 (LPSTR
)EnumLogFontExA
.elfStyle
, LF_FACESIZE
, NULL
, NULL
);
239 WideCharToMultiByte(CP_THREAD_ACP
, 0, Info
[i
].EnumLogFontEx
.elfScript
, -1,
240 (LPSTR
)EnumLogFontExA
.elfScript
, LF_FACESIZE
, NULL
, NULL
);
241 NewTextMetricExW2A(&NewTextMetricExA
,
242 &Info
[i
].NewTextMetricEx
);
243 Ret
= ((FONTENUMPROCA
) EnumProc
)(
244 (LPLOGFONTA
)&EnumLogFontExA
,
245 (LPTEXTMETRICA
)&NewTextMetricExA
,
246 Info
[i
].FontType
, lParam
);
250 RtlFreeHeap(GetProcessHeap(), 0, Info
);
259 EnumFontFamiliesExW(HDC hdc
, LPLOGFONTW lpLogfont
, FONTENUMPROCW lpEnumFontFamExProc
,
260 LPARAM lParam
, DWORD dwFlags
)
262 return IntEnumFontFamilies(hdc
, lpLogfont
, lpEnumFontFamExProc
, lParam
, TRUE
);
270 EnumFontFamiliesW(HDC hdc
, LPCWSTR lpszFamily
, FONTENUMPROCW lpEnumFontFamProc
,
275 ZeroMemory(&LogFont
, sizeof(LOGFONTW
));
276 LogFont
.lfCharSet
= DEFAULT_CHARSET
;
277 if (NULL
!= lpszFamily
)
279 lstrcpynW(LogFont
.lfFaceName
, lpszFamily
, LF_FACESIZE
);
282 return IntEnumFontFamilies(hdc
, &LogFont
, lpEnumFontFamProc
, lParam
, TRUE
);
290 EnumFontFamiliesExA (HDC hdc
, LPLOGFONTA lpLogfont
, FONTENUMPROCA lpEnumFontFamExProc
,
291 LPARAM lParam
, DWORD dwFlags
)
295 LogFontA2W(&LogFontW
, lpLogfont
);
297 /* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */
298 return IntEnumFontFamilies(hdc
, &LogFontW
, lpEnumFontFamExProc
, lParam
, FALSE
);
306 EnumFontFamiliesA(HDC hdc
, LPCSTR lpszFamily
, FONTENUMPROCA lpEnumFontFamProc
,
311 ZeroMemory(&LogFont
, sizeof(LOGFONTW
));
312 LogFont
.lfCharSet
= DEFAULT_CHARSET
;
313 if (NULL
!= lpszFamily
)
315 MultiByteToWideChar(CP_THREAD_ACP
, 0, lpszFamily
, -1, LogFont
.lfFaceName
, LF_FACESIZE
);
318 return IntEnumFontFamilies(hdc
, &LogFont
, lpEnumFontFamProc
, lParam
, FALSE
);
334 /* FIXME what to do with iFirstChar and iLastChar ??? */
335 return NtGdiGetCharWidth32 ( hdc
, iFirstChar
, iLastChar
, lpBuffer
);
351 /* FIXME what to do with iFirstChar and iLastChar ??? */
352 return NtGdiGetCharWidth32 ( hdc
, iFirstChar
, iLastChar
, lpBuffer
);
368 return NtGdiGetCharWidth32 ( hdc
, iFirstChar
, iLastChar
, lpBuffer
);
377 GetCharacterPlacementW(
382 GCP_RESULTSW
*lpResults
,
390 if(dwFlags
&(~GCP_REORDER
)) DPRINT("flags 0x%08lx ignored\n", dwFlags
);
391 if(lpResults
->lpClass
) DPRINT("classes not implemented\n");
392 if (lpResults
->lpCaretPos
&& (dwFlags
& GCP_REORDER
))
393 DPRINT("Caret positions for complex scripts not implemented\n");
396 if(nSet
> lpResults
->nGlyphs
)
397 nSet
= lpResults
->nGlyphs
;
399 /* return number of initialized fields */
400 lpResults
->nGlyphs
= nSet
;
402 /*if((dwFlags&GCP_REORDER)==0 || !BidiAvail)
404 /* Treat the case where no special handling was requested in a fastpath way */
405 /* copy will do if the GCP_REORDER flag is not set */
406 if(lpResults
->lpOutString
)
407 lstrcpynW( lpResults
->lpOutString
, lpString
, nSet
);
409 if(lpResults
->lpGlyphs
)
410 lstrcpynW( lpResults
->lpGlyphs
, lpString
, nSet
);
412 if(lpResults
->lpOrder
)
414 for(i
= 0; i
< nSet
; i
++)
415 lpResults
->lpOrder
[i
] = i
;
419 BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
420 nSet, lpResults->lpOrder );
423 /* FIXME: Will use the placement chars */
427 for (i
= 0; i
< nSet
; i
++)
429 if (NtGdiGetCharWidth32(hdc
, lpString
[i
], lpString
[i
], &c
))
430 lpResults
->lpDx
[i
]= c
;
434 if (lpResults
->lpCaretPos
&& !(dwFlags
& GCP_REORDER
))
438 lpResults
->lpCaretPos
[0] = 0;
439 for (i
= 1; i
< nSet
; i
++)
440 if (GetTextExtentPoint32W(hdc
, &(lpString
[i
- 1]), 1, &size
))
441 lpResults
->lpCaretPos
[i
] = (pos
+= size
.cx
);
444 /*if(lpResults->lpGlyphs)
445 GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);*/
447 if (GetTextExtentPoint32W(hdc
, lpString
, uCount
, &size
))
448 ret
= MAKELONG(size
.cx
, size
.cy
);
466 /* FIXME what to do with iFirstChar and iLastChar ??? */
467 return NtGdiGetCharWidthFloat ( hdc
, iFirstChar
, iLastChar
, pxBuffer
);
483 /* FIXME what to do with uFirstChar and uLastChar ??? */
484 return NtGdiGetCharABCWidths ( hdc
, uFirstChar
, uLastChar
, lpabc
);
493 GetCharABCWidthsFloatA(
500 /* FIXME what to do with iFirstChar and iLastChar ??? */
501 return NtGdiGetCharABCWidthsFloat ( hdc
, iFirstChar
, iLastChar
, lpABCF
);
520 return NtGdiGetGlyphOutline ( hdc
, uChar
, uFormat
, lpgm
, cbBuffer
, lpvBuffer
, (CONST LPMAT2
)lpmat2
, TRUE
);
538 return NtGdiGetGlyphOutline ( hdc
, uChar
, uFormat
, lpgm
, cbBuffer
, lpvBuffer
, (CONST LPMAT2
)lpmat2
, TRUE
);
554 LogFontA2W(&tlf
, lplf
);
556 return NtGdiCreateFontIndirect(&tlf
);
569 return NtGdiCreateFontIndirect((CONST LPLOGFONTW
)lplf
);
588 DWORD fdwOutputPrecision
,
589 DWORD fdwClipPrecision
,
591 DWORD fdwPitchAndFamily
,
596 UNICODE_STRING StringU
;
599 RtlInitAnsiString(&StringA
, (LPSTR
)lpszFace
);
600 RtlAnsiStringToUnicodeString(&StringU
, &StringA
, TRUE
);
602 ret
= CreateFontW(nHeight
, nWidth
, nEscapement
, nOrientation
, fnWeight
, fdwItalic
, fdwUnderline
, fdwStrikeOut
,
603 fdwCharSet
, fdwOutputPrecision
, fdwClipPrecision
, fdwQuality
, fdwPitchAndFamily
, StringU
.Buffer
);
605 RtlFreeUnicodeString(&StringU
);
626 DWORD fdwOutputPrecision
,
627 DWORD fdwClipPrecision
,
629 DWORD fdwPitchAndFamily
,
633 return NtGdiCreateFont(nHeight
, nWidth
, nEscapement
, nOrientation
, nWeight
, fnItalic
, fdwUnderline
, fdwStrikeOut
,
634 fdwCharSet
, fdwOutputPrecision
, fdwClipPrecision
, fdwQuality
, fdwPitchAndFamily
, lpszFace
);
643 CreateScalableFontResourceW(
646 LPCWSTR lpszFontFile
,
647 LPCWSTR lpszCurrentPath
650 return NtGdiCreateScalableFontResource ( fdwHidden
,
662 CreateScalableFontResourceA(
666 LPCSTR lpszCurrentPath
670 LPWSTR lpszFontResW
, lpszFontFileW
, lpszCurrentPathW
;
673 Status
= HEAP_strdupA2W ( &lpszFontResW
, lpszFontRes
);
674 if (!NT_SUCCESS (Status
))
675 SetLastError (RtlNtStatusToDosError(Status
));
678 Status
= HEAP_strdupA2W ( &lpszFontFileW
, lpszFontFile
);
679 if (!NT_SUCCESS (Status
))
680 SetLastError (RtlNtStatusToDosError(Status
));
683 Status
= HEAP_strdupA2W ( &lpszCurrentPathW
, lpszCurrentPath
);
684 if (!NT_SUCCESS (Status
))
685 SetLastError (RtlNtStatusToDosError(Status
));
688 rc
= NtGdiCreateScalableFontResource ( fdwHidden
,
693 HEAP_free ( lpszCurrentPathW
);
696 HEAP_free ( lpszFontFileW
);
699 HEAP_free ( lpszFontResW
);
710 AddFontResourceExW ( LPCWSTR lpszFilename
, DWORD fl
, PVOID pvReserved
)
712 UNICODE_STRING Filename
;
714 /* FIXME handle fl parameter */
715 RtlInitUnicodeString(&Filename
, lpszFilename
);
716 return NtGdiAddFontResource ( &Filename
, fl
);
725 AddFontResourceExA ( LPCSTR lpszFilename
, DWORD fl
, PVOID pvReserved
)
731 Status
= HEAP_strdupA2W ( &FilenameW
, lpszFilename
);
732 if ( !NT_SUCCESS (Status
) )
733 SetLastError (RtlNtStatusToDosError(Status
));
736 rc
= AddFontResourceExW ( FilenameW
, fl
, pvReserved
);
738 HEAP_free ( FilenameW
);
749 AddFontResourceA ( LPCSTR lpszFilename
)
751 return AddFontResourceExA ( lpszFilename
, 0, 0 );
760 AddFontResourceW ( LPCWSTR lpszFilename
)
762 return AddFontResourceExW ( lpszFilename
, 0, 0 );
775 return NtGdiRemoveFontResource ( lpFileName
);
792 Status
= HEAP_strdupA2W ( &lpFileNameW
, lpFileName
);
793 if (!NT_SUCCESS (Status
))
794 SetLastError (RtlNtStatusToDosError(Status
));
797 rc
= NtGdiRemoveFontResource ( lpFileNameW
);
799 HEAP_free ( lpFileNameW
);
805 /***********************************************************************
806 * GdiGetCharDimensions
808 * Gets the average width of the characters in the English alphabet.
811 * hdc [I] Handle to the device context to measure on.
812 * lptm [O] Pointer to memory to store the text metrics into.
813 * height [O] On exit, the maximum height of characters in the English alphabet.
816 * The average width of characters in the English alphabet.
819 * This function is used by the dialog manager to get the size of a dialog
820 * unit. It should also be used by other pieces of code that need to know
821 * the size of a dialog unit in logical units without having access to the
822 * window handle of the dialog.
823 * Windows caches the font metrics from this function, but we don't and
824 * there doesn't appear to be an immediate advantage to do so.
827 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
829 * Despite most of MSDN insisting that the horizontal base unit is
830 * tmAveCharWidth it isn't. Knowledge base article Q145994
831 * "HOWTO: Calculate Dialog Units When Not Using the System Font",
832 * says that we should take the average of the 52 English upper and lower
840 GdiGetCharDimensions(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
)
843 static const WCHAR alphabet
[] = {
844 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
845 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
846 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
848 if(lptm
&& !GetTextMetricsW(hdc
, lptm
)) return 0;
850 if(!GetTextExtentPointW(hdc
, alphabet
, 52, &sz
)) return 0;
852 if (height
) *height
= sz
.cy
;
853 return (sz
.cx
/ 26 + 1) / 2;
865 FONTENUMPROCW FontFunc
,
870 return NtGdiEnumFonts ( hDC
, lpFaceName
, FontFunc
, lParam
);
872 return EnumFontFamiliesW( hDC
, lpFaceName
, FontFunc
, lParam
);
884 FONTENUMPROCA FontFunc
,
893 Status
= HEAP_strdupA2W ( &lpFaceNameW
, lpFaceName
);
894 if (!NT_SUCCESS (Status
))
895 SetLastError (RtlNtStatusToDosError(Status
));
898 rc
= NtGdiEnumFonts ( hDC
, lpFaceNameW
, FontFunc
, lParam
);
900 HEAP_free ( lpFaceNameW
);
904 return EnumFontFamiliesA( hDC
, lpFaceName
, FontFunc
, lParam
);