0950c5d282d4dd3f7309d814f39aaa057c9e413c
[reactos.git] / 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$ */
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 + 32) / 64; // units above baseline
214   FontGDI->TextMetric.tmDescent = (- face->size->metrics.descender + 32) / 64; // 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 = SafeTm.tmAscent + SafeTm.tmDescent;
938           Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
939           }
940       }
941       TEXTOBJ_UnlockText(dc->w.hFont);
942     }
943     else
944     {
945       ASSERT(FALSE);
946       Status = STATUS_INVALID_HANDLE;
947     }
948     DC_UnlockDc(hDC);
949   }
950
951   return NT_SUCCESS(Status);
952 }
953
954 BOOL
955 STDCALL
956 NtGdiPolyTextOut(HDC  hDC,
957                       CONST LPPOLYTEXTW  txt,
958                       int  Count)
959 {
960   UNIMPLEMENTED;
961 }
962
963 BOOL
964 STDCALL
965 NtGdiRemoveFontResource(LPCWSTR  FileName)
966 {
967   UNIMPLEMENTED;
968 }
969
970 DWORD
971 STDCALL
972 NtGdiSetMapperFlags(HDC  hDC,
973                           DWORD  Flag)
974 {
975   UNIMPLEMENTED;
976 }
977
978 UINT
979 STDCALL
980 NtGdiSetTextAlign(HDC  hDC,
981                        UINT  Mode)
982 {
983   UINT prevAlign;
984   DC *dc;
985
986   dc = DC_LockDc(hDC);
987   if (!dc)
988     {
989       return  0;
990     }
991   prevAlign = dc->w.textAlign;
992   dc->w.textAlign = Mode;
993   DC_UnlockDc( hDC );
994   return  prevAlign;
995 }
996
997 COLORREF
998 STDCALL
999 NtGdiSetTextColor(HDC hDC,
1000                  COLORREF color)
1001 {
1002   COLORREF  oldColor;
1003   PDC  dc = DC_LockDc(hDC);
1004
1005   if (!dc)
1006   {
1007     return 0x80000000;
1008   }
1009
1010   oldColor = dc->w.textColor;
1011   dc->w.textColor = color;
1012   DC_UnlockDc( hDC );
1013   return  oldColor;
1014 }
1015
1016 BOOL
1017 STDCALL
1018 NtGdiSetTextJustification(HDC  hDC,
1019                                int  BreakExtra,
1020                                int  BreakCount)
1021 {
1022   UNIMPLEMENTED;
1023 }
1024
1025 BOOL
1026 STDCALL
1027 NtGdiTextOut(HDC  hDC,
1028                   int  XStart,
1029                   int  YStart,
1030                   LPCWSTR  String,
1031                   int  Count)
1032 {
1033   // Fixme: Call EngTextOut, which does the real work (calling DrvTextOut where appropriate)
1034
1035   DC *dc = DC_LockDc(hDC);
1036   SURFOBJ *SurfObj;
1037   int error, glyph_index, n, i;
1038   FT_Face face;
1039   FT_GlyphSlot glyph;
1040   ULONG TextLeft, TextTop, pitch, previous, BackgroundLeft;
1041   FT_Bool use_kerning;
1042   RECTL DestRect, MaskRect;
1043   POINTL SourcePoint, BrushOrigin;
1044   HBRUSH hBrushFg = NULL;
1045   PBRUSHOBJ BrushFg = NULL;
1046   HBRUSH hBrushBg = NULL;
1047   PBRUSHOBJ BrushBg = NULL;
1048   HBITMAP HSourceGlyph;
1049   PSURFOBJ SourceGlyphSurf;
1050   SIZEL bitSize;
1051   FT_CharMap found = 0, charmap;
1052   INT yoff;
1053   PFONTOBJ FontObj;
1054   PFONTGDI FontGDI;
1055   PTEXTOBJ TextObj;
1056   PPALGDI PalDestGDI;
1057   PXLATEOBJ XlateObj;
1058   ULONG Mode;
1059
1060   if( !dc )
1061         return FALSE;
1062   SurfObj = (SURFOBJ*)AccessUserObject((ULONG) dc->Surface);
1063
1064   XStart += dc->w.DCOrgX;
1065   YStart += dc->w.DCOrgY;
1066   TextLeft = XStart;
1067   TextTop = YStart;
1068   BackgroundLeft = XStart;
1069
1070   TextObj = TEXTOBJ_LockText(dc->w.hFont);
1071
1072   if (! NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, &FontObj, &FontGDI)))
1073   {
1074     goto fail;
1075   }
1076   face = FontGDI->face;
1077
1078   if (face->charmap == NULL)
1079   {
1080     DPRINT("WARNING: No charmap selected!\n");
1081     DPRINT("This font face has %d charmaps\n", face->num_charmaps);
1082
1083     for (n = 0; n < face->num_charmaps; n++)
1084     {
1085       charmap = face->charmaps[n];
1086       DPRINT("found charmap encoding: %u\n", charmap->encoding);
1087       if (charmap->encoding != 0)
1088       {
1089         found = charmap;
1090         break;
1091       }
1092     }
1093     if (!found) DPRINT1("WARNING: Could not find desired charmap!\n");
1094     error = FT_Set_Charmap(face, found);
1095     if (error) DPRINT1("WARNING: Could not set the charmap!\n");
1096   }
1097
1098   error = FT_Set_Pixel_Sizes(face,
1099                              /* FIXME should set character height if neg */
1100                              (TextObj->logfont.lfHeight < 0 ?
1101                               - TextObj->logfont.lfHeight :
1102                               TextObj->logfont.lfHeight),
1103                              TextObj->logfont.lfWidth);
1104   if(error) {
1105     DPRINT1("Error in setting pixel sizes: %u\n", error);
1106         goto fail;
1107   }
1108
1109   // Create the brushes
1110   PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
1111   Mode = PalDestGDI->Mode;
1112   PALETTE_UnlockPalette(dc->w.hPalette);
1113   XlateObj = (PXLATEOBJ)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
1114   hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
1115   BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
1116   if (OPAQUE == dc->w.backgroundMode)
1117     {
1118       hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor));
1119       BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
1120     }
1121   EngDeleteXlate(XlateObj);
1122
1123   SourcePoint.x = 0;
1124   SourcePoint.y = 0;
1125   MaskRect.left = 0;
1126   MaskRect.top = 0;
1127   BrushOrigin.x = 0;
1128   BrushOrigin.y = 0;
1129
1130   // Determine the yoff from the dc's w.textAlign
1131   if (dc->w.textAlign & TA_BASELINE) {
1132     yoff = 0;
1133   }
1134   else
1135   if (dc->w.textAlign & TA_BOTTOM) {
1136     yoff = -face->size->metrics.descender / 64;
1137   }
1138   else { // TA_TOP
1139     yoff = face->size->metrics.ascender / 64;
1140   }
1141
1142   use_kerning = FT_HAS_KERNING(face);
1143   previous = 0;
1144
1145   for(i=0; i<Count; i++)
1146   {
1147     glyph_index = FT_Get_Char_Index(face, *String);
1148     error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1149     if(error) {
1150       DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1151       goto fail;
1152     }
1153     glyph = face->glyph;
1154
1155     // retrieve kerning distance and move pen position
1156     if (use_kerning && previous && glyph_index)
1157     {
1158       FT_Vector delta;
1159       FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1160       TextLeft += delta.x >> 6;
1161     }
1162
1163     if (glyph->format == ft_glyph_format_outline)
1164     {
1165       error = FT_Render_Glyph(glyph, ft_render_mode_mono);
1166       if(error) {
1167         DPRINT1("WARNING: Failed to render glyph!\n");
1168                 goto fail;
1169       }
1170       pitch = glyph->bitmap.pitch;
1171     } else {
1172       pitch = glyph->bitmap.width;
1173     }
1174
1175     if (OPAQUE == dc->w.backgroundMode)
1176       {
1177         DestRect.left = BackgroundLeft;
1178         DestRect.right = TextLeft + (glyph->advance.x + 32) / 64;
1179         DestRect.top = TextTop + yoff - (face->size->metrics.ascender + 32) / 64;
1180         DestRect.bottom = TextTop + yoff + (- face->size->metrics.descender + 32) / 64;
1181         IntEngBitBlt(SurfObj,
1182                      NULL,
1183                      NULL,
1184                      dc->CombinedClip,
1185                      NULL,
1186                      &DestRect,
1187                      &SourcePoint,
1188                      &SourcePoint,
1189                      BrushBg,
1190                      &BrushOrigin,
1191                      PATCOPY);
1192         BackgroundLeft = DestRect.right;
1193       }
1194
1195     DestRect.left = TextLeft;
1196     DestRect.right = TextLeft + glyph->bitmap.width;
1197     DestRect.top = TextTop + yoff - glyph->bitmap_top;
1198     DestRect.bottom = DestRect.top + glyph->bitmap.rows;
1199         
1200     bitSize.cx = glyph->bitmap.width;
1201     bitSize.cy = glyph->bitmap.rows;
1202     MaskRect.right = glyph->bitmap.width;
1203     MaskRect.bottom = glyph->bitmap.rows;
1204
1205     // We should create the bitmap out of the loop at the biggest possible glyph size
1206     // Then use memset with 0 to clear it and sourcerect to limit the work of the transbitblt
1207
1208     HSourceGlyph = EngCreateBitmap(bitSize, pitch, BMF_1BPP, 0, glyph->bitmap.buffer);
1209     SourceGlyphSurf = (PSURFOBJ)AccessUserObject((ULONG) HSourceGlyph);
1210
1211     // Use the font data as a mask to paint onto the DCs surface using a brush
1212     IntEngBitBlt (
1213                 SurfObj,
1214                 NULL,
1215                 SourceGlyphSurf,
1216                 dc->CombinedClip,
1217                 NULL,
1218                 &DestRect,
1219                 &SourcePoint,
1220                 (PPOINTL)&MaskRect,
1221                 BrushFg,
1222                 &BrushOrigin,
1223                 0xAACC );
1224
1225     EngDeleteSurface(HSourceGlyph);
1226
1227     TextLeft += (glyph->advance.x + 32) / 64;
1228     previous = glyph_index;
1229
1230     String++;
1231   }
1232   TEXTOBJ_UnlockText(dc->w.hFont);
1233   if (NULL != hBrushBg)
1234     {
1235       BRUSHOBJ_UnlockBrush(hBrushBg);
1236       NtGdiDeleteObject(hBrushBg);
1237     }
1238   BRUSHOBJ_UnlockBrush(hBrushFg);
1239   NtGdiDeleteObject(hBrushFg);
1240   DC_UnlockDc(hDC);
1241   return TRUE;
1242
1243 fail:
1244   TEXTOBJ_UnlockText( dc->w.hFont );
1245   if (NULL != hBrushBg)
1246     {
1247       BRUSHOBJ_UnlockBrush(hBrushBg);
1248       NtGdiDeleteObject(hBrushBg);
1249     }
1250   if (NULL != hBrushFg)
1251     {
1252       BRUSHOBJ_UnlockBrush(hBrushFg);
1253       NtGdiDeleteObject(hBrushFg);
1254     }
1255   DC_UnlockDc( hDC );
1256   return FALSE;
1257 }
1258
1259 UINT
1260 STDCALL
1261 NtGdiTranslateCharsetInfo(PDWORD  Src,
1262                                LPCHARSETINFO  CSI,
1263                                DWORD  Flags)
1264 {
1265   UNIMPLEMENTED;
1266 }
1267
1268 NTSTATUS FASTCALL
1269 TextIntRealizeFont(HFONT FontHandle)
1270 {
1271   LONG i;
1272   NTSTATUS Status = STATUS_SUCCESS;
1273   PTEXTOBJ TextObj;
1274
1275   TextObj = TEXTOBJ_LockText(FontHandle);
1276   ASSERT(TextObj);
1277   if (NULL != TextObj)
1278     {
1279     for(i = 0; NULL == TextObj->GDIFontHandle && i < FontsLoaded; i++)
1280     {
1281       if (0 == wcscmp(FontTable[i].FaceName, TextObj->logfont.lfFaceName))
1282       {
1283         TextObj->GDIFontHandle = FontTable[i].hFont;
1284       }
1285     }
1286
1287     if (NULL == TextObj->GDIFontHandle)
1288     {
1289       if (0 != FontsLoaded)
1290       {
1291         DPRINT("Requested font %S not found, using first available font\n",
1292                TextObj->logfont.lfFaceName)
1293         TextObj->GDIFontHandle = FontTable[0].hFont;
1294       }
1295       else
1296       {
1297         DPRINT1("Requested font %S not found, no fonts loaded at all\n",
1298                 TextObj->logfont.lfFaceName)
1299         Status = STATUS_NOT_FOUND;
1300       }
1301     }
1302
1303     ASSERT(! NT_SUCCESS(Status) || NULL != TextObj->GDIFontHandle);
1304
1305     TEXTOBJ_UnlockText(FontHandle);
1306   }
1307   else
1308   {
1309     Status = STATUS_INVALID_HANDLE;
1310   }
1311
1312   return Status;
1313 }
1314
1315 /* EOF */