2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/objects/font.c
9 /** Includes ******************************************************************/
16 /** Internal ******************************************************************/
20 GreGetCharacterPlacementW(
32 if (GreGetTextExtentW( hdc
, pwsz
, nCount
, &Size
, 1))
33 return MAKELONG(Size
.cx
, Size
.cy
);
41 FontGetObject(PTEXTOBJ TFont
, INT Count
, PVOID Buffer
)
43 if( Buffer
== NULL
) return sizeof(LOGFONTW
);
47 case sizeof(ENUMLOGFONTEXDVW
):
48 RtlCopyMemory( (LPENUMLOGFONTEXDVW
) Buffer
,
50 sizeof(ENUMLOGFONTEXDVW
));
52 case sizeof(ENUMLOGFONTEXW
):
53 RtlCopyMemory( (LPENUMLOGFONTEXW
) Buffer
,
54 &TFont
->logfont
.elfEnumLogfontEx
,
55 sizeof(ENUMLOGFONTEXW
));
58 case sizeof(EXTLOGFONTW
):
59 case sizeof(ENUMLOGFONTW
):
60 RtlCopyMemory((LPENUMLOGFONTW
) Buffer
,
61 &TFont
->logfont
.elfEnumLogfontEx
.elfLogFont
,
62 sizeof(ENUMLOGFONTW
));
65 case sizeof(LOGFONTW
):
66 RtlCopyMemory((LPLOGFONTW
) Buffer
,
67 &TFont
->logfont
.elfEnumLogfontEx
.elfLogFont
,
72 SetLastWin32Error(ERROR_BUFFER_OVERFLOW
);
80 IntGetCharDimensions(HDC hdc
, PTEXTMETRICW ptm
, PDWORD height
)
89 static const WCHAR alphabet
[] = {
90 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
91 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
92 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
94 if(!ftGdiGetTextMetricsW(hdc
, &tmwi
)) return 0;
100 pdcattr
= pdc
->pdcattr
;
102 TextObj
= RealizeFontInit(pdcattr
->hlfntNew
);
108 Good
= TextIntGetTextExtentPoint(pdc
, TextObj
, alphabet
, 52, 0, NULL
, 0, &sz
);
109 TEXTOBJ_UnlockText(TextObj
);
113 if (ptm
) *ptm
= tmwi
.TextMetric
;
114 if (height
) *height
= tmwi
.TextMetric
.tmHeight
;
116 return (sz
.cx
/ 26 + 1) / 2;
122 IntGetFontLanguageInfo(PDC Dc
)
125 FONTSIGNATURE fontsig
;
126 static const DWORD GCP_DBCS_MASK
=0x003F0000,
127 GCP_DIACRITIC_MASK
=0x00000000,
128 FLI_GLYPHS_MASK
=0x00000000,
129 GCP_GLYPHSHAPE_MASK
=0x00000040,
130 GCP_KASHIDA_MASK
=0x00000000,
131 GCP_LIGATE_MASK
=0x00000000,
132 GCP_USEKERNING_MASK
=0x00000000,
133 GCP_REORDER_MASK
=0x00000060;
137 ftGdiGetTextCharsetInfo( Dc
, &fontsig
, 0 );
139 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
140 if( (fontsig
.fsCsb
[0]&GCP_DBCS_MASK
)!=0 )
143 if( (fontsig
.fsCsb
[0]&GCP_DIACRITIC_MASK
)!=0 )
144 result
|=GCP_DIACRITIC
;
146 if( (fontsig
.fsCsb
[0]&FLI_GLYPHS_MASK
)!=0 )
149 if( (fontsig
.fsCsb
[0]&GCP_GLYPHSHAPE_MASK
)!=0 )
150 result
|=GCP_GLYPHSHAPE
;
152 if( (fontsig
.fsCsb
[0]&GCP_KASHIDA_MASK
)!=0 )
155 if( (fontsig
.fsCsb
[0]&GCP_LIGATE_MASK
)!=0 )
158 if( (fontsig
.fsCsb
[0]&GCP_USEKERNING_MASK
)!=0 )
159 result
|=GCP_USEKERNING
;
161 pdcattr
= Dc
->pdcattr
;
163 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
164 if ( pdcattr
->lTextAlign
& TA_RTLREADING
)
165 if( (fontsig
.fsCsb
[0]&GCP_REORDER_MASK
)!=0 )
173 RealizeFontInit(HFONT hFont
)
175 NTSTATUS Status
= STATUS_SUCCESS
;
178 pTextObj
= TEXTOBJ_LockText(hFont
);
180 if ( pTextObj
&& !(pTextObj
->fl
& TEXTOBJECT_INIT
))
182 Status
= TextIntRealizeFont(hFont
, pTextObj
);
183 if (!NT_SUCCESS(Status
))
185 TEXTOBJ_UnlockText(pTextObj
);
192 /** Functions ******************************************************************/
196 NtGdiAddFontResourceW(
202 IN OPTIONAL DESIGNVECTOR
*pdv
)
204 UNICODE_STRING SafeFileName
;
209 /* FIXME - Protect with SEH? */
210 RtlInitUnicodeString(&SafeFileName
, pwszFiles
);
212 /* Reserve for prepending '\??\' */
213 SafeFileName
.Length
+= 4 * sizeof(WCHAR
);
214 SafeFileName
.MaximumLength
+= 4 * sizeof(WCHAR
);
216 src
= SafeFileName
.Buffer
;
217 SafeFileName
.Buffer
= (PWSTR
)ExAllocatePoolWithTag(PagedPool
, SafeFileName
.MaximumLength
, TAG_STRING
);
218 if(!SafeFileName
.Buffer
)
220 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
225 RtlCopyMemory(SafeFileName
.Buffer
, L
"\\??\\", 4 * sizeof(WCHAR
));
227 Status
= MmCopyFromCaller(SafeFileName
.Buffer
+ 4, src
, SafeFileName
.MaximumLength
- (4 * sizeof(WCHAR
)));
228 if(!NT_SUCCESS(Status
))
230 ExFreePoolWithTag(SafeFileName
.Buffer
, TAG_STRING
);
231 SetLastNtError(Status
);
235 Ret
= IntGdiAddFontResource(&SafeFileName
, (DWORD
)fl
);
237 ExFreePoolWithTag(SafeFileName
.Buffer
, TAG_STRING
);
246 NtGdiGetCharacterPlacementW(
251 IN OUT LPGCP_RESULTSW pgcpw
,
272 DWORD Result
= GDI_ERROR
;
273 NTSTATUS Status
= STATUS_SUCCESS
;
279 ProbeForRead(Buffer
, Size
, 1);
281 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
283 Status
= _SEH2_GetExceptionCode();
288 if (!NT_SUCCESS(Status
)) return Result
;
293 SetLastWin32Error(ERROR_INVALID_HANDLE
);
296 pdcattr
= Dc
->pdcattr
;
298 hFont
= pdcattr
->hlfntNew
;
299 TextObj
= RealizeFontInit(hFont
);
304 SetLastWin32Error(ERROR_INVALID_HANDLE
);
308 FontGdi
= ObjToGDI(TextObj
->Font
, FONT
);
310 Result
= ftGdiGetFontData(FontGdi
, Table
, Offset
, Buffer
, Size
);
312 TEXTOBJ_UnlockText(TextObj
);
322 NtGdiGetFontUnicodeRanges(
324 OUT OPTIONAL LPGLYPHSET pgs
)
333 NTSTATUS Status
= STATUS_SUCCESS
;
335 pDc
= DC_LockDc(hdc
);
338 SetLastWin32Error(ERROR_INVALID_HANDLE
);
342 pdcattr
= pDc
->pdcattr
;
344 hFont
= pdcattr
->hlfntNew
;
345 TextObj
= RealizeFontInit(hFont
);
347 if ( TextObj
== NULL
)
349 SetLastWin32Error(ERROR_INVALID_HANDLE
);
352 FontGdi
= ObjToGDI(TextObj
->Font
, FONT
);
354 Size
= ftGetFontUnicodeRanges( FontGdi
, NULL
);
358 pgsSafe
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_GDITEXT
);
361 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
366 Size
= ftGetFontUnicodeRanges( FontGdi
, pgsSafe
);
372 ProbeForWrite(pgs
, Size
, 1);
373 RtlCopyMemory(pgs
, pgsSafe
, Size
);
375 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
377 Status
= _SEH2_GetExceptionCode();
381 if (!NT_SUCCESS(Status
)) Size
= 0;
383 ExFreePoolWithTag(pgsSafe
, TAG_GDITEXT
);
386 TEXTOBJ_UnlockText(TextObj
);
393 NtGdiGetGlyphOutline(
397 OUT LPGLYPHMETRICS pgm
,
399 OUT OPTIONAL PVOID UnsafeBuf
,
401 IN BOOL bIgnoreRotation
)
403 ULONG Ret
= GDI_ERROR
;
407 NTSTATUS Status
= STATUS_SUCCESS
;
412 SetLastWin32Error(ERROR_INVALID_HANDLE
);
416 if (UnsafeBuf
&& cjBuf
)
418 pvBuf
= ExAllocatePoolWithTag(PagedPool
, cjBuf
, TAG_GDITEXT
);
421 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
426 Ret
= ftGdiGetGlyphOutline( dc
,
439 ProbeForWrite(UnsafeBuf
, cjBuf
, 1);
440 RtlCopyMemory(UnsafeBuf
, pvBuf
, cjBuf
);
442 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
444 Status
= _SEH2_GetExceptionCode();
448 ExFreePoolWithTag(pvBuf
, TAG_GDITEXT
);
455 ProbeForWrite(pgm
, sizeof(GLYPHMETRICS
), 1);
456 RtlCopyMemory(pgm
, &gm
, sizeof(GLYPHMETRICS
));
458 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
460 Status
= _SEH2_GetExceptionCode();
465 if (! NT_SUCCESS(Status
))
467 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
478 NtGdiGetKerningPairs(HDC hDC
,
480 LPKERNINGPAIR krnpair
)
488 NTSTATUS Status
= STATUS_SUCCESS
;
493 SetLastWin32Error(ERROR_INVALID_HANDLE
);
497 pdcattr
= dc
->pdcattr
;
498 TextObj
= RealizeFontInit(pdcattr
->hlfntNew
);
503 SetLastWin32Error(ERROR_INVALID_HANDLE
);
507 FontGDI
= ObjToGDI(TextObj
->Font
, FONT
);
508 TEXTOBJ_UnlockText(TextObj
);
510 Count
= ftGdiGetKerningPairs(FontGDI
,0,NULL
);
512 if ( Count
&& krnpair
)
514 if (Count
> NumPairs
)
516 SetLastWin32Error(ERROR_INSUFFICIENT_BUFFER
);
519 pKP
= ExAllocatePoolWithTag(PagedPool
, Count
* sizeof(KERNINGPAIR
), TAG_GDITEXT
);
522 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
525 ftGdiGetKerningPairs(FontGDI
,Count
,pKP
);
528 ProbeForWrite(krnpair
, Count
* sizeof(KERNINGPAIR
), 1);
529 RtlCopyMemory(krnpair
, pKP
, Count
* sizeof(KERNINGPAIR
));
531 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
533 Status
= _SEH2_GetExceptionCode();
536 if (!NT_SUCCESS(Status
))
538 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
541 ExFreePoolWithTag(pKP
,TAG_GDITEXT
);
547 From "Undocumented Windows 2000 Secrets" Appendix B, Table B-2, page
548 472, this is NtGdiGetOutlineTextMetricsInternalW.
552 NtGdiGetOutlineTextMetricsInternalW (HDC hDC
,
554 OUTLINETEXTMETRICW
*otm
,
563 OUTLINETEXTMETRICW
*potm
;
564 NTSTATUS Status
= STATUS_SUCCESS
;
569 SetLastWin32Error(ERROR_INVALID_HANDLE
);
572 pdcattr
= dc
->pdcattr
;
573 hFont
= pdcattr
->hlfntNew
;
574 TextObj
= RealizeFontInit(hFont
);
578 SetLastWin32Error(ERROR_INVALID_HANDLE
);
581 FontGDI
= ObjToGDI(TextObj
->Font
, FONT
);
582 TEXTOBJ_UnlockText(TextObj
);
583 Size
= IntGetOutlineTextMetrics(FontGDI
, 0, NULL
);
584 if (!otm
) return Size
;
587 SetLastWin32Error(ERROR_INSUFFICIENT_BUFFER
);
590 potm
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_GDITEXT
);
593 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
596 IntGetOutlineTextMetrics(FontGDI
, Size
, potm
);
601 ProbeForWrite(otm
, Size
, 1);
602 RtlCopyMemory(otm
, potm
, Size
);
604 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
606 Status
= _SEH2_GetExceptionCode();
610 if (!NT_SUCCESS(Status
))
612 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
616 ExFreePoolWithTag(potm
,TAG_GDITEXT
);
623 NtGdiGetFontResourceInfoInternalW(
628 OUT LPDWORD pdwBytes
,
632 NTSTATUS Status
= STATUS_SUCCESS
;
634 UNICODE_STRING SafeFileNames
;
641 WCHAR FullName
[LF_FULLFACESIZE
];
644 /* FIXME: handle cFiles > 0 */
646 /* Check for valid dwType values
647 dwType == 4 seems to be handled by gdi32 only */
648 if (dwType
== 4 || dwType
> 5)
650 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
654 /* Allocate a safe unicode string buffer */
655 cbStringSize
= cwc
* sizeof(WCHAR
);
656 SafeFileNames
.MaximumLength
= SafeFileNames
.Length
= cbStringSize
- sizeof(WCHAR
);
657 SafeFileNames
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
659 TAG('R','T','S','U'));
660 if (!SafeFileNames
.Buffer
)
662 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
666 /* Check buffers and copy pwszFiles to safe unicode string */
669 ProbeForRead(pwszFiles
, cbStringSize
, 1);
670 ProbeForWrite(pdwBytes
, sizeof(DWORD
), 1);
671 ProbeForWrite(pvBuf
, cjIn
, 1);
673 RtlCopyMemory(SafeFileNames
.Buffer
, pwszFiles
, cbStringSize
);
675 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
677 Status
= _SEH2_GetExceptionCode();
681 if(!NT_SUCCESS(Status
))
683 SetLastNtError(Status
);
684 /* Free the string buffer for the safe filename */
685 ExFreePoolWithTag(SafeFileNames
.Buffer
,TAG('R','T','S','U'));
689 /* Do the actual call */
690 bRet
= IntGdiGetFontResourceInfo(&SafeFileNames
, &Buffer
, &dwBytes
, dwType
);
692 /* Check if succeeded and the buffer is big enough */
693 if (bRet
&& cjIn
>= dwBytes
)
695 /* Copy the data back to caller */
698 /* Buffers are already probed */
699 RtlCopyMemory(pvBuf
, &Buffer
, dwBytes
);
702 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
704 Status
= _SEH2_GetExceptionCode();
708 if(!NT_SUCCESS(Status
))
710 SetLastNtError(Status
);
715 /* Free the string for the safe filenames */
716 ExFreePoolWithTag(SafeFileNames
.Buffer
,TAG('R','T','S','U'));
726 NtGdiGetRealizationInfo(
728 OUT PREALIZATION_INFO pri
,
739 pDc
= DC_LockDc(hdc
);
742 SetLastWin32Error(ERROR_INVALID_HANDLE
);
745 pdcattr
= pDc
->pdcattr
;
746 pTextObj
= RealizeFontInit(pdcattr
->hlfntNew
);
747 pFontGdi
= ObjToGDI(pTextObj
->Font
, FONT
);
748 TEXTOBJ_UnlockText(pTextObj
);
751 Ret
= ftGdiRealizationInfo(pFontGdi
, &ri
);
756 NTSTATUS Status
= STATUS_SUCCESS
;
759 ProbeForWrite(pri
, sizeof(REALIZATION_INFO
), 1);
760 RtlCopyMemory(pri
, &ri
, sizeof(REALIZATION_INFO
));
762 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
764 Status
= _SEH2_GetExceptionCode();
768 if(!NT_SUCCESS(Status
))
770 SetLastNtError(Status
);
776 if (GdiHandleTable
->cfPublic
[i
].hf
== hf
)
778 GdiHandleTable
->cfPublic
[i
].iTechnology
= ri
.iTechnology
;
779 GdiHandleTable
->cfPublic
[i
].iUniq
= ri
.iUniq
;
780 GdiHandleTable
->cfPublic
[i
].dwUnknown
= ri
.dwUnknown
;
781 GdiHandleTable
->cfPublic
[i
].dwCFCount
= GdiHandleTable
->dwCFCount
;
782 GdiHandleTable
->cfPublic
[i
].fl
|= CFONT_REALIZATION
;
786 while ( i
< GDI_CFONT_MAX
);
794 IN PENUMLOGFONTEXDVW pelfw
,
800 ENUMLOGFONTEXDVW SafeLogfont
;
803 NTSTATUS Status
= STATUS_SUCCESS
;
805 /* Silence GCC warnings */
806 SafeLogfont
.elfEnumLogfontEx
.elfLogFont
.lfEscapement
= 0;
807 SafeLogfont
.elfEnumLogfontEx
.elfLogFont
.lfOrientation
= 0;
816 ProbeForRead(pelfw
, sizeof(ENUMLOGFONTEXDVW
), 1);
817 RtlCopyMemory(&SafeLogfont
, pelfw
, sizeof(ENUMLOGFONTEXDVW
));
819 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
821 Status
= _SEH2_GetExceptionCode();
825 if (!NT_SUCCESS(Status
))
830 TextObj
= TEXTOBJ_AllocTextWithHandle();
835 hNewFont
= TextObj
->BaseObject
.hHmgr
;
839 RtlCopyMemory (&TextObj
->logfont
, &SafeLogfont
, sizeof(ENUMLOGFONTEXDVW
));
841 if (SafeLogfont
.elfEnumLogfontEx
.elfLogFont
.lfEscapement
!=
842 SafeLogfont
.elfEnumLogfontEx
.elfLogFont
.lfOrientation
)
844 /* this should really depend on whether GM_ADVANCED is set */
845 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfOrientation
=
846 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfEscapement
;
848 TEXTOBJ_UnlockText(TextObj
);
850 if (pvCliData
&& hNewFont
)
852 // FIXME: use GDIOBJ_InsertUserData
853 KeEnterCriticalRegion();
855 INT Index
= GDI_HANDLE_GET_INDEX((HGDIOBJ
)hNewFont
);
856 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
857 Entry
->UserData
= pvCliData
;
859 KeLeaveCriticalRegion();
876 HFONT hOrgFont
= NULL
;
878 if (hDC
== NULL
|| hFont
== NULL
) return NULL
;
880 pDC
= DC_LockDc(hDC
);
886 pdcattr
= pDC
->pdcattr
;
888 /* FIXME: what if not successful? */
889 if(NT_SUCCESS(TextIntRealizeFont((HFONT
)hFont
,NULL
)))
891 hOrgFont
= pdcattr
->hlfntNew
;
892 pdcattr
->hlfntNew
= hFont
;