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.32 2003/05/18 17:16:18 ea Exp $ */
22 #undef WIN32_LEAN_AND_MEAN
24 #include <ddk/ntddk.h>
25 #include <internal/safe.h>
26 #include <win32k/brush.h>
27 #include <win32k/dc.h>
28 #include <win32k/text.h>
29 #include <win32k/kapi.h>
31 #include FT_FREETYPE_H
33 #include "../eng/handle.h"
35 #include <include/inteng.h>
36 #include <include/text.h>
37 #include <include/eng.h>
40 #include <win32k/debug1.h>
44 typedef struct _FONTTABLE
{
47 } FONTTABLE
, *PFONTTABLE
;
49 FONTTABLE FontTable
[256];
52 BOOL FASTCALL
InitFontSupport(VOID
)
56 static WCHAR
*FontFiles
[] =
58 L
"\\SystemRoot\\media\\fonts\\helb____.ttf",
59 L
"\\SystemRoot\\media\\fonts\\timr____.ttf",
60 L
"\\SystemRoot\\media\\fonts\\Vera.ttf",
61 L
"\\SystemRoot\\media\\fonts\\VeraBd.ttf",
62 L
"\\SystemRoot\\media\\fonts\\VeraBI.ttf",
63 L
"\\SystemRoot\\media\\fonts\\VeraIt.ttf",
64 L
"\\SystemRoot\\media\\fonts\\VeraMoBd.ttf",
65 L
"\\SystemRoot\\media\\fonts\\VeraMoBI.ttf",
66 L
"\\SystemRoot\\media\\fonts\\VeraMoIt.ttf",
67 L
"\\SystemRoot\\media\\fonts\\VeraMono.ttf",
68 L
"\\SystemRoot\\media\\fonts\\VeraSe.ttf",
69 L
"\\SystemRoot\\media\\fonts\\VeraSeBd.ttf"
72 error
= FT_Init_FreeType(&library
);
78 for (File
= 0; File
< sizeof(FontFiles
) / sizeof(WCHAR
*); File
++)
80 DPRINT("Loading font %S\n", FontFiles
[File
]);
82 W32kAddFontResource(FontFiles
[File
]);
85 DPRINT("All fonts loaded\n");
90 static NTSTATUS STDCALL
91 GetFontObjectsFromTextObj(PTEXTOBJ TextObj
, HFONT
*FontHandle
, PFONTOBJ
*FontObj
, PFONTGDI
*FontGDI
)
93 NTSTATUS Status
= STATUS_SUCCESS
;
95 ASSERT(NULL
!= TextObj
&& NULL
!= TextObj
->GDIFontHandle
);
96 if (NULL
!= TextObj
&& NULL
!= TextObj
->GDIFontHandle
)
98 if (NT_SUCCESS(Status
) && NULL
!= FontHandle
)
100 *FontHandle
= TextObj
->GDIFontHandle
;
102 if (NT_SUCCESS(Status
) && NULL
!= FontObj
)
104 *FontObj
= AccessUserObject((ULONG
) TextObj
->GDIFontHandle
);
105 if (NULL
== *FontObj
)
108 Status
= STATUS_INVALID_HANDLE
;
111 if (NT_SUCCESS(Status
) && NULL
!= FontGDI
)
113 *FontGDI
= AccessInternalObject((ULONG
) TextObj
->GDIFontHandle
);
114 if (NULL
== *FontGDI
)
117 Status
= STATUS_INVALID_HANDLE
;
123 Status
= STATUS_INVALID_HANDLE
;
131 W32kAddFontResource(LPCWSTR Filename
)
136 UNICODE_STRING uFileName
;
139 OBJECT_ATTRIBUTES ObjectAttributes
;
140 FILE_STANDARD_INFORMATION FileStdInfo
;
146 UNICODE_STRING StringU
;
147 IO_STATUS_BLOCK Iosb
;
149 NewFont
= (HFONT
)CreateGDIHandle(sizeof( FONTGDI
), sizeof( FONTOBJ
));
150 FontObj
= (PFONTOBJ
) AccessUserObject( (ULONG
) NewFont
);
151 FontGDI
= (PFONTGDI
) AccessInternalObject( (ULONG
) NewFont
);
153 RtlCreateUnicodeString(&uFileName
, (LPWSTR
)Filename
);
156 InitializeObjectAttributes(&ObjectAttributes
, &uFileName
, 0, NULL
, NULL
);
158 Status
= NtOpenFile(&FileHandle
, FILE_ALL_ACCESS
, &ObjectAttributes
, &Iosb
, 0, 0);
160 if (!NT_SUCCESS(Status
))
162 DPRINT1("Could not open module file: %S\n", Filename
);
166 // Get the size of the file
167 Status
= NtQueryInformationFile(FileHandle
, &Iosb
, &FileStdInfo
, sizeof(FileStdInfo
), FileStandardInformation
);
168 if (!NT_SUCCESS(Status
))
170 DPRINT1("Could not get file size\n");
174 // Allocate nonpageable memory for driver
175 size
= FileStdInfo
.EndOfFile
.u
.LowPart
;
176 buffer
= ExAllocatePool(NonPagedPool
, size
);
180 DPRINT1("could not allocate memory for module");
184 // Load driver into memory chunk
185 Status
= NtReadFile(FileHandle
, 0, 0, 0, &Iosb
, buffer
, FileStdInfo
.EndOfFile
.u
.LowPart
, 0, 0);
186 if (!NT_SUCCESS(Status
))
188 DPRINT1("could not read module file into memory");
195 error
= FT_New_Memory_Face(library
, buffer
, size
, 0, &face
);
196 if (error
== FT_Err_Unknown_File_Format
)
198 DPRINT1("Unknown font file format\n");
203 DPRINT1("Error reading font file (error code: %u)\n", error
); // 48
207 // FontGDI->Filename = Filename; perform strcpy
208 FontGDI
->face
= face
;
210 // FIXME: Complete text metrics
211 FontGDI
->TextMetric
.tmAscent
= face
->size
->metrics
.ascender
; // units above baseline
212 FontGDI
->TextMetric
.tmDescent
= face
->size
->metrics
.descender
; // units below baseline
213 FontGDI
->TextMetric
.tmHeight
= FontGDI
->TextMetric
.tmAscent
+ FontGDI
->TextMetric
.tmDescent
;
215 DPRINT("Font loaded: %s (%s)\n", face
->family_name
, face
->style_name
);
216 DPRINT("Num glyphs: %u\n", face
->num_glyphs
);
218 // Add this font resource to the font table
219 FontTable
[FontsLoaded
].hFont
= NewFont
;
221 RtlInitAnsiString(&StringA
, (LPSTR
)face
->family_name
);
222 RtlAnsiStringToUnicodeString(&StringU
, &StringA
, TRUE
);
223 FontTable
[FontsLoaded
].FaceName
= ExAllocatePool(NonPagedPool
, (StringU
.Length
+ 1) * 2);
224 wcscpy((LPWSTR
)FontTable
[FontsLoaded
].FaceName
, StringU
.Buffer
);
225 RtlFreeUnicodeString(&StringU
);
233 TextIntCreateFontIndirect(CONST LPLOGFONTW lf
, HFONT
*NewFont
)
236 NTSTATUS Status
= STATUS_SUCCESS
;
238 *NewFont
= TEXTOBJ_AllocText();
239 if (NULL
!= *NewFont
)
241 TextObj
= TEXTOBJ_LockText(*NewFont
);
244 memcpy(&TextObj
->logfont
, lf
, sizeof(LOGFONTW
));
245 if (lf
->lfEscapement
!= lf
->lfOrientation
)
247 /* this should really depend on whether GM_ADVANCED is set */
248 TextObj
->logfont
.lfOrientation
= TextObj
->logfont
.lfEscapement
;
250 TEXTOBJ_UnlockText(*NewFont
);
255 Status
= STATUS_INVALID_HANDLE
;
260 Status
= STATUS_NO_MEMORY
;
268 W32kCreateFont(int Height
,
277 DWORD OutputPrecision
,
280 DWORD PitchAndFamily
,
285 NTSTATUS Status
= STATUS_SUCCESS
;
287 logfont
.lfHeight
= Height
;
288 logfont
.lfWidth
= Width
;
289 logfont
.lfEscapement
= Escapement
;
290 logfont
.lfOrientation
= Orientation
;
291 logfont
.lfWeight
= Weight
;
292 logfont
.lfItalic
= Italic
;
293 logfont
.lfUnderline
= Underline
;
294 logfont
.lfStrikeOut
= StrikeOut
;
295 logfont
.lfCharSet
= CharSet
;
296 logfont
.lfOutPrecision
= OutputPrecision
;
297 logfont
.lfClipPrecision
= ClipPrecision
;
298 logfont
.lfQuality
= Quality
;
299 logfont
.lfPitchAndFamily
= PitchAndFamily
;
303 Status
= MmCopyFromCaller(logfont
.lfFaceName
, Face
, sizeof(logfont
.lfFaceName
));
307 logfont
.lfFaceName
[0] = L
'\0';
310 if (NT_SUCCESS(Status
))
312 Status
= TextIntCreateFontIndirect(&logfont
, &NewFont
);
315 return NT_SUCCESS(Status
) ? NewFont
: NULL
;
320 W32kCreateFontIndirect(CONST LPLOGFONTW lf
)
322 LOGFONTW SafeLogfont
;
324 NTSTATUS Status
= STATUS_SUCCESS
;
328 Status
= MmCopyFromCaller(&SafeLogfont
, lf
, sizeof(LOGFONTW
));
329 if (NT_SUCCESS(Status
))
331 Status
= TextIntCreateFontIndirect(&SafeLogfont
, &NewFont
);
336 Status
= STATUS_INVALID_PARAMETER
;
339 return NT_SUCCESS(Status
) ? NewFont
: NULL
;
344 W32kCreateScalableFontResource(DWORD Hidden
,
354 W32kEnumFontFamilies(HDC hDC
,
356 FONTENUMPROCW EnumFontFamProc
,
364 W32kEnumFontFamiliesEx(HDC hDC
,
366 FONTENUMPROCW EnumFontFamExProc
,
375 W32kEnumFonts(HDC hDC
,
377 FONTENUMPROCW FontFunc
,
385 W32kExtTextOut(HDC hDC
,
399 W32kGetAspectRatioFilterEx(HDC hDC
,
407 W32kGetCharABCWidths(HDC hDC
,
417 W32kGetCharABCWidthsFloat(HDC hDC
,
427 W32kGetCharacterPlacement(HDC hDC
,
431 LPGCP_RESULTS Results
,
439 W32kGetCharWidth(HDC hDC
,
449 W32kGetCharWidth32(HDC hDC
,
459 W32kGetCharWidthFloat(HDC hDC
,
469 W32kGetFontLanguageInfo(HDC hDC
)
476 W32kGetGlyphOutline(HDC hDC
,
491 W32kGetKerningPairs(HDC hDC
,
493 LPKERNINGPAIR krnpair
)
500 W32kGetOutlineTextMetrics(HDC hDC
,
502 LPOUTLINETEXTMETRICW otm
)
509 W32kGetRasterizerCaps(LPRASTERIZER_STATUS rs
,
517 W32kGetTextCharset(HDC hDC
)
524 W32kGetTextCharsetInfo(HDC hDC
,
533 W32kGetTextExtentExPoint(HDC hDC
,
546 W32kGetTextExtentPoint(HDC hDC
,
551 PDC dc
= (PDC
)AccessUserObject((ULONG
) hDC
);
555 INT error
, pitch
, glyph_index
, i
;
556 ULONG TotalWidth
= 0, MaxHeight
= 0, CurrentChar
= 0, SpaceBetweenChars
= 5;
558 FontGDI
= (PFONTGDI
)AccessInternalObject((ULONG
) dc
->w
.hFont
);
560 for(i
=0; i
<Count
; i
++)
562 glyph_index
= FT_Get_Char_Index(face
, *String
);
563 error
= FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
564 if(error
) DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index
);
567 if (glyph
->format
== ft_glyph_format_outline
)
569 error
= FT_Render_Glyph(glyph
, ft_render_mode_mono
);
570 if(error
) DPRINT1("WARNING: Failed to render glyph!\n");
571 pitch
= glyph
->bitmap
.pitch
;
573 pitch
= glyph
->bitmap
.width
;
576 TotalWidth
+= pitch
-1;
577 if((glyph
->bitmap
.rows
-1) > MaxHeight
) MaxHeight
= glyph
->bitmap
.rows
-1;
581 if(CurrentChar
< Size
->cx
) TotalWidth
+= SpaceBetweenChars
;
585 Size
->cx
= TotalWidth
;
586 Size
->cy
= MaxHeight
;
591 W32kGetTextExtentPoint32(HDC hDC
,
601 W32kGetTextFace(HDC hDC
,
610 W32kGetTextMetrics(HDC hDC
,
616 NTSTATUS Status
= STATUS_SUCCESS
;
621 dc
= DC_HandleToPtr(hDC
);
622 if (NULL
== dc
|| NULL
== tm
)
624 Status
= STATUS_INVALID_PARAMETER
;
628 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
631 Status
= GetFontObjectsFromTextObj(TextObj
, NULL
, NULL
, &FontGDI
);
632 if (NT_SUCCESS(Status
))
634 Face
= FontGDI
->face
;
635 Error
= FT_Set_Pixel_Sizes(Face
, TextObj
->logfont
.lfHeight
,
636 TextObj
->logfont
.lfWidth
);
639 DPRINT1("Error in setting pixel sizes: %u\n", Error
);
640 Status
= STATUS_UNSUCCESSFUL
;
644 memcpy(&SafeTm
, &FontGDI
->TextMetric
, sizeof(TEXTMETRICW
));
645 SafeTm
.tmAscent
= (Face
->size
->metrics
.ascender
+ 32) / 64; // units above baseline
646 SafeTm
.tmDescent
= (Face
->size
->metrics
.descender
+ 32) / 64; // units below baseline
647 SafeTm
.tmHeight
= (Face
->size
->metrics
.ascender
+
648 Face
->size
->metrics
.descender
+ 32) / 64;
649 Status
= MmCopyToCaller(tm
, &SafeTm
, sizeof(TEXTMETRICW
));
652 TEXTOBJ_UnlockText(dc
->w
.hFont
);
657 Status
= STATUS_INVALID_HANDLE
;
662 return NT_SUCCESS(Status
);
667 W32kPolyTextOut(HDC hDC
,
668 CONST LPPOLYTEXT txt
,
676 W32kRemoveFontResource(LPCWSTR FileName
)
683 W32kSetMapperFlags(HDC hDC
,
691 W32kSetTextAlign(HDC hDC
,
697 dc
= DC_HandleToPtr(hDC
);
702 prevAlign
= dc
->w
.textAlign
;
703 dc
->w
.textAlign
= Mode
;
704 DC_ReleasePtr( hDC
);
710 W32kSetTextColor(HDC hDC
,
714 PDC dc
= DC_HandleToPtr(hDC
);
721 oldColor
= dc
->w
.textColor
;
722 dc
->w
.textColor
= color
;
723 DC_ReleasePtr( hDC
);
729 W32kSetTextJustification(HDC hDC
,
744 // Fixme: Call EngTextOut, which does the real work (calling DrvTextOut where appropriate)
746 DC
*dc
= DC_HandleToPtr(hDC
);
747 SURFOBJ
*SurfObj
= (SURFOBJ
*)AccessUserObject((ULONG
) dc
->Surface
);
748 int error
, glyph_index
, n
, i
;
751 ULONG TextLeft
, TextTop
, pitch
, previous
;
753 RECTL DestRect
, MaskRect
;
754 POINTL SourcePoint
, BrushOrigin
;
755 HBRUSH hBrush
= NULL
;
756 PBRUSHOBJ Brush
= NULL
;
757 HBITMAP HSourceGlyph
;
758 PSURFOBJ SourceGlyphSurf
;
760 FT_CharMap found
= 0, charmap
;
771 XStart
+= dc
->w
.DCOrgX
;
772 YStart
+= dc
->w
.DCOrgY
;
776 TextObj
= TEXTOBJ_LockText(dc
->w
.hFont
);
778 if (! NT_SUCCESS(GetFontObjectsFromTextObj(TextObj
, NULL
, &FontObj
, &FontGDI
)))
782 face
= FontGDI
->face
;
784 if (face
->charmap
== NULL
)
786 DPRINT("WARNING: No charmap selected!\n");
787 DPRINT("This font face has %d charmaps\n", face
->num_charmaps
);
789 for (n
= 0; n
< face
->num_charmaps
; n
++)
791 charmap
= face
->charmaps
[n
];
792 DPRINT("found charmap encoding: %u\n", charmap
->encoding
);
793 if (charmap
->encoding
!= 0)
799 if (!found
) DPRINT1("WARNING: Could not find desired charmap!\n");
800 error
= FT_Set_Charmap(face
, found
);
801 if (error
) DPRINT1("WARNING: Could not set the charmap!\n");
804 error
= FT_Set_Pixel_Sizes(face
, TextObj
->logfont
.lfHeight
, TextObj
->logfont
.lfWidth
);
806 DPRINT1("Error in setting pixel sizes: %u\n", error
);
811 PalDestGDI
= (PPALGDI
)AccessInternalObject((ULONG
) dc
->w
.hPalette
);
812 XlateObj
= (PXLATEOBJ
)IntEngCreateXlate(PalDestGDI
->Mode
, PAL_RGB
, dc
->w
.hPalette
, NULL
);
813 hBrush
= W32kCreateSolidBrush(XLATEOBJ_iXlate(XlateObj
, dc
->w
.textColor
));
814 Brush
= BRUSHOBJ_LockBrush(hBrush
);
815 EngDeleteXlate(XlateObj
);
824 // Determine the yoff from the dc's w.textAlign
825 if (dc
->w
.textAlign
& TA_BASELINE
) {
829 if (dc
->w
.textAlign
& TA_BOTTOM
) {
830 yoff
= -face
->size
->metrics
.descender
/ 64;
833 yoff
= face
->size
->metrics
.ascender
/ 64;
836 use_kerning
= FT_HAS_KERNING(face
);
839 for(i
=0; i
<Count
; i
++)
841 glyph_index
= FT_Get_Char_Index(face
, *String
);
842 error
= FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
844 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index
);
849 // retrieve kerning distance and move pen position
850 if (use_kerning
&& previous
&& glyph_index
)
853 FT_Get_Kerning(face
, previous
, glyph_index
, 0, &delta
);
854 TextLeft
+= delta
.x
>> 6;
857 if (glyph
->format
== ft_glyph_format_outline
)
859 error
= FT_Render_Glyph(glyph
, ft_render_mode_mono
);
861 DPRINT1("WARNING: Failed to render glyph!\n");
864 pitch
= glyph
->bitmap
.pitch
;
866 pitch
= glyph
->bitmap
.width
;
869 DestRect
.left
= TextLeft
;
870 DestRect
.top
= TextTop
+ yoff
- glyph
->bitmap_top
;
871 DestRect
.right
= TextLeft
+ glyph
->bitmap
.width
;
872 DestRect
.bottom
= DestRect
.top
+ glyph
->bitmap
.rows
;
874 bitSize
.cy
= glyph
->bitmap
.rows
;
875 MaskRect
.right
= glyph
->bitmap
.width
;
876 MaskRect
.bottom
= glyph
->bitmap
.rows
;
878 // We should create the bitmap out of the loop at the biggest possible glyph size
879 // Then use memset with 0 to clear it and sourcerect to limit the work of the transbitblt
881 HSourceGlyph
= EngCreateBitmap(bitSize
, pitch
, BMF_1BPP
, 0, glyph
->bitmap
.buffer
);
882 SourceGlyphSurf
= (PSURFOBJ
)AccessUserObject((ULONG
) HSourceGlyph
);
884 // Use the font data as a mask to paint onto the DCs surface using a brush
885 IntEngBitBlt(SurfObj
, NULL
, SourceGlyphSurf
, NULL
, NULL
, &DestRect
, &SourcePoint
, &MaskRect
, Brush
, &BrushOrigin
, 0xAACC);
887 EngDeleteSurface(HSourceGlyph
);
889 TextLeft
+= glyph
->advance
.x
>> 6;
890 previous
= glyph_index
;
894 TEXTOBJ_UnlockText( dc
->w
.hFont
);
895 BRUSHOBJ_UnlockBrush(hBrush
);
896 W32kDeleteObject( hBrush
);
897 DC_ReleasePtr( hDC
);
901 TEXTOBJ_UnlockText( dc
->w
.hFont
);
903 BRUSHOBJ_UnlockBrush(hBrush
);
904 W32kDeleteObject( hBrush
);
906 DC_ReleasePtr( hDC
);
912 W32kTranslateCharsetInfo(PDWORD Src
,
920 TextIntRealizeFont(HFONT FontHandle
)
923 NTSTATUS Status
= STATUS_SUCCESS
;
926 TextObj
= TEXTOBJ_LockText(FontHandle
);
930 for(i
= 0; NULL
== TextObj
->GDIFontHandle
&& i
< FontsLoaded
; i
++)
932 if (0 == wcscmp(FontTable
[i
].FaceName
, TextObj
->logfont
.lfFaceName
))
934 TextObj
->GDIFontHandle
= FontTable
[i
].hFont
;
938 if (NULL
== TextObj
->GDIFontHandle
)
940 if (0 != FontsLoaded
)
942 DPRINT("Requested font %S not found, using first available font\n",
943 TextObj
->logfont
.lfFaceName
)
944 TextObj
->GDIFontHandle
= FontTable
[0].hFont
;
948 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
949 TextObj
->logfont
.lfFaceName
)
950 Status
= STATUS_NOT_FOUND
;
954 ASSERT(! NT_SUCCESS(Status
) || NULL
!= TextObj
->GDIFontHandle
);
956 TEXTOBJ_UnlockText(FontHandle
);
960 Status
= STATUS_INVALID_HANDLE
;