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.67 2003/12/26 00:31:22 weiden 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>
45 #include <win32k/debug1.h>
49 typedef struct _FONT_ENTRY
{
52 UNICODE_STRING FaceName
;
54 } FONT_ENTRY
, *PFONT_ENTRY
;
56 static LIST_ENTRY FontListHead
;
57 static FAST_MUTEX FontListLock
;
58 static INT FontsLoaded
= 0; /* number of all fonts loaded (including private fonts */
59 static BOOL RenderingEnabled
= TRUE
;
62 IntIsFontRenderingEnabled(VOID
)
68 Ret
= RenderingEnabled
;
69 hDC
= IntGetScreenDC();
73 SurfObj
= (PSURFOBJ
)AccessUserObject((ULONG
) dc
->Surface
);
75 Ret
= (SurfObj
->iBitmapFormat
>= BMF_8BPP
);
82 IntEnableFontRendering(BOOL Enable
)
84 RenderingEnabled
= Enable
;
87 FT_Render_Mode FASTCALL
88 IntGetFontRenderMode(LOGFONTW
*logfont
)
90 switch(logfont
->lfQuality
)
92 //case ANTIALIASED_QUALITY:
94 return FT_RENDER_MODE_NORMAL
;
96 return FT_RENDER_MODE_LIGHT
;
97 //case NONANTIALIASED_QUALITY:
99 return FT_RENDER_MODE_MONO
;
100 //case CLEARTYPE_QUALITY:
101 // return FT_RENDER_MODE_LCD;
103 return FT_RENDER_MODE_MONO
;
107 IntGdiAddFontResource(PUNICODE_STRING Filename
, DWORD fl
)
114 OBJECT_ATTRIBUTES ObjectAttributes
;
115 FILE_STANDARD_INFORMATION FileStdInfo
;
121 IO_STATUS_BLOCK Iosb
;
124 NewFont
= (HFONT
)CreateGDIHandle(sizeof( FONTGDI
), sizeof( FONTOBJ
));
125 FontObj
= (PFONTOBJ
) AccessUserObject( (ULONG
) NewFont
);
126 FontGDI
= (PFONTGDI
) AccessInternalObject( (ULONG
) NewFont
);
129 InitializeObjectAttributes(&ObjectAttributes
, Filename
, 0, NULL
, NULL
);
131 Status
= ZwOpenFile(&FileHandle
,
132 GENERIC_READ
|SYNCHRONIZE
,
136 FILE_SYNCHRONOUS_IO_NONALERT
);
138 if (!NT_SUCCESS(Status
))
140 DPRINT1("Could not open module file: %wZ\n", Filename
);
144 // Get the size of the file
145 Status
= NtQueryInformationFile(FileHandle
, &Iosb
, &FileStdInfo
, sizeof(FileStdInfo
), FileStandardInformation
);
146 if (!NT_SUCCESS(Status
))
148 DPRINT1("Could not get file size\n");
152 // Allocate nonpageable memory for driver
153 size
= FileStdInfo
.EndOfFile
.u
.LowPart
;
154 buffer
= ExAllocatePool(NonPagedPool
, size
);
158 DPRINT1("could not allocate memory for module");
162 // Load driver into memory chunk
163 Status
= ZwReadFile(FileHandle
,
169 FileStdInfo
.EndOfFile
.u
.LowPart
,
173 if (!NT_SUCCESS(Status
))
175 DPRINT1("could not read module file into memory");
182 error
= FT_New_Memory_Face(library
, buffer
, size
, 0, &face
);
183 if (error
== FT_Err_Unknown_File_Format
)
185 DPRINT1("Unknown font file format\n");
190 DPRINT1("Error reading font file (error code: %u)\n", error
); // 48
194 entry
= ExAllocatePool(NonPagedPool
, sizeof(FONT_ENTRY
));
197 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
201 // FontGDI->Filename = Filename; perform strcpy
202 FontGDI
->face
= face
;
204 // FIXME: Complete text metrics
205 FontGDI
->TextMetric
.tmAscent
= (face
->size
->metrics
.ascender
+ 32) / 64; // units above baseline
206 FontGDI
->TextMetric
.tmDescent
= (- face
->size
->metrics
.descender
+ 32) / 64; // units below baseline
207 FontGDI
->TextMetric
.tmHeight
= FontGDI
->TextMetric
.tmAscent
+ FontGDI
->TextMetric
.tmDescent
;
209 DPRINT("Font loaded: %s (%s)\n", face
->family_name
, face
->style_name
);
210 DPRINT("Num glyphs: %u\n", face
->num_glyphs
);
212 // Add this font resource to the font table
213 entry
->hFont
= NewFont
;
214 entry
->NotEnum
= (fl
& FR_NOT_ENUM
);
215 RtlInitAnsiString(&StringA
, (LPSTR
)face
->family_name
);
216 RtlAnsiStringToUnicodeString(&entry
->FaceName
, &StringA
, TRUE
);
220 PW32PROCESS Win32Process
= PsGetWin32Process();
222 ExAcquireFastMutex(&Win32Process
->PrivateFontListLock
);
223 InsertTailList(&Win32Process
->PrivateFontListHead
, &entry
->ListEntry
);
225 ExReleaseFastMutex(&Win32Process
->PrivateFontListLock
);
229 ExAcquireFastMutex(&FontListLock
);
230 InsertTailList(&FontListHead
, &entry
->ListEntry
);
232 ExReleaseFastMutex(&FontListLock
);
238 BOOL FASTCALL
InitFontSupport(VOID
)
242 UNICODE_STRING Filename
;
244 static WCHAR
*FontFiles
[] =
246 L
"\\SystemRoot\\media\\fonts\\Vera.ttf",
247 L
"\\SystemRoot\\media\\fonts\\helb____.ttf",
248 L
"\\SystemRoot\\media\\fonts\\timr____.ttf",
249 L
"\\SystemRoot\\media\\fonts\\VeraBd.ttf",
250 L
"\\SystemRoot\\media\\fonts\\VeraBI.ttf",
251 L
"\\SystemRoot\\media\\fonts\\VeraIt.ttf",
252 L
"\\SystemRoot\\media\\fonts\\VeraMoBd.ttf",
253 L
"\\SystemRoot\\media\\fonts\\VeraMoBI.ttf",
254 L
"\\SystemRoot\\media\\fonts\\VeraMoIt.ttf",
255 L
"\\SystemRoot\\media\\fonts\\VeraMono.ttf",
256 L
"\\SystemRoot\\media\\fonts\\VeraSe.ttf",
257 L
"\\SystemRoot\\media\\fonts\\VeraSeBd.ttf"
260 InitializeListHead(&FontListHead
);
261 ExInitializeFastMutex(&FontListLock
);
263 error
= FT_Init_FreeType(&library
);
269 /* FIXME load fonts from registry */
271 for (File
= 0; File
< sizeof(FontFiles
) / sizeof(WCHAR
*); File
++)
273 DPRINT("Loading font %S\n", FontFiles
[File
]);
275 RtlInitUnicodeString(&Filename
, FontFiles
[File
]);
276 IntGdiAddFontResource(&Filename
, 0);
279 DPRINT("All fonts loaded\n");
284 static NTSTATUS STDCALL
285 GetFontObjectsFromTextObj(PTEXTOBJ TextObj
, HFONT
*FontHandle
, PFONTOBJ
*FontObj
, PFONTGDI
*FontGDI
)
287 NTSTATUS Status
= STATUS_SUCCESS
;
289 ASSERT(NULL
!= TextObj
&& NULL
!= TextObj
->GDIFontHandle
);
290 if (NULL
!= TextObj
&& NULL
!= TextObj
->GDIFontHandle
)
292 if (NT_SUCCESS(Status
) && NULL
!= FontHandle
)
294 *FontHandle
= TextObj
->GDIFontHandle
;
296 if (NT_SUCCESS(Status
) && NULL
!= FontObj
)
298 *FontObj
= AccessUserObject((ULONG
) TextObj
->GDIFontHandle
);
299 if (NULL
== *FontObj
)
302 Status
= STATUS_INVALID_HANDLE
;
305 if (NT_SUCCESS(Status
) && NULL
!= FontGDI
)
307 *FontGDI
= AccessInternalObject((ULONG
) TextObj
->GDIFontHandle
);
308 if (NULL
== *FontGDI
)
311 Status
= STATUS_INVALID_HANDLE
;
317 Status
= STATUS_INVALID_HANDLE
;
325 NtGdiAddFontResource(PUNICODE_STRING Filename
, DWORD fl
)
327 UNICODE_STRING SafeFileName
;
332 /* Copy the UNICODE_STRING structure */
333 Status
= MmCopyFromCaller(&SafeFileName
, Filename
, sizeof(UNICODE_STRING
));
334 if(!NT_SUCCESS(Status
))
336 SetLastNtError(Status
);
340 src
= SafeFileName
.Buffer
;
341 SafeFileName
.Buffer
= (PWSTR
)ExAllocatePool(PagedPool
, SafeFileName
.MaximumLength
);
342 if(!SafeFileName
.Buffer
)
344 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
348 Status
= MmCopyFromCaller(&SafeFileName
.Buffer
, src
, SafeFileName
.MaximumLength
);
349 if(!NT_SUCCESS(Status
))
351 ExFreePool(SafeFileName
.Buffer
);
352 SetLastNtError(Status
);
356 Ret
= IntGdiAddFontResource(&SafeFileName
, fl
);
358 ExFreePool(SafeFileName
.Buffer
);
363 TextIntCreateFontIndirect(CONST LPLOGFONTW lf
, HFONT
*NewFont
)
366 NTSTATUS Status
= STATUS_SUCCESS
;
368 *NewFont
= TEXTOBJ_AllocText();
369 if (NULL
!= *NewFont
)
371 TextObj
= TEXTOBJ_LockText(*NewFont
);
374 memcpy(&TextObj
->logfont
, lf
, sizeof(LOGFONTW
));
375 if (lf
->lfEscapement
!= lf
->lfOrientation
)
377 /* this should really depend on whether GM_ADVANCED is set */
378 TextObj
->logfont
.lfOrientation
= TextObj
->logfont
.lfEscapement
;
380 TEXTOBJ_UnlockText(*NewFont
);
386 Status
= STATUS_INVALID_HANDLE
;
391 Status
= STATUS_NO_MEMORY
;
399 NtGdiCreateFont(int Height
,
408 DWORD OutputPrecision
,
411 DWORD PitchAndFamily
,
416 NTSTATUS Status
= STATUS_SUCCESS
;
418 logfont
.lfHeight
= Height
;
419 logfont
.lfWidth
= Width
;
420 logfont
.lfEscapement
= Escapement
;
421 logfont
.lfOrientation
= Orientation
;
422 logfont
.lfWeight
= Weight
;
423 logfont
.lfItalic
= Italic
;
424 logfont
.lfUnderline
= Underline
;
425 logfont
.lfStrikeOut
= StrikeOut
;
426 logfont
.lfCharSet
= CharSet
;
427 logfont
.lfOutPrecision
= OutputPrecision
;
428 logfont
.lfClipPrecision
= ClipPrecision
;
429 logfont
.lfQuality
= Quality
;
430 logfont
.lfPitchAndFamily
= PitchAndFamily
;
434 int Size
= sizeof(logfont
.lfFaceName
) / sizeof(WCHAR
);
435 wcsncpy((wchar_t *)logfont
.lfFaceName
, Face
, Size
- 1);
436 /* Be 101% sure to have '\0' at end of string */
437 logfont
.lfFaceName
[Size
- 1] = '\0';
441 logfont
.lfFaceName
[0] = L
'\0';
444 if (NT_SUCCESS(Status
))
446 Status
= TextIntCreateFontIndirect(&logfont
, &NewFont
);
449 return NT_SUCCESS(Status
) ? NewFont
: NULL
;
454 NtGdiCreateFontIndirect(CONST LPLOGFONTW lf
)
456 LOGFONTW SafeLogfont
;
458 NTSTATUS Status
= STATUS_SUCCESS
;
462 Status
= MmCopyFromCaller(&SafeLogfont
, lf
, sizeof(LOGFONTW
));
463 if (NT_SUCCESS(Status
))
465 Status
= TextIntCreateFontIndirect(&SafeLogfont
, &NewFont
);
470 Status
= STATUS_INVALID_PARAMETER
;
473 return NT_SUCCESS(Status
) ? NewFont
: NULL
;
478 NtGdiCreateScalableFontResource(DWORD Hidden
,
488 NtGdiEnumFontFamilies(HDC hDC
,
490 FONTENUMPROCW EnumFontFamProc
,
498 NtGdiEnumFontFamiliesEx(HDC hDC
,
500 FONTENUMEXPROCW EnumFontFamExProc
,
509 NtGdiEnumFonts(HDC hDC
,
511 FONTENUMPROCW FontFunc
,
518 NtGdiExtTextOut(HDC hDC
, int XStart
, int YStart
, UINT fuOptions
,
519 CONST RECT
*lprc
, LPCWSTR String
, UINT Count
, CONST INT
*lpDx
)
522 /* FIXME: Implement */
523 return NtGdiTextOut(hDC
, XStart
, YStart
, String
, Count
);
525 // Fixme: Call EngTextOut, which does the real work (calling DrvTextOut where appropriate)
529 int error
, glyph_index
, n
, i
;
532 ULONG TextLeft
, TextTop
, pitch
, previous
, BackgroundLeft
;
534 RECTL DestRect
, MaskRect
;
535 POINTL SourcePoint
, BrushOrigin
;
536 HBRUSH hBrushFg
= NULL
;
537 PBRUSHOBJ BrushFg
= NULL
;
538 HBRUSH hBrushBg
= NULL
;
539 PBRUSHOBJ BrushBg
= NULL
;
540 HBITMAP HSourceGlyph
;
541 PSURFOBJ SourceGlyphSurf
;
543 FT_CharMap found
= 0, charmap
;
555 SurfObj
= (SURFOBJ
*)AccessUserObject((ULONG
) dc
->Surface
);
557 XStart
+= dc
->w
.DCOrgX
;
558 YStart
+= dc
->w
.DCOrgY
;
561 BackgroundLeft
= XStart
;
563 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
565 if (! NT_SUCCESS(GetFontObjectsFromTextObj(TextObj
, NULL
, &FontObj
, &FontGDI
)))
569 face
= FontGDI
->face
;
571 if (face
->charmap
== NULL
)
573 DPRINT("WARNING: No charmap selected!\n");
574 DPRINT("This font face has %d charmaps\n", face
->num_charmaps
);
576 for (n
= 0; n
< face
->num_charmaps
; n
++)
578 charmap
= face
->charmaps
[n
];
579 DPRINT("found charmap encoding: %u\n", charmap
->encoding
);
580 if (charmap
->encoding
!= 0)
586 if (!found
) DPRINT1("WARNING: Could not find desired charmap!\n");
587 error
= FT_Set_Charmap(face
, found
);
588 if (error
) DPRINT1("WARNING: Could not set the charmap!\n");
591 error
= FT_Set_Pixel_Sizes(face
,
592 /* FIXME should set character height if neg */
593 (TextObj
->logfont
.lfHeight
< 0 ?
594 - TextObj
->logfont
.lfHeight
:
595 TextObj
->logfont
.lfHeight
),
596 TextObj
->logfont
.lfWidth
);
598 DPRINT1("Error in setting pixel sizes: %u\n", error
);
602 // Create the brushes
603 PalDestGDI
= PALETTE_LockPalette(dc
->w
.hPalette
);
604 Mode
= PalDestGDI
->Mode
;
605 PALETTE_UnlockPalette(dc
->w
.hPalette
);
606 XlateObj
= (PXLATEOBJ
)IntEngCreateXlate(Mode
, PAL_RGB
, dc
->w
.hPalette
, NULL
);
607 hBrushFg
= NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj
, dc
->w
.textColor
));
608 BrushFg
= BRUSHOBJ_LockBrush(hBrushFg
);
609 if (OPAQUE
== dc
->w
.backgroundMode
)
611 hBrushBg
= NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj
, dc
->w
.backgroundColor
));
614 BrushBg
= BRUSHOBJ_LockBrush(hBrushBg
);
618 EngDeleteXlate(XlateObj
);
622 EngDeleteXlate(XlateObj
);
631 // Determine the yoff from the dc's w.textAlign
632 if (dc
->w
.textAlign
& TA_BASELINE
) {
636 if (dc
->w
.textAlign
& TA_BOTTOM
) {
637 yoff
= -face
->size
->metrics
.descender
/ 64;
640 yoff
= face
->size
->metrics
.ascender
/ 64;
643 use_kerning
= FT_HAS_KERNING(face
);
646 for(i
=0; i
<Count
; i
++)
648 glyph_index
= FT_Get_Char_Index(face
, *String
);
649 error
= FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
651 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index
);
656 // retrieve kerning distance and move pen position
657 if (use_kerning
&& previous
&& glyph_index
)
660 FT_Get_Kerning(face
, previous
, glyph_index
, 0, &delta
);
661 TextLeft
+= delta
.x
>> 6;
664 if (glyph
->format
== ft_glyph_format_outline
)
666 error
= FT_Render_Glyph(glyph
, IntGetFontRenderMode(&TextObj
->logfont
));
668 DPRINT1("WARNING: Failed to render glyph!\n");
671 pitch
= glyph
->bitmap
.pitch
;
673 pitch
= glyph
->bitmap
.width
;
676 if (OPAQUE
== dc
->w
.backgroundMode
)
678 DestRect
.left
= BackgroundLeft
;
679 DestRect
.right
= TextLeft
+ (glyph
->advance
.x
+ 32) / 64;
680 DestRect
.top
= TextTop
+ yoff
- (face
->size
->metrics
.ascender
+ 32) / 64;
681 DestRect
.bottom
= TextTop
+ yoff
+ (- face
->size
->metrics
.descender
+ 32) / 64;
682 if (fuOptions
& ETO_CLIPPED
)
684 if (DestRect
.left
> lprc
->right
|| DestRect
.right
< lprc
->left
||
685 DestRect
.top
> lprc
->bottom
|| DestRect
.bottom
< lprc
->top
)
687 DestRect
.right
= DestRect
.left
;
691 DestRect
.left
= max(DestRect
.left
, lprc
->left
);
692 DestRect
.right
= min(DestRect
.right
, lprc
->right
);
693 DestRect
.top
= max(DestRect
.top
, lprc
->top
);
694 DestRect
.bottom
= min(DestRect
.bottom
, lprc
->bottom
);
697 IntEngBitBlt(SurfObj
,
708 BackgroundLeft
= DestRect
.right
;
711 DestRect
.left
= TextLeft
;
712 DestRect
.right
= TextLeft
+ glyph
->bitmap
.width
;
713 DestRect
.top
= TextTop
+ yoff
- glyph
->bitmap_top
;
714 DestRect
.bottom
= DestRect
.top
+ glyph
->bitmap
.rows
;
716 if (fuOptions
& ETO_CLIPPED
)
718 if (DestRect
.left
> lprc
->right
|| DestRect
.right
< lprc
->left
||
719 DestRect
.top
> lprc
->bottom
|| DestRect
.bottom
< lprc
->top
)
725 DestRect
.left
= max(DestRect
.left
, lprc
->left
);
726 DestRect
.right
= min(DestRect
.right
, lprc
->right
);
727 DestRect
.top
= max(DestRect
.top
, lprc
->top
);
728 DestRect
.bottom
= min(DestRect
.bottom
, lprc
->bottom
);
732 bitSize
.cx
= glyph
->bitmap
.width
;
733 bitSize
.cy
= glyph
->bitmap
.rows
;
734 MaskRect
.right
= glyph
->bitmap
.width
;
735 MaskRect
.bottom
= glyph
->bitmap
.rows
;
737 // We should create the bitmap out of the loop at the biggest possible glyph size
738 // Then use memset with 0 to clear it and sourcerect to limit the work of the transbitblt
739 HSourceGlyph
= EngCreateBitmap(bitSize
, pitch
, BMF_1BPP
, 0, glyph
->bitmap
.buffer
);
740 SourceGlyphSurf
= (PSURFOBJ
)AccessUserObject((ULONG
) HSourceGlyph
);
742 // Use the font data as a mask to paint onto the DCs surface using a brush
756 EngDeleteSurface(HSourceGlyph
);
758 TextLeft
+= (glyph
->advance
.x
+ 32) / 64;
759 previous
= glyph_index
;
763 TEXTOBJ_UnlockText(dc
->w
.hFont
);
764 if (NULL
!= hBrushBg
)
766 BRUSHOBJ_UnlockBrush(hBrushBg
);
767 NtGdiDeleteObject(hBrushBg
);
769 BRUSHOBJ_UnlockBrush(hBrushFg
);
770 NtGdiDeleteObject(hBrushFg
);
775 TEXTOBJ_UnlockText( dc
->w
.hFont
);
776 if (NULL
!= hBrushBg
)
778 BRUSHOBJ_UnlockBrush(hBrushBg
);
779 NtGdiDeleteObject(hBrushBg
);
781 if (NULL
!= hBrushFg
)
783 BRUSHOBJ_UnlockBrush(hBrushFg
);
784 NtGdiDeleteObject(hBrushFg
);
793 NtGdiGetAspectRatioFilterEx(HDC hDC
,
801 NtGdiGetCharABCWidths(HDC hDC
,
811 NtGdiGetCharABCWidthsFloat(HDC hDC
,
821 NtGdiGetCharacterPlacement(HDC hDC
,
825 LPGCP_RESULTSW Results
,
833 NtGdiGetCharWidth(HDC hDC
,
843 NtGdiGetCharWidth32(HDC hDC
,
853 FT_CharMap charmap
, found
= NULL
;
854 UINT i
, glyph_index
, BufferSize
;
856 if (LastChar
< FirstChar
)
858 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
862 BufferSize
= (LastChar
- FirstChar
) * sizeof(INT
);
863 SafeBuffer
= ExAllocatePool(PagedPool
, BufferSize
);
864 if (SafeBuffer
== NULL
)
866 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
873 ExFreePool(SafeBuffer
);
874 SetLastWin32Error(ERROR_INVALID_HANDLE
);
877 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
880 GetFontObjectsFromTextObj(TextObj
, NULL
, NULL
, &FontGDI
);
882 face
= FontGDI
->face
;
883 if (face
->charmap
== NULL
)
885 for (i
= 0; i
< face
->num_charmaps
; i
++)
887 charmap
= face
->charmaps
[i
];
888 if (charmap
->encoding
!= 0)
897 DPRINT1("WARNING: Could not find desired charmap!\n");
898 ExFreePool(SafeBuffer
);
899 SetLastWin32Error(ERROR_INVALID_HANDLE
);
903 FT_Set_Charmap(face
, found
);
906 FT_Set_Pixel_Sizes(face
,
907 /* FIXME should set character height if neg */
908 (TextObj
->logfont
.lfHeight
< 0 ?
909 - TextObj
->logfont
.lfHeight
:
910 TextObj
->logfont
.lfHeight
),
911 TextObj
->logfont
.lfWidth
);
913 for (i
= FirstChar
; i
<= LastChar
; i
++)
915 glyph_index
= FT_Get_Char_Index(face
, i
);
916 FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
917 SafeBuffer
[i
] = face
->glyph
->advance
.x
>> 6;
919 TEXTOBJ_UnlockText(dc
->w
.hFont
);
920 MmCopyToCaller(Buffer
, SafeBuffer
, BufferSize
);
921 ExFreePool(SafeBuffer
);
927 NtGdiGetCharWidthFloat(HDC hDC
,
937 NtGdiGetFontLanguageInfo(HDC hDC
)
944 NtGdiGetGlyphOutline(HDC hDC
,
959 NtGdiGetKerningPairs(HDC hDC
,
961 LPKERNINGPAIR krnpair
)
968 NtGdiGetOutlineTextMetrics(HDC hDC
,
970 LPOUTLINETEXTMETRICW otm
)
977 NtGdiGetRasterizerCaps(LPRASTERIZER_STATUS rs
,
985 NtGdiGetTextCharset(HDC hDC
)
992 NtGdiGetTextCharsetInfo(HDC hDC
,
1001 TextIntGetTextExtentPoint(PTEXTOBJ TextObj
,
1012 INT error
, n
, glyph_index
, i
, previous
;
1013 LONG TotalWidth
= 0;
1014 FT_CharMap charmap
, found
= NULL
;
1017 GetFontObjectsFromTextObj(TextObj
, NULL
, NULL
, &FontGDI
);
1018 face
= FontGDI
->face
;
1024 if (face
->charmap
== NULL
)
1026 DPRINT("WARNING: No charmap selected!\n");
1027 DPRINT("This font face has %d charmaps\n", face
->num_charmaps
);
1029 for (n
= 0; n
< face
->num_charmaps
; n
++)
1031 charmap
= face
->charmaps
[n
];
1032 DPRINT("found charmap encoding: %u\n", charmap
->encoding
);
1033 if (charmap
->encoding
!= 0)
1042 DPRINT1("WARNING: Could not find desired charmap!\n");
1045 error
= FT_Set_Charmap(face
, found
);
1048 DPRINT1("WARNING: Could not set the charmap!\n");
1052 error
= FT_Set_Pixel_Sizes(face
,
1053 /* FIXME should set character height if neg */
1054 (TextObj
->logfont
.lfHeight
< 0 ?
1055 - TextObj
->logfont
.lfHeight
:
1056 TextObj
->logfont
.lfHeight
),
1057 TextObj
->logfont
.lfWidth
);
1060 DPRINT1("Error in setting pixel sizes: %u\n", error
);
1063 use_kerning
= FT_HAS_KERNING(face
);
1066 for (i
= 0; i
< Count
; i
++)
1068 glyph_index
= FT_Get_Char_Index(face
, *String
);
1069 error
= FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
1072 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index
);
1074 glyph
= face
->glyph
;
1076 /* retrieve kerning distance */
1077 if (use_kerning
&& previous
&& glyph_index
)
1080 FT_Get_Kerning(face
, previous
, glyph_index
, 0, &delta
);
1081 TotalWidth
+= delta
.x
>> 6;
1084 TotalWidth
+= glyph
->advance
.x
>> 6;
1085 if (glyph
->format
== ft_glyph_format_outline
)
1087 error
= FT_Render_Glyph(glyph
, FT_RENDER_MODE_MONO
);
1090 DPRINT1("WARNING: Failed to render glyph!\n");
1094 if (TotalWidth
<= MaxExtent
&& NULL
!= Fit
)
1103 previous
= glyph_index
;
1107 Size
->cx
= TotalWidth
;
1108 Size
->cy
= (TextObj
->logfont
.lfHeight
< 0 ? - TextObj
->logfont
.lfHeight
: TextObj
->logfont
.lfHeight
);
1115 NtGdiGetTextExtentExPoint(HDC hDC
,
1116 LPCWSTR UnsafeString
,
1134 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1141 Status
= MmCopyToCaller(UnsafeSize
, &Size
, sizeof(SIZE
));
1142 if (! NT_SUCCESS(Status
))
1144 SetLastNtError(Status
);
1150 String
= ExAllocatePool(PagedPool
, Count
* sizeof(WCHAR
));
1153 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1157 if (NULL
!= UnsafeDx
)
1159 Dx
= ExAllocatePool(PagedPool
, Count
* sizeof(INT
));
1163 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1172 Status
= MmCopyFromCaller(String
, UnsafeString
, Count
* sizeof(WCHAR
));
1173 if (! NT_SUCCESS(Status
))
1180 SetLastNtError(Status
);
1184 dc
= DC_LockDc(hDC
);
1192 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1195 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
1197 Result
= TextIntGetTextExtentPoint(TextObj
, String
, Count
, MaxExtent
,
1198 NULL
== UnsafeFit
? NULL
: &Fit
, Dx
, &Size
);
1199 TEXTOBJ_UnlockText(dc
->w
.hFont
);
1211 if (NULL
!= UnsafeFit
)
1213 Status
= MmCopyToCaller(UnsafeFit
, &Fit
, sizeof(INT
));
1214 if (! NT_SUCCESS(Status
))
1220 SetLastNtError(Status
);
1225 if (NULL
!= UnsafeDx
)
1227 Status
= MmCopyToCaller(UnsafeDx
, Dx
, Count
* sizeof(INT
));
1228 if (! NT_SUCCESS(Status
))
1234 SetLastNtError(Status
);
1243 Status
= MmCopyToCaller(UnsafeSize
, &Size
, sizeof(SIZE
));
1244 if (! NT_SUCCESS(Status
))
1246 SetLastNtError(Status
);
1255 NtGdiGetTextExtentPoint(HDC hDC
,
1260 return NtGdiGetTextExtentExPoint(hDC
, String
, Count
, 0, NULL
, NULL
, Size
);
1265 NtGdiGetTextExtentPoint32(HDC hDC
,
1266 LPCWSTR UnsafeString
,
1279 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1286 Status
= MmCopyToCaller(UnsafeSize
, &Size
, sizeof(SIZE
));
1287 if (! NT_SUCCESS(Status
))
1289 SetLastNtError(Status
);
1295 String
= ExAllocatePool(PagedPool
, Count
* sizeof(WCHAR
));
1298 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1302 Status
= MmCopyFromCaller(String
, UnsafeString
, Count
* sizeof(WCHAR
));
1303 if (! NT_SUCCESS(Status
))
1306 SetLastNtError(Status
);
1310 dc
= DC_LockDc(hDC
);
1314 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1317 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
1319 Result
= TextIntGetTextExtentPoint (
1320 TextObj
, String
, Count
, 0, NULL
, NULL
, &Size
);
1321 dc
= DC_LockDc(hDC
);
1322 ASSERT(dc
); // it succeeded earlier, it should now, too
1323 TEXTOBJ_UnlockText(dc
->w
.hFont
);
1332 Status
= MmCopyToCaller(UnsafeSize
, &Size
, sizeof(SIZE
));
1333 if (! NT_SUCCESS(Status
))
1335 SetLastNtError(Status
);
1344 NtGdiGetTextFace(HDC hDC
,
1353 NtGdiGetTextMetrics(HDC hDC
,
1359 NTSTATUS Status
= STATUS_SUCCESS
;
1365 dc
= DC_LockDc(hDC
);
1366 if (NULL
== dc
|| NULL
== tm
)
1368 Status
= STATUS_INVALID_PARAMETER
;
1372 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
1373 if (NULL
!= TextObj
)
1375 Status
= GetFontObjectsFromTextObj(TextObj
, NULL
, NULL
, &FontGDI
);
1376 if (NT_SUCCESS(Status
))
1378 Face
= FontGDI
->face
;
1379 Error
= FT_Set_Pixel_Sizes(Face
,
1380 /* FIXME should set character height if neg */
1381 (TextObj
->logfont
.lfHeight
< 0 ?
1382 - TextObj
->logfont
.lfHeight
:
1383 TextObj
->logfont
.lfHeight
),
1384 TextObj
->logfont
.lfWidth
);
1387 DPRINT1("Error in setting pixel sizes: %u\n", Error
);
1388 Status
= STATUS_UNSUCCESSFUL
;
1392 memcpy(&SafeTm
, &FontGDI
->TextMetric
, sizeof(TEXTMETRICW
));
1393 pOS2
= FT_Get_Sfnt_Table(Face
, ft_sfnt_os2
);
1396 DPRINT1("Can't find OS/2 table - not TT font?\n");
1397 Status
= STATUS_UNSUCCESSFUL
;
1401 SafeTm
.tmAveCharWidth
= (pOS2
->xAvgCharWidth
+ 32) / 64;
1403 SafeTm
.tmAscent
= (Face
->size
->metrics
.ascender
+ 32) / 64; // units above baseline
1404 SafeTm
.tmDescent
= (- Face
->size
->metrics
.descender
+ 32) / 64; // units below baseline
1405 SafeTm
.tmHeight
= SafeTm
.tmAscent
+ SafeTm
.tmDescent
;
1406 SafeTm
.tmMaxCharWidth
= (Face
->size
->metrics
.max_advance
+ 32) / 64;
1407 Status
= MmCopyToCaller(tm
, &SafeTm
, sizeof(TEXTMETRICW
));
1410 TEXTOBJ_UnlockText(dc
->w
.hFont
);
1415 Status
= STATUS_INVALID_HANDLE
;
1420 return NT_SUCCESS(Status
);
1425 NtGdiPolyTextOut(HDC hDC
,
1426 CONST LPPOLYTEXTW txt
,
1434 NtGdiRemoveFontResource(LPCWSTR FileName
)
1441 NtGdiSetMapperFlags(HDC hDC
,
1449 NtGdiSetTextAlign(HDC hDC
,
1455 dc
= DC_LockDc(hDC
);
1460 prevAlign
= dc
->w
.textAlign
;
1461 dc
->w
.textAlign
= Mode
;
1468 NtGdiSetTextColor(HDC hDC
,
1472 PDC dc
= DC_LockDc(hDC
);
1479 oldColor
= dc
->w
.textColor
;
1480 dc
->w
.textColor
= color
;
1487 NtGdiSetTextJustification(HDC hDC
,
1496 NtGdiTextOut(HDC hDC
,
1502 // Fixme: Call EngTextOut, which does the real work (calling DrvTextOut where appropriate)
1506 int error
, glyph_index
, n
, i
;
1509 ULONG TextLeft
, TextTop
, pitch
, previous
, BackgroundLeft
;
1510 FT_Bool use_kerning
;
1511 RECTL DestRect
, MaskRect
;
1512 POINTL SourcePoint
, BrushOrigin
;
1513 HBRUSH hBrushFg
= NULL
;
1514 PBRUSHOBJ BrushFg
= NULL
;
1515 HBRUSH hBrushBg
= NULL
;
1516 PBRUSHOBJ BrushBg
= NULL
;
1517 HBITMAP HSourceGlyph
;
1518 PSURFOBJ SourceGlyphSurf
;
1520 FT_CharMap found
= 0, charmap
;
1526 PXLATEOBJ XlateObj
, XlateObj2
;
1528 FT_Render_Mode RenderMode
;
1531 dc
= DC_LockDc(hDC
);
1534 SurfObj
= (SURFOBJ
*)AccessUserObject((ULONG
) dc
->Surface
);
1536 XStart
+= dc
->w
.DCOrgX
;
1537 YStart
+= dc
->w
.DCOrgY
;
1540 BackgroundLeft
= XStart
;
1542 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
1544 if (! NT_SUCCESS(GetFontObjectsFromTextObj(TextObj
, NULL
, &FontObj
, &FontGDI
)))
1548 face
= FontGDI
->face
;
1550 if (face
->charmap
== NULL
)
1552 DPRINT("WARNING: No charmap selected!\n");
1553 DPRINT("This font face has %d charmaps\n", face
->num_charmaps
);
1555 for (n
= 0; n
< face
->num_charmaps
; n
++)
1557 charmap
= face
->charmaps
[n
];
1558 DPRINT("found charmap encoding: %u\n", charmap
->encoding
);
1559 if (charmap
->encoding
!= 0)
1565 if (!found
) DPRINT1("WARNING: Could not find desired charmap!\n");
1566 error
= FT_Set_Charmap(face
, found
);
1567 if (error
) DPRINT1("WARNING: Could not set the charmap!\n");
1571 Render
= IntIsFontRenderingEnabled();
1574 RenderMode
= IntGetFontRenderMode(&TextObj
->logfont
);
1576 RenderMode
= FT_RENDER_MODE_MONO
;
1578 error
= FT_Set_Pixel_Sizes(face
,
1579 /* FIXME should set character height if neg */
1580 (TextObj
->logfont
.lfHeight
< 0 ?
1581 - TextObj
->logfont
.lfHeight
:
1582 TextObj
->logfont
.lfHeight
),
1583 TextObj
->logfont
.lfWidth
);
1585 DPRINT1("Error in setting pixel sizes: %u\n", error
);
1589 // Create the brushes
1590 PalDestGDI
= PALETTE_LockPalette(dc
->w
.hPalette
);
1591 Mode
= PalDestGDI
->Mode
;
1592 PALETTE_UnlockPalette(dc
->w
.hPalette
);
1593 XlateObj
= (PXLATEOBJ
)IntEngCreateXlate(Mode
, PAL_RGB
, dc
->w
.hPalette
, NULL
);
1594 hBrushFg
= NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj
, dc
->w
.textColor
));
1595 BrushFg
= BRUSHOBJ_LockBrush(hBrushFg
);
1596 if (OPAQUE
== dc
->w
.backgroundMode
)
1598 hBrushBg
= NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj
, dc
->w
.backgroundColor
));
1601 BrushBg
= BRUSHOBJ_LockBrush(hBrushBg
);
1605 EngDeleteXlate(XlateObj
);
1609 XlateObj2
= (PXLATEOBJ
)IntEngCreateXlate(PAL_RGB
, Mode
, NULL
, dc
->w
.hPalette
);
1618 // Determine the yoff from the dc's w.textAlign
1619 if (dc
->w
.textAlign
& TA_BASELINE
) {
1623 if (dc
->w
.textAlign
& TA_BOTTOM
) {
1624 yoff
= -face
->size
->metrics
.descender
/ 64;
1627 yoff
= face
->size
->metrics
.ascender
/ 64;
1630 use_kerning
= FT_HAS_KERNING(face
);
1633 for(i
=0; i
<Count
; i
++)
1635 glyph_index
= FT_Get_Char_Index(face
, *String
);
1636 error
= FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
1638 EngDeleteXlate(XlateObj
);
1639 EngDeleteXlate(XlateObj2
);
1640 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index
);
1643 glyph
= face
->glyph
;
1645 // retrieve kerning distance and move pen position
1646 if (use_kerning
&& previous
&& glyph_index
)
1649 FT_Get_Kerning(face
, previous
, glyph_index
, 0, &delta
);
1650 TextLeft
+= delta
.x
>> 6;
1653 if (glyph
->format
== ft_glyph_format_outline
)
1655 error
= FT_Render_Glyph(glyph
, RenderMode
);
1657 EngDeleteXlate(XlateObj
);
1658 EngDeleteXlate(XlateObj2
);
1659 DPRINT1("WARNING: Failed to render glyph!\n");
1662 pitch
= glyph
->bitmap
.pitch
;
1664 pitch
= glyph
->bitmap
.width
;
1667 if (OPAQUE
== dc
->w
.backgroundMode
)
1669 DestRect
.left
= BackgroundLeft
;
1670 DestRect
.right
= TextLeft
+ (glyph
->advance
.x
+ 32) / 64;
1671 DestRect
.top
= TextTop
+ yoff
- (face
->size
->metrics
.ascender
+ 32) / 64;
1672 DestRect
.bottom
= TextTop
+ yoff
+ (- face
->size
->metrics
.descender
+ 32) / 64;
1673 IntEngBitBlt(SurfObj
,
1684 BackgroundLeft
= DestRect
.right
;
1687 DestRect
.left
= TextLeft
;
1688 DestRect
.right
= TextLeft
+ glyph
->bitmap
.width
;
1689 DestRect
.top
= TextTop
+ yoff
- glyph
->bitmap_top
;
1690 DestRect
.bottom
= DestRect
.top
+ glyph
->bitmap
.rows
;
1692 bitSize
.cx
= glyph
->bitmap
.width
;
1693 bitSize
.cy
= glyph
->bitmap
.rows
;
1694 MaskRect
.right
= glyph
->bitmap
.width
;
1695 MaskRect
.bottom
= glyph
->bitmap
.rows
;
1697 // We should create the bitmap out of the loop at the biggest possible glyph size
1698 // Then use memset with 0 to clear it and sourcerect to limit the work of the transbitblt
1699 HSourceGlyph
= EngCreateBitmap(bitSize
, pitch
, (glyph
->bitmap
.pixel_mode
== ft_pixel_mode_grays
) ? BMF_8BPP
: BMF_1BPP
, 0, glyph
->bitmap
.buffer
);
1700 SourceGlyphSurf
= (PSURFOBJ
)AccessUserObject((ULONG
) HSourceGlyph
);
1702 // Use the font data as a mask to paint onto the DCs surface using a brush
1715 EngDeleteSurface(HSourceGlyph
);
1717 TextLeft
+= (glyph
->advance
.x
+ 32) / 64;
1718 previous
= glyph_index
;
1722 EngDeleteXlate(XlateObj
);
1723 EngDeleteXlate(XlateObj2
);
1724 TEXTOBJ_UnlockText(dc
->w
.hFont
);
1725 if (NULL
!= hBrushBg
)
1727 BRUSHOBJ_UnlockBrush(hBrushBg
);
1728 NtGdiDeleteObject(hBrushBg
);
1730 BRUSHOBJ_UnlockBrush(hBrushFg
);
1731 NtGdiDeleteObject(hBrushFg
);
1736 TEXTOBJ_UnlockText( dc
->w
.hFont
);
1737 if (NULL
!= hBrushBg
)
1739 BRUSHOBJ_UnlockBrush(hBrushBg
);
1740 NtGdiDeleteObject(hBrushBg
);
1742 if (NULL
!= hBrushFg
)
1744 BRUSHOBJ_UnlockBrush(hBrushFg
);
1745 NtGdiDeleteObject(hBrushFg
);
1753 NtGdiTranslateCharsetInfo(PDWORD Src
,
1761 TextIntRealizeFont(HFONT FontHandle
)
1763 NTSTATUS Status
= STATUS_SUCCESS
;
1765 UNICODE_STRING FaceName
;
1767 PFONT_ENTRY CurrentEntry
;
1768 PW32PROCESS Win32Process
;
1769 BOOL Private
= FALSE
;
1771 TextObj
= TEXTOBJ_LockText(FontHandle
);
1773 if (NULL
!= TextObj
)
1775 RtlInitUnicodeString(&FaceName
, TextObj
->logfont
.lfFaceName
);
1777 /* find font in private fonts */
1778 Win32Process
= PsGetWin32Process();
1780 ExAcquireFastMutex(&Win32Process
->PrivateFontListLock
);
1782 Entry
= Win32Process
->PrivateFontListHead
.Flink
;
1783 while(Entry
!= &Win32Process
->PrivateFontListHead
)
1785 CurrentEntry
= (PFONT_ENTRY
)CONTAINING_RECORD(Entry
, FONT_ENTRY
, ListEntry
);
1787 if (0 == RtlCompareUnicodeString(&CurrentEntry
->FaceName
, &FaceName
, TRUE
))
1789 TextObj
->GDIFontHandle
= CurrentEntry
->hFont
;
1793 Entry
= Entry
->Flink
;
1795 ExReleaseFastMutex(&Win32Process
->PrivateFontListLock
);
1797 /* find font in system fonts */
1798 ExAcquireFastMutex(&FontListLock
);
1800 Entry
= FontListHead
.Flink
;
1801 while(Entry
!= &FontListHead
)
1803 CurrentEntry
= (PFONT_ENTRY
)CONTAINING_RECORD(Entry
, FONT_ENTRY
, ListEntry
);
1805 if (0 == RtlCompareUnicodeString(&CurrentEntry
->FaceName
, &FaceName
, TRUE
))
1807 TextObj
->GDIFontHandle
= CurrentEntry
->hFont
;
1810 Entry
= Entry
->Flink
;
1814 if (NULL
== TextObj
->GDIFontHandle
)
1816 Entry
= (Private
? Win32Process
->PrivateFontListHead
.Flink
: FontListHead
.Flink
);
1818 if(Entry
!= (Private
? &Win32Process
->PrivateFontListHead
: &FontListHead
))
1820 DPRINT("Requested font %S not found, using first available font\n",
1821 TextObj
->logfont
.lfFaceName
)
1822 CurrentEntry
= (PFONT_ENTRY
)CONTAINING_RECORD(Entry
, FONT_ENTRY
, ListEntry
);
1823 TextObj
->GDIFontHandle
= CurrentEntry
->hFont
;
1827 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
1828 TextObj
->logfont
.lfFaceName
);
1829 Status
= STATUS_NOT_FOUND
;
1834 ExReleaseFastMutex((Private
? &Win32Process
->PrivateFontListLock
: &FontListLock
));
1836 ASSERT(! NT_SUCCESS(Status
) || NULL
!= TextObj
->GDIFontHandle
);
1838 TEXTOBJ_UnlockText(FontHandle
);
1842 Status
= STATUS_INVALID_HANDLE
;