2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: text.c,v 1.76 2004/02/21 21:15:22 navaraf Exp $ */
22 #undef WIN32_LEAN_AND_MEAN
24 #include <ddk/ntddk.h>
25 #include <napi/win32.h>
26 #include <internal/safe.h>
27 #include <win32k/brush.h>
28 #include <win32k/dc.h>
29 #include <win32k/text.h>
30 #include <win32k/kapi.h>
31 #include <include/error.h>
32 #include <include/desktop.h>
34 #include FT_FREETYPE_H
35 #include <freetype/tttables.h>
37 #include "../eng/handle.h"
39 #include <include/inteng.h>
40 #include <include/text.h>
41 #include <include/eng.h>
42 #include <include/palette.h>
43 #include <include/tags.h>
46 #include <win32k/debug1.h>
50 typedef struct _FONT_ENTRY
{
53 UNICODE_STRING FaceName
;
55 } FONT_ENTRY
, *PFONT_ENTRY
;
57 /* The FreeType library is not thread safe, so we have
58 to serialize access to it */
59 static FAST_MUTEX FreeTypeLock
;
61 static LIST_ENTRY FontListHead
;
62 static FAST_MUTEX FontListLock
;
63 static INT FontsLoaded
= 0; /* number of all fonts loaded (including private fonts */
64 static BOOL RenderingEnabled
= TRUE
;
67 IntIsFontRenderingEnabled(VOID
)
73 Ret
= RenderingEnabled
;
74 hDC
= IntGetScreenDC();
78 SurfObj
= (PSURFOBJ
)AccessUserObject((ULONG
) dc
->Surface
);
80 Ret
= (SurfObj
->iBitmapFormat
>= BMF_8BPP
);
87 IntEnableFontRendering(BOOL Enable
)
89 RenderingEnabled
= Enable
;
92 FT_Render_Mode FASTCALL
93 IntGetFontRenderMode(LOGFONTW
*logfont
)
95 switch(logfont
->lfQuality
)
97 //case ANTIALIASED_QUALITY:
99 return FT_RENDER_MODE_NORMAL
;
101 return FT_RENDER_MODE_LIGHT
;
102 //case NONANTIALIASED_QUALITY:
104 return FT_RENDER_MODE_MONO
;
105 //case CLEARTYPE_QUALITY:
106 // return FT_RENDER_MODE_LCD;
108 return FT_RENDER_MODE_MONO
;
112 IntGdiAddFontResource(PUNICODE_STRING Filename
, DWORD fl
)
119 OBJECT_ATTRIBUTES ObjectAttributes
;
120 FILE_STANDARD_INFORMATION FileStdInfo
;
126 IO_STATUS_BLOCK Iosb
;
129 NewFont
= (HFONT
)CreateGDIHandle(sizeof( FONTGDI
), sizeof( FONTOBJ
));
130 FontObj
= (PFONTOBJ
) AccessUserObject( (ULONG
) NewFont
);
131 FontGDI
= (PFONTGDI
) AccessInternalObject( (ULONG
) NewFont
);
134 InitializeObjectAttributes(&ObjectAttributes
, Filename
, 0, NULL
, NULL
);
136 Status
= ZwOpenFile(&FileHandle
,
137 GENERIC_READ
|SYNCHRONIZE
,
141 FILE_SYNCHRONOUS_IO_NONALERT
);
143 if (!NT_SUCCESS(Status
))
145 DPRINT1("Could not open module file: %wZ\n", Filename
);
149 // Get the size of the file
150 Status
= NtQueryInformationFile(FileHandle
, &Iosb
, &FileStdInfo
, sizeof(FileStdInfo
), FileStandardInformation
);
151 if (!NT_SUCCESS(Status
))
153 DPRINT1("Could not get file size\n");
157 // Allocate nonpageable memory for driver
158 size
= FileStdInfo
.EndOfFile
.u
.LowPart
;
159 buffer
= ExAllocatePoolWithTag(NonPagedPool
, size
, TAG_GDITEXT
);
163 DPRINT1("could not allocate memory for module");
167 // Load driver into memory chunk
168 Status
= ZwReadFile(FileHandle
,
174 FileStdInfo
.EndOfFile
.u
.LowPart
,
178 if (!NT_SUCCESS(Status
))
180 DPRINT1("could not read module file into memory");
187 ExAcquireFastMutex(&FreeTypeLock
);
188 error
= FT_New_Memory_Face(library
, buffer
, size
, 0, &face
);
189 ExReleaseFastMutex(&FreeTypeLock
);
190 if (error
== FT_Err_Unknown_File_Format
)
192 DPRINT1("Unknown font file format\n");
197 DPRINT1("Error reading font file (error code: %u)\n", error
); // 48
201 entry
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(FONT_ENTRY
), TAG_FONT
);
204 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
208 // FontGDI->Filename = Filename; perform strcpy
209 FontGDI
->face
= face
;
211 // FIXME: Complete text metrics
212 FontGDI
->TextMetric
.tmAscent
= (face
->size
->metrics
.ascender
+ 32) / 64; // units above baseline
213 FontGDI
->TextMetric
.tmDescent
= (- face
->size
->metrics
.descender
+ 32) / 64; // units below baseline
214 FontGDI
->TextMetric
.tmHeight
= FontGDI
->TextMetric
.tmAscent
+ FontGDI
->TextMetric
.tmDescent
;
216 DPRINT("Font loaded: %s (%s)\n", face
->family_name
, face
->style_name
);
217 DPRINT("Num glyphs: %u\n", face
->num_glyphs
);
219 // Add this font resource to the font table
220 entry
->hFont
= NewFont
;
221 entry
->NotEnum
= (fl
& FR_NOT_ENUM
);
222 RtlInitAnsiString(&StringA
, (LPSTR
)face
->family_name
);
223 RtlAnsiStringToUnicodeString(&entry
->FaceName
, &StringA
, TRUE
);
227 PW32PROCESS Win32Process
= PsGetWin32Process();
229 ExAcquireFastMutex(&Win32Process
->PrivateFontListLock
);
230 InsertTailList(&Win32Process
->PrivateFontListHead
, &entry
->ListEntry
);
232 ExReleaseFastMutex(&Win32Process
->PrivateFontListLock
);
236 ExAcquireFastMutex(&FontListLock
);
237 InsertTailList(&FontListHead
, &entry
->ListEntry
);
239 ExReleaseFastMutex(&FontListLock
);
245 BOOL FASTCALL
InitFontSupport(VOID
)
248 UNICODE_STRING cchDir
, cchFilename
, cchSearchPattern
;
249 OBJECT_ATTRIBUTES obAttr
;
250 IO_STATUS_BLOCK Iosb
;
253 PFILE_DIRECTORY_INFORMATION iFileData
;
255 BOOLEAN bRestartScan
= TRUE
;
257 InitializeListHead(&FontListHead
);
258 ExInitializeFastMutex(&FontListLock
);
259 ExInitializeFastMutex(&FreeTypeLock
);
261 ulError
= FT_Init_FreeType(&library
);
265 RtlInitUnicodeString(&cchDir
, L
"\\SystemRoot\\Media\\Fonts\\");
267 RtlInitUnicodeString(&cchSearchPattern
,L
"*.ttf");
268 InitializeObjectAttributes( &obAttr
,
270 OBJ_CASE_INSENSITIVE
,
274 Status
= ZwOpenFile( &hDirectory
,
275 SYNCHRONIZE
| FILE_LIST_DIRECTORY
,
278 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
279 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_DIRECTORY_FILE
);
280 if( NT_SUCCESS(Status
) )
285 pBuff
= ExAllocatePool(NonPagedPool
,0x4000);
286 RtlInitUnicodeString(&cchFilename
,0);
287 cchFilename
.MaximumLength
= 0x1000;
288 cchFilename
.Buffer
= ExAllocatePoolWithTag(PagedPool
,cchFilename
.MaximumLength
, TAG_STRING
);
290 cchFilename
.Length
= 0;
292 Status
= NtQueryDirectoryFile( hDirectory
,
299 FileDirectoryInformation
,
304 iFileData
= (PFILE_DIRECTORY_INFORMATION
)pBuff
;
306 RtlAppendUnicodeToString(&cchFilename
, cchDir
.Buffer
);
307 RtlAppendUnicodeToString(&cchFilename
, iFileData
->FileName
);
308 RtlAppendUnicodeToString(&cchFilename
, L
"\0");
310 if( !NT_SUCCESS(Status
) || Status
== STATUS_NO_MORE_FILES
)
313 IntGdiAddFontResource(&cchFilename
, 0);
315 ExFreePool(cchFilename
.Buffer
);
316 bRestartScan
= FALSE
;
318 ExFreePool(cchFilename
.Buffer
);
329 static NTSTATUS STDCALL
330 GetFontObjectsFromTextObj(PTEXTOBJ TextObj
, HFONT
*FontHandle
, PFONTOBJ
*FontObj
, PFONTGDI
*FontGDI
)
332 NTSTATUS Status
= STATUS_SUCCESS
;
334 ASSERT(NULL
!= TextObj
&& NULL
!= TextObj
->GDIFontHandle
);
335 if (NULL
!= TextObj
&& NULL
!= TextObj
->GDIFontHandle
)
337 if (NT_SUCCESS(Status
) && NULL
!= FontHandle
)
339 *FontHandle
= TextObj
->GDIFontHandle
;
341 if (NT_SUCCESS(Status
) && NULL
!= FontObj
)
343 *FontObj
= AccessUserObject((ULONG
) TextObj
->GDIFontHandle
);
344 if (NULL
== *FontObj
)
347 Status
= STATUS_INVALID_HANDLE
;
350 if (NT_SUCCESS(Status
) && NULL
!= FontGDI
)
352 *FontGDI
= AccessInternalObject((ULONG
) TextObj
->GDIFontHandle
);
353 if (NULL
== *FontGDI
)
356 Status
= STATUS_INVALID_HANDLE
;
362 Status
= STATUS_INVALID_HANDLE
;
370 NtGdiAddFontResource(PUNICODE_STRING Filename
, DWORD fl
)
372 UNICODE_STRING SafeFileName
;
377 /* Copy the UNICODE_STRING structure */
378 Status
= MmCopyFromCaller(&SafeFileName
, Filename
, sizeof(UNICODE_STRING
));
379 if(!NT_SUCCESS(Status
))
381 SetLastNtError(Status
);
385 src
= SafeFileName
.Buffer
;
386 SafeFileName
.Buffer
= (PWSTR
)ExAllocatePoolWithTag(PagedPool
, SafeFileName
.MaximumLength
, TAG_STRING
);
387 if(!SafeFileName
.Buffer
)
389 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
393 Status
= MmCopyFromCaller(&SafeFileName
.Buffer
, src
, SafeFileName
.MaximumLength
);
394 if(!NT_SUCCESS(Status
))
396 ExFreePool(SafeFileName
.Buffer
);
397 SetLastNtError(Status
);
401 Ret
= IntGdiAddFontResource(&SafeFileName
, fl
);
403 ExFreePool(SafeFileName
.Buffer
);
408 TextIntCreateFontIndirect(CONST LPLOGFONTW lf
, HFONT
*NewFont
)
411 NTSTATUS Status
= STATUS_SUCCESS
;
413 *NewFont
= TEXTOBJ_AllocText();
414 if (NULL
!= *NewFont
)
416 TextObj
= TEXTOBJ_LockText(*NewFont
);
419 memcpy(&TextObj
->logfont
, lf
, sizeof(LOGFONTW
));
420 if (lf
->lfEscapement
!= lf
->lfOrientation
)
422 /* this should really depend on whether GM_ADVANCED is set */
423 TextObj
->logfont
.lfOrientation
= TextObj
->logfont
.lfEscapement
;
425 TEXTOBJ_UnlockText(*NewFont
);
431 Status
= STATUS_INVALID_HANDLE
;
436 Status
= STATUS_NO_MEMORY
;
444 NtGdiCreateFont(int Height
,
453 DWORD OutputPrecision
,
456 DWORD PitchAndFamily
,
461 NTSTATUS Status
= STATUS_SUCCESS
;
463 logfont
.lfHeight
= Height
;
464 logfont
.lfWidth
= Width
;
465 logfont
.lfEscapement
= Escapement
;
466 logfont
.lfOrientation
= Orientation
;
467 logfont
.lfWeight
= Weight
;
468 logfont
.lfItalic
= Italic
;
469 logfont
.lfUnderline
= Underline
;
470 logfont
.lfStrikeOut
= StrikeOut
;
471 logfont
.lfCharSet
= CharSet
;
472 logfont
.lfOutPrecision
= OutputPrecision
;
473 logfont
.lfClipPrecision
= ClipPrecision
;
474 logfont
.lfQuality
= Quality
;
475 logfont
.lfPitchAndFamily
= PitchAndFamily
;
479 int Size
= sizeof(logfont
.lfFaceName
) / sizeof(WCHAR
);
480 wcsncpy((wchar_t *)logfont
.lfFaceName
, Face
, Size
- 1);
481 /* Be 101% sure to have '\0' at end of string */
482 logfont
.lfFaceName
[Size
- 1] = '\0';
486 logfont
.lfFaceName
[0] = L
'\0';
489 if (NT_SUCCESS(Status
))
491 Status
= TextIntCreateFontIndirect(&logfont
, &NewFont
);
494 return NT_SUCCESS(Status
) ? NewFont
: NULL
;
499 NtGdiCreateFontIndirect(CONST LPLOGFONTW lf
)
501 LOGFONTW SafeLogfont
;
503 NTSTATUS Status
= STATUS_SUCCESS
;
507 Status
= MmCopyFromCaller(&SafeLogfont
, lf
, sizeof(LOGFONTW
));
508 if (NT_SUCCESS(Status
))
510 Status
= TextIntCreateFontIndirect(&SafeLogfont
, &NewFont
);
515 Status
= STATUS_INVALID_PARAMETER
;
518 return NT_SUCCESS(Status
) ? NewFont
: NULL
;
523 NtGdiCreateScalableFontResource(DWORD Hidden
,
533 NtGdiEnumFontFamilies(HDC hDC
,
535 FONTENUMPROCW EnumFontFamProc
,
543 NtGdiEnumFontFamiliesEx(HDC hDC
,
545 FONTENUMEXPROCW EnumFontFamExProc
,
554 NtGdiEnumFonts(HDC hDC
,
556 FONTENUMPROCW FontFunc
,
563 NtGdiExtTextOut(HDC hDC
, int XStart
, int YStart
, UINT fuOptions
,
564 CONST RECT
*lprc
, LPCWSTR String
, UINT Count
, CONST INT
*lpDx
)
568 * Call EngTextOut, which does the real work (calling DrvTextOut where
574 int error
, glyph_index
, n
, i
;
577 ULONG TextLeft
, TextTop
, pitch
, previous
, BackgroundLeft
;
579 RECTL DestRect
, MaskRect
;
580 POINTL SourcePoint
, BrushOrigin
;
581 HBRUSH hBrushFg
= NULL
;
582 PBRUSHOBJ BrushFg
= NULL
;
583 HBRUSH hBrushBg
= NULL
;
584 PBRUSHOBJ BrushBg
= NULL
;
585 HBITMAP HSourceGlyph
;
586 PSURFOBJ SourceGlyphSurf
;
588 FT_CharMap found
= 0, charmap
;
594 PXLATEOBJ XlateObj
, XlateObj2
;
596 FT_Render_Mode RenderMode
;
603 SurfObj
= (SURFOBJ
*)AccessUserObject((ULONG
) dc
->Surface
);
605 XStart
+= dc
->w
.DCOrgX
;
606 YStart
+= dc
->w
.DCOrgY
;
609 BackgroundLeft
= XStart
;
611 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
613 if (!NT_SUCCESS(GetFontObjectsFromTextObj(TextObj
, NULL
, &FontObj
, &FontGDI
)))
618 face
= FontGDI
->face
;
619 if (face
->charmap
== NULL
)
621 DPRINT("WARNING: No charmap selected!\n");
622 DPRINT("This font face has %d charmaps\n", face
->num_charmaps
);
624 for (n
= 0; n
< face
->num_charmaps
; n
++)
626 charmap
= face
->charmaps
[n
];
627 DPRINT("found charmap encoding: %u\n", charmap
->encoding
);
628 if (charmap
->encoding
!= 0)
635 DPRINT1("WARNING: Could not find desired charmap!\n");
636 ExAcquireFastMutex(&FreeTypeLock
);
637 error
= FT_Set_Charmap(face
, found
);
638 ExReleaseFastMutex(&FreeTypeLock
);
640 DPRINT1("WARNING: Could not set the charmap!\n");
643 Render
= IntIsFontRenderingEnabled();
645 RenderMode
= IntGetFontRenderMode(&TextObj
->logfont
);
647 RenderMode
= FT_RENDER_MODE_MONO
;
649 ExAcquireFastMutex(&FreeTypeLock
);
650 error
= FT_Set_Pixel_Sizes(
652 /* FIXME should set character height if neg */
653 (TextObj
->logfont
.lfHeight
< 0 ?
654 - TextObj
->logfont
.lfHeight
:
655 TextObj
->logfont
.lfHeight
),
656 TextObj
->logfont
.lfWidth
);
657 ExReleaseFastMutex(&FreeTypeLock
);
660 DPRINT1("Error in setting pixel sizes: %u\n", error
);
664 /* Create the brushes */
665 PalDestGDI
= PALETTE_LockPalette(dc
->w
.hPalette
);
666 Mode
= PalDestGDI
->Mode
;
667 PALETTE_UnlockPalette(dc
->w
.hPalette
);
668 XlateObj
= (PXLATEOBJ
)IntEngCreateXlate(Mode
, PAL_RGB
, dc
->w
.hPalette
, NULL
);
669 hBrushFg
= NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj
, dc
->w
.textColor
));
670 BrushFg
= BRUSHOBJ_LockBrush(hBrushFg
);
671 if ((fuOptions
& ETO_OPAQUE
) || dc
->w
.backgroundMode
== OPAQUE
)
673 hBrushBg
= NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj
, dc
->w
.backgroundColor
));
676 BrushBg
= BRUSHOBJ_LockBrush(hBrushBg
);
680 EngDeleteXlate(XlateObj
);
684 XlateObj2
= (PXLATEOBJ
)IntEngCreateXlate(PAL_RGB
, Mode
, NULL
, dc
->w
.hPalette
);
693 if ((fuOptions
& ETO_OPAQUE
) && lprc
)
695 MmCopyFromCaller(&DestRect
, lprc
, sizeof(RECT
));
696 DestRect
.left
+= dc
->w
.DCOrgX
;
697 DestRect
.top
+= dc
->w
.DCOrgY
;
698 DestRect
.right
+= dc
->w
.DCOrgX
;
699 DestRect
.bottom
+= dc
->w
.DCOrgY
;
712 fuOptions
&= ~ETO_OPAQUE
;
716 if (dc
->w
.backgroundMode
== OPAQUE
)
718 fuOptions
|= ETO_OPAQUE
;
722 // Determine the yoff from the dc's w.textAlign
723 if (dc
->w
.textAlign
& TA_BASELINE
) {
727 if (dc
->w
.textAlign
& TA_BOTTOM
) {
728 yoff
= -face
->size
->metrics
.descender
/ 64;
731 yoff
= face
->size
->metrics
.ascender
/ 64;
734 use_kerning
= FT_HAS_KERNING(face
);
737 for(i
=0; i
<Count
; i
++)
739 ExAcquireFastMutex(&FreeTypeLock
);
740 glyph_index
= FT_Get_Char_Index(face
, *String
);
741 error
= FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
742 ExReleaseFastMutex(&FreeTypeLock
);
744 EngDeleteXlate(XlateObj
);
745 EngDeleteXlate(XlateObj2
);
746 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index
);
751 // retrieve kerning distance and move pen position
752 if (use_kerning
&& previous
&& glyph_index
)
755 ExAcquireFastMutex(&FreeTypeLock
);
756 FT_Get_Kerning(face
, previous
, glyph_index
, 0, &delta
);
757 ExReleaseFastMutex(&FreeTypeLock
);
758 TextLeft
+= delta
.x
>> 6;
761 if (glyph
->format
== ft_glyph_format_outline
)
763 ExAcquireFastMutex(&FreeTypeLock
);
764 error
= FT_Render_Glyph(glyph
, RenderMode
);
765 ExReleaseFastMutex(&FreeTypeLock
);
767 EngDeleteXlate(XlateObj
);
768 EngDeleteXlate(XlateObj2
);
769 DPRINT1("WARNING: Failed to render glyph!\n");
772 pitch
= glyph
->bitmap
.pitch
;
774 pitch
= glyph
->bitmap
.width
;
777 if (fuOptions
& ETO_OPAQUE
)
779 DestRect
.left
= BackgroundLeft
;
780 DestRect
.right
= TextLeft
+ (glyph
->advance
.x
+ 32) / 64;
781 DestRect
.top
= TextTop
+ yoff
- (face
->size
->metrics
.ascender
+ 32) / 64;
782 DestRect
.bottom
= TextTop
+ yoff
+ (- face
->size
->metrics
.descender
+ 32) / 64;
783 IntEngBitBlt(SurfObj
,
794 BackgroundLeft
= DestRect
.right
;
797 DestRect
.left
= TextLeft
;
798 DestRect
.right
= TextLeft
+ glyph
->bitmap
.width
;
799 DestRect
.top
= TextTop
+ yoff
- glyph
->bitmap_top
;
800 DestRect
.bottom
= DestRect
.top
+ glyph
->bitmap
.rows
;
802 bitSize
.cx
= glyph
->bitmap
.width
;
803 bitSize
.cy
= glyph
->bitmap
.rows
;
804 MaskRect
.right
= glyph
->bitmap
.width
;
805 MaskRect
.bottom
= glyph
->bitmap
.rows
;
807 // We should create the bitmap out of the loop at the biggest possible glyph size
808 // Then use memset with 0 to clear it and sourcerect to limit the work of the transbitblt
809 HSourceGlyph
= EngCreateBitmap(bitSize
, pitch
, (glyph
->bitmap
.pixel_mode
== ft_pixel_mode_grays
) ? BMF_8BPP
: BMF_1BPP
, 0, glyph
->bitmap
.buffer
);
810 SourceGlyphSurf
= (PSURFOBJ
)AccessUserObject((ULONG
) HSourceGlyph
);
812 // Use the font data as a mask to paint onto the DCs surface using a brush
825 EngDeleteSurface(HSourceGlyph
);
827 TextLeft
+= (glyph
->advance
.x
+ 32) / 64;
828 previous
= glyph_index
;
832 EngDeleteXlate(XlateObj
);
833 EngDeleteXlate(XlateObj2
);
834 TEXTOBJ_UnlockText(dc
->w
.hFont
);
835 if (NULL
!= hBrushBg
)
837 BRUSHOBJ_UnlockBrush(hBrushBg
);
838 NtGdiDeleteObject(hBrushBg
);
840 BRUSHOBJ_UnlockBrush(hBrushFg
);
841 NtGdiDeleteObject(hBrushFg
);
846 TEXTOBJ_UnlockText( dc
->w
.hFont
);
847 if (NULL
!= hBrushBg
)
849 BRUSHOBJ_UnlockBrush(hBrushBg
);
850 NtGdiDeleteObject(hBrushBg
);
852 if (NULL
!= hBrushFg
)
854 BRUSHOBJ_UnlockBrush(hBrushFg
);
855 NtGdiDeleteObject(hBrushFg
);
863 NtGdiGetAspectRatioFilterEx(HDC hDC
,
871 NtGdiGetCharABCWidths(HDC hDC
,
876 DPRINT1("NtGdiGetCharABCWidths Is unimplemented, keep going anyway\n");
882 NtGdiGetCharABCWidthsFloat(HDC hDC
,
892 NtGdiGetCharacterPlacement(HDC hDC
,
896 LPGCP_RESULTSW Results
,
904 NtGdiGetCharWidth(HDC hDC
,
909 DPRINT1("NtGdiGetCharWidth isnt really unimplemented - keep going anyway\n");
915 NtGdiGetCharWidth32(HDC hDC
,
925 FT_CharMap charmap
, found
= NULL
;
926 UINT i
, glyph_index
, BufferSize
;
928 if (LastChar
< FirstChar
)
930 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
934 BufferSize
= (LastChar
- FirstChar
) * sizeof(INT
);
935 SafeBuffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_GDITEXT
);
936 if (SafeBuffer
== NULL
)
938 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
945 ExFreePool(SafeBuffer
);
946 SetLastWin32Error(ERROR_INVALID_HANDLE
);
949 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
952 GetFontObjectsFromTextObj(TextObj
, NULL
, NULL
, &FontGDI
);
954 face
= FontGDI
->face
;
955 if (face
->charmap
== NULL
)
957 for (i
= 0; i
< face
->num_charmaps
; i
++)
959 charmap
= face
->charmaps
[i
];
960 if (charmap
->encoding
!= 0)
969 DPRINT1("WARNING: Could not find desired charmap!\n");
970 ExFreePool(SafeBuffer
);
971 SetLastWin32Error(ERROR_INVALID_HANDLE
);
975 ExAcquireFastMutex(&FreeTypeLock
);
976 FT_Set_Charmap(face
, found
);
977 ExReleaseFastMutex(&FreeTypeLock
);
980 ExAcquireFastMutex(&FreeTypeLock
);
981 FT_Set_Pixel_Sizes(face
,
982 /* FIXME should set character height if neg */
983 (TextObj
->logfont
.lfHeight
< 0 ?
984 - TextObj
->logfont
.lfHeight
:
985 TextObj
->logfont
.lfHeight
),
986 TextObj
->logfont
.lfWidth
);
988 for (i
= FirstChar
; i
<= LastChar
; i
++)
990 glyph_index
= FT_Get_Char_Index(face
, i
);
991 FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
992 SafeBuffer
[i
] = face
->glyph
->advance
.x
>> 6;
994 ExReleaseFastMutex(&FreeTypeLock
);
995 TEXTOBJ_UnlockText(dc
->w
.hFont
);
996 MmCopyToCaller(Buffer
, SafeBuffer
, BufferSize
);
997 ExFreePool(SafeBuffer
);
1003 NtGdiGetCharWidthFloat(HDC hDC
,
1013 NtGdiGetFontLanguageInfo(HDC hDC
)
1020 NtGdiGetGlyphOutline(HDC hDC
,
1035 NtGdiGetKerningPairs(HDC hDC
,
1037 LPKERNINGPAIR krnpair
)
1044 NtGdiGetOutlineTextMetrics(HDC hDC
,
1046 LPOUTLINETEXTMETRICW otm
)
1053 NtGdiGetRasterizerCaps(LPRASTERIZER_STATUS rs
,
1061 NtGdiGetTextCharset(HDC hDC
)
1068 NtGdiGetTextCharsetInfo(HDC hDC
,
1069 LPFONTSIGNATURE Sig
,
1077 TextIntGetTextExtentPoint(HDC hDC
,
1089 INT error
, n
, glyph_index
, i
, previous
;
1090 LONG TotalWidth
= 0;
1091 FT_CharMap charmap
, found
= NULL
;
1094 GetFontObjectsFromTextObj(TextObj
, NULL
, NULL
, &FontGDI
);
1095 face
= FontGDI
->face
;
1101 if (face
->charmap
== NULL
)
1103 DPRINT("WARNING: No charmap selected!\n");
1104 DPRINT("This font face has %d charmaps\n", face
->num_charmaps
);
1106 for (n
= 0; n
< face
->num_charmaps
; n
++)
1108 charmap
= face
->charmaps
[n
];
1109 DPRINT("found charmap encoding: %u\n", charmap
->encoding
);
1110 if (charmap
->encoding
!= 0)
1119 DPRINT1("WARNING: Could not find desired charmap!\n");
1122 ExAcquireFastMutex(&FreeTypeLock
);
1123 error
= FT_Set_Charmap(face
, found
);
1124 ExReleaseFastMutex(&FreeTypeLock
);
1127 DPRINT1("WARNING: Could not set the charmap!\n");
1131 ExAcquireFastMutex(&FreeTypeLock
);
1132 error
= FT_Set_Pixel_Sizes(face
,
1133 /* FIXME should set character height if neg */
1134 (TextObj
->logfont
.lfHeight
< 0 ?
1135 - TextObj
->logfont
.lfHeight
:
1136 TextObj
->logfont
.lfHeight
),
1137 TextObj
->logfont
.lfWidth
);
1138 ExReleaseFastMutex(&FreeTypeLock
);
1141 DPRINT1("Error in setting pixel sizes: %u\n", error
);
1144 use_kerning
= FT_HAS_KERNING(face
);
1147 for (i
= 0; i
< Count
; i
++)
1149 ExAcquireFastMutex(&FreeTypeLock
);
1150 glyph_index
= FT_Get_Char_Index(face
, *String
);
1151 error
= FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
1152 ExReleaseFastMutex(&FreeTypeLock
);
1155 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index
);
1157 glyph
= face
->glyph
;
1159 /* retrieve kerning distance */
1160 if (use_kerning
&& previous
&& glyph_index
)
1163 ExAcquireFastMutex(&FreeTypeLock
);
1164 FT_Get_Kerning(face
, previous
, glyph_index
, 0, &delta
);
1165 ExReleaseFastMutex(&FreeTypeLock
);
1166 TotalWidth
+= delta
.x
>> 6;
1169 TotalWidth
+= glyph
->advance
.x
>> 6;
1170 if (glyph
->format
== ft_glyph_format_outline
)
1172 ExAcquireFastMutex(&FreeTypeLock
);
1173 error
= FT_Render_Glyph(glyph
, FT_RENDER_MODE_MONO
);
1174 ExReleaseFastMutex(&FreeTypeLock
);
1177 DPRINT1("WARNING: Failed to render glyph!\n");
1181 if (TotalWidth
<= MaxExtent
&& NULL
!= Fit
)
1190 previous
= glyph_index
;
1194 Size
->cx
= TotalWidth
;
1195 Size
->cy
= (TextObj
->logfont
.lfHeight
< 0 ? - TextObj
->logfont
.lfHeight
: TextObj
->logfont
.lfHeight
);
1196 Size
->cy
= EngMulDiv(Size
->cy
, NtGdiGetDeviceCaps(hDC
, LOGPIXELSY
), 72);
1203 NtGdiGetTextExtentExPoint(HDC hDC
,
1204 LPCWSTR UnsafeString
,
1222 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1229 Status
= MmCopyToCaller(UnsafeSize
, &Size
, sizeof(SIZE
));
1230 if (! NT_SUCCESS(Status
))
1232 SetLastNtError(Status
);
1238 String
= ExAllocatePoolWithTag(PagedPool
, Count
* sizeof(WCHAR
), TAG_GDITEXT
);
1241 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1245 if (NULL
!= UnsafeDx
)
1247 Dx
= ExAllocatePoolWithTag(PagedPool
, Count
* sizeof(INT
), TAG_GDITEXT
);
1251 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1260 Status
= MmCopyFromCaller(String
, UnsafeString
, Count
* sizeof(WCHAR
));
1261 if (! NT_SUCCESS(Status
))
1268 SetLastNtError(Status
);
1272 dc
= DC_LockDc(hDC
);
1280 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1283 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
1285 Result
= TextIntGetTextExtentPoint(hDC
, TextObj
, String
, Count
, MaxExtent
,
1286 NULL
== UnsafeFit
? NULL
: &Fit
, Dx
, &Size
);
1287 TEXTOBJ_UnlockText(dc
->w
.hFont
);
1299 if (NULL
!= UnsafeFit
)
1301 Status
= MmCopyToCaller(UnsafeFit
, &Fit
, sizeof(INT
));
1302 if (! NT_SUCCESS(Status
))
1308 SetLastNtError(Status
);
1313 if (NULL
!= UnsafeDx
)
1315 Status
= MmCopyToCaller(UnsafeDx
, Dx
, Count
* sizeof(INT
));
1316 if (! NT_SUCCESS(Status
))
1322 SetLastNtError(Status
);
1331 Status
= MmCopyToCaller(UnsafeSize
, &Size
, sizeof(SIZE
));
1332 if (! NT_SUCCESS(Status
))
1334 SetLastNtError(Status
);
1343 NtGdiGetTextExtentPoint(HDC hDC
,
1348 return NtGdiGetTextExtentExPoint(hDC
, String
, Count
, 0, NULL
, NULL
, Size
);
1353 NtGdiGetTextExtentPoint32(HDC hDC
,
1354 LPCWSTR UnsafeString
,
1367 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1374 Status
= MmCopyToCaller(UnsafeSize
, &Size
, sizeof(SIZE
));
1375 if (! NT_SUCCESS(Status
))
1377 SetLastNtError(Status
);
1383 String
= ExAllocatePool(PagedPool
, Count
* sizeof(WCHAR
));
1386 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1390 Status
= MmCopyFromCaller(String
, UnsafeString
, Count
* sizeof(WCHAR
));
1391 if (! NT_SUCCESS(Status
))
1394 SetLastNtError(Status
);
1398 dc
= DC_LockDc(hDC
);
1402 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1405 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
1407 Result
= TextIntGetTextExtentPoint (
1408 hDC
, TextObj
, String
, Count
, 0, NULL
, NULL
, &Size
);
1409 dc
= DC_LockDc(hDC
);
1410 ASSERT(dc
); // it succeeded earlier, it should now, too
1411 TEXTOBJ_UnlockText(dc
->w
.hFont
);
1420 Status
= MmCopyToCaller(UnsafeSize
, &Size
, sizeof(SIZE
));
1421 if (! NT_SUCCESS(Status
))
1423 SetLastNtError(Status
);
1432 NtGdiGetTextFace(HDC hDC
,
1441 NtGdiGetTextMetrics(HDC hDC
,
1447 NTSTATUS Status
= STATUS_SUCCESS
;
1453 dc
= DC_LockDc(hDC
);
1454 if (NULL
== dc
|| NULL
== tm
)
1456 Status
= STATUS_INVALID_PARAMETER
;
1460 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
1461 if (NULL
!= TextObj
)
1463 Status
= GetFontObjectsFromTextObj(TextObj
, NULL
, NULL
, &FontGDI
);
1464 if (NT_SUCCESS(Status
))
1466 Face
= FontGDI
->face
;
1467 ExAcquireFastMutex(&FreeTypeLock
);
1468 Error
= FT_Set_Pixel_Sizes(Face
,
1469 /* FIXME should set character height if neg */
1470 (TextObj
->logfont
.lfHeight
< 0 ?
1471 - TextObj
->logfont
.lfHeight
:
1472 TextObj
->logfont
.lfHeight
),
1473 TextObj
->logfont
.lfWidth
);
1474 ExReleaseFastMutex(&FreeTypeLock
);
1477 DPRINT1("Error in setting pixel sizes: %u\n", Error
);
1478 Status
= STATUS_UNSUCCESSFUL
;
1482 memcpy(&SafeTm
, &FontGDI
->TextMetric
, sizeof(TEXTMETRICW
));
1483 ExAcquireFastMutex(&FreeTypeLock
);
1484 pOS2
= FT_Get_Sfnt_Table(Face
, ft_sfnt_os2
);
1485 ExReleaseFastMutex(&FreeTypeLock
);
1488 DPRINT1("Can't find OS/2 table - not TT font?\n");
1489 Status
= STATUS_UNSUCCESSFUL
;
1493 SafeTm
.tmAveCharWidth
= (pOS2
->xAvgCharWidth
+ 32) / 64;
1495 SafeTm
.tmAscent
= (Face
->size
->metrics
.ascender
+ 32) / 64; // units above baseline
1496 SafeTm
.tmDescent
= (- Face
->size
->metrics
.descender
+ 32) / 64; // units below baseline
1497 SafeTm
.tmHeight
= SafeTm
.tmAscent
+ SafeTm
.tmDescent
;
1498 SafeTm
.tmMaxCharWidth
= (Face
->size
->metrics
.max_advance
+ 32) / 64;
1499 Status
= MmCopyToCaller(tm
, &SafeTm
, sizeof(TEXTMETRICW
));
1502 TEXTOBJ_UnlockText(dc
->w
.hFont
);
1507 Status
= STATUS_INVALID_HANDLE
;
1512 return NT_SUCCESS(Status
);
1517 NtGdiPolyTextOut(HDC hDC
,
1518 CONST LPPOLYTEXTW txt
,
1526 NtGdiRemoveFontResource(LPCWSTR FileName
)
1533 NtGdiSetMapperFlags(HDC hDC
,
1541 NtGdiSetTextAlign(HDC hDC
,
1547 dc
= DC_LockDc(hDC
);
1552 prevAlign
= dc
->w
.textAlign
;
1553 dc
->w
.textAlign
= Mode
;
1560 NtGdiSetTextColor(HDC hDC
,
1564 PDC dc
= DC_LockDc(hDC
);
1571 oldColor
= dc
->w
.textColor
;
1572 dc
->w
.textColor
= color
;
1579 NtGdiSetTextJustification(HDC hDC
,
1594 return NtGdiExtTextOut(hDC
, XStart
, YStart
, 0, NULL
, String
, Count
, NULL
);
1599 NtGdiTranslateCharsetInfo(PDWORD Src
,
1607 TextIntRealizeFont(HFONT FontHandle
)
1609 NTSTATUS Status
= STATUS_SUCCESS
;
1611 UNICODE_STRING FaceName
;
1613 PFONT_ENTRY CurrentEntry
;
1614 PW32PROCESS Win32Process
;
1615 BOOL Private
= FALSE
;
1617 TextObj
= TEXTOBJ_LockText(FontHandle
);
1619 if (NULL
!= TextObj
)
1621 RtlInitUnicodeString(&FaceName
, TextObj
->logfont
.lfFaceName
);
1623 /* find font in private fonts */
1624 Win32Process
= PsGetWin32Process();
1626 ExAcquireFastMutex(&Win32Process
->PrivateFontListLock
);
1628 Entry
= Win32Process
->PrivateFontListHead
.Flink
;
1629 while(Entry
!= &Win32Process
->PrivateFontListHead
)
1631 CurrentEntry
= (PFONT_ENTRY
)CONTAINING_RECORD(Entry
, FONT_ENTRY
, ListEntry
);
1633 if (0 == RtlCompareUnicodeString(&CurrentEntry
->FaceName
, &FaceName
, TRUE
))
1635 TextObj
->GDIFontHandle
= CurrentEntry
->hFont
;
1639 Entry
= Entry
->Flink
;
1641 ExReleaseFastMutex(&Win32Process
->PrivateFontListLock
);
1643 /* find font in system fonts */
1644 ExAcquireFastMutex(&FontListLock
);
1646 Entry
= FontListHead
.Flink
;
1647 while(Entry
!= &FontListHead
)
1649 CurrentEntry
= (PFONT_ENTRY
)CONTAINING_RECORD(Entry
, FONT_ENTRY
, ListEntry
);
1651 if (0 == RtlCompareUnicodeString(&CurrentEntry
->FaceName
, &FaceName
, TRUE
))
1653 TextObj
->GDIFontHandle
= CurrentEntry
->hFont
;
1656 Entry
= Entry
->Flink
;
1660 if (NULL
== TextObj
->GDIFontHandle
)
1662 Entry
= (Private
? Win32Process
->PrivateFontListHead
.Flink
: FontListHead
.Flink
);
1664 if(Entry
!= (Private
? &Win32Process
->PrivateFontListHead
: &FontListHead
))
1666 DPRINT("Requested font %S not found, using first available font\n",
1667 TextObj
->logfont
.lfFaceName
)
1668 CurrentEntry
= (PFONT_ENTRY
)CONTAINING_RECORD(Entry
, FONT_ENTRY
, ListEntry
);
1669 TextObj
->GDIFontHandle
= CurrentEntry
->hFont
;
1673 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
1674 TextObj
->logfont
.lfFaceName
);
1675 Status
= STATUS_NOT_FOUND
;
1680 ExReleaseFastMutex((Private
? &Win32Process
->PrivateFontListLock
: &FontListLock
));
1682 ASSERT(! NT_SUCCESS(Status
) || NULL
!= TextObj
->GDIFontHandle
);
1684 TEXTOBJ_UnlockText(FontHandle
);
1688 Status
= STATUS_INVALID_HANDLE
;