Use Vera instead of helmet for drawing menus, button captions, etc. Please note...
[reactos.git] / reactos / subsys / win32k / objects / text.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id: text.c,v 1.49 2003/08/29 21:53:50 rcampbell Exp $ */
20
21
22 #undef WIN32_LEAN_AND_MEAN
23 #include <windows.h>
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>
30 #include <include/error.h>
31 #include <ft2build.h>
32 #include FT_FREETYPE_H
33
34 #include "../eng/handle.h"
35
36 #include <include/inteng.h>
37 #include <include/text.h>
38 #include <include/eng.h>
39 #include <include/palette.h>
40
41 #define NDEBUG
42 #include <win32k/debug1.h>
43
44 FT_Library library;
45
46 typedef struct _FONTTABLE {
47 HFONT hFont;
48 LPCWSTR FaceName;
49 } FONTTABLE, *PFONTTABLE;
50
51 FONTTABLE FontTable[256];
52 INT FontsLoaded = 0;
53
54 BOOL FASTCALL InitFontSupport(VOID)
55 {
56 ULONG error;
57 UINT File;
58 static WCHAR *FontFiles[] =
59 {
60 L"\\SystemRoot\\media\\fonts\\Vera.ttf",
61 L"\\SystemRoot\\media\\fonts\\helb____.ttf",
62 L"\\SystemRoot\\media\\fonts\\timr____.ttf",
63 L"\\SystemRoot\\media\\fonts\\VeraBd.ttf",
64 L"\\SystemRoot\\media\\fonts\\VeraBI.ttf",
65 L"\\SystemRoot\\media\\fonts\\VeraIt.ttf",
66 L"\\SystemRoot\\media\\fonts\\VeraMoBd.ttf",
67 L"\\SystemRoot\\media\\fonts\\VeraMoBI.ttf",
68 L"\\SystemRoot\\media\\fonts\\VeraMoIt.ttf",
69 L"\\SystemRoot\\media\\fonts\\VeraMono.ttf",
70 L"\\SystemRoot\\media\\fonts\\VeraSe.ttf",
71 L"\\SystemRoot\\media\\fonts\\VeraSeBd.ttf"
72 };
73
74 error = FT_Init_FreeType(&library);
75 if(error)
76 {
77 return FALSE;
78 }
79
80 for (File = 0; File < sizeof(FontFiles) / sizeof(WCHAR *); File++)
81 {
82 DPRINT("Loading font %S\n", FontFiles[File]);
83
84 NtGdiAddFontResource(FontFiles[File]);
85 }
86
87 DPRINT("All fonts loaded\n");
88
89 return TRUE;
90 }
91
92 static NTSTATUS STDCALL
93 GetFontObjectsFromTextObj(PTEXTOBJ TextObj, HFONT *FontHandle, PFONTOBJ *FontObj, PFONTGDI *FontGDI)
94 {
95 NTSTATUS Status = STATUS_SUCCESS;
96
97 ASSERT(NULL != TextObj && NULL != TextObj->GDIFontHandle);
98 if (NULL != TextObj && NULL != TextObj->GDIFontHandle)
99 {
100 if (NT_SUCCESS(Status) && NULL != FontHandle)
101 {
102 *FontHandle = TextObj->GDIFontHandle;
103 }
104 if (NT_SUCCESS(Status) && NULL != FontObj)
105 {
106 *FontObj = AccessUserObject((ULONG) TextObj->GDIFontHandle);
107 if (NULL == *FontObj)
108 {
109 ASSERT(FALSE);
110 Status = STATUS_INVALID_HANDLE;
111 }
112 }
113 if (NT_SUCCESS(Status) && NULL != FontGDI)
114 {
115 *FontGDI = AccessInternalObject((ULONG) TextObj->GDIFontHandle);
116 if (NULL == *FontGDI)
117 {
118 ASSERT(FALSE);
119 Status = STATUS_INVALID_HANDLE;
120 }
121 }
122 }
123 else
124 {
125 Status = STATUS_INVALID_HANDLE;
126 }
127
128 return Status;
129 }
130
131 int
132 STDCALL
133 NtGdiAddFontResource(LPCWSTR Filename)
134 {
135 HFONT NewFont;
136 PFONTOBJ FontObj;
137 PFONTGDI FontGDI;
138 UNICODE_STRING uFileName;
139 NTSTATUS Status;
140 HANDLE FileHandle;
141 OBJECT_ATTRIBUTES ObjectAttributes;
142 FILE_STANDARD_INFORMATION FileStdInfo;
143 PVOID buffer;
144 ULONG size;
145 INT error;
146 FT_Face face;
147 ANSI_STRING StringA;
148 UNICODE_STRING StringU;
149 IO_STATUS_BLOCK Iosb;
150
151 NewFont = (HFONT)CreateGDIHandle(sizeof( FONTGDI ), sizeof( FONTOBJ ));
152 FontObj = (PFONTOBJ) AccessUserObject( (ULONG) NewFont );
153 FontGDI = (PFONTGDI) AccessInternalObject( (ULONG) NewFont );
154
155 RtlCreateUnicodeString(&uFileName, (LPWSTR)Filename);
156
157 // Open the Module
158 InitializeObjectAttributes(&ObjectAttributes, &uFileName, 0, NULL, NULL);
159
160 Status = NtOpenFile(&FileHandle, FILE_ALL_ACCESS, &ObjectAttributes, &Iosb, 0, 0);
161
162 if (!NT_SUCCESS(Status))
163 {
164 DPRINT1("Could not open module file: %S\n", Filename);
165 return 0;
166 }
167
168 // Get the size of the file
169 Status = NtQueryInformationFile(FileHandle, &Iosb, &FileStdInfo, sizeof(FileStdInfo), FileStandardInformation);
170 if (!NT_SUCCESS(Status))
171 {
172 DPRINT1("Could not get file size\n");
173 return 0;
174 }
175
176 // Allocate nonpageable memory for driver
177 size = FileStdInfo.EndOfFile.u.LowPart;
178 buffer = ExAllocatePool(NonPagedPool, size);
179
180 if (buffer == NULL)
181 {
182 DPRINT1("could not allocate memory for module");
183 return 0;
184 }
185
186 // Load driver into memory chunk
187 Status = NtReadFile(FileHandle, 0, 0, 0, &Iosb, buffer, FileStdInfo.EndOfFile.u.LowPart, 0, 0);
188 if (!NT_SUCCESS(Status))
189 {
190 DPRINT1("could not read module file into memory");
191 ExFreePool(buffer);
192 return 0;
193 }
194
195 NtClose(FileHandle);
196
197 error = FT_New_Memory_Face(library, buffer, size, 0, &face);
198 if (error == FT_Err_Unknown_File_Format)
199 {
200 DPRINT1("Unknown font file format\n");
201 return 0;
202 }
203 else if (error)
204 {
205 DPRINT1("Error reading font file (error code: %u)\n", error); // 48
206 return 0;
207 }
208
209 // FontGDI->Filename = Filename; perform strcpy
210 FontGDI->face = face;
211
212 // FIXME: Complete text metrics
213 FontGDI->TextMetric.tmAscent = face->size->metrics.ascender; // units above baseline
214 FontGDI->TextMetric.tmDescent = face->size->metrics.descender; // units below baseline
215 FontGDI->TextMetric.tmHeight = FontGDI->TextMetric.tmAscent + FontGDI->TextMetric.tmDescent;
216
217 DPRINT("Font loaded: %s (%s)\n", face->family_name, face->style_name);
218 DPRINT("Num glyphs: %u\n", face->num_glyphs);
219
220 // Add this font resource to the font table
221 FontTable[FontsLoaded].hFont = NewFont;
222
223 RtlInitAnsiString(&StringA, (LPSTR)face->family_name);
224 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
225 FontTable[FontsLoaded].FaceName = ExAllocatePool(NonPagedPool, (StringU.Length + 1) * 2);
226 wcscpy((LPWSTR)FontTable[FontsLoaded].FaceName, StringU.Buffer);
227 RtlFreeUnicodeString(&StringU);
228
229 FontsLoaded++;
230
231 return 1;
232 }
233
234 NTSTATUS FASTCALL
235 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
236 {
237 PTEXTOBJ TextObj;
238 NTSTATUS Status = STATUS_SUCCESS;
239
240 *NewFont = TEXTOBJ_AllocText();
241 if (NULL != *NewFont)
242 {
243 TextObj = TEXTOBJ_LockText(*NewFont);
244 if (NULL != TextObj)
245 {
246 memcpy(&TextObj->logfont, lf, sizeof(LOGFONTW));
247 if (lf->lfEscapement != lf->lfOrientation)
248 {
249 /* this should really depend on whether GM_ADVANCED is set */
250 TextObj->logfont.lfOrientation = TextObj->logfont.lfEscapement;
251 }
252 TEXTOBJ_UnlockText(*NewFont);
253 }
254 else
255 {
256 /* FIXME */
257 /* ASSERT(FALSE);*/
258 Status = STATUS_INVALID_HANDLE;
259 }
260 }
261 else
262 {
263 Status = STATUS_NO_MEMORY;
264 }
265
266 return Status;
267 }
268
269 HFONT
270 STDCALL
271 NtGdiCreateFont(int Height,
272 int Width,
273 int Escapement,
274 int Orientation,
275 int Weight,
276 DWORD Italic,
277 DWORD Underline,
278 DWORD StrikeOut,
279 DWORD CharSet,
280 DWORD OutputPrecision,
281 DWORD ClipPrecision,
282 DWORD Quality,
283 DWORD PitchAndFamily,
284 LPCWSTR Face)
285 {
286 LOGFONTW logfont;
287 HFONT NewFont;
288 NTSTATUS Status = STATUS_SUCCESS;
289
290 logfont.lfHeight = Height;
291 logfont.lfWidth = Width;
292 logfont.lfEscapement = Escapement;
293 logfont.lfOrientation = Orientation;
294 logfont.lfWeight = Weight;
295 logfont.lfItalic = Italic;
296 logfont.lfUnderline = Underline;
297 logfont.lfStrikeOut = StrikeOut;
298 logfont.lfCharSet = CharSet;
299 logfont.lfOutPrecision = OutputPrecision;
300 logfont.lfClipPrecision = ClipPrecision;
301 logfont.lfQuality = Quality;
302 logfont.lfPitchAndFamily = PitchAndFamily;
303
304 if (NULL != Face)
305 {
306 int Size = sizeof(logfont.lfFaceName) / sizeof(WCHAR);
307 wcsncpy((wchar_t *)logfont.lfFaceName, Face, Size - 1);
308 /* Be 101% sure to have '\0' at end of string */
309 logfont.lfFaceName[Size - 1] = '\0';
310 }
311 else
312 {
313 logfont.lfFaceName[0] = L'\0';
314 }
315
316 if (NT_SUCCESS(Status))
317 {
318 Status = TextIntCreateFontIndirect(&logfont, &NewFont);
319 }
320
321 return NT_SUCCESS(Status) ? NewFont : NULL;
322 }
323
324 HFONT
325 STDCALL
326 NtGdiCreateFontIndirect(CONST LPLOGFONTW lf)
327 {
328 LOGFONTW SafeLogfont;
329 HFONT NewFont;
330 NTSTATUS Status = STATUS_SUCCESS;
331
332 if (NULL != lf)
333 {
334 Status = MmCopyFromCaller(&SafeLogfont, lf, sizeof(LOGFONTW));
335 if (NT_SUCCESS(Status))
336 {
337 Status = TextIntCreateFontIndirect(&SafeLogfont, &NewFont);
338 }
339 }
340 else
341 {
342 Status = STATUS_INVALID_PARAMETER;
343 }
344
345 return NT_SUCCESS(Status) ? NewFont : NULL;
346 }
347
348 BOOL
349 STDCALL
350 NtGdiCreateScalableFontResource(DWORD Hidden,
351 LPCWSTR FontRes,
352 LPCWSTR FontFile,
353 LPCWSTR CurrentPath)
354 {
355 UNIMPLEMENTED;
356 }
357
358 int
359 STDCALL
360 NtGdiEnumFontFamilies(HDC hDC,
361 LPCWSTR Family,
362 FONTENUMPROCW EnumFontFamProc,
363 LPARAM lParam)
364 {
365 UNIMPLEMENTED;
366 }
367
368 int
369 STDCALL
370 NtGdiEnumFontFamiliesEx(HDC hDC,
371 LPLOGFONTW Logfont,
372 FONTENUMEXPROCW EnumFontFamExProc,
373 LPARAM lParam,
374 DWORD Flags)
375 {
376 UNIMPLEMENTED;
377 }
378
379 int
380 STDCALL
381 NtGdiEnumFonts(HDC hDC,
382 LPCWSTR FaceName,
383 FONTENUMPROCW FontFunc,
384 LPARAM lParam)
385 {
386 UNIMPLEMENTED;
387 }
388
389 BOOL
390 STDCALL
391 NtGdiExtTextOut(HDC hDC,
392 int X,
393 int Y,
394 UINT Options,
395 CONST LPRECT rc,
396 LPCWSTR String,
397 UINT Count,
398 CONST LPINT Dx)
399 {
400 UNIMPLEMENTED;
401 }
402
403 BOOL
404 STDCALL
405 NtGdiGetAspectRatioFilterEx(HDC hDC,
406 LPSIZE AspectRatio)
407 {
408 UNIMPLEMENTED;
409 }
410
411 BOOL
412 STDCALL
413 NtGdiGetCharABCWidths(HDC hDC,
414 UINT FirstChar,
415 UINT LastChar,
416 LPABC abc)
417 {
418 UNIMPLEMENTED;
419 }
420
421 BOOL
422 STDCALL
423 NtGdiGetCharABCWidthsFloat(HDC hDC,
424 UINT FirstChar,
425 UINT LastChar,
426 LPABCFLOAT abcF)
427 {
428 UNIMPLEMENTED;
429 }
430
431 DWORD
432 STDCALL
433 NtGdiGetCharacterPlacement(HDC hDC,
434 LPCWSTR String,
435 int Count,
436 int MaxExtent,
437 LPGCP_RESULTSW Results,
438 DWORD Flags)
439 {
440 UNIMPLEMENTED;
441 }
442
443 BOOL
444 STDCALL
445 NtGdiGetCharWidth(HDC hDC,
446 UINT FirstChar,
447 UINT LastChar,
448 LPINT Buffer)
449 {
450 UNIMPLEMENTED;
451 }
452
453 BOOL
454 STDCALL
455 NtGdiGetCharWidth32(HDC hDC,
456 UINT FirstChar,
457 UINT LastChar,
458 LPINT Buffer)
459 {
460 UNIMPLEMENTED;
461 }
462
463 BOOL
464 STDCALL
465 NtGdiGetCharWidthFloat(HDC hDC,
466 UINT FirstChar,
467 UINT LastChar,
468 PFLOAT Buffer)
469 {
470 UNIMPLEMENTED;
471 }
472
473 DWORD
474 STDCALL
475 NtGdiGetFontLanguageInfo(HDC hDC)
476 {
477 UNIMPLEMENTED;
478 }
479
480 DWORD
481 STDCALL
482 NtGdiGetGlyphOutline(HDC hDC,
483 UINT Char,
484 UINT Format,
485 LPGLYPHMETRICS gm,
486 DWORD Bufsize,
487 LPVOID Buffer,
488 CONST LPMAT2 mat2)
489 {
490 UNIMPLEMENTED;
491
492
493 }
494
495 DWORD
496 STDCALL
497 NtGdiGetKerningPairs(HDC hDC,
498 DWORD NumPairs,
499 LPKERNINGPAIR krnpair)
500 {
501 UNIMPLEMENTED;
502 }
503
504 UINT
505 STDCALL
506 NtGdiGetOutlineTextMetrics(HDC hDC,
507 UINT Data,
508 LPOUTLINETEXTMETRICW otm)
509 {
510 UNIMPLEMENTED;
511 }
512
513 BOOL
514 STDCALL
515 NtGdiGetRasterizerCaps(LPRASTERIZER_STATUS rs,
516 UINT Size)
517 {
518 UNIMPLEMENTED;
519 }
520
521 UINT
522 STDCALL
523 NtGdiGetTextCharset(HDC hDC)
524 {
525 UNIMPLEMENTED;
526 }
527
528 UINT
529 STDCALL
530 NtGdiGetTextCharsetInfo(HDC hDC,
531 LPFONTSIGNATURE Sig,
532 DWORD Flags)
533 {
534 UNIMPLEMENTED;
535 }
536
537 static BOOL
538 FASTCALL
539 TextIntGetTextExtentPoint(PTEXTOBJ TextObj,
540 LPCWSTR String,
541 int Count,
542 int MaxExtent,
543 LPINT Fit,
544 LPINT Dx,
545 LPSIZE Size)
546 {
547 PFONTGDI FontGDI;
548 FT_Face face;
549 FT_GlyphSlot glyph;
550 INT error, n, glyph_index, i, previous;
551 LONG TotalWidth = 0, MaxHeight = 0;
552 FT_CharMap charmap, found = NULL;
553 BOOL use_kerning;
554
555 GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI);
556 face = FontGDI->face;
557 if (NULL != Fit)
558 {
559 *Fit = 0;
560 }
561
562 if (face->charmap == NULL)
563 {
564 DPRINT("WARNING: No charmap selected!\n");
565 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
566
567 for (n = 0; n < face->num_charmaps; n++)
568 {
569 charmap = face->charmaps[n];
570 DPRINT("found charmap encoding: %u\n", charmap->encoding);
571 if (charmap->encoding != 0)
572 {
573 found = charmap;
574 break;
575 }
576 }
577
578 if (! found)
579 {
580 DPRINT1("WARNING: Could not find desired charmap!\n");
581 }
582
583 error = FT_Set_Charmap(face, found);
584 if (error)
585 {
586 DPRINT1("WARNING: Could not set the charmap!\n");
587 }
588 }
589
590 error = FT_Set_Pixel_Sizes(face,
591 /* FIXME should set character height if neg */
592 (TextObj->logfont.lfHeight < 0 ?
593 - TextObj->logfont.lfHeight :
594 TextObj->logfont.lfHeight),
595 TextObj->logfont.lfWidth);
596 if (error)
597 {
598 DPRINT1("Error in setting pixel sizes: %u\n", error);
599 }
600
601 use_kerning = FT_HAS_KERNING(face);
602 previous = 0;
603
604 for (i = 0; i < Count; i++)
605 {
606 glyph_index = FT_Get_Char_Index(face, *String);
607 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
608 if (error)
609 {
610 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
611 }
612 glyph = face->glyph;
613
614 /* retrieve kerning distance */
615 if (use_kerning && previous && glyph_index)
616 {
617 FT_Vector delta;
618 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
619 TotalWidth += delta.x >> 6;
620 }
621
622 TotalWidth += glyph->advance.x >> 6;
623 if (glyph->format == ft_glyph_format_outline)
624 {
625 error = FT_Render_Glyph(glyph, ft_render_mode_mono);
626 if (error)
627 {
628 DPRINT1("WARNING: Failed to render glyph!\n");
629 }
630
631 if (0 != glyph->bitmap.rows && MaxHeight < (glyph->bitmap.rows - 1))
632 {
633 MaxHeight = glyph->bitmap.rows - 1;
634 }
635 }
636
637 if (TotalWidth <= MaxExtent && NULL != Fit)
638 {
639 *Fit = i + 1;
640 }
641 if (NULL != Dx)
642 {
643 Dx[i] = TotalWidth;
644 }
645
646 previous = glyph_index;
647 String++;
648 }
649
650 Size->cx = TotalWidth;
651 Size->cy = MaxHeight;
652
653 return TRUE;
654 }
655
656 BOOL
657 STDCALL
658 NtGdiGetTextExtentExPoint(HDC hDC,
659 LPCWSTR UnsafeString,
660 int Count,
661 int MaxExtent,
662 LPINT UnsafeFit,
663 LPINT UnsafeDx,
664 LPSIZE UnsafeSize)
665 {
666 PDC dc;
667 LPWSTR String;
668 SIZE Size;
669 NTSTATUS Status;
670 BOOLEAN Result;
671 INT Fit;
672 LPINT Dx;
673 PTEXTOBJ TextObj;
674
675 if (Count < 0)
676 {
677 SetLastWin32Error(ERROR_INVALID_PARAMETER);
678 return FALSE;
679 }
680 if (0 == Count)
681 {
682 Size.cx = 0;
683 Size.cy = 0;
684 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
685 if (! NT_SUCCESS(Status))
686 {
687 SetLastNtError(Status);
688 return FALSE;
689 }
690 return TRUE;
691 }
692
693 String = ExAllocatePool(PagedPool, Count * sizeof(WCHAR));
694 if (NULL == String)
695 {
696 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
697 return FALSE;
698 }
699
700 if (NULL != UnsafeDx)
701 {
702 Dx = ExAllocatePool(PagedPool, Count * sizeof(INT));
703 if (NULL == Dx)
704 {
705 ExFreePool(String);
706 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
707 return FALSE;
708 }
709 }
710 else
711 {
712 Dx = NULL;
713 }
714
715 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
716 if (! NT_SUCCESS(Status))
717 {
718 if (NULL != Dx)
719 {
720 ExFreePool(Dx);
721 }
722 ExFreePool(String);
723 SetLastNtError(Status);
724 return FALSE;
725 }
726
727 dc = DC_LockDc(hDC);
728 if (NULL == dc)
729 {
730 if (NULL != Dx)
731 {
732 ExFreePool(Dx);
733 }
734 ExFreePool(String);
735 SetLastWin32Error(ERROR_INVALID_HANDLE);
736 return FALSE;
737 }
738 TextObj = TEXTOBJ_LockText(dc->w.hFont);
739 DC_UnlockDc(hDC);
740 Result = TextIntGetTextExtentPoint(TextObj, String, Count, MaxExtent,
741 NULL == UnsafeFit ? NULL : &Fit, Dx, &Size);
742 TEXTOBJ_UnlockText(dc->w.hFont);
743
744 ExFreePool(String);
745 if (! Result)
746 {
747 if (NULL != Dx)
748 {
749 ExFreePool(Dx);
750 }
751 return FALSE;
752 }
753
754 if (NULL != UnsafeFit)
755 {
756 Status = MmCopyToCaller(UnsafeFit, &Fit, sizeof(INT));
757 if (! NT_SUCCESS(Status))
758 {
759 if (NULL != Dx)
760 {
761 ExFreePool(Dx);
762 }
763 SetLastNtError(Status);
764 return FALSE;
765 }
766 }
767
768 if (NULL != UnsafeDx)
769 {
770 Status = MmCopyToCaller(UnsafeDx, Dx, Count * sizeof(INT));
771 if (! NT_SUCCESS(Status))
772 {
773 if (NULL != Dx)
774 {
775 ExFreePool(Dx);
776 }
777 SetLastNtError(Status);
778 return FALSE;
779 }
780 }
781 if (NULL != Dx)
782 {
783 ExFreePool(Dx);
784 }
785
786 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
787 if (! NT_SUCCESS(Status))
788 {
789 SetLastNtError(Status);
790 return FALSE;
791 }
792
793 return TRUE;
794 }
795
796 BOOL
797 STDCALL
798 NtGdiGetTextExtentPoint(HDC hDC,
799 LPCWSTR String,
800 int Count,
801 LPSIZE Size)
802 {
803 return NtGdiGetTextExtentExPoint(hDC, String, Count, 0, NULL, NULL, Size);
804 }
805
806 BOOL
807 STDCALL
808 NtGdiGetTextExtentPoint32(HDC hDC,
809 LPCWSTR UnsafeString,
810 int Count,
811 LPSIZE UnsafeSize)
812 {
813 PDC dc;
814 LPWSTR String;
815 SIZE Size;
816 NTSTATUS Status;
817 BOOLEAN Result;
818 PTEXTOBJ TextObj;
819
820 if (Count < 0)
821 {
822 SetLastWin32Error(ERROR_INVALID_PARAMETER);
823 return FALSE;
824 }
825 if (0 == Count)
826 {
827 Size.cx = 0;
828 Size.cy = 0;
829 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
830 if (! NT_SUCCESS(Status))
831 {
832 SetLastNtError(Status);
833 return FALSE;
834 }
835 return TRUE;
836 }
837
838 String = ExAllocatePool(PagedPool, Count * sizeof(WCHAR));
839 if (NULL == String)
840 {
841 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
842 return FALSE;
843 }
844
845 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
846 if (! NT_SUCCESS(Status))
847 {
848 ExFreePool(String);
849 SetLastNtError(Status);
850 return FALSE;
851 }
852
853 dc = DC_LockDc(hDC);
854 if (NULL == dc)
855 {
856 ExFreePool(String);
857 SetLastWin32Error(ERROR_INVALID_HANDLE);
858 return FALSE;
859 }
860 TextObj = TEXTOBJ_LockText(dc->w.hFont);
861 DC_UnlockDc(hDC);
862 Result = TextIntGetTextExtentPoint (
863 TextObj, String, Count, 0, NULL, NULL, &Size);
864 dc = DC_LockDc(hDC);
865 ASSERT(dc); // it succeeded earlier, it should now, too
866 TEXTOBJ_UnlockText(dc->w.hFont);
867 DC_UnlockDc(hDC);
868
869 ExFreePool(String);
870 if (! Result)
871 {
872 return FALSE;
873 }
874
875 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
876 if (! NT_SUCCESS(Status))
877 {
878 SetLastNtError(Status);
879 return FALSE;
880 }
881
882 return TRUE;
883 }
884
885 int
886 STDCALL
887 NtGdiGetTextFace(HDC hDC,
888 int Count,
889 LPWSTR FaceName)
890 {
891 UNIMPLEMENTED;
892 }
893
894 BOOL
895 STDCALL
896 NtGdiGetTextMetrics(HDC hDC,
897 LPTEXTMETRICW tm)
898 {
899 PDC dc;
900 PTEXTOBJ TextObj;
901 PFONTGDI FontGDI;
902 NTSTATUS Status = STATUS_SUCCESS;
903 TEXTMETRICW SafeTm;
904 FT_Face Face;
905 ULONG Error;
906
907 dc = DC_LockDc(hDC);
908 if (NULL == dc || NULL == tm)
909 {
910 Status = STATUS_INVALID_PARAMETER;
911 }
912 else
913 {
914 TextObj = TEXTOBJ_LockText(dc->w.hFont);
915 if (NULL != TextObj)
916 {
917 Status = GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI);
918 if (NT_SUCCESS(Status))
919 {
920 Face = FontGDI->face;
921 Error = FT_Set_Pixel_Sizes(Face,
922 /* FIXME should set character height if neg */
923 (TextObj->logfont.lfHeight < 0 ?
924 - TextObj->logfont.lfHeight :
925 TextObj->logfont.lfHeight),
926 TextObj->logfont.lfWidth);
927 if (0 != Error)
928 {
929 DPRINT1("Error in setting pixel sizes: %u\n", Error);
930 Status = STATUS_UNSUCCESSFUL;
931 }
932 else
933 {
934 memcpy(&SafeTm, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
935 SafeTm.tmAscent = (Face->size->metrics.ascender + 32) / 64; // units above baseline
936 SafeTm.tmDescent = (Face->size->metrics.descender + 32) / 64; // units below baseline
937 SafeTm.tmHeight = (Face->size->metrics.ascender +
938 Face->size->metrics.descender + 32) / 64;
939 Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
940 }
941 }
942 TEXTOBJ_UnlockText(dc->w.hFont);
943 }
944 else
945 {
946 ASSERT(FALSE);
947 Status = STATUS_INVALID_HANDLE;
948 }
949 DC_UnlockDc(hDC);
950 }
951
952 return NT_SUCCESS(Status);
953 }
954
955 BOOL
956 STDCALL
957 NtGdiPolyTextOut(HDC hDC,
958 CONST LPPOLYTEXTW txt,
959 int Count)
960 {
961 UNIMPLEMENTED;
962 }
963
964 BOOL
965 STDCALL
966 NtGdiRemoveFontResource(LPCWSTR FileName)
967 {
968 UNIMPLEMENTED;
969 }
970
971 DWORD
972 STDCALL
973 NtGdiSetMapperFlags(HDC hDC,
974 DWORD Flag)
975 {
976 UNIMPLEMENTED;
977 }
978
979 UINT
980 STDCALL
981 NtGdiSetTextAlign(HDC hDC,
982 UINT Mode)
983 {
984 UINT prevAlign;
985 DC *dc;
986
987 dc = DC_LockDc(hDC);
988 if (!dc)
989 {
990 return 0;
991 }
992 prevAlign = dc->w.textAlign;
993 dc->w.textAlign = Mode;
994 DC_UnlockDc( hDC );
995 return prevAlign;
996 }
997
998 COLORREF
999 STDCALL
1000 NtGdiSetTextColor(HDC hDC,
1001 COLORREF color)
1002 {
1003 COLORREF oldColor;
1004 PDC dc = DC_LockDc(hDC);
1005
1006 if (!dc)
1007 {
1008 return 0x80000000;
1009 }
1010
1011 oldColor = dc->w.textColor;
1012 dc->w.textColor = color;
1013 DC_UnlockDc( hDC );
1014 return oldColor;
1015 }
1016
1017 BOOL
1018 STDCALL
1019 NtGdiSetTextJustification(HDC hDC,
1020 int BreakExtra,
1021 int BreakCount)
1022 {
1023 UNIMPLEMENTED;
1024 }
1025
1026 BOOL
1027 STDCALL
1028 NtGdiTextOut(HDC hDC,
1029 int XStart,
1030 int YStart,
1031 LPCWSTR String,
1032 int Count)
1033 {
1034 // Fixme: Call EngTextOut, which does the real work (calling DrvTextOut where appropriate)
1035
1036 DC *dc = DC_LockDc(hDC);
1037 SURFOBJ *SurfObj = (SURFOBJ*)AccessUserObject((ULONG) dc->Surface);
1038 int error, glyph_index, n, i;
1039 FT_Face face;
1040 FT_GlyphSlot glyph;
1041 ULONG TextLeft, TextTop, pitch, previous;
1042 FT_Bool use_kerning;
1043 RECTL DestRect, MaskRect;
1044 POINTL SourcePoint, BrushOrigin;
1045 HBRUSH hBrush = NULL;
1046 PBRUSHOBJ Brush = NULL;
1047 HBITMAP HSourceGlyph;
1048 PSURFOBJ SourceGlyphSurf;
1049 SIZEL bitSize;
1050 FT_CharMap found = 0, charmap;
1051 INT yoff;
1052 PFONTOBJ FontObj;
1053 PFONTGDI FontGDI;
1054 PTEXTOBJ TextObj;
1055 PPALGDI PalDestGDI;
1056 PXLATEOBJ XlateObj;
1057 ULONG Mode;
1058
1059 if( !dc )
1060 return FALSE;
1061
1062 XStart += dc->w.DCOrgX;
1063 YStart += dc->w.DCOrgY;
1064 TextLeft = XStart;
1065 TextTop = YStart;
1066
1067 TextObj = TEXTOBJ_LockText(dc->w.hFont);
1068
1069 if (! NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, &FontObj, &FontGDI)))
1070 {
1071 goto fail;
1072 }
1073 face = FontGDI->face;
1074
1075 if (face->charmap == NULL)
1076 {
1077 DPRINT("WARNING: No charmap selected!\n");
1078 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
1079
1080 for (n = 0; n < face->num_charmaps; n++)
1081 {
1082 charmap = face->charmaps[n];
1083 DPRINT("found charmap encoding: %u\n", charmap->encoding);
1084 if (charmap->encoding != 0)
1085 {
1086 found = charmap;
1087 break;
1088 }
1089 }
1090 if (!found) DPRINT1("WARNING: Could not find desired charmap!\n");
1091 error = FT_Set_Charmap(face, found);
1092 if (error) DPRINT1("WARNING: Could not set the charmap!\n");
1093 }
1094
1095 error = FT_Set_Pixel_Sizes(face,
1096 /* FIXME should set character height if neg */
1097 (TextObj->logfont.lfHeight < 0 ?
1098 - TextObj->logfont.lfHeight :
1099 TextObj->logfont.lfHeight),
1100 TextObj->logfont.lfWidth);
1101 if(error) {
1102 DPRINT1("Error in setting pixel sizes: %u\n", error);
1103 goto fail;
1104 }
1105
1106 // Create the brush
1107 PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
1108 Mode = PalDestGDI->Mode;
1109 PALETTE_UnlockPalette(dc->w.hPalette);
1110 XlateObj = (PXLATEOBJ)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
1111 hBrush = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
1112 Brush = BRUSHOBJ_LockBrush(hBrush);
1113 EngDeleteXlate(XlateObj);
1114
1115 SourcePoint.x = 0;
1116 SourcePoint.y = 0;
1117 MaskRect.left = 0;
1118 MaskRect.top = 0;
1119 BrushOrigin.x = 0;
1120 BrushOrigin.y = 0;
1121
1122 // Determine the yoff from the dc's w.textAlign
1123 if (dc->w.textAlign & TA_BASELINE) {
1124 yoff = 0;
1125 }
1126 else
1127 if (dc->w.textAlign & TA_BOTTOM) {
1128 yoff = -face->size->metrics.descender / 64;
1129 }
1130 else { // TA_TOP
1131 yoff = face->size->metrics.ascender / 64;
1132 }
1133
1134 use_kerning = FT_HAS_KERNING(face);
1135 previous = 0;
1136
1137 for(i=0; i<Count; i++)
1138 {
1139 glyph_index = FT_Get_Char_Index(face, *String);
1140 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1141 if(error) {
1142 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1143 goto fail;
1144 }
1145 glyph = face->glyph;
1146
1147 // retrieve kerning distance and move pen position
1148 if (use_kerning && previous && glyph_index)
1149 {
1150 FT_Vector delta;
1151 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1152 TextLeft += delta.x >> 6;
1153 }
1154
1155 if (glyph->format == ft_glyph_format_outline)
1156 {
1157 error = FT_Render_Glyph(glyph, ft_render_mode_mono);
1158 if(error) {
1159 DPRINT1("WARNING: Failed to render glyph!\n");
1160 goto fail;
1161 }
1162 pitch = glyph->bitmap.pitch;
1163 } else {
1164 pitch = glyph->bitmap.width;
1165 }
1166
1167 DestRect.left = TextLeft;
1168 DestRect.top = TextTop + yoff - glyph->bitmap_top;
1169 DestRect.right = TextLeft + glyph->bitmap.width;
1170 DestRect.bottom = DestRect.top + glyph->bitmap.rows;
1171 bitSize.cx = pitch;
1172 bitSize.cy = glyph->bitmap.rows;
1173 MaskRect.right = glyph->bitmap.width;
1174 MaskRect.bottom = glyph->bitmap.rows;
1175
1176 // We should create the bitmap out of the loop at the biggest possible glyph size
1177 // Then use memset with 0 to clear it and sourcerect to limit the work of the transbitblt
1178
1179 HSourceGlyph = EngCreateBitmap(bitSize, pitch, BMF_1BPP, 0, glyph->bitmap.buffer);
1180 SourceGlyphSurf = (PSURFOBJ)AccessUserObject((ULONG) HSourceGlyph);
1181
1182 // Use the font data as a mask to paint onto the DCs surface using a brush
1183 IntEngBitBlt (
1184 SurfObj,
1185 NULL,
1186 SourceGlyphSurf,
1187 dc->CombinedClip,
1188 NULL,
1189 &DestRect,
1190 &SourcePoint,
1191 (PPOINTL)&MaskRect,
1192 Brush,
1193 &BrushOrigin,
1194 0xAACC );
1195
1196 EngDeleteSurface(HSourceGlyph);
1197
1198 TextLeft += glyph->advance.x >> 6;
1199 previous = glyph_index;
1200
1201 String++;
1202 }
1203 TEXTOBJ_UnlockText( dc->w.hFont );
1204 BRUSHOBJ_UnlockBrush(hBrush);
1205 NtGdiDeleteObject( hBrush );
1206 DC_UnlockDc( hDC );
1207 return TRUE;
1208
1209 fail:
1210 TEXTOBJ_UnlockText( dc->w.hFont );
1211 if( hBrush ){
1212 BRUSHOBJ_UnlockBrush(hBrush);
1213 NtGdiDeleteObject( hBrush );
1214 }
1215 DC_UnlockDc( hDC );
1216 return FALSE;
1217 }
1218
1219 UINT
1220 STDCALL
1221 NtGdiTranslateCharsetInfo(PDWORD Src,
1222 LPCHARSETINFO CSI,
1223 DWORD Flags)
1224 {
1225 UNIMPLEMENTED;
1226 }
1227
1228 NTSTATUS FASTCALL
1229 TextIntRealizeFont(HFONT FontHandle)
1230 {
1231 LONG i;
1232 NTSTATUS Status = STATUS_SUCCESS;
1233 PTEXTOBJ TextObj;
1234
1235 TextObj = TEXTOBJ_LockText(FontHandle);
1236 ASSERT(TextObj);
1237 if (NULL != TextObj)
1238 {
1239 for(i = 0; NULL == TextObj->GDIFontHandle && i < FontsLoaded; i++)
1240 {
1241 if (0 == wcscmp(FontTable[i].FaceName, TextObj->logfont.lfFaceName))
1242 {
1243 TextObj->GDIFontHandle = FontTable[i].hFont;
1244 }
1245 }
1246
1247 if (NULL == TextObj->GDIFontHandle)
1248 {
1249 if (0 != FontsLoaded)
1250 {
1251 DPRINT("Requested font %S not found, using first available font\n",
1252 TextObj->logfont.lfFaceName)
1253 TextObj->GDIFontHandle = FontTable[0].hFont;
1254 }
1255 else
1256 {
1257 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
1258 TextObj->logfont.lfFaceName)
1259 Status = STATUS_NOT_FOUND;
1260 }
1261 }
1262
1263 ASSERT(! NT_SUCCESS(Status) || NULL != TextObj->GDIFontHandle);
1264
1265 TEXTOBJ_UnlockText(FontHandle);
1266 }
1267 else
1268 {
1269 Status = STATUS_INVALID_HANDLE;
1270 }
1271
1272 return Status;
1273 }
1274
1275 /* EOF */