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